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