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