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