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