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