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