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