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