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