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