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