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