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