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