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