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