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