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