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