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