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