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