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