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