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