build HTML, text and PDF versions of the documentation from source
[privoxy.git] / parsers.c
1 const char parsers_rcs[] = "$Id: parsers.c,v 1.56.2.7 2003/05/06 12:07:26 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/Attic/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.56.2.7  2003/05/06 12:07:26  oes
44  *    Fixed bug #729900: Suspicious HOST: headers are now killed and regenerated if necessary
45  *
46  *    Revision 1.56.2.6  2003/04/14 21:28:30  oes
47  *    Completing the previous change
48  *
49  *    Revision 1.56.2.5  2003/04/14 12:08:16  oes
50  *    Added temporary workaround for bug in PHP < 4.2.3
51  *
52  *    Revision 1.56.2.4  2003/03/07 03:41:05  david__schmidt
53  *    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.
54  *
55  *    Revision 1.56.2.3  2002/11/10 04:20:02  hal9
56  *    Fix typo: supressed -> suppressed
57  *
58  *    Revision 1.56.2.2  2002/09/25 14:59:53  oes
59  *    Improved cookie logging
60  *
61  *    Revision 1.56.2.1  2002/09/25 14:52:45  oes
62  *    Added basic support for OPTIONS and TRACE HTTP methods:
63  *     - New parser function client_max_forwards which decrements
64  *       the Max-Forwards HTTP header field of OPTIONS and TRACE
65  *       requests by one before forwarding
66  *     - New parser function client_host which extracts the host
67  *       and port information from the HTTP header field if the
68  *       request URI was not absolute
69  *     - Don't crumble and re-add the Host: header, but only generate
70  *       and append if missing
71  *
72  *    Revision 1.56  2002/05/12 15:34:22  jongfoster
73  *    Fixing typo in a comment
74  *
75  *    Revision 1.55  2002/05/08 16:01:07  oes
76  *    Optimized add_to_iob:
77  *     - Use realloc instead of malloc(), memcpy(), free()
78  *     - Expand to powers of two if possible, to get
79  *       O(log n) reallocs instead of O(n).
80  *     - Moved check for buffer limit here from chat
81  *     - Report failure via returncode
82  *
83  *    Revision 1.54  2002/04/02 15:03:16  oes
84  *    Tiny code cosmetics
85  *
86  *    Revision 1.53  2002/03/26 22:29:55  swa
87  *    we have a new homepage!
88  *
89  *    Revision 1.52  2002/03/24 13:25:43  swa
90  *    name change related issues
91  *
92  *    Revision 1.51  2002/03/13 00:27:05  jongfoster
93  *    Killing warnings
94  *
95  *    Revision 1.50  2002/03/12 01:45:35  oes
96  *    More verbose logging
97  *
98  *    Revision 1.49  2002/03/09 20:03:52  jongfoster
99  *    - Making various functions return int rather than size_t.
100  *      (Undoing a recent change).  Since size_t is unsigned on
101  *      Windows, functions like read_socket that return -1 on
102  *      error cannot return a size_t.
103  *
104  *      THIS WAS A MAJOR BUG - it caused frequent, unpredictable
105  *      crashes, and also frequently caused JB to jump to 100%
106  *      CPU and stay there.  (Because it thought it had just
107  *      read ((unsigned)-1) == 4Gb of data...)
108  *
109  *    - The signature of write_socket has changed, it now simply
110  *      returns success=0/failure=nonzero.
111  *
112  *    - Trying to get rid of a few warnings --with-debug on
113  *      Windows, I've introduced a new type "jb_socket".  This is
114  *      used for the socket file descriptors.  On Windows, this
115  *      is SOCKET (a typedef for unsigned).  Everywhere else, it's
116  *      an int.  The error value can't be -1 any more, so it's
117  *      now JB_INVALID_SOCKET (which is -1 on UNIX, and in
118  *      Windows it maps to the #define INVALID_SOCKET.)
119  *
120  *    - The signature of bind_port has changed.
121  *
122  *    Revision 1.48  2002/03/07 03:46:53  oes
123  *    Fixed compiler warnings etc
124  *
125  *    Revision 1.47  2002/02/20 23:15:13  jongfoster
126  *    Parsing functions now handle out-of-memory gracefully by returning
127  *    an error code.
128  *
129  *    Revision 1.46  2002/01/17 21:03:47  jongfoster
130  *    Moving all our URL and URL pattern parsing code to urlmatch.c.
131  *
132  *    Revision 1.45  2002/01/09 14:33:03  oes
133  *    Added support for localtime_r.
134  *
135  *    Revision 1.44  2001/12/14 01:22:54  steudten
136  *    Remove 'user:pass@' from 'proto://user:pass@host' for the
137  *    new added header 'Host: ..'. (See Req ID 491818)
138  *
139  *    Revision 1.43  2001/11/23 00:26:38  jongfoster
140  *    Fixing two really stupid errors in my previous commit
141  *
142  *    Revision 1.42  2001/11/22 21:59:30  jongfoster
143  *    Adding code to handle +no-cookies-keep
144  *
145  *    Revision 1.41  2001/11/05 23:43:05  steudten
146  *    Add time+date to log files.
147  *
148  *    Revision 1.40  2001/10/26 20:13:09  jongfoster
149  *    ctype.h is needed in Windows, too.
150  *
151  *    Revision 1.39  2001/10/26 17:40:04  oes
152  *    Introduced get_header_value()
153  *    Removed http->user_agent, csp->referrer and csp->accept_types
154  *    Removed client_accept()
155  *
156  *    Revision 1.38  2001/10/25 03:40:48  david__schmidt
157  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
158  *    threads to call select() simultaneously.  So, it's time to do a real, live,
159  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
160  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
161  *
162  *    Revision 1.37  2001/10/23 21:36:02  jongfoster
163  *    Documenting sed()'s error behaviou (doc change only)
164  *
165  *    Revision 1.36  2001/10/13 12:51:51  joergs
166  *    Removed client_host, (was only required for the old 2.0.2-11 http://noijb.
167  *    force-load), instead crumble Host: and add it (again) in client_host_adder
168  *    (in case we get a HTTP/1.0 request without Host: header and forward it to
169  *    a HTTP/1.1 server/proxy).
170  *
171  *    Revision 1.35  2001/10/09 22:39:21  jongfoster
172  *    assert.h is also required under Win32, so moving out of #ifndef _WIN32
173  *    block.
174  *
175  *    Revision 1.34  2001/10/07 18:50:55  oes
176  *    Added server_content_encoding, renamed server_transfer_encoding
177  *
178  *    Revision 1.33  2001/10/07 18:04:49  oes
179  *    Changed server_http11 to server_http and its pattern to "HTTP".
180  *      Additional functionality: it now saves the HTTP status into
181  *      csp->http->status and sets CT_TABOO for Status 206 (partial range)
182  *
183  *    Revision 1.32  2001/10/07 15:43:28  oes
184  *    Removed FEATURE_DENY_GZIP and replaced it with client_accept_encoding,
185  *       client_te and client_accept_encoding_adder, triggered by the new
186  *       +no-compression action. For HTTP/1.1 the Accept-Encoding header is
187  *       changed to allow only identity and chunked, and the TE header is
188  *       crunched. For HTTP/1.0, Accept-Encoding is crunched.
189  *
190  *    parse_http_request no longer does anything than parsing. The rewriting
191  *      of http->cmd and version mangling are gone. It now also recognizes
192  *      the put and delete methods and saves the url in http->url. Removed
193  *      unused variable.
194  *
195  *    renamed content_type and content_length to have the server_ prefix
196  *
197  *    server_content_type now only works if csp->content_type != CT_TABOO
198  *
199  *    added server_transfer_encoding, which
200  *      - Sets CT_TABOO to prohibit filtering if encoding compresses
201  *      - Raises the CSP_FLAG_CHUNKED flag if Encoding is "chunked"
202  *      - Change from "chunked" to "identity" if body was chunked
203  *        but has been de-chunked for filtering.
204  *
205  *    added server_content_md5 which crunches any Content-MD5 headers
206  *      if the body was modified.
207  *
208  *    made server_http11 conditional on +downgrade action
209  *
210  *    Replaced 6 boolean members of csp with one bitmap (csp->flags)
211  *
212  *    Revision 1.31  2001/10/05 14:25:02  oes
213  *    Crumble Keep-Alive from Server
214  *
215  *    Revision 1.30  2001/09/29 12:56:03  joergs
216  *    IJB now changes HTTP/1.1 to HTTP/1.0 in requests and answers.
217  *
218  *    Revision 1.29  2001/09/24 21:09:24  jongfoster
219  *    Fixing 2 memory leaks that Guy spotted, where the paramater to
220  *    enlist() was not being free()d.
221  *
222  *    Revision 1.28  2001/09/22 16:32:28  jongfoster
223  *    Removing unused #includes.
224  *
225  *    Revision 1.27  2001/09/20 15:45:25  steudten
226  *
227  *    add casting from size_t to int for printf()
228  *    remove local variable shadow s2
229  *
230  *    Revision 1.26  2001/09/16 17:05:14  jongfoster
231  *    Removing unused #include showarg.h
232  *
233  *    Revision 1.25  2001/09/16 13:21:27  jongfoster
234  *    Changes to use new list functions.
235  *
236  *    Revision 1.24  2001/09/13 23:05:50  jongfoster
237  *    Changing the string paramater to the header parsers a "const".
238  *
239  *    Revision 1.23  2001/09/12 18:08:19  steudten
240  *
241  *    In parse_http_request() header rewriting miss the host value, so
242  *    from http://www.mydomain.com the result was just " / " not
243  *    http://www.mydomain.com/ in case we forward.
244  *
245  *    Revision 1.22  2001/09/10 10:58:53  oes
246  *    Silenced compiler warnings
247  *
248  *    Revision 1.21  2001/07/31 14:46:00  oes
249  *     - Persistant connections now suppressed
250  *     - sed() no longer appends empty header to csp->headers
251  *
252  *    Revision 1.20  2001/07/30 22:08:36  jongfoster
253  *    Tidying up #defines:
254  *    - All feature #defines are now of the form FEATURE_xxx
255  *    - Permanently turned off WIN_GUI_EDIT
256  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
257  *
258  *    Revision 1.19  2001/07/25 17:21:54  oes
259  *    client_uagent now saves copy of User-Agent: header value
260  *
261  *    Revision 1.18  2001/07/13 14:02:46  oes
262  *     - Included fix to repair broken HTTP requests that
263  *       don't contain a path, not even '/'.
264  *     - Removed all #ifdef PCRS
265  *     - content_type now always inspected and classified as
266  *       text, gif or other.
267  *     - formatting / comments
268  *
269  *    Revision 1.17  2001/06/29 21:45:41  oes
270  *    Indentation, CRLF->LF, Tab-> Space
271  *
272  *    Revision 1.16  2001/06/29 13:32:42  oes
273  *    - Fixed a comment
274  *    - Adapted free_http_request
275  *    - Removed logentry from cancelled commit
276  *
277  *    Revision 1.15  2001/06/03 19:12:38  oes
278  *    deleted const struct interceptors
279  *
280  *    Revision 1.14  2001/06/01 18:49:17  jongfoster
281  *    Replaced "list_share" with "list" - the tiny memory gain was not
282  *    worth the extra complexity.
283  *
284  *    Revision 1.13  2001/05/31 21:30:33  jongfoster
285  *    Removed list code - it's now in list.[ch]
286  *    Renamed "permission" to "action", and changed many features
287  *    to use the actions file rather than the global config.
288  *
289  *    Revision 1.12  2001/05/31 17:33:13  oes
290  *
291  *    CRLF -> LF
292  *
293  *    Revision 1.11  2001/05/29 20:11:19  joergs
294  *    '/ * inside comment' warning removed.
295  *
296  *    Revision 1.10  2001/05/29 09:50:24  jongfoster
297  *    Unified blocklist/imagelist/permissionslist.
298  *    File format is still under discussion, but the internal changes
299  *    are (mostly) done.
300  *
301  *    Also modified interceptor behaviour:
302  *    - We now intercept all URLs beginning with one of the following
303  *      prefixes (and *only* these prefixes):
304  *        * http://i.j.b/
305  *        * http://ijbswa.sf.net/config/
306  *        * http://ijbswa.sourceforge.net/config/
307  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
308  *    - Internal changes so that intercepted and fast redirect pages
309  *      are not replaced with an image.
310  *    - Interceptors now have the option to send a binary page direct
311  *      to the client. (i.e. ijb-send-banner uses this)
312  *    - Implemented show-url-info interceptor.  (Which is why I needed
313  *      the above interceptors changes - a typical URL is
314  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
315  *      The previous mechanism would not have intercepted that, and
316  *      if it had been intercepted then it then it would have replaced
317  *      it with an image.)
318  *
319  *    Revision 1.9  2001/05/28 17:26:33  jongfoster
320  *    Fixing segfault if last header was crunched.
321  *    Fixing Windows build (snprintf() is _snprintf() under Win32, but we
322  *    can use the cross-platform sprintf() instead.)
323  *
324  *    Revision 1.8  2001/05/27 22:17:04  oes
325  *
326  *    - re_process_buffer no longer writes the modified buffer
327  *      to the client, which was very ugly. It now returns the
328  *      buffer, which it is then written by chat.
329  *
330  *    - content_length now adjusts the Content-Length: header
331  *      for modified documents rather than crunch()ing it.
332  *      (Length info in csp->content_length, which is 0 for
333  *      unmodified documents)
334  *
335  *    - For this to work, sed() is called twice when filtering.
336  *
337  *    Revision 1.7  2001/05/27 13:19:06  oes
338  *    Patched Joergs solution for the content-length in.
339  *
340  *    Revision 1.6  2001/05/26 13:39:32  jongfoster
341  *    Only crunches Content-Length header if applying RE filtering.
342  *    Without this fix, Microsoft Windows Update wouldn't work.
343  *
344  *    Revision 1.5  2001/05/26 00:28:36  jongfoster
345  *    Automatic reloading of config file.
346  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
347  *    Most of the global variables have been moved to a new
348  *    struct configuration_spec, accessed through csp->config->globalname
349  *    Most of the globals remaining are used by the Win32 GUI.
350  *
351  *    Revision 1.4  2001/05/22 18:46:04  oes
352  *
353  *    - Enabled filtering banners by size rather than URL
354  *      by adding patterns that replace all standard banner
355  *      sizes with the "Junkbuster" gif to the re_filterfile
356  *
357  *    - Enabled filtering WebBugs by providing a pattern
358  *      which kills all 1x1 images
359  *
360  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
361  *      which is selected by the (nonstandard and therefore
362  *      capital) letter 'U' in the option string.
363  *      It causes the quantifiers to be ungreedy by default.
364  *      Appending a ? turns back to greedy (!).
365  *
366  *    - Added a new interceptor ijb-send-banner, which
367  *      sends back the "Junkbuster" gif. Without imagelist or
368  *      MSIE detection support, or if tinygif = 1, or the
369  *      URL isn't recognized as an imageurl, a lame HTML
370  *      explanation is sent instead.
371  *
372  *    - Added new feature, which permits blocking remote
373  *      script redirects and firing back a local redirect
374  *      to the browser.
375  *      The feature is conditionally compiled, i.e. it
376  *      can be disabled with --disable-fast-redirects,
377  *      plus it must be activated by a "fast-redirects"
378  *      line in the config file, has its own log level
379  *      and of course wants to be displayed by show-proxy-args
380  *      Note: Boy, all the #ifdefs in 1001 locations and
381  *      all the fumbling with configure.in and acconfig.h
382  *      were *way* more work than the feature itself :-(
383  *
384  *    - Because a generic redirect template was needed for
385  *      this, tinygif = 3 now uses the same.
386  *
387  *    - Moved GIFs, and other static HTTP response templates
388  *      to project.h
389  *
390  *    - Some minor fixes
391  *
392  *    - Removed some >400 CRs again (Jon, you really worked
393  *      a lot! ;-)
394  *
395  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
396  *    Version 2.9.4 checkin.
397  *    - Merged popupfile and cookiefile, and added control over PCRS
398  *      filtering, in new "permissionsfile".
399  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
400  *      file error you now get a message box (in the Win32 GUI) rather
401  *      than the program exiting with no explanation.
402  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
403  *      skipping.
404  *    - Removed tabs from "config"
405  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
406  *    - Bumped up version number.
407  *
408  *    Revision 1.2  2001/05/17 23:02:36  oes
409  *     - Made referrer option accept 'L' as a substitute for '§'
410  *
411  *    Revision 1.1.1.1  2001/05/15 13:59:01  oes
412  *    Initial import of version 2.9.3 source tree
413  *
414  *
415  *********************************************************************/
416 \f
417
418 #include "config.h"
419
420 #ifndef _WIN32
421 #include <stdio.h>
422 #include <sys/types.h>
423 #endif
424
425 #include <stdlib.h>
426 #include <ctype.h>
427 #include <assert.h>
428 #include <string.h>
429
430 #if !defined(_WIN32) && !defined(__OS2__)
431 #include <unistd.h>
432 #endif
433
434 #ifdef OSX_DARWIN
435 #include <pthread.h>
436 #include "jcc.h"
437 /* jcc.h is for mutex semapores only */
438 #endif /* def OSX_DARWIN */
439 #include "project.h"
440 #include "list.h"
441 #include "parsers.h"
442 #include "encode.h"
443 #include "ssplit.h"
444 #include "errlog.h"
445 #include "jbsockets.h"
446 #include "miscutil.h"
447 #include "list.h"
448
449 const char parsers_h_rcs[] = PARSERS_H_VERSION;
450
451 /* Fix a problem with Solaris.  There should be no effect on other
452  * platforms.
453  * Solaris's isspace() is a macro which uses it's argument directly
454  * as an array index.  Therefore we need to make sure that high-bit
455  * characters generate +ve values, and ideally we also want to make
456  * the argument match the declared parameter type of "int".
457  *
458  * Why did they write a character function that can't take a simple
459  * "char" argument?  Doh!
460  */
461 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
462 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
463
464
465 const struct parsers client_patterns[] = {
466    { "referer:",                 8,    client_referrer },
467    { "user-agent:",              11,   client_uagent },
468    { "ua-",                      3,    client_ua },
469    { "from:",                    5,    client_from },
470    { "cookie:",                  7,    client_send_cookie },
471    { "x-forwarded-for:",         16,   client_x_forwarded },
472    { "Accept-Encoding:",         16,   client_accept_encoding },
473    { "TE:",                       3,   client_te },
474    { "Host:",                     5,   client_host },
475 /* { "if-modified-since:",       18,   crumble }, */
476    { "Keep-Alive:",              11,   crumble },
477    { "connection:",              11,   crumble },
478    { "proxy-connection:",        17,   crumble },
479    { "max-forwards:",            13,   client_max_forwards },
480    { NULL,                       0,    NULL }
481 };
482
483
484 const struct parsers server_patterns[] = {
485    { "HTTP",                4, server_http },
486    { "set-cookie:",        11, server_set_cookie },
487    { "connection:",        11, crumble },
488    { "Content-Type:",      13, server_content_type },
489    { "Content-Length:",    15, server_content_length },
490    { "Content-MD5:",       12, server_content_md5 },
491    { "Content-Encoding:",  17, server_content_encoding },
492    { "Transfer-Encoding:", 18, server_transfer_coding },
493    { "Keep-Alive:",        11, crumble },
494    { NULL, 0, NULL }
495 };
496
497
498 const add_header_func_ptr add_client_headers[] = {
499    client_host_adder,
500    client_cookie_adder,
501    client_x_forwarded_adder,
502    client_xtra_adder,
503    /* Temporarily disabled:    client_accept_encoding_adder, */
504    connection_close_adder,
505    NULL
506 };
507
508
509 const add_header_func_ptr add_server_headers[] = {
510    connection_close_adder,
511    NULL
512 };
513
514
515 /*********************************************************************
516  *
517  * Function    :  flush_socket
518  *
519  * Description :  Write any pending "buffered" content.
520  *
521  * Parameters  :
522  *          1  :  fd = file descriptor of the socket to read
523  *          2  :  csp = Current client state (buffers, headers, etc...)
524  *
525  * Returns     :  On success, the number of bytes written are returned (zero
526  *                indicates nothing was written).  On error, -1 is returned,
527  *                and errno is set appropriately.  If count is zero and the
528  *                file descriptor refers to a regular file, 0 will be
529  *                returned without causing any other effect.  For a special
530  *                file, the results are not portable.
531  *
532  *********************************************************************/
533 int flush_socket(jb_socket fd, struct client_state *csp)
534 {
535    struct iob *iob = csp->iob;
536    int len = iob->eod - iob->cur;
537
538    if (len <= 0)
539    {
540       return(0);
541    }
542
543    if (write_socket(fd, iob->cur, (size_t)len))
544    {
545       return(-1);
546    }
547    iob->eod = iob->cur = iob->buf;
548    return(len);
549
550 }
551
552
553 /*********************************************************************
554  *
555  * Function    :  add_to_iob
556  *
557  * Description :  Add content to the buffered page, expanding the
558  *                buffer if necessary.
559  *
560  * Parameters  :
561  *          1  :  csp = Current client state (buffers, headers, etc...)
562  *          2  :  buf = holds the content to be added to the page
563  *          3  :  n = number of bytes to be added
564  *
565  * Returns     :  JB_ERR_OK on success, JB_ERR_MEMORY if out-of-memory
566  *                or buffer limit reached.
567  *
568  *********************************************************************/
569 jb_err add_to_iob(struct client_state *csp, char *buf, int n)
570 {
571    struct iob *iob = csp->iob;
572    size_t used, offset, need, want;
573    char *p;
574
575    if (n <= 0) return JB_ERR_OK;
576
577    used   = iob->eod - iob->buf;
578    offset = iob->cur - iob->buf;
579    need   = used + n + 1;
580
581    /*
582     * If the buffer can't hold the new data, extend it first.
583     * Use the next power of two if possible, else use the actual need.
584     */
585    if (need > csp->config->buffer_limit)
586    {
587       log_error(LOG_LEVEL_ERROR, "Buffer limit reached while extending the buffer (iob)");
588       return JB_ERR_MEMORY;
589    }
590
591    if (need > iob->size)
592    {
593       for (want = csp->iob->size ? csp->iob->size : 512; want <= need;) want *= 2;
594       
595       if (want <= csp->config->buffer_limit && NULL != (p = (char *)realloc(iob->buf, want)))
596       {
597          iob->size = want;
598       }
599       else if (NULL != (p = (char *)realloc(iob->buf, need)))
600       {
601          iob->size = need;
602       }
603       else
604       {
605          log_error(LOG_LEVEL_ERROR, "Extending the buffer (iob) failed: %E");
606          return JB_ERR_MEMORY;
607       }
608
609       /* Update the iob pointers */
610       iob->cur = p + offset;
611       iob->eod = p + used;
612       iob->buf = p;
613    }
614
615    /* copy the new data into the iob buffer */
616    memcpy(iob->eod, buf, (size_t)n);
617
618    /* point to the end of the data */
619    iob->eod += n;
620
621    /* null terminate == cheap insurance */
622    *iob->eod = '\0';
623
624    return JB_ERR_OK;
625
626 }
627
628
629 /*********************************************************************
630  *
631  * Function    :  get_header
632  *
633  * Description :  This (odd) routine will parse the csp->iob
634  *
635  * Parameters  :
636  *          1  :  csp = Current client state (buffers, headers, etc...)
637  *
638  * Returns     :  Any one of the following:
639  *
640  * 1) a pointer to a dynamically allocated string that contains a header line
641  * 2) NULL  indicating that the end of the header was reached
642  * 3) ""    indicating that the end of the iob was reached before finding
643  *          a complete header line.
644  *
645  *********************************************************************/
646 char *get_header(struct client_state *csp)
647 {
648    struct iob *iob;
649    char *p, *q, *ret;
650    iob = csp->iob;
651
652    if ((iob->cur == NULL)
653       || ((p = strchr(iob->cur, '\n')) == NULL))
654    {
655       return(""); /* couldn't find a complete header */
656    }
657
658    *p = '\0';
659
660    ret = strdup(iob->cur);
661    if (ret == NULL)
662    {
663       /* FIXME No way to handle error properly */
664       log_error(LOG_LEVEL_FATAL, "Out of memory in get_header()");
665    }
666
667    iob->cur = p+1;
668
669    if ((q = strchr(ret, '\r')) != NULL) *q = '\0';
670
671    /* is this a blank line (i.e. the end of the header) ? */
672    if (*ret == '\0')
673    {
674       freez(ret);
675       return(NULL);
676    }
677
678    return(ret);
679
680 }
681
682
683 /*********************************************************************
684  *
685  * Function    :  get_header_value
686  *
687  * Description :  Get the value of a given header from a chained list
688  *                of header lines or return NULL if no such header is
689  *                present in the list.
690  *
691  * Parameters  :
692  *          1  :  header_list = pointer to list
693  *          2  :  header_name = string with name of header to look for.
694  *                              Trailing colon required, capitalization
695  *                              doesn't matter.
696  *
697  * Returns     :  NULL if not found, else value of header
698  *
699  *********************************************************************/
700 char *get_header_value(const struct list *header_list, const char *header_name)
701 {
702    struct list_entry *cur_entry;
703    char *ret = NULL;
704    size_t length = 0;
705
706    assert(header_list);
707    assert(header_name);
708    length = strlen(header_name);
709
710    for (cur_entry = header_list->first; cur_entry ; cur_entry = cur_entry->next)
711    {
712       if (cur_entry->str)
713       {
714          if (!strncmpic(cur_entry->str, header_name, length))
715          {
716             /*
717              * Found: return pointer to start of value
718              */
719             ret = (char *) (cur_entry->str + length);
720             while (*ret && ijb_isspace(*ret)) ret++;
721             return(ret);
722          }
723       }
724    }
725
726    /* 
727     * Not found
728     */
729    return NULL;
730
731 }
732
733 /*********************************************************************
734  *
735  * Function    :  sed
736  *
737  * Description :  add, delete or modify lines in the HTTP header streams.
738  *                On entry, it receives a linked list of headers space
739  *                that was allocated dynamically (both the list nodes
740  *                and the header contents).
741  *
742  *                As a side effect it frees the space used by the original
743  *                header lines.
744  *
745  * Parameters  :
746  *          1  :  pats = list of patterns to match against headers
747  *          2  :  more_headers = list of functions to add more
748  *                headers (client or server)
749  *          3  :  csp = Current client state (buffers, headers, etc...)
750  *
751  * Returns     :  Single pointer to a fully formed header, or NULL
752  *                on out-of-memory error.
753  *
754  *********************************************************************/
755 char *sed(const struct parsers pats[],
756           const add_header_func_ptr more_headers[],
757           struct client_state *csp)
758 {
759    struct list_entry *p;
760    const struct parsers *v;
761    const add_header_func_ptr *f;
762    jb_err err = JB_ERR_OK;
763
764    for (v = pats; (err == JB_ERR_OK) && (v->str != NULL) ; v++)
765    {
766       for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL) ; p = p->next)
767       {
768          /* Header crunch()ed in previous run? -> ignore */
769          if (p->str == NULL) continue;
770
771          if (v == pats) log_error(LOG_LEVEL_HEADER, "scan: %s", p->str);
772
773          if (strncmpic(p->str, v->str, v->len) == 0)
774          {
775             err = v->parser(csp, (char **)&(p->str));
776          }
777       }
778    }
779
780    /* place any additional headers on the csp->headers list */
781    for (f = more_headers; (err == JB_ERR_OK) && (*f) ; f++)
782    {
783       err = (*f)(csp);
784    }
785
786    if (err != JB_ERR_OK)
787    {
788       return NULL;
789    }
790
791    return list_to_text(csp->headers);
792 }
793
794
795 /* here begins the family of parser functions that reformat header lines */
796
797
798 /*********************************************************************
799  *
800  * Function    :  crumble
801  *
802  * Description :  This is called if a header matches a pattern to "crunch"
803  *
804  * Parameters  :
805  *          1  :  csp = Current client state (buffers, headers, etc...)
806  *          2  :  header = On input, pointer to header to modify.
807  *                On output, pointer to the modified header, or NULL
808  *                to remove the header.  This function frees the
809  *                original string if necessary.
810  *
811  * Returns     :  JB_ERR_OK on success, or
812  *                JB_ERR_MEMORY on out-of-memory error.
813  *
814  *********************************************************************/
815 jb_err crumble(struct client_state *csp, char **header)
816 {
817    log_error(LOG_LEVEL_HEADER, "crunch!");
818    freez(*header);
819    return JB_ERR_OK;
820 }
821
822
823 /*********************************************************************
824  *
825  * Function    :  server_content_type
826  *
827  * Description :  Set the content-type for filterable types (text/.*,
828  *                javascript and image/gif) unless filtering has been
829  *                forbidden (CT_TABOO) while parsing earlier headers.
830  *                NOTE: Since text/plain is commonly used by web servers
831  *                      for files whose correct type is unknown, we don't
832  *                      set CT_TEXT for it.
833  *
834  * Parameters  :
835  *          1  :  csp = Current client state (buffers, headers, etc...)
836  *          2  :  header = On input, pointer to header to modify.
837  *                On output, pointer to the modified header, or NULL
838  *                to remove the header.  This function frees the
839  *                original string if necessary.
840  *
841  * Returns     :  JB_ERR_OK on success, or
842  *                JB_ERR_MEMORY on out-of-memory error.
843  *
844  *********************************************************************/
845 jb_err server_content_type(struct client_state *csp, char **header)
846 {
847    if (csp->content_type != CT_TABOO)
848    {
849       if ((strstr(*header, " text/") && !strstr(*header, "plain"))
850        || strstr(*header, "application/x-javascript"))
851          csp->content_type = CT_TEXT;
852       else if (strstr(*header, " image/gif"))
853          csp->content_type = CT_GIF;
854       else
855          csp->content_type = 0;
856    }
857
858    return JB_ERR_OK;
859 }
860
861
862 /*********************************************************************
863  *
864  * Function    :  server_transfer_coding
865  *
866  * Description :  - Prohibit filtering (CT_TABOO) if transfer coding compresses
867  *                - Raise the CSP_FLAG_CHUNKED flag if coding is "chunked"
868  *                - Change from "chunked" to "identity" if body was chunked
869  *                  but has been de-chunked for filtering.
870  *
871  * Parameters  :
872  *          1  :  csp = Current client state (buffers, headers, etc...)
873  *          2  :  header = On input, pointer to header to modify.
874  *                On output, pointer to the modified header, or NULL
875  *                to remove the header.  This function frees the
876  *                original string if necessary.
877  *
878  * Returns     :  JB_ERR_OK on success, or
879  *                JB_ERR_MEMORY on out-of-memory error.
880  *
881  *********************************************************************/
882 jb_err server_transfer_coding(struct client_state *csp, char **header)
883 {
884    /*
885     * Turn off pcrs and gif filtering if body compressed
886     */
887    if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate"))
888    {
889       csp->content_type = CT_TABOO;
890    }
891
892    /*
893     * Raise flag if body chunked
894     */
895    if (strstr(*header, "chunked"))
896    {
897       csp->flags |= CSP_FLAG_CHUNKED;
898
899       /*
900        * If the body was modified, it has been
901        * de-chunked first, so adjust the header:
902        */
903       if (csp->flags & CSP_FLAG_MODIFIED)
904       {
905          freez(*header);
906          *header = strdup("Transfer-Encoding: identity");
907          return (header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
908       }
909    }
910
911    return JB_ERR_OK;
912 }
913
914
915 /*********************************************************************
916  *
917  * Function    :  server_content_encoding
918  *
919  * Description :  Prohibit filtering (CT_TABOO) if content encoding compresses
920  *
921  * Parameters  :
922  *          1  :  csp = Current client state (buffers, headers, etc...)
923  *          2  :  header = On input, pointer to header to modify.
924  *                On output, pointer to the modified header, or NULL
925  *                to remove the header.  This function frees the
926  *                original string if necessary.
927  *
928  * Returns     :  JB_ERR_OK on success, or
929  *                JB_ERR_MEMORY on out-of-memory error.
930  *
931  *********************************************************************/
932 jb_err server_content_encoding(struct client_state *csp, char **header)
933 {
934    /*
935     * Turn off pcrs and gif filtering if body compressed
936     */
937    if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate"))
938    {
939       csp->content_type = CT_TABOO;
940    }
941
942    return JB_ERR_OK;
943
944 }
945
946
947 /*********************************************************************
948  *
949  * Function    :  server_content_length
950  *
951  * Description :  Adjust Content-Length header if we modified
952  *                the body.
953  *
954  * Parameters  :
955  *          1  :  csp = Current client state (buffers, headers, etc...)
956  *          2  :  header = On input, pointer to header to modify.
957  *                On output, pointer to the modified header, or NULL
958  *                to remove the header.  This function frees the
959  *                original string if necessary.
960  *
961  * Returns     :  JB_ERR_OK on success, or
962  *                JB_ERR_MEMORY on out-of-memory error.
963  *
964  *********************************************************************/
965 jb_err server_content_length(struct client_state *csp, char **header)
966 {
967    if (csp->content_length != 0) /* Content length has been modified */
968    {
969       freez(*header);
970       *header = (char *) zalloc(100);
971       if (*header == NULL)
972       {
973          return JB_ERR_MEMORY;
974       }
975
976       sprintf(*header, "Content-Length: %d", (int) csp->content_length);
977
978       log_error(LOG_LEVEL_HEADER, "Adjust Content-Length to %d", (int) csp->content_length);
979    }
980
981    return JB_ERR_OK;
982 }
983
984
985 /*********************************************************************
986  *
987  * Function    :  server_content_md5
988  *
989  * Description :  Crumble any Content-MD5 headers if the document was
990  *                modified. FIXME: Should we re-compute instead?
991  *
992  * Parameters  :
993  *          1  :  csp = Current client state (buffers, headers, etc...)
994  *          2  :  header = On input, pointer to header to modify.
995  *                On output, pointer to the modified header, or NULL
996  *                to remove the header.  This function frees the
997  *                original string if necessary.
998  *
999  * Returns     :  JB_ERR_OK on success, or
1000  *                JB_ERR_MEMORY on out-of-memory error.
1001  *
1002  *********************************************************************/
1003 jb_err server_content_md5(struct client_state *csp, char **header)
1004 {
1005    if (csp->flags & CSP_FLAG_MODIFIED)
1006    {
1007       log_error(LOG_LEVEL_HEADER, "Crunching Content-MD5");
1008       freez(*header);
1009    }
1010
1011    return JB_ERR_OK;
1012 }
1013
1014
1015 /*********************************************************************
1016  *
1017  * Function    :  client_accept_encoding
1018  *
1019  * Description :  Rewrite the client's Accept-Encoding header so that
1020  *                if doesn't allow compression, if the action applies.
1021  *                Note: For HTTP/1.0 the absence of the header is enough.
1022  *
1023  * Parameters  :
1024  *          1  :  csp = Current client state (buffers, headers, etc...)
1025  *          2  :  header = On input, pointer to header to modify.
1026  *                On output, pointer to the modified header, or NULL
1027  *                to remove the header.  This function frees the
1028  *                original string if necessary.
1029  *
1030  * Returns     :  JB_ERR_OK on success, or
1031  *                JB_ERR_MEMORY on out-of-memory error.
1032  *
1033  *********************************************************************/
1034 jb_err client_accept_encoding(struct client_state *csp, char **header)
1035 {
1036    if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
1037    {
1038       log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress content");
1039
1040       freez(*header);
1041
1042       /* Temporarily disable the correct behaviour to
1043        * work around a PHP bug. 
1044        *
1045        * if (!strcmpic(csp->http->ver, "HTTP/1.1"))
1046        * {
1047        *    *header = strdup("Accept-Encoding: identity;q=1.0, *;q=0");
1048        *    if (*header == NULL)
1049        *    {
1050        *       return JB_ERR_MEMORY;
1051        *    }
1052        * }
1053        * 
1054        */
1055    }
1056
1057    return JB_ERR_OK;
1058 }
1059
1060
1061 /*********************************************************************
1062  *
1063  * Function    :  client_te
1064  *
1065  * Description :  Rewrite the client's TE header so that
1066  *                if doesn't allow compression, if the action applies.
1067  *
1068  * Parameters  :
1069  *          1  :  csp = Current client state (buffers, headers, etc...)
1070  *          2  :  header = On input, pointer to header to modify.
1071  *                On output, pointer to the modified header, or NULL
1072  *                to remove the header.  This function frees the
1073  *                original string if necessary.
1074  *
1075  * Returns     :  JB_ERR_OK on success, or
1076  *                JB_ERR_MEMORY on out-of-memory error.
1077  *
1078  *********************************************************************/
1079 jb_err client_te(struct client_state *csp, char **header)
1080 {
1081    if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
1082    {
1083       freez(*header);
1084       log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress transfer");
1085    }
1086
1087    return JB_ERR_OK;
1088 }
1089
1090 /*********************************************************************
1091  *
1092  * Function    :  client_referrer
1093  *
1094  * Description :  Handle the "referer" config setting properly.
1095  *                Called from `sed'.
1096  *
1097  * Parameters  :
1098  *          1  :  csp = Current client state (buffers, headers, etc...)
1099  *          2  :  header = On input, pointer to header to modify.
1100  *                On output, pointer to the modified header, or NULL
1101  *                to remove the header.  This function frees the
1102  *                original string if necessary.
1103  *
1104  * Returns     :  JB_ERR_OK on success, or
1105  *                JB_ERR_MEMORY on out-of-memory error.
1106  *
1107  *********************************************************************/
1108 jb_err client_referrer(struct client_state *csp, char **header)
1109 {
1110    const char *newval;
1111
1112 #ifdef FEATURE_FORCE_LOAD
1113    /* Since the referrer can include the prefix even
1114     * even if the request itself is non-forced, we must
1115     * clean it unconditionally
1116     */
1117    strclean(*header, FORCE_PREFIX);
1118 #endif /* def FEATURE_FORCE_LOAD */
1119
1120    /*
1121     * Are we sending referer?
1122     */
1123    if ((csp->action->flags & ACTION_HIDE_REFERER) == 0)
1124    {
1125       return JB_ERR_OK;
1126    }
1127
1128    freez(*header);
1129
1130    newval = csp->action->string[ACTION_STRING_REFERER];
1131
1132    if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
1133    {
1134       /*
1135        * Blocking referer
1136        */
1137       log_error(LOG_LEVEL_HEADER, "crunch!");
1138       return JB_ERR_OK;
1139    }
1140    else if (0 == strncmpic(newval, "http://", 7))
1141    {
1142       /*
1143        * We have a specific (fixed) referer we want to send.
1144        */
1145       log_error(LOG_LEVEL_HEADER, "modified");
1146
1147       *header = strdup("Referer: ");
1148       string_append(header, newval);
1149
1150       return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
1151    }
1152    else
1153    {
1154       /*
1155        * Forge a referer as http://[hostname:port of REQUEST]/
1156        * to fool stupid checks for in-site links
1157        */
1158       if (0 != strcmpic(newval, "forge"))
1159       {
1160          /*
1161           * Invalid choice - but forge is probably the best default.
1162           */
1163          log_error(LOG_LEVEL_ERROR, "Bad parameter: +referer{%s}", newval);
1164       }
1165
1166       *header = strdup("Referer: http://");
1167       string_append(header, csp->http->hostport);
1168       string_append(header, "/");
1169       log_error(LOG_LEVEL_HEADER, "crunch+forge to %s", *header);
1170       
1171       return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
1172    }
1173 }
1174
1175
1176 /*********************************************************************
1177  *
1178  * Function    :  client_uagent
1179  *
1180  * Description :  Handle the "user-agent" config setting properly
1181  *                and remember its original value to enable browser
1182  *                bug workarounds. Called from `sed'.
1183  *
1184  * Parameters  :
1185  *          1  :  csp = Current client state (buffers, headers, etc...)
1186  *          2  :  header = On input, pointer to header to modify.
1187  *                On output, pointer to the modified header, or NULL
1188  *                to remove the header.  This function frees the
1189  *                original string if necessary.
1190  *
1191  * Returns     :  JB_ERR_OK on success, or
1192  *                JB_ERR_MEMORY on out-of-memory error.
1193  *
1194  *********************************************************************/
1195 jb_err client_uagent(struct client_state *csp, char **header)
1196 {
1197    const char *newval;
1198
1199    if ((csp->action->flags & ACTION_HIDE_USER_AGENT) == 0)
1200    {
1201       return JB_ERR_OK;
1202    }
1203
1204    newval = csp->action->string[ACTION_STRING_USER_AGENT];
1205    if (newval == NULL)
1206    {
1207       return JB_ERR_OK;
1208    }
1209
1210    log_error(LOG_LEVEL_HEADER, "modified");
1211
1212    freez(*header);
1213    *header = strdup("User-Agent: ");
1214    string_append(header, newval);
1215
1216    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
1217 }
1218
1219
1220 /*********************************************************************
1221  *
1222  * Function    :  client_ua
1223  *
1224  * Description :  Handle "ua-" headers properly.  Called from `sed'.
1225  *
1226  * Parameters  :
1227  *          1  :  csp = Current client state (buffers, headers, etc...)
1228  *          2  :  header = On input, pointer to header to modify.
1229  *                On output, pointer to the modified header, or NULL
1230  *                to remove the header.  This function frees the
1231  *                original string if necessary.
1232  *
1233  * Returns     :  JB_ERR_OK on success, or
1234  *                JB_ERR_MEMORY on out-of-memory error.
1235  *
1236  *********************************************************************/
1237 jb_err client_ua(struct client_state *csp, char **header)
1238 {
1239    if ((csp->action->flags & ACTION_HIDE_USER_AGENT) != 0)
1240    {
1241       log_error(LOG_LEVEL_HEADER, "crunch!");
1242       freez(*header);
1243    }
1244
1245    return JB_ERR_OK;
1246 }
1247
1248
1249 /*********************************************************************
1250  *
1251  * Function    :  client_from
1252  *
1253  * Description :  Handle the "from" config setting properly.
1254  *                Called from `sed'.
1255  *
1256  * Parameters  :
1257  *          1  :  csp = Current client state (buffers, headers, etc...)
1258  *          2  :  header = On input, pointer to header to modify.
1259  *                On output, pointer to the modified header, or NULL
1260  *                to remove the header.  This function frees the
1261  *                original string if necessary.
1262  *
1263  * Returns     :  JB_ERR_OK on success, or
1264  *                JB_ERR_MEMORY on out-of-memory error.
1265  *
1266  *********************************************************************/
1267 jb_err client_from(struct client_state *csp, char **header)
1268 {
1269    const char *newval;
1270
1271    if ((csp->action->flags & ACTION_HIDE_FROM) == 0)
1272    {
1273       return JB_ERR_OK;
1274    }
1275
1276    freez(*header);
1277
1278    newval = csp->action->string[ACTION_STRING_FROM];
1279
1280    /*
1281     * Are we blocking the e-mail address?
1282     */
1283    if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
1284    {
1285       log_error(LOG_LEVEL_HEADER, "crunch!");
1286       return JB_ERR_OK;
1287    }
1288
1289    log_error(LOG_LEVEL_HEADER, " modified");
1290
1291    *header = strdup("From: ");
1292    string_append(header, newval);
1293
1294    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
1295 }
1296
1297
1298 /*********************************************************************
1299  *
1300  * Function    :  client_send_cookie
1301  *
1302  * Description :  Handle the "cookie" header properly.  Called from `sed'.
1303  *                If cookie is accepted, add it to the cookie_list,
1304  *                else we crunch it.  Mmmmmmmmmmm ... cookie ......
1305  *
1306  * Parameters  :
1307  *          1  :  csp = Current client state (buffers, headers, etc...)
1308  *          2  :  header = On input, pointer to header to modify.
1309  *                On output, pointer to the modified header, or NULL
1310  *                to remove the header.  This function frees the
1311  *                original string if necessary.
1312  *
1313  * Returns     :  JB_ERR_OK on success, or
1314  *                JB_ERR_MEMORY on out-of-memory error.
1315  *
1316  *********************************************************************/
1317 jb_err client_send_cookie(struct client_state *csp, char **header)
1318 {
1319    jb_err result = JB_ERR_OK;
1320
1321    if ((csp->action->flags & ACTION_NO_COOKIE_READ) == 0)
1322    {
1323       /* strlen("cookie: ") == 8 */
1324       result = enlist(csp->cookie_list, *header + 8);
1325    }
1326    else
1327    {
1328       log_error(LOG_LEVEL_HEADER, "Crunched outgoing cookie -- yum!");
1329    }
1330
1331    /*
1332     * Always remove the cookie here.  The cookie header
1333     * will be sent at the end of the header.
1334     */
1335    freez(*header);
1336
1337    return result;
1338 }
1339
1340
1341 /*********************************************************************
1342  *
1343  * Function    :  client_x_forwarded
1344  *
1345  * Description :  Handle the "x-forwarded-for" config setting properly,
1346  *                also used in the add_client_headers list.  Called from `sed'.
1347  *
1348  * Parameters  :
1349  *          1  :  csp = Current client state (buffers, headers, etc...)
1350  *          2  :  header = On input, pointer to header to modify.
1351  *                On output, pointer to the modified header, or NULL
1352  *                to remove the header.  This function frees the
1353  *                original string if necessary.
1354  *
1355  * Returns     :  JB_ERR_OK on success, or
1356  *                JB_ERR_MEMORY on out-of-memory error.
1357  *
1358  *********************************************************************/
1359 jb_err client_x_forwarded(struct client_state *csp, char **header)
1360 {
1361    if ((csp->action->flags & ACTION_HIDE_FORWARDED) == 0)
1362    {
1363       /* Save it so we can re-add it later */
1364       freez(csp->x_forwarded);
1365       csp->x_forwarded = *header;
1366
1367       /*
1368        * Always set *header = NULL, since this information
1369        * will be sent at the end of the header.
1370        */
1371       *header = NULL;
1372    }
1373    else
1374    {
1375       freez(*header);
1376       log_error(LOG_LEVEL_HEADER, " crunch!");
1377    }
1378
1379    return JB_ERR_OK;
1380 }
1381
1382
1383 /*********************************************************************
1384  *
1385  * Function    :  client_max_forwards
1386  *
1387  * Description :  If the HTTP method is OPTIONS or TRACE, subtract one
1388  *                from the value of the Max-Forwards header field.
1389  *
1390  * Parameters  :
1391  *          1  :  csp = Current client state (buffers, headers, etc...)
1392  *          2  :  header = On input, pointer to header to modify.
1393  *                On output, pointer to the modified header, or NULL
1394  *                to remove the header.  This function frees the
1395  *                original string if necessary.
1396  *
1397  * Returns     :  JB_ERR_OK on success, or
1398  *                JB_ERR_MEMORY on out-of-memory error.
1399  *
1400  *********************************************************************/
1401 jb_err client_max_forwards(struct client_state *csp, char **header)
1402 {
1403    unsigned int max_forwards;
1404
1405    if ((0 == strcmpic(csp->http->gpc, "trace"))
1406       || (0 == strcmpic(csp->http->gpc, "options")))
1407    {
1408       if (1 == sscanf(*header, "Max-Forwards: %u", &max_forwards))
1409       {
1410          if (max_forwards-- >= 1)
1411          {
1412             sprintf(*header, "Max-Forwards: %u", max_forwards);
1413             log_error(LOG_LEVEL_HEADER, "Max forwards of %s request now %d", csp->http->gpc, max_forwards);
1414          }
1415          else
1416          {
1417             log_error(LOG_LEVEL_ERROR, "Non-intercepted %s request with Max-Forwards zero!", csp->http->gpc);
1418          }
1419       }
1420    }
1421
1422    return JB_ERR_OK;
1423 }
1424
1425
1426 /*********************************************************************
1427  *
1428  * Function    :  client_host
1429  *
1430  * Description :  If the request URI did not contain host and
1431  *                port information, parse and evaluate the Host
1432  *                header field.
1433  *
1434  *                Also, kill ill-formed HOST: headers as sent by
1435  *                Apple's iTunes software when used with a proxy.
1436  *
1437  * Parameters  :
1438  *          1  :  csp = Current client state (buffers, headers, etc...)
1439  *          2  :  header = On input, pointer to header to modify.
1440  *                On output, pointer to the modified header, or NULL
1441  *                to remove the header.  This function frees the
1442  *                original string if necessary.
1443  *
1444  * Returns     :  JB_ERR_OK on success, or
1445  *                JB_ERR_MEMORY on out-of-memory error.
1446  *
1447  *********************************************************************/
1448 jb_err client_host(struct client_state *csp, char **header)
1449 {
1450    char *p, *q;
1451
1452    /*
1453     * If the header field name is all upper-case, chances are that it's
1454     * an ill-formed one from iTunes. BTW, killing innocent headers here is
1455     * not a problem -- they are regenerated later.
1456     */
1457    if ((*header)[1] == 'O')
1458    {
1459       log_error(LOG_LEVEL_HEADER, "Killed all-caps Host header line: %s", *header);
1460       freez(*header);
1461       return JB_ERR_OK;
1462    }
1463
1464    if (!csp->http->hostport || (*csp->http->hostport == '*') ||  
1465        *csp->http->hostport == ' ' || *csp->http->hostport == '\0')
1466    {
1467       
1468       if (NULL == (p = strdup((*header)+6)))
1469       {
1470          return JB_ERR_MEMORY;
1471       }
1472       chomp(p);
1473       if (NULL == (q = strdup(p)))
1474       {
1475          freez(p);
1476          return JB_ERR_MEMORY;
1477       }
1478
1479       freez(csp->http->hostport);
1480       csp->http->hostport = p;
1481       freez(csp->http->host);
1482       csp->http->host = q;
1483       q = strchr(csp->http->host, ':');
1484       if (q != NULL)
1485       {
1486          /* Terminate hostname and evaluate port string */
1487          *q++ = '\0';
1488          csp->http->port = atoi(q);
1489       }
1490       else
1491       {
1492          csp->http->port = csp->http->ssl ? 443 : 80;
1493       }
1494
1495       log_error(LOG_LEVEL_HEADER, "New host and port from Host field: %s = %s:%d",
1496                 csp->http->hostport, csp->http->host, csp->http->port);
1497    }
1498
1499    return JB_ERR_OK;
1500 }
1501
1502
1503 /* the following functions add headers directly to the header list */
1504
1505 /*********************************************************************
1506  *
1507  * Function    :  client_host_adder
1508  *
1509  * Description :  Adds the Host: header field if it is missing.
1510  *                Called from `sed'.
1511  *
1512  * Parameters  :
1513  *          1  :  csp = Current client state (buffers, headers, etc...)
1514  *
1515  * Returns     :  JB_ERR_OK on success, or
1516  *                JB_ERR_MEMORY on out-of-memory error.
1517  *
1518  *********************************************************************/
1519 jb_err client_host_adder(struct client_state *csp)
1520 {
1521    char *p;
1522    jb_err err;
1523
1524    if ( !csp->http->hostport || !*(csp->http->hostport))
1525    {
1526       return JB_ERR_OK;
1527    }
1528
1529    /*
1530     * remove 'user:pass@' from 'proto://user:pass@host'
1531     */
1532    if ( (p = strchr( csp->http->hostport, '@')) != NULL )
1533    {
1534       p++;
1535    }
1536    else
1537    {
1538       p = csp->http->hostport;
1539    }
1540
1541    log_error(LOG_LEVEL_HEADER, "addh-unique: Host: %s", p);
1542    err = enlist_unique_header(csp->headers, "Host", p);
1543    return err;
1544
1545 }
1546
1547
1548 /*********************************************************************
1549  *
1550  * Function    :  client_cookie_adder
1551  *
1552  * Description :  Used in the add_client_headers list.  Called from `sed'.
1553  *
1554  * Parameters  :
1555  *          1  :  csp = Current client state (buffers, headers, etc...)
1556  *
1557  * Returns     :  JB_ERR_OK on success, or
1558  *                JB_ERR_MEMORY on out-of-memory error.
1559  *
1560  *********************************************************************/
1561 jb_err client_cookie_adder(struct client_state *csp)
1562 {
1563    struct list_entry *lst;
1564    char *tmp;
1565    struct list_entry *list1 = csp->cookie_list->first;
1566    struct list_entry *list2 = csp->action->multi[ACTION_MULTI_WAFER]->first;
1567    int first_cookie = 1;
1568    jb_err err;
1569
1570    if ((list1 == NULL) && (list2 == NULL))
1571    {
1572       /* Nothing to do */
1573       return JB_ERR_OK;
1574    }
1575
1576    tmp = strdup("Cookie: ");
1577
1578    for (lst = list1; lst ; lst = lst->next)
1579    {
1580       if (first_cookie)
1581       {
1582          first_cookie = 0;
1583       }
1584       else
1585       {
1586          string_append(&tmp, "; ");
1587       }
1588       string_append(&tmp, lst->str);
1589    }
1590
1591    for (lst = list2;  lst ; lst = lst->next)
1592    {
1593       if (first_cookie)
1594       {
1595          first_cookie = 0;
1596       }
1597       else
1598       {
1599          string_append(&tmp, "; ");
1600       }
1601       string_join(&tmp, cookie_encode(lst->str));
1602    }
1603
1604    if (tmp == NULL)
1605    {
1606       return JB_ERR_MEMORY;
1607    }
1608
1609    log_error(LOG_LEVEL_HEADER, "addh: %s", tmp);
1610    err = enlist(csp->headers, tmp);
1611    free(tmp);
1612    return err;
1613 }
1614
1615
1616 /*********************************************************************
1617  *
1618  * Function    :  client_accept_encoding_adder
1619  *
1620  * Description :  Add an Accept-Encoding header to the client's request
1621  *                that disables compression if the action applies, and
1622  *                the header is not already there. Called from `sed'.
1623  *                Note: For HTTP/1.0, the absence of the header is enough.
1624  *
1625  * Parameters  :
1626  *          1  :  csp = Current client state (buffers, headers, etc...)
1627  *
1628  * Returns     :  JB_ERR_OK on success, or
1629  *                JB_ERR_MEMORY on out-of-memory error.
1630  *
1631  *********************************************************************/
1632 jb_err client_accept_encoding_adder(struct client_state *csp)
1633 {
1634    if (   ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
1635        && (!strcmpic(csp->http->ver, "HTTP/1.1")) )
1636    {
1637       return enlist_unique(csp->headers, "Accept-Encoding: identity;q=1.0, *;q=0", 16);
1638    }
1639
1640    return JB_ERR_OK;
1641 }
1642
1643
1644 /*********************************************************************
1645  *
1646  * Function    :  client_xtra_adder
1647  *
1648  * Description :  Used in the add_client_headers list.  Called from `sed'.
1649  *
1650  * Parameters  :
1651  *          1  :  csp = Current client state (buffers, headers, etc...)
1652  *
1653  * Returns     :  JB_ERR_OK on success, or
1654  *                JB_ERR_MEMORY on out-of-memory error.
1655  *
1656  *********************************************************************/
1657 jb_err client_xtra_adder(struct client_state *csp)
1658 {
1659    struct list_entry *lst;
1660    jb_err err;
1661
1662    for (lst = csp->action->multi[ACTION_MULTI_ADD_HEADER]->first;
1663         lst ; lst = lst->next)
1664    {
1665       log_error(LOG_LEVEL_HEADER, "addh: %s", lst->str);
1666       err = enlist(csp->headers, lst->str);
1667       if (err)
1668       {
1669          return err;
1670       }
1671
1672    }
1673
1674    return JB_ERR_OK;
1675 }
1676
1677
1678 /*********************************************************************
1679  *
1680  * Function    :  client_x_forwarded_adder
1681  *
1682  * Description :  Used in the add_client_headers list.  Called from `sed'.
1683  *
1684  * Parameters  :
1685  *          1  :  csp = Current client state (buffers, headers, etc...)
1686  *
1687  * Returns     :  JB_ERR_OK on success, or
1688  *                JB_ERR_MEMORY on out-of-memory error.
1689  *
1690  *********************************************************************/
1691 jb_err client_x_forwarded_adder(struct client_state *csp)
1692 {
1693    char *p = NULL;
1694    jb_err err;
1695
1696    if ((csp->action->flags & ACTION_HIDE_FORWARDED) != 0)
1697    {
1698       return JB_ERR_OK;
1699    }
1700
1701    if (csp->x_forwarded)
1702    {
1703       p = strdup(csp->x_forwarded);
1704       string_append(&p, ", ");
1705    }
1706    else
1707    {
1708       p = strdup("X-Forwarded-For: ");
1709    }
1710    string_append(&p, csp->ip_addr_str);
1711
1712    if (p == NULL)
1713    {
1714       return JB_ERR_MEMORY;
1715    }
1716
1717    log_error(LOG_LEVEL_HEADER, "addh: %s", p);
1718    err = enlist(csp->headers, p);
1719    free(p);
1720
1721    return err;
1722 }
1723
1724
1725 /*********************************************************************
1726  *
1727  * Function    :  connection_close_adder
1728  *
1729  * Description :  Adds a "Connection: close" header to csp->headers
1730  *                as a temporary fix for the needed but missing HTTP/1.1
1731  *                support. Called from `sed'.
1732  *                FIXME: This whole function shouldn't be neccessary!
1733  *
1734  * Parameters  :
1735  *          1  :  csp = Current client state (buffers, headers, etc...)
1736  *
1737  * Returns     :  JB_ERR_OK on success, or
1738  *                JB_ERR_MEMORY on out-of-memory error.
1739  *
1740  *********************************************************************/
1741 jb_err connection_close_adder(struct client_state *csp)
1742 {
1743    return enlist(csp->headers, "Connection: close");
1744 }
1745
1746
1747 /*********************************************************************
1748  *
1749  * Function    :  server_http
1750  *
1751  * Description :  - Save the HTTP Status into csp->http->status
1752  *                - Set CT_TABOO to prevent filtering if the answer
1753  *                  is a partial range (HTTP status 206)
1754  *                - Rewrite HTTP/1.1 answers to HTTP/1.0 if +downgrade
1755  *                  action applies.
1756  *
1757  * Parameters  :
1758  *          1  :  csp = Current client state (buffers, headers, etc...)
1759  *          2  :  header = On input, pointer to header to modify.
1760  *                On output, pointer to the modified header, or NULL
1761  *                to remove the header.  This function frees the
1762  *                original string if necessary.
1763  *
1764  * Returns     :  JB_ERR_OK on success, or
1765  *                JB_ERR_MEMORY on out-of-memory error.
1766  *
1767  *********************************************************************/
1768 jb_err server_http(struct client_state *csp, char **header)
1769 {
1770    sscanf(*header, "HTTP/%*d.%*d %d", &(csp->http->status));
1771    if (csp->http->status == 206)
1772    {
1773       csp->content_type = CT_TABOO;
1774    }
1775
1776    if ((csp->action->flags & ACTION_DOWNGRADE) != 0)
1777    {
1778       (*header)[7] = '0';
1779       log_error(LOG_LEVEL_HEADER, "Downgraded answer to HTTP/1.0");
1780    }
1781
1782    return JB_ERR_OK;
1783 }
1784
1785
1786 /*********************************************************************
1787  *
1788  * Function    :  server_set_cookie
1789  *
1790  * Description :  Handle the server "cookie" header properly.
1791  *                Log cookie to the jar file.  Then "crunch" it,
1792  *                or accept it.  Called from `sed'.
1793  *
1794  * Parameters  :
1795  *          1  :  csp = Current client state (buffers, headers, etc...)
1796  *          2  :  header = On input, pointer to header to modify.
1797  *                On output, pointer to the modified header, or NULL
1798  *                to remove the header.  This function frees the
1799  *                original string if necessary.
1800  *
1801  * Returns     :  JB_ERR_OK on success, or
1802  *                JB_ERR_MEMORY on out-of-memory error.
1803  *
1804  *********************************************************************/
1805 jb_err server_set_cookie(struct client_state *csp, char **header)
1806 {
1807 #ifdef FEATURE_COOKIE_JAR
1808    if (csp->config->jar)
1809    {
1810       /*
1811        * Write timestamp into outbuf.
1812        *
1813        * Complex because not all OSs have tm_gmtoff or
1814        * the %z field in strftime()
1815        */
1816       char tempbuf[ BUFFER_SIZE ];
1817       time_t now; 
1818       struct tm tm_now; 
1819       time (&now); 
1820 #ifdef HAVE_LOCALTIME_R
1821       tm_now = *localtime_r(&now, &tm_now);
1822 #elif OSX_DARWIN
1823       pthread_mutex_lock(&localtime_mutex);
1824       tm_now = *localtime (&now); 
1825       pthread_mutex_unlock(&localtime_mutex);
1826 #else
1827       tm_now = *localtime (&now); 
1828 #endif
1829       strftime(tempbuf, BUFFER_SIZE-6, "%b %d %H:%M:%S ", &tm_now); 
1830
1831       /* strlen("set-cookie: ") = 12 */
1832       fprintf(csp->config->jar, "%s %s\t%s\n", tempbuf, csp->http->host, *header + 12);
1833    }
1834 #endif /* def FEATURE_COOKIE_JAR */
1835
1836    if ((csp->action->flags & ACTION_NO_COOKIE_SET) != 0)
1837    {
1838       log_error(LOG_LEVEL_HEADER, "Crunched incoming cookie -- yum!");
1839       return crumble(csp, header);
1840    }
1841    else if ((csp->action->flags & ACTION_NO_COOKIE_KEEP) != 0)
1842    {
1843       /* Flag whether or not to log a message */
1844       int changed = 0;
1845
1846       /* A variable to store the tag we're working on */
1847       char *cur_tag;
1848
1849       /* Skip "Set-Cookie:" (11 characters) in header */
1850       cur_tag = *header + 11;
1851
1852       /* skip whitespace between "Set-Cookie:" and value */
1853       while (*cur_tag && ijb_isspace(*cur_tag))
1854       {
1855          cur_tag++;
1856       }
1857
1858       /* Loop through each tag in the cookie */
1859       while (*cur_tag)
1860       {
1861          /* Find next tag */
1862          char *next_tag = strchr(cur_tag, ';');
1863          if (next_tag != NULL)
1864          {
1865             /* Skip the ';' character itself */
1866             next_tag++;
1867
1868             /* skip whitespace ";" and start of tag */
1869             while (*next_tag && ijb_isspace(*next_tag))
1870             {
1871                next_tag++;
1872             }
1873          }
1874          else
1875          {
1876             /* "Next tag" is the end of the string */
1877             next_tag = cur_tag + strlen(cur_tag);
1878          }
1879
1880          /* Is this the "Expires" tag? */
1881          if (strncmpic(cur_tag, "expires=", 8) == 0)
1882          {
1883             /* Delete the tag by copying the rest of the string over it.
1884              * (Note that we cannot just use "strcpy(cur_tag, next_tag)",
1885              * since the behaviour of strcpy is undefined for overlapping
1886              * strings.)
1887              */
1888             memmove(cur_tag, next_tag, strlen(next_tag) + 1);
1889
1890             /* That changed the header, need to issue a log message */
1891             changed = 1;
1892
1893             /* Note that the next tag has now been moved to *cur_tag,
1894              * so we do not need to update the cur_tag pointer.
1895              */
1896          }
1897          else
1898          {
1899             /* Move on to next cookie tag */
1900             cur_tag = next_tag;
1901          }
1902       }
1903
1904       if (changed)
1905       {
1906          log_error(LOG_LEVEL_HEADER, "Changed cookie to a temporary one.");
1907       }
1908    }
1909
1910    return JB_ERR_OK;
1911 }
1912
1913
1914 #ifdef FEATURE_FORCE_LOAD
1915 /*********************************************************************
1916  *
1917  * Function    :  strclean
1918  *
1919  * Description :  In-Situ-Eliminate all occurances of substring in
1920  *                string
1921  *
1922  * Parameters  :
1923  *          1  :  string = string to clean
1924  *          2  :  substring = substring to eliminate
1925  *
1926  * Returns     :  Number of eliminations
1927  *
1928  *********************************************************************/
1929 int strclean(const char *string, const char *substring)
1930 {
1931    int hits = 0, len = strlen(substring);
1932    char *pos, *p;
1933
1934    while((pos = strstr(string, substring)) != NULL)
1935    {
1936       p = pos + len;
1937       do
1938       {
1939          *(p - len) = *p;
1940       }
1941       while (*p++ != '\0');
1942
1943       hits++;
1944    }
1945
1946    return(hits);
1947 }
1948 #endif /* def FEATURE_FORCE_LOAD */
1949
1950
1951 /*
1952   Local Variables:
1953   tab-width: 3
1954   end:
1955 */