Merge in Debian changes from Debian packages 3.0.5-beta-3 and 3.0.6-1.
[privoxy.git] / parsers.c
1 const char parsers_rcs[] = "$Id: parsers.c,v 1.76 2006/12/06 19:52:25 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/parsers.c,v $
5  *
6  * Purpose     :  Declares functions to parse/crunch headers and pages.
7  *                Functions declared include:
8  *                   `add_to_iob', `client_cookie_adder', `client_from',
9  *                   `client_referrer', `client_send_cookie', `client_ua',
10  *                   `client_uagent', `client_x_forwarded',
11  *                   `client_x_forwarded_adder', `client_xtra_adder',
12  *                   `content_type', `crumble', `destroy_list', `enlist',
13  *                   `flush_socket', ``get_header', `sed', `filter_server_header'
14  *                   `filter_client_header', `filter_header', `crunch_server_header',
15  *                   `server_content_encoding', `server_content_disposition',
16  *                   `server_last_modified', `client_accept_language',
17  *                   `crunch_client_header', `client_if_modified_since',
18  *                   `client_if_none_match', `get_destination_from_headers',
19  *                   `parse_header_time' and `server_set_cookie'.
20  *
21  * Copyright   :  Written by and Copyright (C) 2001-2006 the SourceForge
22  *                Privoxy team. http://www.privoxy.org/
23  *
24  *                Based on the Internet Junkbuster originally written
25  *                by and Copyright (C) 1997 Anonymous Coders and
26  *                Junkbusters Corporation.  http://www.junkbusters.com
27  *
28  *                This program is free software; you can redistribute it
29  *                and/or modify it under the terms of the GNU General
30  *                Public License as published by the Free Software
31  *                Foundation; either version 2 of the License, or (at
32  *                your option) any later version.
33  *
34  *                This program is distributed in the hope that it will
35  *                be useful, but WITHOUT ANY WARRANTY; without even the
36  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
37  *                PARTICULAR PURPOSE.  See the GNU General Public
38  *                License for more details.
39  *
40  *                The GNU General Public License should be included with
41  *                this file.  If not, you can view it at
42  *                http://www.gnu.org/copyleft/gpl.html
43  *                or write to the Free Software Foundation, Inc., 59
44  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
45  *
46  * Revisions   :
47  *    $Log: parsers.c,v $
48  *    Revision 1.76  2006/12/06 19:52:25  fabiankeil
49  *    Added get_destination_from_headers().
50  *
51  *    Revision 1.75  2006/11/13 19:05:51  fabiankeil
52  *    Make pthread mutex locking more generic. Instead of
53  *    checking for OSX and OpenBSD, check for FEATURE_PTHREAD
54  *    and use mutex locking unless there is an _r function
55  *    available. Better safe than sorry.
56  *
57  *    Fixes "./configure --disable-pthread" and should result
58  *    in less threading-related problems on pthread-using platforms,
59  *    but it still doesn't fix BR#1122404.
60  *
61  *    Revision 1.74  2006/10/02 16:59:12  fabiankeil
62  *    The special header "X-Filter: No" now disables
63  *    header filtering as well.
64  *
65  *    Revision 1.73  2006/09/23 13:26:38  roro
66  *    Replace TABs by spaces in source code.
67  *
68  *    Revision 1.72  2006/09/23 12:37:21  fabiankeil
69  *    Don't print a log message every time filter_headers is
70  *    entered or left. It only creates noise without any real
71  *    information.
72  *
73  *    Revision 1.71  2006/09/21 19:55:17  fabiankeil
74  *    Fix +hide-if-modified-since{-n}.
75  *
76  *    Revision 1.70  2006/09/08 12:06:34  fabiankeil
77  *    Have hide-if-modified-since interpret the random
78  *    range value as minutes instead of hours. Allows
79  *    more fine-grained configuration.
80  *
81  *    Revision 1.69  2006/09/06 16:25:51  fabiankeil
82  *    Always have parse_header_time return a pointer
83  *    that actual makes sense, even though we currently
84  *    only need it to detect problems.
85  *
86  *    Revision 1.68  2006/09/06 10:43:32  fabiankeil
87  *    Added config option enable-remote-http-toggle
88  *    to specify if Privoxy should recognize special
89  *    headers (currently only X-Filter) to change its
90  *    behaviour. Disabled by default.
91  *
92  *    Revision 1.67  2006/09/04 11:01:26  fabiankeil
93  *    After filtering de-chunked instances, remove
94  *    "Transfer-Encoding" header entirely instead of changing
95  *    it to "Transfer-Encoding: identity", which is invalid.
96  *    Thanks Michael Shields <shields@msrl.com>. Fixes PR 1318658.
97  *
98  *    Don't use localtime in parse_header_time. An empty time struct
99  *    is good enough, it gets overwritten by strptime anyway.
100  *
101  *    Revision 1.66  2006/09/03 19:38:28  fabiankeil
102  *    Use gmtime_r if available, fallback to gmtime with mutex
103  *    protection for MacOSX and use vanilla gmtime for the rest.
104  *
105  *    Revision 1.65  2006/08/22 10:55:56  fabiankeil
106  *    Changed client_referrer to use the right type (size_t) for
107  *    hostlenght and to shorten the temporary referrer string with
108  *    '\0' instead of adding a useless line break.
109  *
110  *    Revision 1.64  2006/08/17 17:15:10  fabiankeil
111  *    - Back to timegm() using GnuPG's replacement if necessary.
112  *      Using mktime() and localtime() could add a on hour offset if
113  *      the randomize factor was big enough to lead to a summer/wintertime
114  *      switch.
115  *
116  *    - Removed now-useless Privoxy 3.0.3 compatibility glue.
117  *
118  *    - Moved randomization code into pick_from_range().
119  *
120  *    - Changed parse_header_time definition.
121  *      time_t isn't guaranteed to be signed and
122  *      if it isn't, -1 isn't available as error code.
123  *      Changed some variable types in client_if_modified_since()
124  *      because of the same reason.
125  *
126  *    Revision 1.63  2006/08/14 13:18:08  david__schmidt
127  *    OS/2 compilation compatibility fixups
128  *
129  *    Revision 1.62  2006/08/14 08:58:42  fabiankeil
130  *    Changed include from strptime.c to strptime.h
131  *
132  *    Revision 1.61  2006/08/14 08:25:19  fabiankeil
133  *    Split filter-headers{} into filter-client-headers{}
134  *    and filter-server-headers{}.
135  *    Added parse_header_time() to share some code.
136  *    Replaced timegm() with mktime().
137  *
138  *    Revision 1.60  2006/08/12 03:54:37  david__schmidt
139  *    Windows service integration
140  *
141  *    Revision 1.59  2006/08/03 02:46:41  david__schmidt
142  *    Incorporate Fabian Keil's patch work:\rhttp://www.fabiankeil.de/sourcecode/privoxy/
143  *
144  *    Revision 1.58  2006/07/18 14:48:47  david__schmidt
145  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
146  *    with what was really the latest development (the v_3_0_branch branch)
147  *
148  *    Revision 1.56.2.10  2006/01/21 16:16:08  david__schmidt
149  *    Thanks to  Edward Carrel for his patch to modernize OSX's\rpthreads support.  See bug #1409623.
150  *
151  *    Revision 1.56.2.9  2004/10/03 12:53:45  david__schmidt
152  *    Add the ability to check jpeg images for invalid
153  *    lengths of comment blocks.  Defensive strategy
154  *    against the exploit:
155  *       Microsoft Security Bulletin MS04-028
156  *       Buffer Overrun in JPEG Processing (GDI+) Could
157  *       Allow Code Execution (833987)
158  *    Enabled with +inspect-jpegs in actions files.
159  *
160  *    Revision 1.56.2.8  2003/07/11 13:21:25  oes
161  *    Excluded text/plain objects from filtering. This fixes a
162  *    couple of client-crashing, download corruption and
163  *    Privoxy performance issues, whose root cause lies in
164  *    web servers labelling content of unknown type as text/plain.
165  *
166  *    Revision 1.56.2.7  2003/05/06 12:07:26  oes
167  *    Fixed bug #729900: Suspicious HOST: headers are now killed and regenerated if necessary
168  *
169  *    Revision 1.56.2.6  2003/04/14 21:28:30  oes
170  *    Completing the previous change
171  *
172  *    Revision 1.56.2.5  2003/04/14 12:08:16  oes
173  *    Added temporary workaround for bug in PHP < 4.2.3
174  *
175  *    Revision 1.56.2.4  2003/03/07 03:41:05  david__schmidt
176  *    Wrapping all *_r functions (the non-_r versions of them) with mutex semaphores for OSX.  Hopefully this will take care of all of those pesky crash reports.
177  *
178  *    Revision 1.56.2.3  2002/11/10 04:20:02  hal9
179  *    Fix typo: supressed -> suppressed
180  *
181  *    Revision 1.56.2.2  2002/09/25 14:59:53  oes
182  *    Improved cookie logging
183  *
184  *    Revision 1.56.2.1  2002/09/25 14:52:45  oes
185  *    Added basic support for OPTIONS and TRACE HTTP methods:
186  *     - New parser function client_max_forwards which decrements
187  *       the Max-Forwards HTTP header field of OPTIONS and TRACE
188  *       requests by one before forwarding
189  *     - New parser function client_host which extracts the host
190  *       and port information from the HTTP header field if the
191  *       request URI was not absolute
192  *     - Don't crumble and re-add the Host: header, but only generate
193  *       and append if missing
194  *
195  *    Revision 1.56  2002/05/12 15:34:22  jongfoster
196  *    Fixing typo in a comment
197  *
198  *    Revision 1.55  2002/05/08 16:01:07  oes
199  *    Optimized add_to_iob:
200  *     - Use realloc instead of malloc(), memcpy(), free()
201  *     - Expand to powers of two if possible, to get
202  *       O(log n) reallocs instead of O(n).
203  *     - Moved check for buffer limit here from chat
204  *     - Report failure via returncode
205  *
206  *    Revision 1.54  2002/04/02 15:03:16  oes
207  *    Tiny code cosmetics
208  *
209  *    Revision 1.53  2002/03/26 22:29:55  swa
210  *    we have a new homepage!
211  *
212  *    Revision 1.52  2002/03/24 13:25:43  swa
213  *    name change related issues
214  *
215  *    Revision 1.51  2002/03/13 00:27:05  jongfoster
216  *    Killing warnings
217  *
218  *    Revision 1.50  2002/03/12 01:45:35  oes
219  *    More verbose logging
220  *
221  *    Revision 1.49  2002/03/09 20:03:52  jongfoster
222  *    - Making various functions return int rather than size_t.
223  *      (Undoing a recent change).  Since size_t is unsigned on
224  *      Windows, functions like read_socket that return -1 on
225  *      error cannot return a size_t.
226  *
227  *      THIS WAS A MAJOR BUG - it caused frequent, unpredictable
228  *      crashes, and also frequently caused JB to jump to 100%
229  *      CPU and stay there.  (Because it thought it had just
230  *      read ((unsigned)-1) == 4Gb of data...)
231  *
232  *    - The signature of write_socket has changed, it now simply
233  *      returns success=0/failure=nonzero.
234  *
235  *    - Trying to get rid of a few warnings --with-debug on
236  *      Windows, I've introduced a new type "jb_socket".  This is
237  *      used for the socket file descriptors.  On Windows, this
238  *      is SOCKET (a typedef for unsigned).  Everywhere else, it's
239  *      an int.  The error value can't be -1 any more, so it's
240  *      now JB_INVALID_SOCKET (which is -1 on UNIX, and in
241  *      Windows it maps to the #define INVALID_SOCKET.)
242  *
243  *    - The signature of bind_port has changed.
244  *
245  *    Revision 1.48  2002/03/07 03:46:53  oes
246  *    Fixed compiler warnings etc
247  *
248  *    Revision 1.47  2002/02/20 23:15:13  jongfoster
249  *    Parsing functions now handle out-of-memory gracefully by returning
250  *    an error code.
251  *
252  *    Revision 1.46  2002/01/17 21:03:47  jongfoster
253  *    Moving all our URL and URL pattern parsing code to urlmatch.c.
254  *
255  *    Revision 1.45  2002/01/09 14:33:03  oes
256  *    Added support for localtime_r.
257  *
258  *    Revision 1.44  2001/12/14 01:22:54  steudten
259  *    Remove 'user:pass@' from 'proto://user:pass@host' for the
260  *    new added header 'Host: ..'. (See Req ID 491818)
261  *
262  *    Revision 1.43  2001/11/23 00:26:38  jongfoster
263  *    Fixing two really stupid errors in my previous commit
264  *
265  *    Revision 1.42  2001/11/22 21:59:30  jongfoster
266  *    Adding code to handle +no-cookies-keep
267  *
268  *    Revision 1.41  2001/11/05 23:43:05  steudten
269  *    Add time+date to log files.
270  *
271  *    Revision 1.40  2001/10/26 20:13:09  jongfoster
272  *    ctype.h is needed in Windows, too.
273  *
274  *    Revision 1.39  2001/10/26 17:40:04  oes
275  *    Introduced get_header_value()
276  *    Removed http->user_agent, csp->referrer and csp->accept_types
277  *    Removed client_accept()
278  *
279  *    Revision 1.38  2001/10/25 03:40:48  david__schmidt
280  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
281  *    threads to call select() simultaneously.  So, it's time to do a real, live,
282  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
283  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
284  *
285  *    Revision 1.37  2001/10/23 21:36:02  jongfoster
286  *    Documenting sed()'s error behaviou (doc change only)
287  *
288  *    Revision 1.36  2001/10/13 12:51:51  joergs
289  *    Removed client_host, (was only required for the old 2.0.2-11 http://noijb.
290  *    force-load), instead crumble Host: and add it (again) in client_host_adder
291  *    (in case we get a HTTP/1.0 request without Host: header and forward it to
292  *    a HTTP/1.1 server/proxy).
293  *
294  *    Revision 1.35  2001/10/09 22:39:21  jongfoster
295  *    assert.h is also required under Win32, so moving out of #ifndef _WIN32
296  *    block.
297  *
298  *    Revision 1.34  2001/10/07 18:50:55  oes
299  *    Added server_content_encoding, renamed server_transfer_encoding
300  *
301  *    Revision 1.33  2001/10/07 18:04:49  oes
302  *    Changed server_http11 to server_http and its pattern to "HTTP".
303  *      Additional functionality: it now saves the HTTP status into
304  *      csp->http->status and sets CT_TABOO for Status 206 (partial range)
305  *
306  *    Revision 1.32  2001/10/07 15:43:28  oes
307  *    Removed FEATURE_DENY_GZIP and replaced it with client_accept_encoding,
308  *       client_te and client_accept_encoding_adder, triggered by the new
309  *       +no-compression action. For HTTP/1.1 the Accept-Encoding header is
310  *       changed to allow only identity and chunked, and the TE header is
311  *       crunched. For HTTP/1.0, Accept-Encoding is crunched.
312  *
313  *    parse_http_request no longer does anything than parsing. The rewriting
314  *      of http->cmd and version mangling are gone. It now also recognizes
315  *      the put and delete methods and saves the url in http->url. Removed
316  *      unused variable.
317  *
318  *    renamed content_type and content_length to have the server_ prefix
319  *
320  *    server_content_type now only works if csp->content_type != CT_TABOO
321  *
322  *    added server_transfer_encoding, which
323  *      - Sets CT_TABOO to prohibit filtering if encoding compresses
324  *      - Raises the CSP_FLAG_CHUNKED flag if Encoding is "chunked"
325  *      - Change from "chunked" to "identity" if body was chunked
326  *        but has been de-chunked for filtering.
327  *
328  *    added server_content_md5 which crunches any Content-MD5 headers
329  *      if the body was modified.
330  *
331  *    made server_http11 conditional on +downgrade action
332  *
333  *    Replaced 6 boolean members of csp with one bitmap (csp->flags)
334  *
335  *    Revision 1.31  2001/10/05 14:25:02  oes
336  *    Crumble Keep-Alive from Server
337  *
338  *    Revision 1.30  2001/09/29 12:56:03  joergs
339  *    IJB now changes HTTP/1.1 to HTTP/1.0 in requests and answers.
340  *
341  *    Revision 1.29  2001/09/24 21:09:24  jongfoster
342  *    Fixing 2 memory leaks that Guy spotted, where the paramater to
343  *    enlist() was not being free()d.
344  *
345  *    Revision 1.28  2001/09/22 16:32:28  jongfoster
346  *    Removing unused #includes.
347  *
348  *    Revision 1.27  2001/09/20 15:45:25  steudten
349  *
350  *    add casting from size_t to int for printf()
351  *    remove local variable shadow s2
352  *
353  *    Revision 1.26  2001/09/16 17:05:14  jongfoster
354  *    Removing unused #include showarg.h
355  *
356  *    Revision 1.25  2001/09/16 13:21:27  jongfoster
357  *    Changes to use new list functions.
358  *
359  *    Revision 1.24  2001/09/13 23:05:50  jongfoster
360  *    Changing the string paramater to the header parsers a "const".
361  *
362  *    Revision 1.23  2001/09/12 18:08:19  steudten
363  *
364  *    In parse_http_request() header rewriting miss the host value, so
365  *    from http://www.mydomain.com the result was just " / " not
366  *    http://www.mydomain.com/ in case we forward.
367  *
368  *    Revision 1.22  2001/09/10 10:58:53  oes
369  *    Silenced compiler warnings
370  *
371  *    Revision 1.21  2001/07/31 14:46:00  oes
372  *     - Persistant connections now suppressed
373  *     - sed() no longer appends empty header to csp->headers
374  *
375  *    Revision 1.20  2001/07/30 22:08:36  jongfoster
376  *    Tidying up #defines:
377  *    - All feature #defines are now of the form FEATURE_xxx
378  *    - Permanently turned off WIN_GUI_EDIT
379  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
380  *
381  *    Revision 1.19  2001/07/25 17:21:54  oes
382  *    client_uagent now saves copy of User-Agent: header value
383  *
384  *    Revision 1.18  2001/07/13 14:02:46  oes
385  *     - Included fix to repair broken HTTP requests that
386  *       don't contain a path, not even '/'.
387  *     - Removed all #ifdef PCRS
388  *     - content_type now always inspected and classified as
389  *       text, gif or other.
390  *     - formatting / comments
391  *
392  *    Revision 1.17  2001/06/29 21:45:41  oes
393  *    Indentation, CRLF->LF, Tab-> Space
394  *
395  *    Revision 1.16  2001/06/29 13:32:42  oes
396  *    - Fixed a comment
397  *    - Adapted free_http_request
398  *    - Removed logentry from cancelled commit
399  *
400  *    Revision 1.15  2001/06/03 19:12:38  oes
401  *    deleted const struct interceptors
402  *
403  *    Revision 1.14  2001/06/01 18:49:17  jongfoster
404  *    Replaced "list_share" with "list" - the tiny memory gain was not
405  *    worth the extra complexity.
406  *
407  *    Revision 1.13  2001/05/31 21:30:33  jongfoster
408  *    Removed list code - it's now in list.[ch]
409  *    Renamed "permission" to "action", and changed many features
410  *    to use the actions file rather than the global config.
411  *
412  *    Revision 1.12  2001/05/31 17:33:13  oes
413  *
414  *    CRLF -> LF
415  *
416  *    Revision 1.11  2001/05/29 20:11:19  joergs
417  *    '/ * inside comment' warning removed.
418  *
419  *    Revision 1.10  2001/05/29 09:50:24  jongfoster
420  *    Unified blocklist/imagelist/permissionslist.
421  *    File format is still under discussion, but the internal changes
422  *    are (mostly) done.
423  *
424  *    Also modified interceptor behaviour:
425  *    - We now intercept all URLs beginning with one of the following
426  *      prefixes (and *only* these prefixes):
427  *        * http://i.j.b/
428  *        * http://ijbswa.sf.net/config/
429  *        * http://ijbswa.sourceforge.net/config/
430  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
431  *    - Internal changes so that intercepted and fast redirect pages
432  *      are not replaced with an image.
433  *    - Interceptors now have the option to send a binary page direct
434  *      to the client. (i.e. ijb-send-banner uses this)
435  *    - Implemented show-url-info interceptor.  (Which is why I needed
436  *      the above interceptors changes - a typical URL is
437  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
438  *      The previous mechanism would not have intercepted that, and
439  *      if it had been intercepted then it then it would have replaced
440  *      it with an image.)
441  *
442  *    Revision 1.9  2001/05/28 17:26:33  jongfoster
443  *    Fixing segfault if last header was crunched.
444  *    Fixing Windows build (snprintf() is _snprintf() under Win32, but we
445  *    can use the cross-platform sprintf() instead.)
446  *
447  *    Revision 1.8  2001/05/27 22:17:04  oes
448  *
449  *    - re_process_buffer no longer writes the modified buffer
450  *      to the client, which was very ugly. It now returns the
451  *      buffer, which it is then written by chat.
452  *
453  *    - content_length now adjusts the Content-Length: header
454  *      for modified documents rather than crunch()ing it.
455  *      (Length info in csp->content_length, which is 0 for
456  *      unmodified documents)
457  *
458  *    - For this to work, sed() is called twice when filtering.
459  *
460  *    Revision 1.7  2001/05/27 13:19:06  oes
461  *    Patched Joergs solution for the content-length in.
462  *
463  *    Revision 1.6  2001/05/26 13:39:32  jongfoster
464  *    Only crunches Content-Length header if applying RE filtering.
465  *    Without this fix, Microsoft Windows Update wouldn't work.
466  *
467  *    Revision 1.5  2001/05/26 00:28:36  jongfoster
468  *    Automatic reloading of config file.
469  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
470  *    Most of the global variables have been moved to a new
471  *    struct configuration_spec, accessed through csp->config->globalname
472  *    Most of the globals remaining are used by the Win32 GUI.
473  *
474  *    Revision 1.4  2001/05/22 18:46:04  oes
475  *
476  *    - Enabled filtering banners by size rather than URL
477  *      by adding patterns that replace all standard banner
478  *      sizes with the "Junkbuster" gif to the re_filterfile
479  *
480  *    - Enabled filtering WebBugs by providing a pattern
481  *      which kills all 1x1 images
482  *
483  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
484  *      which is selected by the (nonstandard and therefore
485  *      capital) letter 'U' in the option string.
486  *      It causes the quantifiers to be ungreedy by default.
487  *      Appending a ? turns back to greedy (!).
488  *
489  *    - Added a new interceptor ijb-send-banner, which
490  *      sends back the "Junkbuster" gif. Without imagelist or
491  *      MSIE detection support, or if tinygif = 1, or the
492  *      URL isn't recognized as an imageurl, a lame HTML
493  *      explanation is sent instead.
494  *
495  *    - Added new feature, which permits blocking remote
496  *      script redirects and firing back a local redirect
497  *      to the browser.
498  *      The feature is conditionally compiled, i.e. it
499  *      can be disabled with --disable-fast-redirects,
500  *      plus it must be activated by a "fast-redirects"
501  *      line in the config file, has its own log level
502  *      and of course wants to be displayed by show-proxy-args
503  *      Note: Boy, all the #ifdefs in 1001 locations and
504  *      all the fumbling with configure.in and acconfig.h
505  *      were *way* more work than the feature itself :-(
506  *
507  *    - Because a generic redirect template was needed for
508  *      this, tinygif = 3 now uses the same.
509  *
510  *    - Moved GIFs, and other static HTTP response templates
511  *      to project.h
512  *
513  *    - Some minor fixes
514  *
515  *    - Removed some >400 CRs again (Jon, you really worked
516  *      a lot! ;-)
517  *
518  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
519  *    Version 2.9.4 checkin.
520  *    - Merged popupfile and cookiefile, and added control over PCRS
521  *      filtering, in new "permissionsfile".
522  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
523  *      file error you now get a message box (in the Win32 GUI) rather
524  *      than the program exiting with no explanation.
525  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
526  *      skipping.
527  *    - Removed tabs from "config"
528  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
529  *    - Bumped up version number.
530  *
531  *    Revision 1.2  2001/05/17 23:02:36  oes
532  *     - Made referrer option accept 'L' as a substitute for '§'
533  *
534  *    Revision 1.1.1.1  2001/05/15 13:59:01  oes
535  *    Initial import of version 2.9.3 source tree
536  *
537  *
538  *********************************************************************/
539 \f
540
541 #include "config.h"
542
543 #ifndef _WIN32
544 #include <stdio.h>
545 #include <sys/types.h>
546 #endif
547
548 #include <stdlib.h>
549 #include <ctype.h>
550 #include <assert.h>
551 #include <string.h>
552 #include <time.h>
553
554 #if !defined(_WIN32) && !defined(__OS2__)
555 #include <unistd.h>
556 #endif
557
558 #include "project.h"
559
560 #ifdef FEATURE_PTHREAD
561 #include "jcc.h"
562 /* jcc.h is for mutex semapores only */
563 #endif /* def FEATURE_PTHREAD */
564 #include "list.h"
565 #include "parsers.h"
566 #include "encode.h"
567 #include "ssplit.h"
568 #include "errlog.h"
569 #include "jbsockets.h"
570 #include "miscutil.h"
571 #include "list.h"
572
573 #ifndef HAVE_STRPTIME
574 #include "strptime.h"
575 #endif
576
577 const char parsers_h_rcs[] = PARSERS_H_VERSION;
578
579 /* Fix a problem with Solaris.  There should be no effect on other
580  * platforms.
581  * Solaris's isspace() is a macro which uses it's argument directly
582  * as an array index.  Therefore we need to make sure that high-bit
583  * characters generate +ve values, and ideally we also want to make
584  * the argument match the declared parameter type of "int".
585  *
586  * Why did they write a character function that can't take a simple
587  * "char" argument?  Doh!
588  */
589 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
590 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
591
592
593 const struct parsers client_patterns[] = {
594    { "referer:",                  8,   client_referrer },
595    { "user-agent:",              11,   client_uagent },
596    { "ua-",                       3,   client_ua },
597    { "from:",                     5,   client_from },
598    { "cookie:",                   7,   client_send_cookie },
599    { "x-forwarded-for:",         16,   client_x_forwarded },
600    { "Accept-Encoding:",         16,   client_accept_encoding },
601    { "TE:",                       3,   client_te },
602    { "Host:",                     5,   client_host },
603    { "if-modified-since:",       18,   client_if_modified_since },
604    { "Keep-Alive:",              11,   crumble },
605    { "connection:",              11,   crumble },
606    { "proxy-connection:",        17,   crumble },
607    { "max-forwards:",            13,   client_max_forwards },
608    { "Accept-Language:",         16,   client_accept_language },
609    { "if-none-match:",           14,   client_if_none_match },
610    { "X-Filter:",                 9,   client_x_filter },
611    { "*",                         0,   crunch_client_header },
612    { "*",                         0,   filter_client_header },
613    { NULL,                        0,   NULL }
614 };
615
616 const struct parsers server_patterns[] = {
617    { "HTTP",                      4, server_http },
618    { "set-cookie:",              11, server_set_cookie },
619    { "connection:",              11, crumble },
620    { "Content-Type:",            13, server_content_type },
621    { "Content-Length:",          15, server_content_length },
622    { "Content-MD5:",             12, server_content_md5 },
623    { "Content-Encoding:",        17, server_content_encoding },
624    { "Transfer-Encoding:",       18, server_transfer_coding },
625    { "Keep-Alive:",              11, crumble },
626    { "content-disposition:",     20, server_content_disposition },
627    { "Last-Modified:",           14, server_last_modified },
628    { "*",                         0, crunch_server_header },
629    { "*",                         0, filter_server_header },
630    { NULL, 0, NULL }
631 };
632
633 const struct parsers server_patterns_light[] = {
634    { "Content-Length:",          15, server_content_length },
635    { "Transfer-Encoding:",       18, server_transfer_coding },
636    { NULL, 0, NULL }
637 };
638
639 const add_header_func_ptr add_client_headers[] = {
640    client_host_adder,
641    client_cookie_adder,
642    client_x_forwarded_adder,
643    client_xtra_adder,
644    /* Temporarily disabled:    client_accept_encoding_adder, */
645    connection_close_adder,
646    NULL
647 };
648
649
650 const add_header_func_ptr add_server_headers[] = {
651    connection_close_adder,
652    NULL
653 };
654
655 /*********************************************************************
656  *
657  * Function    :  flush_socket
658  *
659  * Description :  Write any pending "buffered" content.
660  *
661  * Parameters  :
662  *          1  :  fd = file descriptor of the socket to read
663  *          2  :  csp = Current client state (buffers, headers, etc...)
664  *
665  * Returns     :  On success, the number of bytes written are returned (zero
666  *                indicates nothing was written).  On error, -1 is returned,
667  *                and errno is set appropriately.  If count is zero and the
668  *                file descriptor refers to a regular file, 0 will be
669  *                returned without causing any other effect.  For a special
670  *                file, the results are not portable.
671  *
672  *********************************************************************/
673 int flush_socket(jb_socket fd, struct client_state *csp)
674 {
675    struct iob *iob = csp->iob;
676    int len = iob->eod - iob->cur;
677
678    if (len <= 0)
679    {
680       return(0);
681    }
682
683    if (write_socket(fd, iob->cur, (size_t)len))
684    {
685       return(-1);
686    }
687    iob->eod = iob->cur = iob->buf;
688    return(len);
689
690 }
691
692
693 /*********************************************************************
694  *
695  * Function    :  add_to_iob
696  *
697  * Description :  Add content to the buffered page, expanding the
698  *                buffer if necessary.
699  *
700  * Parameters  :
701  *          1  :  csp = Current client state (buffers, headers, etc...)
702  *          2  :  buf = holds the content to be added to the page
703  *          3  :  n = number of bytes to be added
704  *
705  * Returns     :  JB_ERR_OK on success, JB_ERR_MEMORY if out-of-memory
706  *                or buffer limit reached.
707  *
708  *********************************************************************/
709 jb_err add_to_iob(struct client_state *csp, char *buf, int n)
710 {
711    struct iob *iob = csp->iob;
712    size_t used, offset, need, want;
713    char *p;
714
715    if (n <= 0) return JB_ERR_OK;
716
717    used   = iob->eod - iob->buf;
718    offset = iob->cur - iob->buf;
719    need   = used + n + 1;
720
721    /*
722     * If the buffer can't hold the new data, extend it first.
723     * Use the next power of two if possible, else use the actual need.
724     */
725    if (need > csp->config->buffer_limit)
726    {
727       log_error(LOG_LEVEL_ERROR, "Buffer limit reached while extending the buffer (iob)");
728       return JB_ERR_MEMORY;
729    }
730
731    if (need > iob->size)
732    {
733       for (want = csp->iob->size ? csp->iob->size : 512; want <= need;) want *= 2;
734       
735       if (want <= csp->config->buffer_limit && NULL != (p = (char *)realloc(iob->buf, want)))
736       {
737          iob->size = want;
738       }
739       else if (NULL != (p = (char *)realloc(iob->buf, need)))
740       {
741          iob->size = need;
742       }
743       else
744       {
745          log_error(LOG_LEVEL_ERROR, "Extending the buffer (iob) failed: %E");
746          return JB_ERR_MEMORY;
747       }
748
749       /* Update the iob pointers */
750       iob->cur = p + offset;
751       iob->eod = p + used;
752       iob->buf = p;
753    }
754
755    /* copy the new data into the iob buffer */
756    memcpy(iob->eod, buf, (size_t)n);
757
758    /* point to the end of the data */
759    iob->eod += n;
760
761    /* null terminate == cheap insurance */
762    *iob->eod = '\0';
763
764    return JB_ERR_OK;
765
766 }
767
768
769 /*********************************************************************
770  *
771  * Function    :  get_header
772  *
773  * Description :  This (odd) routine will parse the csp->iob
774  *
775  * Parameters  :
776  *          1  :  csp = Current client state (buffers, headers, etc...)
777  *
778  * Returns     :  Any one of the following:
779  *
780  * 1) a pointer to a dynamically allocated string that contains a header line
781  * 2) NULL  indicating that the end of the header was reached
782  * 3) ""    indicating that the end of the iob was reached before finding
783  *          a complete header line.
784  *
785  *********************************************************************/
786 char *get_header(struct client_state *csp)
787 {
788    struct iob *iob;
789    char *p, *q, *ret;
790    iob = csp->iob;
791
792    if ((iob->cur == NULL)
793       || ((p = strchr(iob->cur, '\n')) == NULL))
794    {
795       return(""); /* couldn't find a complete header */
796    }
797
798    *p = '\0';
799
800    ret = strdup(iob->cur);
801    if (ret == NULL)
802    {
803       /* FIXME No way to handle error properly */
804       log_error(LOG_LEVEL_FATAL, "Out of memory in get_header()");
805    }
806
807    iob->cur = p+1;
808
809    if ((q = strchr(ret, '\r')) != NULL) *q = '\0';
810
811    /* is this a blank line (i.e. the end of the header) ? */
812    if (*ret == '\0')
813    {
814       freez(ret);
815       return(NULL);
816    }
817
818    return(ret);
819
820 }
821
822
823 /*********************************************************************
824  *
825  * Function    :  get_header_value
826  *
827  * Description :  Get the value of a given header from a chained list
828  *                of header lines or return NULL if no such header is
829  *                present in the list.
830  *
831  * Parameters  :
832  *          1  :  header_list = pointer to list
833  *          2  :  header_name = string with name of header to look for.
834  *                              Trailing colon required, capitalization
835  *                              doesn't matter.
836  *
837  * Returns     :  NULL if not found, else value of header
838  *
839  *********************************************************************/
840 char *get_header_value(const struct list *header_list, const char *header_name)
841 {
842    struct list_entry *cur_entry;
843    char *ret = NULL;
844    size_t length = 0;
845
846    assert(header_list);
847    assert(header_name);
848    length = strlen(header_name);
849
850    for (cur_entry = header_list->first; cur_entry ; cur_entry = cur_entry->next)
851    {
852       if (cur_entry->str)
853       {
854          if (!strncmpic(cur_entry->str, header_name, length))
855          {
856             /*
857              * Found: return pointer to start of value
858              */
859             ret = (char *) (cur_entry->str + length);
860             while (*ret && ijb_isspace(*ret)) ret++;
861             return(ret);
862          }
863       }
864    }
865
866    /* 
867     * Not found
868     */
869    return NULL;
870
871 }
872
873 /*********************************************************************
874  *
875  * Function    :  sed
876  *
877  * Description :  add, delete or modify lines in the HTTP header streams.
878  *                On entry, it receives a linked list of headers space
879  *                that was allocated dynamically (both the list nodes
880  *                and the header contents).
881  *
882  *                As a side effect it frees the space used by the original
883  *                header lines.
884  *
885  * Parameters  :
886  *          1  :  pats = list of patterns to match against headers
887  *          2  :  more_headers = list of functions to add more
888  *                headers (client or server)
889  *          3  :  csp = Current client state (buffers, headers, etc...)
890  *
891  * Returns     :  Single pointer to a fully formed header, or NULL
892  *                on out-of-memory error.
893  *
894  *********************************************************************/
895 char *sed(const struct parsers pats[],
896           const add_header_func_ptr more_headers[],
897           struct client_state *csp)
898 {
899    struct list_entry *p;
900    const struct parsers *v;
901    const add_header_func_ptr *f;
902    jb_err err = JB_ERR_OK;
903    int first_run;
904
905    /*
906     * If filtering is enabled, sed is run twice,
907     * but most of the work needs to be done only once.
908     */
909    first_run = (more_headers != NULL ) ? 1 : 0;
910
911    if (first_run) /* Parse and print */
912    {
913       for (v = pats; (err == JB_ERR_OK) && (v->str != NULL) ; v++)
914       {
915          for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL) ; p = p->next)
916          {
917             /* Header crunch()ed in previous run? -> ignore */
918             if (p->str == NULL) continue;
919
920             if (v == pats) log_error(LOG_LEVEL_HEADER, "scan: %s", p->str);
921
922             /* Does the current parser handle this header? */
923             if ((strncmpic(p->str, v->str, v->len) == 0) || (v->len == CHECK_EVERY_HEADER_REMAINING))
924             {
925                err = v->parser(csp, (char **)&(p->str));
926             }
927          }
928       }
929       /* place any additional headers on the csp->headers list */
930       for (f = more_headers; (err == JB_ERR_OK) && (*f) ; f++)
931       {
932          err = (*f)(csp);
933       }
934    }
935    else /* Parse only */
936    {
937       /*
938        * The second run is only needed if the body was modified
939        * and the content-lenght has changed.
940        */
941       if (strncmpic(csp->http->cmd, "HEAD", 4))
942       {
943          /*XXX: Code duplication*/
944          for (v = pats; (err == JB_ERR_OK) && (v->str != NULL) ; v++)
945          {
946             for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL) ; p = p->next)
947             {
948                /* Header crunch()ed in previous run? -> ignore */
949                if (p->str == NULL) continue;
950
951                /* Does the current parser handle this header? */
952                if (strncmpic(p->str, v->str, v->len) == 0)
953                {
954                   err = v->parser(csp, (char **)&(p->str));
955                }
956             }
957          }
958       }
959    }
960
961    if (err != JB_ERR_OK)
962    {
963       return NULL;
964    }
965
966    return list_to_text(csp->headers);
967 }
968
969
970 /* here begins the family of parser functions that reformat header lines */
971
972 /*********************************************************************
973  *
974  * Function    :  filter_server_header
975  *
976  * Description :  Checks if server header filtering is enabled.
977  *                If it is, filter_header is called to do the work. 
978  *
979  * Parameters  :
980  *          1  :  csp = Current client state (buffers, headers, etc...)
981  *          2  :  header = On input, pointer to header to modify.
982  *                On output, pointer to the modified header, or NULL
983  *                to remove the header.  This function frees the
984  *                original string if necessary.
985  *
986  * Returns     :  JB_ERR_OK on success and always succeeds
987  *
988  *********************************************************************/
989 jb_err filter_server_header(struct client_state *csp, char **header)
990 {
991    if (csp->action->flags & ACTION_FILTER_SERVER_HEADERS)
992    {
993       filter_header(csp, header);
994    }
995    return(JB_ERR_OK);
996 }
997
998 /*********************************************************************
999  *
1000  * Function    :  filter_client_header
1001  *
1002  * Description :  Checks if client header filtering is enabled.
1003  *                If it is, filter_header is called to do the work. 
1004  *
1005  * Parameters  :
1006  *          1  :  csp = Current client state (buffers, headers, etc...)
1007  *          2  :  header = On input, pointer to header to modify.
1008  *                On output, pointer to the modified header, or NULL
1009  *                to remove the header.  This function frees the
1010  *                original string if necessary.
1011  *
1012  * Returns     :  JB_ERR_OK on success and always succeeds
1013  *
1014  *********************************************************************/
1015 jb_err filter_client_header(struct client_state *csp, char **header)
1016 {
1017    if (csp->action->flags & ACTION_FILTER_CLIENT_HEADERS)
1018    {
1019       filter_header(csp, header);
1020    }
1021    return(JB_ERR_OK);
1022 }
1023
1024 /*********************************************************************
1025  *
1026  * Function    :  filter_header
1027  *
1028  * Description :  Executes all text substitutions from all applying
1029  *                +filter actions on the header.
1030  *                Most of the code was copied from pcrs_filter_response,
1031  *                including the rather short variable names
1032  *
1033  * Parameters  :
1034  *          1  :  csp = Current client state (buffers, headers, etc...)
1035  *          2  :  header = On input, pointer to header to modify.
1036  *                On output, pointer to the modified header, or NULL
1037  *                to remove the header.  This function frees the
1038  *                original string if necessary.
1039  *
1040  * Returns     :  JB_ERR_OK on success and always succeeds
1041  *
1042  *********************************************************************/
1043 jb_err filter_header(struct client_state *csp, char **header)
1044 {
1045    int hits=0;
1046    int matches;
1047    size_t size = strlen(*header);
1048
1049    char *newheader = NULL;
1050    pcrs_job *job;
1051
1052    struct file_list *fl;
1053    struct re_filterfile_spec *b;
1054    struct list_entry *filtername;
1055
1056    int i, found_filters = 0;
1057
1058    /*
1059     * Need to check the set of re_filterfiles...
1060     */
1061    for (i = 0; i < MAX_AF_FILES; i++)
1062    {
1063       fl = csp->rlist[i];
1064       if (NULL != fl)
1065       {
1066          if (NULL != fl->f)
1067          {
1068            found_filters = 1;
1069            break;
1070          }
1071       }
1072    }
1073
1074    if (0 == found_filters)
1075    {
1076       log_error(LOG_LEVEL_ERROR, "Unable to get current state of regexp filtering.");
1077          return(JB_ERR_OK);
1078    }
1079
1080    for (i = 0; i < MAX_AF_FILES; i++)
1081    {
1082       fl = csp->rlist[i];
1083       if ((NULL == fl) || (NULL == fl->f))
1084          break;
1085       /*
1086        * For all applying +filter actions, look if a filter by that
1087        * name exists and if yes, execute its pcrs_joblist on the
1088        * buffer.
1089        */
1090       for (b = fl->f; b; b = b->next)
1091       {
1092          for (filtername = csp->action->multi[ACTION_MULTI_FILTER]->first;
1093               filtername ; filtername = filtername->next)
1094          {
1095             if (strcmp(b->name, filtername->str) == 0)
1096             {
1097                int current_hits = 0;
1098
1099                if ( NULL == b->joblist )
1100                {
1101                   log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name);
1102                   continue;
1103                }
1104
1105                log_error(LOG_LEVEL_RE_FILTER, "re_filtering %s (size %d) with filter %s...",
1106                          *header, size, b->name);
1107
1108                /* Apply all jobs from the joblist */
1109                for (job = b->joblist; NULL != job; job = job->next)
1110                {
1111                   matches = pcrs_execute(job, *header, size, &newheader, &size);
1112                   if ( 0 < matches )
1113                   {
1114                      current_hits += matches; 
1115                      log_error(LOG_LEVEL_HEADER, "Transforming \"%s\" to \"%s\"", *header, newheader);
1116                      freez(*header);
1117                      *header = newheader;
1118                   }
1119                   else if ( 0 == matches )
1120                   {
1121                      /* Filter doesn't change header */
1122                      freez(newheader);
1123                   }
1124                   else
1125                   {
1126                      /* RegEx failure */
1127                      log_error(LOG_LEVEL_ERROR, "Filtering \'%s\' with \'%s\' didn't work out: %s",
1128                         *header, b->name, pcrs_strerror(matches));
1129                      if( newheader != NULL)
1130                      {
1131                         log_error(LOG_LEVEL_ERROR, "Freeing what's left: %s", newheader);
1132                         freez(newheader);
1133                      }
1134                   }
1135                }
1136                log_error(LOG_LEVEL_RE_FILTER, " ...produced %d hits (new size %d).", current_hits, size);
1137                hits += current_hits;
1138             }
1139          }
1140       }
1141    }
1142
1143    if ( 0 == size )
1144    {
1145       log_error(LOG_LEVEL_HEADER, "Removing empty header %s", *header);
1146       freez(*header);
1147    }
1148
1149    return(JB_ERR_OK);
1150 }
1151
1152
1153 /*********************************************************************
1154  *
1155  * Function    :  crumble
1156  *
1157  * Description :  This is called if a header matches a pattern to "crunch"
1158  *
1159  * Parameters  :
1160  *          1  :  csp = Current client state (buffers, headers, etc...)
1161  *          2  :  header = On input, pointer to header to modify.
1162  *                On output, pointer to the modified header, or NULL
1163  *                to remove the header.  This function frees the
1164  *                original string if necessary.
1165  *
1166  * Returns     :  JB_ERR_OK on success, or
1167  *                JB_ERR_MEMORY on out-of-memory error.
1168  *
1169  *********************************************************************/
1170 jb_err crumble(struct client_state *csp, char **header)
1171 {
1172    log_error(LOG_LEVEL_HEADER, "crumble crunched: %s!", *header);
1173    freez(*header);
1174    return JB_ERR_OK;
1175 }
1176
1177 /*********************************************************************
1178  *
1179  * Function    :  crunch_server_header
1180  *
1181  * Description :  Crunch server header if it matches a string supplied by the
1182  *                user. Called from `sed'.
1183  *
1184  * Parameters  :
1185  *          1  :  csp = Current client state (buffers, headers, etc...)
1186  *          2  :  header = On input, pointer to header to modify.
1187  *                On output, pointer to the modified header, or NULL
1188  *                to remove the header.  This function frees the
1189  *                original string if necessary.
1190  *
1191  * Returns     :  JB_ERR_OK on success and always succeeds
1192  *
1193  *********************************************************************/
1194 jb_err crunch_server_header(struct client_state *csp, char **header)
1195 {
1196    const char *crunch_pattern;
1197    /*Is there a header to crunch*/
1198
1199    if ((csp->action->flags & ACTION_CRUNCH_SERVER_HEADER))
1200    {
1201       crunch_pattern = csp->action->string[ACTION_STRING_SERVER_HEADER];
1202
1203       /*Is the current header the lucky one?*/
1204       if (strstr(*header, crunch_pattern))
1205       {
1206          log_error(LOG_LEVEL_HEADER, "Crunching server header: %s (contains: %s)", *header, crunch_pattern);  
1207          freez(*header);
1208       }
1209    }
1210
1211    return JB_ERR_OK;
1212 }
1213 /*********************************************************************
1214  *
1215  * Function    :  server_content_type
1216  *
1217  * Description :  Set the content-type for filterable types (text/.*,
1218  *                javascript and image/gif) unless filtering has been
1219  *                forbidden (CT_TABOO) while parsing earlier headers.
1220  *                NOTE: Since text/plain is commonly used by web servers
1221  *                      for files whose correct type is unknown, we don't
1222  *                      set CT_TEXT for it.
1223  *
1224  * Parameters  :
1225  *          1  :  csp = Current client state (buffers, headers, etc...)
1226  *          2  :  header = On input, pointer to header to modify.
1227  *                On output, pointer to the modified header, or NULL
1228  *                to remove the header.  This function frees the
1229  *                original string if necessary.
1230  *
1231  * Returns     :  JB_ERR_OK on success, or
1232  *                JB_ERR_MEMORY on out-of-memory error.
1233  *
1234  *********************************************************************/
1235 jb_err server_content_type(struct client_state *csp, char **header)
1236 {
1237    const char *newval;
1238    
1239    newval = csp->action->string[ACTION_STRING_CONTENT_TYPE]; 
1240
1241    if (csp->content_type != CT_TABOO)
1242    {
1243       if ((strstr(*header, " text/") && !strstr(*header, "plain"))
1244        || strstr(*header, "xml")
1245        || strstr(*header, "application/x-javascript"))
1246          csp->content_type = CT_TEXT;
1247       else if (strstr(*header, " image/gif"))
1248          csp->content_type = CT_GIF;
1249       else if (strstr(*header, " image/jpeg"))
1250          csp->content_type = CT_JPEG;
1251       else
1252          csp->content_type = 0;
1253    }
1254    /*
1255     * Are we enabling text mode by force?
1256     */
1257    if (csp->action->flags & ACTION_FORCE_TEXT_MODE)
1258    {
1259      /*
1260       * Do we really have to?
1261       */
1262       if (csp->content_type == CT_TEXT)
1263       {
1264          log_error(LOG_LEVEL_HEADER, "Text mode is already enabled.");   
1265       }
1266       else
1267       {
1268          csp->content_type = CT_TEXT;
1269          log_error(LOG_LEVEL_HEADER, "Text mode enabled by force. Take cover!");   
1270       }
1271    }
1272    /*
1273     * Are we messing with the content type?
1274     */ 
1275    if (csp->action->flags & ACTION_CONTENT_TYPE_OVERWRITE)
1276    { 
1277      /*
1278       * Make sure the user doesn't accidently
1279       * change the content type of binary documents. 
1280       */ 
1281      if (csp->content_type == CT_TEXT)
1282      { 
1283         freez(*header);
1284         *header = strdup("Content-Type: ");
1285         string_append(header, newval);
1286         
1287         if (header == NULL)
1288         { 
1289            log_error(LOG_LEVEL_HEADER, "Insufficient memory. Conten-Type crunched without replacement!");
1290            return JB_ERR_MEMORY;
1291         }
1292         log_error(LOG_LEVEL_HEADER, "Modified: %s!", *header);
1293      }
1294      else
1295      {
1296         log_error(LOG_LEVEL_HEADER, "%s not replaced. It doesn't look like text. "
1297                  "Enable force-text-mode if you know what you're doing.", *header);   
1298      }
1299    }  
1300    return JB_ERR_OK;
1301 }
1302
1303
1304 /*********************************************************************
1305  *
1306  * Function    :  server_transfer_coding
1307  *
1308  * Description :  - Prohibit filtering (CT_TABOO) if transfer coding compresses
1309  *                - Raise the CSP_FLAG_CHUNKED flag if coding is "chunked"
1310  *                - Remove header if body was chunked but has been
1311  *                  de-chunked for filtering.
1312  *
1313  * Parameters  :
1314  *          1  :  csp = Current client state (buffers, headers, etc...)
1315  *          2  :  header = On input, pointer to header to modify.
1316  *                On output, pointer to the modified header, or NULL
1317  *                to remove the header.  This function frees the
1318  *                original string if necessary.
1319  *
1320  * Returns     :  JB_ERR_OK on success, or
1321  *                JB_ERR_MEMORY on out-of-memory error.
1322  *
1323  *********************************************************************/
1324 jb_err server_transfer_coding(struct client_state *csp, char **header)
1325 {
1326    /*
1327     * Turn off pcrs and gif filtering if body compressed
1328     */
1329    if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate"))
1330    {
1331       csp->content_type = CT_TABOO;
1332    }
1333
1334    /*
1335     * Raise flag if body chunked
1336     */
1337    if (strstr(*header, "chunked"))
1338    {
1339       csp->flags |= CSP_FLAG_CHUNKED;
1340
1341       /*
1342        * If the body was modified, it has been de-chunked first
1343        * and the header must be removed. 
1344        */
1345       if (csp->flags & CSP_FLAG_MODIFIED)
1346       {
1347          log_error(LOG_LEVEL_HEADER, "Removing: %s", *header);
1348          freez(*header);
1349       }
1350    }
1351
1352    return JB_ERR_OK;
1353 }
1354
1355
1356 /*********************************************************************
1357  *
1358  * Function    :  server_content_encoding
1359  *
1360  * Description :  Prohibit filtering (CT_TABOO) if content encoding compresses
1361  *
1362  * Parameters  :
1363  *          1  :  csp = Current client state (buffers, headers, etc...)
1364  *          2  :  header = On input, pointer to header to modify.
1365  *                On output, pointer to the modified header, or NULL
1366  *                to remove the header.  This function frees the
1367  *                original string if necessary.
1368  *
1369  * Returns     :  JB_ERR_OK on success, or
1370  *                JB_ERR_MEMORY on out-of-memory error.
1371  *
1372  *********************************************************************/
1373 jb_err server_content_encoding(struct client_state *csp, char **header)
1374 {
1375    /*
1376     * Turn off pcrs and gif filtering if body compressed
1377     */
1378    if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate"))
1379    {
1380       csp->content_type = CT_TABOO;
1381    }
1382
1383    return JB_ERR_OK;
1384
1385 }
1386
1387
1388 /*********************************************************************
1389  *
1390  * Function    :  server_content_length
1391  *
1392  * Description :  Adjust Content-Length header if we modified
1393  *                the body.
1394  *
1395  * Parameters  :
1396  *          1  :  csp = Current client state (buffers, headers, etc...)
1397  *          2  :  header = On input, pointer to header to modify.
1398  *                On output, pointer to the modified header, or NULL
1399  *                to remove the header.  This function frees the
1400  *                original string if necessary.
1401  *
1402  * Returns     :  JB_ERR_OK on success, or
1403  *                JB_ERR_MEMORY on out-of-memory error.
1404  *
1405  *********************************************************************/
1406 jb_err server_content_length(struct client_state *csp, char **header)
1407 {
1408    if (csp->content_length != 0) /* Content length could have been modified */
1409    {
1410       /*
1411        * XXX: Shouldn't we check if csp->content_length
1412        * is different than the original value?
1413        */
1414       freez(*header);
1415       *header = (char *) zalloc(100);
1416       if (*header == NULL)
1417       {
1418          return JB_ERR_MEMORY;
1419       }
1420
1421       sprintf(*header, "Content-Length: %d", (int) csp->content_length);
1422
1423       log_error(LOG_LEVEL_HEADER, "Adjust Content-Length to %d", (int) csp->content_length);
1424    }
1425
1426    return JB_ERR_OK;
1427 }
1428
1429
1430 /*********************************************************************
1431  *
1432  * Function    :  server_content_md5
1433  *
1434  * Description :  Crumble any Content-MD5 headers if the document was
1435  *                modified. FIXME: Should we re-compute instead?
1436  *
1437  * Parameters  :
1438  *          1  :  csp = Current client state (buffers, headers, etc...)
1439  *          2  :  header = On input, pointer to header to modify.
1440  *                On output, pointer to the modified header, or NULL
1441  *                to remove the header.  This function frees the
1442  *                original string if necessary.
1443  *
1444  * Returns     :  JB_ERR_OK on success, or
1445  *                JB_ERR_MEMORY on out-of-memory error.
1446  *
1447  *********************************************************************/
1448 jb_err server_content_md5(struct client_state *csp, char **header)
1449 {
1450    if (csp->flags & CSP_FLAG_MODIFIED)
1451    {
1452       log_error(LOG_LEVEL_HEADER, "Crunching Content-MD5");
1453       freez(*header);
1454    }
1455
1456    return JB_ERR_OK;
1457 }
1458
1459 /*********************************************************************
1460  *
1461  * Function    :  server_content_disposition
1462  *
1463  * Description :  If enabled, blocks or modifies the "content-disposition" header.
1464  *                Called from `sed'.
1465  *
1466  * Parameters  :
1467  *          1  :  csp = Current client state (buffers, headers, etc...)
1468  *          2  :  header = On input, pointer to header to modify.
1469  *                On output, pointer to the modified header, or NULL
1470  *                to remove the header.  This function frees the
1471  *                original string if necessary.
1472  *
1473  * Returns     :  JB_ERR_OK on success, or
1474  *                JB_ERR_MEMORY on out-of-memory error.
1475  *
1476  *********************************************************************/
1477 jb_err server_content_disposition(struct client_state *csp, char **header)
1478 {
1479    const char *newval;
1480
1481    /*
1482     * Are we messing with the content-disposition header?
1483     */
1484    if ((csp->action->flags & ACTION_HIDE_CONTENT_DISPOSITION) == 0)
1485    {
1486       /*Me tinks not*/
1487       return JB_ERR_OK;
1488    }
1489
1490    newval = csp->action->string[ACTION_STRING_CONTENT_DISPOSITION];
1491
1492    if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
1493    {
1494       /*
1495        * Blocking content-disposition header
1496        */
1497       log_error(LOG_LEVEL_HEADER, "Crunching %s!", *header);
1498       freez(*header);
1499       return JB_ERR_OK;
1500    }
1501    else
1502    {  
1503       /*
1504        * Replacing content-disposition header
1505        */
1506       freez(*header);
1507       *header = strdup("content-disposition: ");
1508       string_append(header, newval);   
1509
1510       if (*header == NULL)
1511       {
1512          log_error(LOG_LEVEL_HEADER, "Insufficent memory. content-disposition header not fully replaced.");  
1513       }
1514       else
1515       {
1516          log_error(LOG_LEVEL_HEADER, "content-disposition header crunched and replaced with: %s", *header);
1517       }
1518    }
1519    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
1520 }
1521
1522 /*********************************************************************
1523  *
1524  * Function    :  server_last_modified
1525  *
1526  * Description :  Changes Last-Modified header to the actual date
1527  *                to help hide-if-modified-since.
1528  *                Called from `sed'.
1529  *
1530  * Parameters  :
1531  *          1  :  csp = Current client state (buffers, headers, etc...)
1532  *          2  :  header = On input, pointer to header to modify.
1533  *                On output, pointer to the modified header, or NULL
1534  *                to remove the header.  This function frees the
1535  *                original string if necessary.
1536  *
1537  * Returns     :  JB_ERR_OK on success, or
1538  *                JB_ERR_MEMORY on out-of-memory error.
1539  *
1540  *********************************************************************/
1541 jb_err server_last_modified(struct client_state *csp, char **header)
1542 {
1543    const char *newval;
1544    char buf[BUFFER_SIZE];
1545
1546    char newheader[50];
1547 #ifdef HAVE_GMTIME_R
1548    struct tm gmt;
1549 #endif
1550    struct tm *timeptr = NULL;
1551    time_t now, last_modified;                  
1552    long int rtime;
1553    long int days, hours, minutes, seconds;
1554    
1555    /*
1556     * Are we messing with the Last-Modified header?
1557     */
1558    if ((csp->action->flags & ACTION_OVERWRITE_LAST_MODIFIED) == 0)
1559    {
1560       /*Nope*/
1561       return JB_ERR_OK;
1562    }
1563
1564    newval = csp->action->string[ACTION_STRING_LAST_MODIFIED];
1565
1566    if (0 == strcmpic(newval, "block") )
1567    {
1568       /*
1569        * Blocking Last-Modified header. Useless but why not.
1570        */
1571       log_error(LOG_LEVEL_HEADER, "Crunching %s!", *header);
1572       freez(*header);
1573       return JB_ERR_OK;
1574    }
1575    else if (0 == strcmpic(newval, "reset-to-request-time"))
1576    {  
1577       /*
1578        * Setting Last-Modified Header to now.
1579        */
1580       get_http_time(0, buf);
1581       freez(*header);
1582       *header = strdup("Last-Modified: ");
1583       string_append(header, buf);   
1584
1585       if (*header == NULL)
1586       {
1587          log_error(LOG_LEVEL_HEADER, "Insufficent memory. Last-Modified header got lost, boohoo.");  
1588       }
1589       else
1590       {
1591          log_error(LOG_LEVEL_HEADER, "Reset to present time: %s", *header);
1592       }
1593    }
1594    else if (0 == strcmpic(newval, "randomize"))
1595    {
1596       log_error(LOG_LEVEL_HEADER, "Randomizing: %s", *header);
1597       now = time(NULL);
1598 #ifdef HAVE_GMTIME_R
1599       timeptr = gmtime_r(&now, &gmt);
1600 #elif FEATURE_PTHREAD
1601       pthread_mutex_lock(&gmtime_mutex);
1602       timeptr = gmtime(&now);
1603       pthread_mutex_unlock(&gmtime_mutex);
1604 #else
1605       timeptr = gmtime(&now);
1606 #endif
1607       if ((timeptr = parse_header_time(*header, &last_modified)) == NULL)
1608       {
1609          log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s (crunching!)", *header);
1610          freez(*header);
1611       }
1612       else
1613       {
1614          rtime = difftime(now, last_modified);
1615          if (rtime)
1616          {
1617             rtime = pick_from_range(rtime);
1618             last_modified += rtime;
1619 #ifdef HAVE_GMTIME_R
1620             timeptr = gmtime_r(&last_modified, &gmt);
1621 #elif FEATURE_PTHREAD
1622             pthread_mutex_lock(&gmtime_mutex);
1623             timeptr = gmtime(&last_modified);
1624             pthread_mutex_unlock(&gmtime_mutex);
1625 #else
1626             timeptr = gmtime(&last_modified);
1627 #endif
1628             strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr);
1629             freez(*header);
1630             *header = strdup("Last-Modified: ");
1631             string_append(header, newheader);
1632
1633             if (*header == NULL)
1634             {
1635                log_error(LOG_LEVEL_ERROR, "Insufficent memory, header crunched without replacement.");
1636                return JB_ERR_MEMORY;  
1637             }
1638
1639             if(LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */
1640             {
1641                days    = rtime / (3600 * 24);
1642                hours   = rtime / 3600 % 24;
1643                minutes = rtime / 60 % 60;
1644                seconds = rtime % 60;            
1645
1646                log_error(LOG_LEVEL_HEADER, "Randomized:  %s (added %d da%s %d hou%s %d minut%s %d second%s",
1647                   *header, days, (days == 1) ? "y" : "ys", hours, (hours == 1) ? "r" : "rs",
1648                   minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)");
1649             }
1650          }
1651          else
1652          {
1653             log_error(LOG_LEVEL_HEADER, "Randomized ... or not. No time difference to work with.");
1654          }
1655       }
1656    }
1657
1658    return JB_ERR_OK;
1659 }
1660
1661 /*********************************************************************
1662  *
1663  * Function    :  client_accept_encoding
1664  *
1665  * Description :  Rewrite the client's Accept-Encoding header so that
1666  *                if doesn't allow compression, if the action applies.
1667  *                Note: For HTTP/1.0 the absence of the header is enough.
1668  *
1669  * Parameters  :
1670  *          1  :  csp = Current client state (buffers, headers, etc...)
1671  *          2  :  header = On input, pointer to header to modify.
1672  *                On output, pointer to the modified header, or NULL
1673  *                to remove the header.  This function frees the
1674  *                original string if necessary.
1675  *
1676  * Returns     :  JB_ERR_OK on success, or
1677  *                JB_ERR_MEMORY on out-of-memory error.
1678  *
1679  *********************************************************************/
1680 jb_err client_accept_encoding(struct client_state *csp, char **header)
1681 {
1682    if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
1683    {
1684       log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress content");
1685
1686       freez(*header);
1687
1688       /* Temporarily disable the correct behaviour to
1689        * work around a PHP bug. 
1690        *
1691        * if (!strcmpic(csp->http->ver, "HTTP/1.1"))
1692        * {
1693        *    *header = strdup("Accept-Encoding: identity;q=1.0, *;q=0");
1694        *    if (*header == NULL)
1695        *    {
1696        *       return JB_ERR_MEMORY;
1697        *    }
1698        * }
1699        * 
1700        */
1701    }
1702
1703    return JB_ERR_OK;
1704 }
1705
1706
1707 /*********************************************************************
1708  *
1709  * Function    :  client_te
1710  *
1711  * Description :  Rewrite the client's TE header so that
1712  *                if doesn't allow compression, if the action applies.
1713  *
1714  * Parameters  :
1715  *          1  :  csp = Current client state (buffers, headers, etc...)
1716  *          2  :  header = On input, pointer to header to modify.
1717  *                On output, pointer to the modified header, or NULL
1718  *                to remove the header.  This function frees the
1719  *                original string if necessary.
1720  *
1721  * Returns     :  JB_ERR_OK on success, or
1722  *                JB_ERR_MEMORY on out-of-memory error.
1723  *
1724  *********************************************************************/
1725 jb_err client_te(struct client_state *csp, char **header)
1726 {
1727    if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
1728    {
1729       freez(*header);
1730       log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress transfer");
1731    }
1732
1733    return JB_ERR_OK;
1734 }
1735
1736 /*********************************************************************
1737  *
1738  * Function    :  client_referrer
1739  *
1740  * Description :  Handle the "referer" config setting properly.
1741  *                Called from `sed'.
1742  *
1743  * Parameters  :
1744  *          1  :  csp = Current client state (buffers, headers, etc...)
1745  *          2  :  header = On input, pointer to header to modify.
1746  *                On output, pointer to the modified header, or NULL
1747  *                to remove the header.  This function frees the
1748  *                original string if necessary.
1749  *
1750  * Returns     :  JB_ERR_OK on success, or
1751  *                JB_ERR_MEMORY on out-of-memory error.
1752  *
1753  *********************************************************************/
1754 jb_err client_referrer(struct client_state *csp, char **header)
1755 {
1756    const char *newval;
1757    const char *host;
1758    char *referer;
1759    size_t hostlenght;
1760  
1761 #ifdef FEATURE_FORCE_LOAD
1762    /* Since the referrer can include the prefix even
1763     * if the request itself is non-forced, we must
1764     * clean it unconditionally
1765     */
1766    strclean(*header, FORCE_PREFIX);
1767 #endif /* def FEATURE_FORCE_LOAD */
1768
1769    /*
1770     * Are we sending referer?
1771     */
1772    if ((csp->action->flags & ACTION_HIDE_REFERER) == 0)
1773    {
1774       return JB_ERR_OK;
1775    }
1776
1777    newval = csp->action->string[ACTION_STRING_REFERER];
1778
1779    if ((0 != strcmpic(newval, "conditional-block")))
1780    {  
1781       freez(*header);
1782    }
1783    if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
1784    {
1785       /*
1786        * Blocking referer
1787        */
1788       log_error(LOG_LEVEL_HEADER, "Referer crunched!");
1789       return JB_ERR_OK;
1790    }
1791    else if (0 == strcmpic(newval, "conditional-block"))
1792    {
1793       /*
1794        * Block referer if host has changed.
1795        */
1796
1797       if (NULL == (host = strdup(csp->http->hostport)))
1798       {
1799          freez(*header);
1800          log_error(LOG_LEVEL_HEADER, "Referer crunched! Couldn't allocate memory for temporary host copy.");
1801          return JB_ERR_MEMORY;
1802       }
1803       if (NULL == (referer = strdup(*header)))
1804       {
1805          freez(*header);
1806          freez(host);
1807          log_error(LOG_LEVEL_HEADER, "Referer crunched! Couldn't allocate memory for temporary referer copy.");
1808          return JB_ERR_MEMORY;
1809       }
1810       hostlenght = strlen(host);
1811       if ( hostlenght < (strlen(referer)-17) ) /*referer begins with 'Referer: http[s]://'*/
1812       {
1813          /*Shorten referer to make sure the referer is blocked
1814           *if www.example.org/www.example.com-shall-see-the-referer/
1815           *links to www.example.com/
1816           */
1817          referer[hostlenght+17] = '\0';
1818       }
1819       if ( 0 == strstr(referer, host)) /*Host has changed*/
1820       {
1821          log_error(LOG_LEVEL_HEADER, "New host is: %s. Crunching %s!", host, *header);
1822          freez(*header);
1823       }
1824       else
1825       {
1826          log_error(LOG_LEVEL_HEADER, "%s (not modified, still on %s)", *header, host);
1827       }
1828       freez(referer);
1829       freez(host);
1830       return JB_ERR_OK;    
1831    }
1832    else if (0 != strcmpic(newval, "forge"))
1833    {
1834       /*
1835        * We have a specific (fixed) referer we want to send.
1836        */
1837       if ((0 != strncmpic(newval, "http://", 7)) && (0 != strncmpic(newval, "https://", 8)))
1838       {
1839          log_error(LOG_LEVEL_HEADER, "Parameter: +referrer{%s} is a bad idea, but I don't care.", newval);
1840       }
1841       *header = strdup("Referer: ");
1842       string_append(header, newval);
1843       log_error(LOG_LEVEL_HEADER, "Referer overwritten with: %s", *header);
1844
1845       return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
1846    }
1847    else
1848    {
1849       /*
1850        * Forge a referer as http://[hostname:port of REQUEST]/
1851        * to fool stupid checks for in-site links
1852        */
1853
1854       *header = strdup("Referer: http://");
1855       string_append(header, csp->http->hostport);
1856       string_append(header, "/");
1857       log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header);
1858       
1859       return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
1860    }
1861 }
1862
1863 /*********************************************************************
1864  *
1865  * Function    :  client_accept_language
1866  *
1867  * Description :  Handle the "Accept-Language" config setting properly.
1868  *                Called from `sed'.
1869  *
1870  * Parameters  :
1871  *          1  :  csp = Current client state (buffers, headers, etc...)
1872  *          2  :  header = On input, pointer to header to modify.
1873  *                On output, pointer to the modified header, or NULL
1874  *                to remove the header.  This function frees the
1875  *                original string if necessary.
1876  *
1877  * Returns     :  JB_ERR_OK on success, or
1878  *                JB_ERR_MEMORY on out-of-memory error.
1879  *
1880  *********************************************************************/
1881 jb_err client_accept_language(struct client_state *csp, char **header)
1882 {
1883    const char *newval;
1884
1885    /*
1886     * Are we messing with the Accept-Language?
1887     */
1888    if ((csp->action->flags & ACTION_HIDE_ACCEPT_LANGUAGE) == 0)
1889    {
1890       /*I don't think so*/
1891       return JB_ERR_OK;
1892    }
1893
1894    newval = csp->action->string[ACTION_STRING_LANGUAGE];
1895
1896    if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
1897    {
1898       /*
1899        * Blocking Accept-Language header
1900        */
1901       log_error(LOG_LEVEL_HEADER, "Crunching Accept-Language!");
1902       freez(*header);
1903       return JB_ERR_OK;
1904    }
1905    else
1906    {  
1907       /*
1908        * Replacing Accept-Language header
1909        */
1910       freez(*header);
1911       *header = strdup("Accept-Language: ");
1912       string_append(header, newval);   
1913
1914       if (*header == NULL)
1915       {
1916          log_error(LOG_LEVEL_ERROR, " Insufficent memory. Accept-Language header crunched without replacement.");  
1917       }
1918       else
1919       {
1920          log_error(LOG_LEVEL_HEADER, "Accept-Language header crunched and replaced with: %s", *header);
1921       }
1922    }
1923    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
1924 }
1925
1926 /*********************************************************************
1927  *
1928  * Function    :  crunch_client_header
1929  *
1930  * Description :  Crunch client header if it matches a string supplied by the
1931  *                user. Called from `sed'.
1932  *
1933  * Parameters  :
1934  *          1  :  csp = Current client state (buffers, headers, etc...)
1935  *          2  :  header = On input, pointer to header to modify.
1936  *                On output, pointer to the modified header, or NULL
1937  *                to remove the header.  This function frees the
1938  *                original string if necessary.
1939  *
1940  * Returns     :  JB_ERR_OK on success and always succeeds
1941  *
1942  *********************************************************************/
1943 jb_err crunch_client_header(struct client_state *csp, char **header)
1944 {
1945    const char *crunch_pattern;
1946    /*Is there a header to crunch*/
1947    
1948    if ((csp->action->flags & ACTION_CRUNCH_CLIENT_HEADER))
1949    {
1950       crunch_pattern = csp->action->string[ACTION_STRING_CLIENT_HEADER];
1951
1952       /*Is the current header the lucky one?*/
1953       if (strstr(*header, crunch_pattern))
1954       {
1955          log_error(LOG_LEVEL_HEADER, "Crunching client header: %s (contains: %s)", *header, crunch_pattern);  
1956          freez(*header);
1957       }
1958    }
1959    return JB_ERR_OK;
1960 }
1961
1962
1963 /*********************************************************************
1964  *
1965  * Function    :  client_uagent
1966  *
1967  * Description :  Handle the "user-agent" config setting properly
1968  *                and remember its original value to enable browser
1969  *                bug workarounds. Called from `sed'.
1970  *
1971  * Parameters  :
1972  *          1  :  csp = Current client state (buffers, headers, etc...)
1973  *          2  :  header = On input, pointer to header to modify.
1974  *                On output, pointer to the modified header, or NULL
1975  *                to remove the header.  This function frees the
1976  *                original string if necessary.
1977  *
1978  * Returns     :  JB_ERR_OK on success, or
1979  *                JB_ERR_MEMORY on out-of-memory error.
1980  *
1981  *********************************************************************/
1982 jb_err client_uagent(struct client_state *csp, char **header)
1983 {
1984    const char *newval;
1985
1986    if ((csp->action->flags & ACTION_HIDE_USER_AGENT) == 0)
1987    {
1988       return JB_ERR_OK;
1989    }
1990
1991    newval = csp->action->string[ACTION_STRING_USER_AGENT];
1992    if (newval == NULL)
1993    {
1994       return JB_ERR_OK;
1995    }
1996
1997    freez(*header);
1998    *header = strdup("User-Agent: ");
1999    string_append(header, newval);
2000
2001    log_error(LOG_LEVEL_HEADER, "Modified: %s", *header);
2002
2003    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2004 }
2005
2006 /*********************************************************************
2007  *
2008  * Function    :  client_ua
2009  *
2010  * Description :  Handle "ua-" headers properly.  Called from `sed'.
2011  *
2012  * Parameters  :
2013  *          1  :  csp = Current client state (buffers, headers, etc...)
2014  *          2  :  header = On input, pointer to header to modify.
2015  *                On output, pointer to the modified header, or NULL
2016  *                to remove the header.  This function frees the
2017  *                original string if necessary.
2018  *
2019  * Returns     :  JB_ERR_OK on success, or
2020  *                JB_ERR_MEMORY on out-of-memory error.
2021  *
2022  *********************************************************************/
2023 jb_err client_ua(struct client_state *csp, char **header)
2024 {
2025    if ((csp->action->flags & ACTION_HIDE_USER_AGENT) != 0)
2026    {
2027       log_error(LOG_LEVEL_HEADER, "crunched User-Agent!");
2028       freez(*header);
2029    }
2030
2031    return JB_ERR_OK;
2032 }
2033
2034
2035 /*********************************************************************
2036  *
2037  * Function    :  client_from
2038  *
2039  * Description :  Handle the "from" config setting properly.
2040  *                Called from `sed'.
2041  *
2042  * Parameters  :
2043  *          1  :  csp = Current client state (buffers, headers, etc...)
2044  *          2  :  header = On input, pointer to header to modify.
2045  *                On output, pointer to the modified header, or NULL
2046  *                to remove the header.  This function frees the
2047  *                original string if necessary.
2048  *
2049  * Returns     :  JB_ERR_OK on success, or
2050  *                JB_ERR_MEMORY on out-of-memory error.
2051  *
2052  *********************************************************************/
2053 jb_err client_from(struct client_state *csp, char **header)
2054 {
2055    const char *newval;
2056
2057    if ((csp->action->flags & ACTION_HIDE_FROM) == 0)
2058    {
2059       return JB_ERR_OK;
2060    }
2061
2062    freez(*header);
2063
2064    newval = csp->action->string[ACTION_STRING_FROM];
2065
2066    /*
2067     * Are we blocking the e-mail address?
2068     */
2069    if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
2070    {
2071       log_error(LOG_LEVEL_HEADER, "crunched From!");
2072       return JB_ERR_OK;
2073    }
2074
2075    log_error(LOG_LEVEL_HEADER, " modified");
2076
2077    *header = strdup("From: ");
2078    string_append(header, newval);
2079
2080    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2081 }
2082
2083
2084 /*********************************************************************
2085  *
2086  * Function    :  client_send_cookie
2087  *
2088  * Description :  Handle the "cookie" header properly.  Called from `sed'.
2089  *                If cookie is accepted, add it to the cookie_list,
2090  *                else we crunch it.  Mmmmmmmmmmm ... cookie ......
2091  *
2092  * Parameters  :
2093  *          1  :  csp = Current client state (buffers, headers, etc...)
2094  *          2  :  header = On input, pointer to header to modify.
2095  *                On output, pointer to the modified header, or NULL
2096  *                to remove the header.  This function frees the
2097  *                original string if necessary.
2098  *
2099  * Returns     :  JB_ERR_OK on success, or
2100  *                JB_ERR_MEMORY on out-of-memory error.
2101  *
2102  *********************************************************************/
2103 jb_err client_send_cookie(struct client_state *csp, char **header)
2104 {
2105    jb_err result = JB_ERR_OK;
2106
2107    if ((csp->action->flags & ACTION_NO_COOKIE_READ) == 0)
2108    {
2109       /* strlen("cookie: ") == 8 */
2110       result = enlist(csp->cookie_list, *header + 8);
2111    }
2112    else
2113    {
2114       log_error(LOG_LEVEL_HEADER, "Crunched outgoing cookie -- yum!");
2115    }
2116
2117    /*
2118     * Always remove the cookie here.  The cookie header
2119     * will be sent at the end of the header.
2120     */
2121    freez(*header);
2122
2123    return result;
2124 }
2125
2126
2127 /*********************************************************************
2128  *
2129  * Function    :  client_x_forwarded
2130  *
2131  * Description :  Handle the "x-forwarded-for" config setting properly,
2132  *                also used in the add_client_headers list.  Called from `sed'.
2133  *
2134  * Parameters  :
2135  *          1  :  csp = Current client state (buffers, headers, etc...)
2136  *          2  :  header = On input, pointer to header to modify.
2137  *                On output, pointer to the modified header, or NULL
2138  *                to remove the header.  This function frees the
2139  *                original string if necessary.
2140  *
2141  * Returns     :  JB_ERR_OK on success, or
2142  *                JB_ERR_MEMORY on out-of-memory error.
2143  *
2144  *********************************************************************/
2145 jb_err client_x_forwarded(struct client_state *csp, char **header)
2146 {
2147    if ((csp->action->flags & ACTION_HIDE_FORWARDED) == 0)
2148    {
2149       /* Save it so we can re-add it later */
2150       freez(csp->x_forwarded);
2151       csp->x_forwarded = *header;
2152
2153       /*
2154        * Always set *header = NULL, since this information
2155        * will be sent at the end of the header.
2156        */
2157       *header = NULL;
2158    }
2159    else
2160    {
2161       freez(*header);
2162       log_error(LOG_LEVEL_HEADER, "crunched x-forwarded-for!");
2163    }
2164
2165    return JB_ERR_OK;
2166 }
2167
2168
2169 /*********************************************************************
2170  *
2171  * Function    :  client_max_forwards
2172  *
2173  * Description :  If the HTTP method is OPTIONS or TRACE, subtract one
2174  *                from the value of the Max-Forwards header field.
2175  *
2176  * Parameters  :
2177  *          1  :  csp = Current client state (buffers, headers, etc...)
2178  *          2  :  header = On input, pointer to header to modify.
2179  *                On output, pointer to the modified header, or NULL
2180  *                to remove the header.  This function frees the
2181  *                original string if necessary.
2182  *
2183  * Returns     :  JB_ERR_OK on success, or
2184  *                JB_ERR_MEMORY on out-of-memory error.
2185  *
2186  *********************************************************************/
2187 jb_err client_max_forwards(struct client_state *csp, char **header)
2188 {
2189    unsigned int max_forwards;
2190
2191    if ((0 == strcmpic(csp->http->gpc, "trace"))
2192       || (0 == strcmpic(csp->http->gpc, "options")))
2193    {
2194       if (1 == sscanf(*header, "Max-Forwards: %u", &max_forwards))
2195       {
2196          if (max_forwards-- >= 1)
2197          {
2198             sprintf(*header, "Max-Forwards: %u", max_forwards);
2199             log_error(LOG_LEVEL_HEADER, "Max forwards of %s request now %d", csp->http->gpc, max_forwards);
2200          }
2201          else
2202          {
2203             log_error(LOG_LEVEL_ERROR, "Non-intercepted %s request with Max-Forwards zero!", csp->http->gpc);
2204          }
2205       }
2206    }
2207
2208    return JB_ERR_OK;
2209 }
2210
2211
2212 /*********************************************************************
2213  *
2214  * Function    :  client_host
2215  *
2216  * Description :  If the request URI did not contain host and
2217  *                port information, parse and evaluate the Host
2218  *                header field.
2219  *
2220  *                Also, kill ill-formed HOST: headers as sent by
2221  *                Apple's iTunes software when used with a proxy.
2222  *
2223  * Parameters  :
2224  *          1  :  csp = Current client state (buffers, headers, etc...)
2225  *          2  :  header = On input, pointer to header to modify.
2226  *                On output, pointer to the modified header, or NULL
2227  *                to remove the header.  This function frees the
2228  *                original string if necessary.
2229  *
2230  * Returns     :  JB_ERR_OK on success, or
2231  *                JB_ERR_MEMORY on out-of-memory error.
2232  *
2233  *********************************************************************/
2234 jb_err client_host(struct client_state *csp, char **header)
2235 {
2236    char *p, *q;
2237
2238    /*
2239     * If the header field name is all upper-case, chances are that it's
2240     * an ill-formed one from iTunes. BTW, killing innocent headers here is
2241     * not a problem -- they are regenerated later.
2242     */
2243    if ((*header)[1] == 'O')
2244    {
2245       log_error(LOG_LEVEL_HEADER, "Killed all-caps Host header line: %s", *header);
2246       freez(*header);
2247       return JB_ERR_OK;
2248    }
2249
2250    if (!csp->http->hostport || (*csp->http->hostport == '*') ||  
2251        *csp->http->hostport == ' ' || *csp->http->hostport == '\0')
2252    {
2253       
2254       if (NULL == (p = strdup((*header)+6)))
2255       {
2256          return JB_ERR_MEMORY;
2257       }
2258       chomp(p);
2259       if (NULL == (q = strdup(p)))
2260       {
2261          freez(p);
2262          return JB_ERR_MEMORY;
2263       }
2264
2265       freez(csp->http->hostport);
2266       csp->http->hostport = p;
2267       freez(csp->http->host);
2268       csp->http->host = q;
2269       q = strchr(csp->http->host, ':');
2270       if (q != NULL)
2271       {
2272          /* Terminate hostname and evaluate port string */
2273          *q++ = '\0';
2274          csp->http->port = atoi(q);
2275       }
2276       else
2277       {
2278          csp->http->port = csp->http->ssl ? 443 : 80;
2279       }
2280
2281       log_error(LOG_LEVEL_HEADER, "New host and port from Host field: %s = %s:%d",
2282                 csp->http->hostport, csp->http->host, csp->http->port);
2283    }
2284
2285    return JB_ERR_OK;
2286 }
2287
2288 /*********************************************************************
2289  *
2290  * Function    :  client_if_modified_since
2291  *
2292  * Description :  Remove or modify the If-Modified-Since header.
2293  *
2294  * Parameters  :
2295  *          1  :  csp = Current client state (buffers, headers, etc...)
2296  *          2  :  header = On input, pointer to header to modify.
2297  *                On output, pointer to the modified header, or NULL
2298  *                to remove the header.  This function frees the
2299  *                original string if necessary.
2300  *
2301  * Returns     :  JB_ERR_OK on success, or
2302  *                JB_ERR_MEMORY on out-of-memory error.
2303  *
2304  *********************************************************************/
2305 jb_err client_if_modified_since(struct client_state *csp, char **header)
2306 {
2307    char newheader[50];
2308 #ifdef HAVE_GMTIME_R
2309    struct tm gmt;
2310 #endif
2311    struct tm *timeptr = NULL;
2312    time_t tm = 0;                  
2313    const char *newval;
2314    long int rtime;
2315    long int hours, minutes, seconds;
2316    int negative = 0;
2317    char * endptr;
2318    
2319    if ( 0 == strcmpic(*header, "If-Modified-Since: Wed, 08 Jun 1955 12:00:00 GMT"))
2320    {
2321       /* 
2322        * The client got an error message because of a temporary problem,
2323        * the problem is gone and the client now tries to revalidate our
2324        * error message on the real server. The revalidation would always
2325        * end with the transmission of the whole document and there is
2326        * no need to expose the bogus If-Modified-Since header.
2327        */
2328       log_error(LOG_LEVEL_HEADER, "Crunching useless If-Modified-Since header.");
2329       freez(*header);
2330    }
2331    else if (csp->action->flags & ACTION_HIDE_IF_MODIFIED_SINCE)
2332    {
2333       newval = csp->action->string[ACTION_STRING_IF_MODIFIED_SINCE];
2334
2335       if ((0 == strcmpic(newval, "block")))
2336       {
2337          log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
2338          freez(*header);
2339       }
2340       else /* add random value */
2341       {
2342          if ((timeptr = parse_header_time(*header, &tm)) == NULL)
2343          {
2344             log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s (crunching!)", *header);
2345             freez(*header);
2346          }
2347          else
2348          {
2349             rtime = strtol(newval, &endptr, 0);
2350             if(rtime)
2351             {
2352                log_error(LOG_LEVEL_HEADER, "Randomizing: %s (random range: %d minut%s)",
2353                   *header, rtime, (rtime == 1 || rtime == -1) ? "e": "es");
2354                if(rtime < 0)
2355                {
2356                   rtime *= -1; 
2357                   negative = 1;
2358                }
2359                rtime *= 60;
2360                rtime = pick_from_range(rtime);
2361             }
2362             else
2363             {
2364                log_error(LOG_LEVEL_ERROR, "Random range is 0. Assuming time transformation test.",
2365                   *header);
2366             }
2367             tm += rtime * (negative ? -1 : 1);
2368 #ifdef HAVE_GMTIME_R
2369             timeptr = gmtime_r(&tm, &gmt);
2370 #elif FEATURE_PTHREAD
2371             pthread_mutex_lock(&gmtime_mutex);
2372             timeptr = gmtime(&tm);
2373             pthread_mutex_unlock(&gmtime_mutex);
2374 #else
2375             timeptr = gmtime(&tm);
2376 #endif
2377             strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr);
2378
2379             freez(*header);
2380             *header = strdup("If-Modified-Since: ");
2381             string_append(header, newheader);
2382
2383             if (*header == NULL)
2384             {
2385                log_error(LOG_LEVEL_HEADER, "Insufficent memory, header crunched without replacement.");
2386                return JB_ERR_MEMORY;  
2387             }
2388
2389             if(LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */
2390             {
2391                hours   = rtime / 3600;
2392                minutes = rtime / 60 % 60;
2393                seconds = rtime % 60;            
2394
2395                log_error(LOG_LEVEL_HEADER, "Randomized:  %s (%s %d hou%s %d minut%s %d second%s",
2396                   *header, (negative) ? "subtracted" : "added", hours, (hours == 1) ? "r" : "rs",
2397                   minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)");
2398             }
2399          }
2400       }
2401    }
2402
2403    return JB_ERR_OK;
2404 }
2405
2406 /*********************************************************************
2407  *
2408  * Function    :  client_if_none_match
2409  *
2410  * Description :  Remove the If-None-Match header.
2411  *
2412  * Parameters  :
2413  *          1  :  csp = Current client state (buffers, headers, etc...)
2414  *          2  :  header = On input, pointer to header to modify.
2415  *                On output, pointer to the modified header, or NULL
2416  *                to remove the header.  This function frees the
2417  *                original string if necessary.
2418  *
2419  * Returns     :  JB_ERR_OK on success, or
2420  *                JB_ERR_MEMORY on out-of-memory error.
2421  *
2422  *********************************************************************/
2423 jb_err client_if_none_match(struct client_state *csp, char **header)
2424 {
2425    if (csp->action->flags & ACTION_CRUNCH_IF_NONE_MATCH)
2426    {  
2427       log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
2428       freez(*header);
2429    }
2430
2431    return JB_ERR_OK;
2432 }
2433
2434 /*********************************************************************
2435  *
2436  * Function    :  client_x_filter
2437  *
2438  * Description :  Disables filtering if the client set "X-Filter: No".
2439  *                Called from `sed'.
2440  *
2441  * Parameters  :
2442  *          1  :  csp = Current client state (buffers, headers, etc...)
2443  *          2  :  header = On input, pointer to header to modify.
2444  *                On output, pointer to the modified header, or NULL
2445  *                to remove the header.  This function frees the
2446  *                original string if necessary.
2447  *
2448  * Returns     :  JB_ERR_OK on success
2449  *
2450  *********************************************************************/
2451 jb_err client_x_filter(struct client_state *csp, char **header)
2452 {
2453    if ( 0 == strcmpic(*header, "X-Filter: No"))
2454    {
2455       if (!(csp->config->feature_flags & RUNTIME_FEATURE_HTTP_TOGGLE))
2456       {
2457          log_error(LOG_LEVEL_INFO, "Ignored the client's request to fetch without filtering.");
2458       }
2459       else
2460       {
2461          if (csp->action->flags & ACTION_FORCE_TEXT_MODE)
2462          {
2463             log_error(LOG_LEVEL_HEADER, "force-text-mode overruled the client's request to fetch without filtering!");
2464          }
2465          else
2466          {  
2467             csp->content_type = CT_TABOO;
2468             csp->action->flags &= ~ACTION_FILTER_SERVER_HEADERS;
2469             csp->action->flags &= ~ACTION_FILTER_CLIENT_HEADERS;
2470             log_error(LOG_LEVEL_HEADER, "Accepted the client's request to fetch without filtering.");
2471          }
2472          log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
2473          freez(*header);
2474       }
2475    }
2476    return JB_ERR_OK; 
2477 }
2478
2479 /* the following functions add headers directly to the header list */
2480
2481 /*********************************************************************
2482  *
2483  * Function    :  client_host_adder
2484  *
2485  * Description :  Adds the Host: header field if it is missing.
2486  *                Called from `sed'.
2487  *
2488  * Parameters  :
2489  *          1  :  csp = Current client state (buffers, headers, etc...)
2490  *
2491  * Returns     :  JB_ERR_OK on success, or
2492  *                JB_ERR_MEMORY on out-of-memory error.
2493  *
2494  *********************************************************************/
2495 jb_err client_host_adder(struct client_state *csp)
2496 {
2497    char *p;
2498    jb_err err;
2499
2500    if ( !csp->http->hostport || !*(csp->http->hostport))
2501    {
2502       return JB_ERR_OK;
2503    }
2504
2505    /*
2506     * remove 'user:pass@' from 'proto://user:pass@host'
2507     */
2508    if ( (p = strchr( csp->http->hostport, '@')) != NULL )
2509    {
2510       p++;
2511    }
2512    else
2513    {
2514       p = csp->http->hostport;
2515    }
2516
2517    log_error(LOG_LEVEL_HEADER, "addh-unique: Host: %s", p);
2518    err = enlist_unique_header(csp->headers, "Host", p);
2519    return err;
2520
2521 }
2522
2523
2524 /*********************************************************************
2525  *
2526  * Function    :  client_cookie_adder
2527  *
2528  * Description :  Used in the add_client_headers list.  Called from `sed'.
2529  *
2530  * Parameters  :
2531  *          1  :  csp = Current client state (buffers, headers, etc...)
2532  *
2533  * Returns     :  JB_ERR_OK on success, or
2534  *                JB_ERR_MEMORY on out-of-memory error.
2535  *
2536  *********************************************************************/
2537 jb_err client_cookie_adder(struct client_state *csp)
2538 {
2539    struct list_entry *lst;
2540    char *tmp;
2541    struct list_entry *list1 = csp->cookie_list->first;
2542    struct list_entry *list2 = csp->action->multi[ACTION_MULTI_WAFER]->first;
2543    int first_cookie = 1;
2544    jb_err err;
2545
2546    if ((list1 == NULL) && (list2 == NULL))
2547    {
2548       /* Nothing to do */
2549       return JB_ERR_OK;
2550    }
2551
2552    tmp = strdup("Cookie: ");
2553
2554    for (lst = list1; lst ; lst = lst->next)
2555    {
2556       if (first_cookie)
2557       {
2558          first_cookie = 0;
2559       }
2560       else
2561       {
2562          string_append(&tmp, "; ");
2563       }
2564       string_append(&tmp, lst->str);
2565    }
2566
2567    for (lst = list2;  lst ; lst = lst->next)
2568    {
2569       if (first_cookie)
2570       {
2571          first_cookie = 0;
2572       }
2573       else
2574       {
2575          string_append(&tmp, "; ");
2576       }
2577       string_join(&tmp, cookie_encode(lst->str));
2578    }
2579
2580    if (tmp == NULL)
2581    {
2582       return JB_ERR_MEMORY;
2583    }
2584
2585    log_error(LOG_LEVEL_HEADER, "addh: %s", tmp);
2586    err = enlist(csp->headers, tmp);
2587    free(tmp);
2588    return err;
2589 }
2590
2591
2592 /*********************************************************************
2593  *
2594  * Function    :  client_accept_encoding_adder
2595  *
2596  * Description :  Add an Accept-Encoding header to the client's request
2597  *                that disables compression if the action applies, and
2598  *                the header is not already there. Called from `sed'.
2599  *                Note: For HTTP/1.0, the absence of the header is enough.
2600  *
2601  * Parameters  :
2602  *          1  :  csp = Current client state (buffers, headers, etc...)
2603  *
2604  * Returns     :  JB_ERR_OK on success, or
2605  *                JB_ERR_MEMORY on out-of-memory error.
2606  *
2607  *********************************************************************/
2608 jb_err client_accept_encoding_adder(struct client_state *csp)
2609 {
2610    if (   ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
2611        && (!strcmpic(csp->http->ver, "HTTP/1.1")) )
2612    {
2613       return enlist_unique(csp->headers, "Accept-Encoding: identity;q=1.0, *;q=0", 16);
2614    }
2615
2616    return JB_ERR_OK;
2617 }
2618
2619
2620 /*********************************************************************
2621  *
2622  * Function    :  client_xtra_adder
2623  *
2624  * Description :  Used in the add_client_headers list.  Called from `sed'.
2625  *
2626  * Parameters  :
2627  *          1  :  csp = Current client state (buffers, headers, etc...)
2628  *
2629  * Returns     :  JB_ERR_OK on success, or
2630  *                JB_ERR_MEMORY on out-of-memory error.
2631  *
2632  *********************************************************************/
2633 jb_err client_xtra_adder(struct client_state *csp)
2634 {
2635    struct list_entry *lst;
2636    jb_err err;
2637
2638    for (lst = csp->action->multi[ACTION_MULTI_ADD_HEADER]->first;
2639         lst ; lst = lst->next)
2640    {
2641       log_error(LOG_LEVEL_HEADER, "addh: %s", lst->str);
2642       err = enlist(csp->headers, lst->str);
2643       if (err)
2644       {
2645          return err;
2646       }
2647
2648    }
2649
2650    return JB_ERR_OK;
2651 }
2652
2653
2654 /*********************************************************************
2655  *
2656  * Function    :  client_x_forwarded_adder
2657  *
2658  * Description :  Used in the add_client_headers list.  Called from `sed'.
2659  *
2660  * Parameters  :
2661  *          1  :  csp = Current client state (buffers, headers, etc...)
2662  *
2663  * Returns     :  JB_ERR_OK on success, or
2664  *                JB_ERR_MEMORY on out-of-memory error.
2665  *
2666  *********************************************************************/
2667 jb_err client_x_forwarded_adder(struct client_state *csp)
2668 {
2669    char *p = NULL;
2670    jb_err err;
2671
2672    if ((csp->action->flags & ACTION_HIDE_FORWARDED) != 0)
2673    {
2674       return JB_ERR_OK;
2675    }
2676
2677    if (csp->x_forwarded)
2678    {
2679       p = strdup(csp->x_forwarded);
2680       string_append(&p, ", ");
2681    }
2682    else
2683    {
2684       p = strdup("X-Forwarded-For: ");
2685    }
2686    string_append(&p, csp->ip_addr_str);
2687
2688    if (p == NULL)
2689    {
2690       return JB_ERR_MEMORY;
2691    }
2692
2693    log_error(LOG_LEVEL_HEADER, "addh: %s", p);
2694    err = enlist(csp->headers, p);
2695    free(p);
2696
2697    return err;
2698 }
2699
2700
2701 /*********************************************************************
2702  *
2703  * Function    :  connection_close_adder
2704  *
2705  * Description :  Adds a "Connection: close" header to csp->headers
2706  *                as a temporary fix for the needed but missing HTTP/1.1
2707  *                support. Called from `sed'.
2708  *                FIXME: This whole function shouldn't be neccessary!
2709  *
2710  * Parameters  :
2711  *          1  :  csp = Current client state (buffers, headers, etc...)
2712  *
2713  * Returns     :  JB_ERR_OK on success, or
2714  *                JB_ERR_MEMORY on out-of-memory error.
2715  *
2716  *********************************************************************/
2717 jb_err connection_close_adder(struct client_state *csp)
2718 {
2719    log_error(LOG_LEVEL_HEADER, "Adding: Connection: close");
2720    return enlist(csp->headers, "Connection: close");
2721 }
2722
2723
2724 /*********************************************************************
2725  *
2726  * Function    :  server_http
2727  *
2728  * Description :  - Save the HTTP Status into csp->http->status
2729  *                - Set CT_TABOO to prevent filtering if the answer
2730  *                  is a partial range (HTTP status 206)
2731  *                - Rewrite HTTP/1.1 answers to HTTP/1.0 if +downgrade
2732  *                  action applies.
2733  *
2734  * Parameters  :
2735  *          1  :  csp = Current client state (buffers, headers, etc...)
2736  *          2  :  header = On input, pointer to header to modify.
2737  *                On output, pointer to the modified header, or NULL
2738  *                to remove the header.  This function frees the
2739  *                original string if necessary.
2740  *
2741  * Returns     :  JB_ERR_OK on success, or
2742  *                JB_ERR_MEMORY on out-of-memory error.
2743  *
2744  *********************************************************************/
2745 jb_err server_http(struct client_state *csp, char **header)
2746 {
2747    sscanf(*header, "HTTP/%*d.%*d %d", &(csp->http->status));
2748    if (csp->http->status == 206)
2749    {
2750       csp->content_type = CT_TABOO;
2751    }
2752
2753    if ((csp->action->flags & ACTION_DOWNGRADE) != 0)
2754    {
2755       (*header)[7] = '0';
2756       log_error(LOG_LEVEL_HEADER, "Downgraded answer to HTTP/1.0");
2757    }
2758
2759    return JB_ERR_OK;
2760 }
2761
2762
2763 /*********************************************************************
2764  *
2765  * Function    :  server_set_cookie
2766  *
2767  * Description :  Handle the server "cookie" header properly.
2768  *                Log cookie to the jar file.  Then "crunch" it,
2769  *                or accept it.  Called from `sed'.
2770  *
2771  * Parameters  :
2772  *          1  :  csp = Current client state (buffers, headers, etc...)
2773  *          2  :  header = On input, pointer to header to modify.
2774  *                On output, pointer to the modified header, or NULL
2775  *                to remove the header.  This function frees the
2776  *                original string if necessary.
2777  *
2778  * Returns     :  JB_ERR_OK on success, or
2779  *                JB_ERR_MEMORY on out-of-memory error.
2780  *
2781  *********************************************************************/
2782 jb_err server_set_cookie(struct client_state *csp, char **header)
2783 {
2784 #ifdef FEATURE_COOKIE_JAR
2785    if (csp->config->jar)
2786    {
2787       /*
2788        * Write timestamp into outbuf.
2789        *
2790        * Complex because not all OSs have tm_gmtoff or
2791        * the %z field in strftime()
2792        */
2793       char tempbuf[ BUFFER_SIZE ];
2794       time_t now; 
2795       struct tm tm_now; 
2796       time (&now); 
2797 #ifdef HAVE_LOCALTIME_R
2798       tm_now = *localtime_r(&now, &tm_now);
2799 #elif FEATURE_PTHREAD
2800       pthread_mutex_lock(&localtime_mutex);
2801       tm_now = *localtime (&now); 
2802       pthread_mutex_unlock(&localtime_mutex);
2803 #else
2804       tm_now = *localtime (&now); 
2805 #endif
2806       strftime(tempbuf, BUFFER_SIZE-6, "%b %d %H:%M:%S ", &tm_now); 
2807
2808       /* strlen("set-cookie: ") = 12 */
2809       fprintf(csp->config->jar, "%s %s\t%s\n", tempbuf, csp->http->host, *header + 12);
2810    }
2811 #endif /* def FEATURE_COOKIE_JAR */
2812
2813    if ((csp->action->flags & ACTION_NO_COOKIE_SET) != 0)
2814    {
2815       log_error(LOG_LEVEL_HEADER, "Crunched incoming cookie -- yum!");
2816       return crumble(csp, header);
2817    }
2818    else if ((csp->action->flags & ACTION_NO_COOKIE_KEEP) != 0)
2819    {
2820       /* Flag whether or not to log a message */
2821       int changed = 0;
2822
2823       /* A variable to store the tag we're working on */
2824       char *cur_tag;
2825
2826       /* Skip "Set-Cookie:" (11 characters) in header */
2827       cur_tag = *header + 11;
2828
2829       /* skip whitespace between "Set-Cookie:" and value */
2830       while (*cur_tag && ijb_isspace(*cur_tag))
2831       {
2832          cur_tag++;
2833       }
2834
2835       /* Loop through each tag in the cookie */
2836       while (*cur_tag)
2837       {
2838          /* Find next tag */
2839          char *next_tag = strchr(cur_tag, ';');
2840          if (next_tag != NULL)
2841          {
2842             /* Skip the ';' character itself */
2843             next_tag++;
2844
2845             /* skip whitespace ";" and start of tag */
2846             while (*next_tag && ijb_isspace(*next_tag))
2847             {
2848                next_tag++;
2849             }
2850          }
2851          else
2852          {
2853             /* "Next tag" is the end of the string */
2854             next_tag = cur_tag + strlen(cur_tag);
2855          }
2856
2857          /* Is this the "Expires" tag? */
2858          if (strncmpic(cur_tag, "expires=", 8) == 0)
2859          {
2860             /* Delete the tag by copying the rest of the string over it.
2861              * (Note that we cannot just use "strcpy(cur_tag, next_tag)",
2862              * since the behaviour of strcpy is undefined for overlapping
2863              * strings.)
2864              */
2865             memmove(cur_tag, next_tag, strlen(next_tag) + 1);
2866
2867             /* That changed the header, need to issue a log message */
2868             changed = 1;
2869
2870             /* Note that the next tag has now been moved to *cur_tag,
2871              * so we do not need to update the cur_tag pointer.
2872              */
2873          }
2874          else
2875          {
2876             /* Move on to next cookie tag */
2877             cur_tag = next_tag;
2878          }
2879       }
2880
2881       if (changed)
2882       {
2883          log_error(LOG_LEVEL_HEADER, "Changed cookie to a temporary one.");
2884       }
2885    }
2886
2887    return JB_ERR_OK;
2888 }
2889
2890
2891 #ifdef FEATURE_FORCE_LOAD
2892 /*********************************************************************
2893  *
2894  * Function    :  strclean
2895  *
2896  * Description :  In-Situ-Eliminate all occurances of substring in
2897  *                string
2898  *
2899  * Parameters  :
2900  *          1  :  string = string to clean
2901  *          2  :  substring = substring to eliminate
2902  *
2903  * Returns     :  Number of eliminations
2904  *
2905  *********************************************************************/
2906 int strclean(const char *string, const char *substring)
2907 {
2908    int hits = 0, len = strlen(substring);
2909    char *pos, *p;
2910
2911    while((pos = strstr(string, substring)) != NULL)
2912    {
2913       p = pos + len;
2914       do
2915       {
2916          *(p - len) = *p;
2917       }
2918       while (*p++ != '\0');
2919
2920       hits++;
2921    }
2922
2923    return(hits);
2924 }
2925 #endif /* def FEATURE_FORCE_LOAD */
2926
2927 /*********************************************************************
2928  *
2929  * Function    :  parse_header_time
2930  *
2931  * Description :  Transforms time inside a HTTP header into
2932  *                the usual time format.
2933  *
2934  * Parameters  :
2935  *          1  :  header = header to parse
2936  *          2  :  tm = storage for the resulting time in seconds 
2937  *
2938  * Returns     :  Time struct containing the header time, or
2939  *                NULL in case of a parsing problem.
2940  *
2941  *********************************************************************/
2942 struct tm *parse_header_time(char *header, time_t *tm) {
2943
2944    char * timestring;
2945    struct tm gmt;
2946    struct tm * timeptr;
2947
2948    /* Skipping header name */
2949    timestring = strstr(header, ": ");
2950    if (strptime(timestring, ": %a, %d %b %Y %H:%M:%S", &gmt) == NULL)
2951    {
2952       timeptr = NULL;
2953    }
2954    else
2955    {
2956       *tm = timegm(&gmt);
2957       timeptr=&gmt;
2958    }
2959    return(timeptr);
2960
2961 }
2962
2963 /*********************************************************************
2964  *
2965  * Function    :  get_destination_from_headers
2966  *
2967  * Description :  Parse the "Host:" header to get the request's destination.
2968  *                Only needed if the client's request was forcefully
2969  *                redirected into Privoxy.
2970  *
2971  *                Code mainly copied from client_host() which is currently
2972  *                run too late for this purpose.
2973  *
2974  * Parameters  :
2975  *          1  :  headers = List of headers (one of them hopefully being
2976  *                the "Host:" header)
2977  *          2  :  http = storage for the result (host, port and hostport). 
2978  *
2979  * Returns     :  JB_ERR_MEMORY in case of memory problems,
2980  *                JB_ERR_PARSE if the host header couldn't be found,
2981  *                JB_ERR_OK otherwise.
2982  *
2983  *********************************************************************/
2984 jb_err get_destination_from_headers(const struct list *headers, struct http_request *http)
2985 {
2986    char *q;
2987    char *p;
2988    char *host;
2989
2990    host = get_header_value(headers, "Host:");
2991
2992    if (NULL == host)
2993    {
2994       log_error(LOG_LEVEL_ERROR, "No \"Host:\" header found.");
2995       return JB_ERR_PARSE;
2996    }
2997
2998    if (NULL == (p = strdup((host))))
2999    {
3000       log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header");
3001       return JB_ERR_MEMORY;
3002    }
3003    chomp(p);
3004    if (NULL == (q = strdup(p)))
3005    {
3006       freez(p);
3007       log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header");
3008       return JB_ERR_MEMORY;
3009    }
3010
3011    freez(http->hostport);
3012    http->hostport = p;
3013    freez(http->host);
3014    http->host = q;
3015    q = strchr(http->host, ':');
3016    if (q != NULL)
3017    {
3018       /* Terminate hostname and evaluate port string */
3019       *q++ = '\0';
3020       http->port = atoi(q);
3021    }
3022    else
3023    {
3024       http->port = http->ssl ? 443 : 80;
3025    }
3026
3027    /* Rebuild request URL */
3028    freez(http->url);
3029    http->url = strdup(http->ssl ? "https://" : "http://");
3030    string_append(&http->url, http->hostport);
3031    string_append(&http->url, http->path);
3032    if (http->url == NULL)
3033    {
3034       return JB_ERR_MEMORY;
3035    }
3036
3037    log_error(LOG_LEVEL_HEADER, "Destination extracted from \"Host:\" header. New request URL: %s",
3038       http->url);
3039
3040    return JB_ERR_OK;
3041
3042 }
3043
3044
3045 /*
3046   Local Variables:
3047   tab-width: 3
3048   end:
3049 */