Fix the log message from the last commit.
[privoxy.git] / parsers.c
1 const char parsers_rcs[] = "$Id: parsers.c,v 1.179 2009/06/16 15:42:28 fabiankeil 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', `filter_header'
14  *                   `server_content_encoding', `server_content_disposition',
15  *                   `server_last_modified', `client_accept_language',
16  *                   `crunch_client_header', `client_if_modified_since',
17  *                   `client_if_none_match', `get_destination_from_headers',
18  *                   `parse_header_time', `decompress_iob' and `server_set_cookie'.
19  *
20  * Copyright   :  Written by and Copyright (C) 2001-2009 the
21  *                Privoxy team. http://www.privoxy.org/
22  *
23  *                Based on the Internet Junkbuster originally written
24  *                by and Copyright (C) 1997 Anonymous Coders and
25  *                Junkbusters Corporation.  http://www.junkbusters.com
26  *
27  *                This program is free software; you can redistribute it
28  *                and/or modify it under the terms of the GNU General
29  *                Public License as published by the Free Software
30  *                Foundation; either version 2 of the License, or (at
31  *                your option) any later version.
32  *
33  *                This program is distributed in the hope that it will
34  *                be useful, but WITHOUT ANY WARRANTY; without even the
35  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
36  *                PARTICULAR PURPOSE.  See the GNU General Public
37  *                License for more details.
38  *
39  *                The GNU General Public License should be included with
40  *                this file.  If not, you can view it at
41  *                http://www.gnu.org/copyleft/gpl.html
42  *                or write to the Free Software Foundation, Inc., 59
43  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
44  *
45  *********************************************************************/
46
47
48 #include "config.h"
49
50 #ifndef _WIN32
51 #include <stdio.h>
52 #include <sys/types.h>
53 #endif
54
55 #include <stdlib.h>
56 #include <ctype.h>
57 #include <assert.h>
58 #include <string.h>
59
60 #ifdef __GLIBC__
61 /*
62  * Convince GNU's libc to provide a strptime prototype.
63  */
64 #define __USE_XOPEN
65 #endif /*__GLIBC__ */
66 #include <time.h>
67
68 #ifdef FEATURE_ZLIB
69 #include <zlib.h>
70
71 #define GZIP_IDENTIFIER_1       0x1f
72 #define GZIP_IDENTIFIER_2       0x8b
73
74 #define GZIP_FLAG_CHECKSUM      0x02
75 #define GZIP_FLAG_EXTRA_FIELDS  0x04
76 #define GZIP_FLAG_FILE_NAME     0x08
77 #define GZIP_FLAG_COMMENT       0x10
78 #define GZIP_FLAG_RESERVED_BITS 0xe0
79 #endif
80
81 #if !defined(_WIN32) && !defined(__OS2__)
82 #include <unistd.h>
83 #endif
84
85 #include "project.h"
86
87 #ifdef FEATURE_PTHREAD
88 #include "jcc.h"
89 /* jcc.h is for mutex semapores only */
90 #endif /* def FEATURE_PTHREAD */
91 #include "list.h"
92 #include "parsers.h"
93 #include "ssplit.h"
94 #include "errlog.h"
95 #include "jbsockets.h"
96 #include "miscutil.h"
97 #include "list.h"
98 #include "actions.h"
99 #include "filters.h"
100
101 #ifndef HAVE_STRPTIME
102 #include "strptime.h"
103 #endif
104
105 const char parsers_h_rcs[] = PARSERS_H_VERSION;
106
107 /* Fix a problem with Solaris.  There should be no effect on other
108  * platforms.
109  * Solaris's isspace() is a macro which uses its argument directly
110  * as an array index.  Therefore we need to make sure that high-bit
111  * characters generate +ve values, and ideally we also want to make
112  * the argument match the declared parameter type of "int".
113  *
114  * Why did they write a character function that can't take a simple
115  * "char" argument?  Doh!
116  */
117 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
118 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
119
120 static char *get_header_line(struct iob *iob);
121 static jb_err scan_headers(struct client_state *csp);
122 static jb_err header_tagger(struct client_state *csp, char *header);
123 static jb_err parse_header_time(const char *header_time, time_t *result);
124
125 static jb_err crumble                   (struct client_state *csp, char **header);
126 static jb_err filter_header             (struct client_state *csp, char **header);
127 static jb_err client_connection         (struct client_state *csp, char **header);
128 static jb_err client_referrer           (struct client_state *csp, char **header);
129 static jb_err client_uagent             (struct client_state *csp, char **header);
130 static jb_err client_ua                 (struct client_state *csp, char **header);
131 static jb_err client_from               (struct client_state *csp, char **header);
132 static jb_err client_send_cookie        (struct client_state *csp, char **header);
133 static jb_err client_x_forwarded        (struct client_state *csp, char **header);
134 static jb_err client_accept_encoding    (struct client_state *csp, char **header);
135 static jb_err client_te                 (struct client_state *csp, char **header);
136 static jb_err client_max_forwards       (struct client_state *csp, char **header);
137 static jb_err client_host               (struct client_state *csp, char **header);
138 static jb_err client_if_modified_since  (struct client_state *csp, char **header);
139 static jb_err client_accept_language    (struct client_state *csp, char **header);
140 static jb_err client_if_none_match      (struct client_state *csp, char **header);
141 static jb_err crunch_client_header      (struct client_state *csp, char **header);
142 static jb_err client_x_filter           (struct client_state *csp, char **header);
143 static jb_err client_range              (struct client_state *csp, char **header);
144 static jb_err server_set_cookie         (struct client_state *csp, char **header);
145 static jb_err server_connection         (struct client_state *csp, char **header);
146 static jb_err server_content_type       (struct client_state *csp, char **header);
147 static jb_err server_adjust_content_length(struct client_state *csp, char **header);
148 static jb_err server_content_md5        (struct client_state *csp, char **header);
149 static jb_err server_content_encoding   (struct client_state *csp, char **header);
150 static jb_err server_transfer_coding    (struct client_state *csp, char **header);
151 static jb_err server_http               (struct client_state *csp, char **header);
152 static jb_err crunch_server_header      (struct client_state *csp, char **header);
153 static jb_err server_last_modified      (struct client_state *csp, char **header);
154 static jb_err server_content_disposition(struct client_state *csp, char **header);
155
156 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
157 static jb_err server_save_content_length(struct client_state *csp, char **header);
158 static jb_err server_keep_alive(struct client_state *csp, char **header);
159 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
160
161 static jb_err client_host_adder       (struct client_state *csp);
162 static jb_err client_xtra_adder       (struct client_state *csp);
163 static jb_err client_x_forwarded_for_adder(struct client_state *csp);
164 static jb_err client_connection_header_adder(struct client_state *csp);
165 static jb_err server_connection_adder(struct client_state *csp);
166 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
167 static jb_err server_proxy_connection_adder(struct client_state *csp);
168 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
169
170 static jb_err create_forged_referrer(char **header, const char *hostport);
171 static jb_err create_fake_referrer(char **header, const char *fake_referrer);
172 static jb_err handle_conditional_hide_referrer_parameter(char **header,
173    const char *host, const int parameter_conditional_block);
174 static const char *get_appropiate_connection_header(const struct client_state *csp);
175 static void create_content_length_header(unsigned long long content_length,
176                                          char *header, size_t buffer_length);
177
178 /*
179  * List of functions to run on a list of headers.
180  */
181 struct parsers
182 {
183    /** The header prefix to match */
184    const char *str;
185    
186    /** The length of the prefix to match */
187    const size_t len;
188    
189    /** The function to apply to this line */
190    const parser_func_ptr parser;
191 };
192
193 static const struct parsers client_patterns[] = {
194    { "referer:",                  8,   client_referrer },
195    { "user-agent:",              11,   client_uagent },
196    { "ua-",                       3,   client_ua },
197    { "from:",                     5,   client_from },
198    { "cookie:",                   7,   client_send_cookie },
199    { "x-forwarded-for:",         16,   client_x_forwarded },
200    { "Accept-Encoding:",         16,   client_accept_encoding },
201    { "TE:",                       3,   client_te },
202    { "Host:",                     5,   client_host },
203    { "if-modified-since:",       18,   client_if_modified_since },
204 #ifndef FEATURE_CONNECTION_KEEP_ALIVE
205    { "Keep-Alive:",              11,   crumble },
206 #endif
207    { "connection:",              11,   client_connection },
208    { "proxy-connection:",        17,   crumble },
209    { "max-forwards:",            13,   client_max_forwards },
210    { "Accept-Language:",         16,   client_accept_language },
211    { "if-none-match:",           14,   client_if_none_match },
212    { "Range:",                    6,   client_range },
213    { "Request-Range:",           14,   client_range },
214    { "If-Range:",                 9,   client_range },
215    { "X-Filter:",                 9,   client_x_filter },
216    { "*",                         0,   crunch_client_header },
217    { "*",                         0,   filter_header },
218    { NULL,                        0,   NULL }
219 };
220
221 static const struct parsers server_patterns[] = {
222    { "HTTP/",                     5, server_http },
223    { "set-cookie:",              11, server_set_cookie },
224    { "connection:",              11, server_connection },
225    { "Content-Type:",            13, server_content_type },
226    { "Content-MD5:",             12, server_content_md5 },
227    { "Content-Encoding:",        17, server_content_encoding },
228 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
229    { "Content-Length:",          15, server_save_content_length },
230    { "Keep-Alive:",              11, server_keep_alive },
231 #else
232    { "Keep-Alive:",              11, crumble },
233 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
234    { "Transfer-Encoding:",       18, server_transfer_coding },
235    { "content-disposition:",     20, server_content_disposition },
236    { "Last-Modified:",           14, server_last_modified },
237    { "*",                         0, crunch_server_header },
238    { "*",                         0, filter_header },
239    { NULL,                        0, NULL }
240 };
241
242 static const add_header_func_ptr add_client_headers[] = {
243    client_host_adder,
244    client_x_forwarded_for_adder,
245    client_xtra_adder,
246    /* Temporarily disabled:    client_accept_encoding_adder, */
247    client_connection_header_adder,
248    NULL
249 };
250
251 static const add_header_func_ptr add_server_headers[] = {
252    server_connection_adder,
253 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
254    server_proxy_connection_adder,
255 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
256    NULL
257 };
258
259 /*********************************************************************
260  *
261  * Function    :  flush_socket
262  *
263  * Description :  Write any pending "buffered" content.
264  *
265  * Parameters  :
266  *          1  :  fd = file descriptor of the socket to read
267  *          2  :  iob = The I/O buffer to flush, usually csp->iob.
268  *
269  * Returns     :  On success, the number of bytes written are returned (zero
270  *                indicates nothing was written).  On error, -1 is returned,
271  *                and errno is set appropriately.  If count is zero and the
272  *                file descriptor refers to a regular file, 0 will be
273  *                returned without causing any other effect.  For a special
274  *                file, the results are not portable.
275  *
276  *********************************************************************/
277 long flush_socket(jb_socket fd, struct iob *iob)
278 {
279    long len = iob->eod - iob->cur;
280
281    if (len <= 0)
282    {
283       return(0);
284    }
285
286    if (write_socket(fd, iob->cur, (size_t)len))
287    {
288       return(-1);
289    }
290    iob->eod = iob->cur = iob->buf;
291    return(len);
292
293 }
294
295
296 /*********************************************************************
297  *
298  * Function    :  add_to_iob
299  *
300  * Description :  Add content to the buffered page, expanding the
301  *                buffer if necessary.
302  *
303  * Parameters  :
304  *          1  :  csp = Current client state (buffers, headers, etc...)
305  *          2  :  buf = holds the content to be added to the page
306  *          3  :  n = number of bytes to be added
307  *
308  * Returns     :  JB_ERR_OK on success, JB_ERR_MEMORY if out-of-memory
309  *                or buffer limit reached.
310  *
311  *********************************************************************/
312 jb_err add_to_iob(struct client_state *csp, char *buf, long n)
313 {
314    struct iob *iob = csp->iob;
315    size_t used, offset, need, want;
316    char *p;
317
318    if (n <= 0) return JB_ERR_OK;
319
320    used   = (size_t)(iob->eod - iob->buf);
321    offset = (size_t)(iob->cur - iob->buf);
322    need   = used + (size_t)n + 1;
323
324    /*
325     * If the buffer can't hold the new data, extend it first.
326     * Use the next power of two if possible, else use the actual need.
327     */
328    if (need > csp->config->buffer_limit)
329    {
330       log_error(LOG_LEVEL_INFO,
331          "Buffer limit reached while extending the buffer (iob). Needed: %d. Limit: %d",
332          need, csp->config->buffer_limit);
333       return JB_ERR_MEMORY;
334    }
335
336    if (need > iob->size)
337    {
338       for (want = csp->iob->size ? csp->iob->size : 512; want <= need;) want *= 2;
339       
340       if (want <= csp->config->buffer_limit && NULL != (p = (char *)realloc(iob->buf, want)))
341       {
342          iob->size = want;
343       }
344       else if (NULL != (p = (char *)realloc(iob->buf, need)))
345       {
346          iob->size = need;
347       }
348       else
349       {
350          log_error(LOG_LEVEL_ERROR, "Extending the buffer (iob) failed: %E");
351          return JB_ERR_MEMORY;
352       }
353
354       /* Update the iob pointers */
355       iob->cur = p + offset;
356       iob->eod = p + used;
357       iob->buf = p;
358    }
359
360    /* copy the new data into the iob buffer */
361    memcpy(iob->eod, buf, (size_t)n);
362
363    /* point to the end of the data */
364    iob->eod += n;
365
366    /* null terminate == cheap insurance */
367    *iob->eod = '\0';
368
369    return JB_ERR_OK;
370
371 }
372
373
374 #ifdef FEATURE_ZLIB
375 /*********************************************************************
376  *
377  * Function    :  decompress_iob
378  *
379  * Description :  Decompress buffered page, expanding the
380  *                buffer as necessary.  csp->iob->cur
381  *                should point to the the beginning of the
382  *                compressed data block.
383  *
384  * Parameters  :
385  *          1  :  csp = Current client state (buffers, headers, etc...)
386  *
387  * Returns     :  JB_ERR_OK on success,
388  *                JB_ERR_MEMORY if out-of-memory limit reached, and
389  *                JB_ERR_COMPRESS if error decompressing buffer.
390  *
391  *********************************************************************/
392 jb_err decompress_iob(struct client_state *csp)
393 {
394    char  *buf;       /* new, uncompressed buffer */
395    char  *cur;       /* Current iob position (to keep the original 
396                       * iob->cur unmodified if we return early) */
397    size_t bufsize;   /* allocated size of the new buffer */
398    size_t old_size;  /* Content size before decompression */
399    size_t skip_size; /* Number of bytes at the beginning of the iob
400                         that we should NOT decompress. */
401    int status;       /* return status of the inflate() call */
402    z_stream zstr;    /* used by calls to zlib */
403
404    assert(csp->iob->cur - csp->iob->buf > 0);
405    assert(csp->iob->eod - csp->iob->cur > 0);
406
407    bufsize = csp->iob->size;
408    skip_size = (size_t)(csp->iob->cur - csp->iob->buf);
409    old_size = (size_t)(csp->iob->eod - csp->iob->cur);
410
411    cur = csp->iob->cur;
412
413    if (bufsize < (size_t)10)
414    {
415       /*
416        * This is to protect the parsing of gzipped data,
417        * but it should(?) be valid for deflated data also.
418        */
419       log_error(LOG_LEVEL_ERROR, "Buffer too small decompressing iob");
420       return JB_ERR_COMPRESS;
421    }
422
423    if (csp->content_type & CT_GZIP)
424    {
425       /*
426        * Our task is slightly complicated by the facts that data
427        * compressed by gzip does not include a zlib header, and
428        * that there is no easily accessible interface in zlib to
429        * handle a gzip header. We strip off the gzip header by
430        * hand, and later inform zlib not to expect a header.
431        */
432
433       /*
434        * Strip off the gzip header. Please see RFC 1952 for more
435        * explanation of the appropriate fields.
436        */
437       if (((*cur++ & 0xff) != GZIP_IDENTIFIER_1)
438        || ((*cur++ & 0xff) != GZIP_IDENTIFIER_2)
439        || (*cur++ != Z_DEFLATED))
440       {
441          log_error(LOG_LEVEL_ERROR, "Invalid gzip header when decompressing");
442          return JB_ERR_COMPRESS;
443       }
444       else
445       {
446          int flags = *cur++;
447          if (flags & GZIP_FLAG_RESERVED_BITS)
448          {
449             /* The gzip header has reserved bits set; bail out. */
450             log_error(LOG_LEVEL_ERROR, "Invalid gzip header flags when decompressing");
451             return JB_ERR_COMPRESS;
452          }
453
454          /*
455           * Skip mtime (4 bytes), extra flags (1 byte)
456           * and OS type (1 byte).
457           */
458          cur += 6;
459
460          /* Skip extra fields if necessary. */
461          if (flags & GZIP_FLAG_EXTRA_FIELDS)
462          {
463             /*
464              * Skip a given number of bytes, specified
465              * as a 16-bit little-endian value.
466              *
467              * XXX: this code is untested and should probably be removed.
468              */
469             int skip_bytes;
470             skip_bytes = *cur++;
471             skip_bytes += *cur++ << 8;
472
473             /*
474              * The number of bytes to skip should be positive
475              * and we'd like to stay in the buffer.
476              */
477             if ((skip_bytes < 0) || (skip_bytes >= (csp->iob->eod - cur)))
478             {
479                log_error(LOG_LEVEL_ERROR,
480                   "Unreasonable amount of bytes to skip (%d). Stopping decompression",
481                   skip_bytes);
482                return JB_ERR_COMPRESS;
483             }
484             log_error(LOG_LEVEL_INFO,
485                "Skipping %d bytes for gzip compression. Does this sound right?",
486                skip_bytes);
487             cur += skip_bytes;
488          }
489
490          /* Skip the filename if necessary. */
491          if (flags & GZIP_FLAG_FILE_NAME)
492          {
493             /* A null-terminated string is supposed to follow. */
494             while (*cur++ && (cur < csp->iob->eod));
495          }
496
497          /* Skip the comment if necessary. */
498          if (flags & GZIP_FLAG_COMMENT)
499          {
500             /* A null-terminated string is supposed to follow. */
501             while (*cur++ && (cur < csp->iob->eod));
502          }
503
504          /* Skip the CRC if necessary. */
505          if (flags & GZIP_FLAG_CHECKSUM)
506          {
507             cur += 2;
508          }
509
510          if (cur >= csp->iob->eod)
511          {
512             /*
513              * If the current position pointer reached or passed
514              * the buffer end, we were obviously tricked to skip
515              * too much.
516              */
517             log_error(LOG_LEVEL_ERROR,
518                "Malformed gzip header detected. Aborting decompression.");
519             return JB_ERR_COMPRESS;
520          }
521       }
522    }
523    else if (csp->content_type & CT_DEFLATE)
524    {
525       /*
526        * XXX: The debug level should be lowered
527        * before the next stable release.
528        */
529       log_error(LOG_LEVEL_INFO, "Decompressing deflated iob: %d", *cur);
530       /*
531        * In theory (that is, according to RFC 1950), deflate-compressed
532        * data should begin with a two-byte zlib header and have an
533        * adler32 checksum at the end. It seems that in practice only
534        * the raw compressed data is sent. Note that this means that
535        * we are not RFC 1950-compliant here, but the advantage is that
536        * this actually works. :)
537        *
538        * We add a dummy null byte to tell zlib where the data ends,
539        * and later inform it not to expect a header.
540        *
541        * Fortunately, add_to_iob() has thoughtfully null-terminated
542        * the buffer; we can just increment the end pointer to include
543        * the dummy byte.  
544        */
545       csp->iob->eod++;
546    }
547    else
548    {
549       log_error(LOG_LEVEL_ERROR,
550          "Unable to determine compression format for decompression");
551       return JB_ERR_COMPRESS;
552    }
553
554    /* Set up the fields required by zlib. */
555    zstr.next_in  = (Bytef *)cur;
556    zstr.avail_in = (unsigned int)(csp->iob->eod - cur);
557    zstr.zalloc   = Z_NULL;
558    zstr.zfree    = Z_NULL;
559    zstr.opaque   = Z_NULL;
560
561    /*
562     * Passing -MAX_WBITS to inflateInit2 tells the library
563     * that there is no zlib header.
564     */
565    if (inflateInit2(&zstr, -MAX_WBITS) != Z_OK)
566    {
567       log_error(LOG_LEVEL_ERROR, "Error initializing decompression");
568       return JB_ERR_COMPRESS;
569    }
570
571    /*
572     * Next, we allocate new storage for the inflated data.
573     * We don't modify the existing iob yet, so in case there
574     * is error in decompression we can recover gracefully.
575     */
576    buf = zalloc(bufsize);
577    if (NULL == buf)
578    {
579       log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob");
580       return JB_ERR_MEMORY;
581    }
582
583    assert(bufsize >= skip_size);
584    memcpy(buf, csp->iob->buf, skip_size);
585    zstr.avail_out = bufsize - skip_size;
586    zstr.next_out  = (Bytef *)buf + skip_size;
587
588    /* Try to decompress the whole stream in one shot. */
589    while (Z_BUF_ERROR == (status = inflate(&zstr, Z_FINISH)))
590    {
591       /* We need to allocate more memory for the output buffer. */
592
593       char *tmpbuf;                /* used for realloc'ing the buffer */
594       size_t oldbufsize = bufsize; /* keep track of the old bufsize */
595
596       if (0 == zstr.avail_in)
597       {
598          /*
599           * If zlib wants more data then there's a problem, because
600           * the complete compressed file should have been buffered.
601           */
602          log_error(LOG_LEVEL_ERROR,
603             "Unexpected end of compressed iob. Using what we got so far.");
604          break;
605       }
606
607       /*
608        * If we tried the limit and still didn't have enough
609        * memory, just give up.
610        */
611       if (bufsize == csp->config->buffer_limit)
612       {
613          log_error(LOG_LEVEL_ERROR, "Buffer limit reached while decompressing iob");
614          return JB_ERR_MEMORY;
615       }
616
617       /* Try doubling the buffer size each time. */
618       bufsize *= 2;
619
620       /* Don't exceed the buffer limit. */
621       if (bufsize > csp->config->buffer_limit)
622       {
623          bufsize = csp->config->buffer_limit;
624       }
625     
626       /* Try to allocate the new buffer. */
627       tmpbuf = realloc(buf, bufsize);
628       if (NULL == tmpbuf)
629       {
630          log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob");
631          freez(buf);
632          return JB_ERR_MEMORY;
633       }
634       else
635       {
636          char *oldnext_out = (char *)zstr.next_out;
637
638          /*
639           * Update the fields for inflate() to use the new
640           * buffer, which may be in a location different from
641           * the old one.
642           */
643          zstr.avail_out += bufsize - oldbufsize;
644          zstr.next_out   = (Bytef *)tmpbuf + bufsize - zstr.avail_out;
645
646          /*
647           * Compare with an uglier method of calculating these values
648           * that doesn't require the extra oldbufsize variable.
649           */
650          assert(zstr.avail_out == tmpbuf + bufsize - (char *)zstr.next_out);
651          assert((char *)zstr.next_out == tmpbuf + ((char *)oldnext_out - buf));
652          assert(zstr.avail_out > 0U);
653
654          buf = tmpbuf;
655       }
656    }
657
658    if (Z_STREAM_ERROR == inflateEnd(&zstr))
659    {
660       log_error(LOG_LEVEL_ERROR,
661          "Inconsistent stream state after decompression: %s", zstr.msg);
662       /*
663        * XXX: Intentionally no return.
664        *
665        * According to zlib.h, Z_STREAM_ERROR is returned
666        * "if the stream state was inconsistent".
667        *
668        * I assume in this case inflate()'s status
669        * would also be something different than Z_STREAM_END
670        * so this check should be redundant, but lets see.
671        */
672    }
673
674    if ((status != Z_STREAM_END) && (0 != zstr.avail_in))
675    {
676       /*
677        * We failed to decompress the stream and it's
678        * not simply because of missing data.
679        */
680       log_error(LOG_LEVEL_ERROR,
681          "Unexpected error while decompressing to the buffer (iob): %s",
682          zstr.msg);
683       return JB_ERR_COMPRESS;
684    }
685
686    /*
687     * Finally, we can actually update the iob, since the
688     * decompression was successful. First, free the old
689     * buffer.
690     */
691    freez(csp->iob->buf);
692
693    /* Now, update the iob to use the new buffer. */
694    csp->iob->buf  = buf;
695    csp->iob->cur  = csp->iob->buf + skip_size;
696    csp->iob->eod  = (char *)zstr.next_out;
697    csp->iob->size = bufsize;
698   
699    /*
700     * Make sure the new uncompressed iob obeys some minimal
701     * consistency conditions.
702     */
703    if ((csp->iob->buf <  csp->iob->cur)
704     && (csp->iob->cur <= csp->iob->eod)
705     && (csp->iob->eod <= csp->iob->buf + csp->iob->size))
706    {
707       const size_t new_size = (size_t)(csp->iob->eod - csp->iob->cur);
708       if (new_size > (size_t)0)
709       {
710          log_error(LOG_LEVEL_RE_FILTER,
711             "Decompression successful. Old size: %d, new size: %d.",
712             old_size, new_size);
713       }
714       else
715       {
716          /* zlib thinks this is OK, so lets do the same. */
717          log_error(LOG_LEVEL_INFO, "Decompression didn't result in any content.");
718       }
719    }
720    else
721    {
722       /* It seems that zlib did something weird. */
723       log_error(LOG_LEVEL_ERROR,
724          "Unexpected error decompressing the buffer (iob): %d==%d, %d>%d, %d<%d",
725          csp->iob->cur, csp->iob->buf + skip_size, csp->iob->eod, csp->iob->buf,
726          csp->iob->eod, csp->iob->buf + csp->iob->size);
727       return JB_ERR_COMPRESS;
728    }
729
730    return JB_ERR_OK;
731
732 }
733 #endif /* defined(FEATURE_ZLIB) */
734
735
736 /*********************************************************************
737  *
738  * Function    :  string_move
739  *
740  * Description :  memmove wrapper to move the last part of a string
741  *                towards the beginning, overwriting the part in
742  *                the middle. strlcpy() can't be used here as the
743  *                strings overlap.
744  *
745  * Parameters  :
746  *          1  :  dst = Destination to overwrite
747  *          2  :  src = Source to move.
748  *
749  * Returns     :  N/A
750  *
751  *********************************************************************/
752 static void string_move(char *dst, char *src)
753 {
754    assert(dst < src);
755
756    /* +1 to copy the terminating nul as well. */
757    memmove(dst, src, strlen(src)+1);
758 }
759
760
761 /*********************************************************************
762  *
763  * Function    :  normalize_lws
764  *
765  * Description :  Reduces unquoted linear white space in headers
766  *                to a single space in accordance with RFC 2616 2.2.
767  *                This simplifies parsing and filtering later on.
768  *
769  *                XXX: Remove log messages before
770  *                     the next stable release?
771  *
772  * Parameters  :
773  *          1  :  header = A header with linear white space to reduce.
774  *
775  * Returns     :  N/A
776  *
777  *********************************************************************/
778 static void normalize_lws(char *header)
779 {
780    char *p = header;
781
782    while (*p != '\0')
783    {
784       if (ijb_isspace(*p) && ijb_isspace(*(p+1)))
785       {
786          char *q = p+1;
787
788          while (ijb_isspace(*q))
789          {
790             q++;
791          }
792          log_error(LOG_LEVEL_HEADER, "Reducing white space in '%s'", header);
793          string_move(p+1, q);
794       }
795
796       if (*p == '\t')
797       {
798          log_error(LOG_LEVEL_HEADER,
799             "Converting tab to space in '%s'", header);
800          *p = ' ';
801       }
802       else if (*p == '"')
803       {
804          char *end_of_token = strstr(p+1, "\"");
805
806          if (NULL != end_of_token)
807          {
808             /* Don't mess with quoted text. */
809             p = end_of_token;
810          }
811          else
812          {
813             log_error(LOG_LEVEL_HEADER,
814                "Ignoring single quote in '%s'", header);
815          }
816       }
817       p++;
818    }
819
820    p = strchr(header, ':');
821    if ((p != NULL) && (p != header) && ijb_isspace(*(p-1)))
822    {
823       /*
824        * There's still space before the colon.
825        * We don't want it.
826        */
827       string_move(p-1, p);
828    }
829 }
830
831
832 /*********************************************************************
833  *
834  * Function    :  get_header
835  *
836  * Description :  This (odd) routine will parse the csp->iob
837  *                to get the next complete header.
838  *
839  * Parameters  :
840  *          1  :  iob = The I/O buffer to parse, usually csp->iob.
841  *
842  * Returns     :  Any one of the following:
843  *
844  * 1) a pointer to a dynamically allocated string that contains a header line
845  * 2) NULL  indicating that the end of the header was reached
846  * 3) ""    indicating that the end of the iob was reached before finding
847  *          a complete header line.
848  *
849  *********************************************************************/
850 char *get_header(struct iob *iob)
851 {
852    char *header;
853
854    header = get_header_line(iob);
855
856    if ((header == NULL) || (*header == '\0'))
857    {
858       /*
859        * No complete header read yet, tell the client.
860        */
861       return header;
862    }
863
864    while ((iob->cur[0] == ' ') || (iob->cur[0] == '\t'))
865    {
866       /*
867        * Header spans multiple lines, append the next one.
868        */
869       char *continued_header;
870       
871       continued_header = get_header_line(iob);
872       if ((continued_header == NULL) || (*continued_header == '\0'))
873       {
874          /*
875           * No complete header read yet, return what we got.
876           * XXX: Should "unread" header instead.
877           */
878          log_error(LOG_LEVEL_INFO,
879             "Failed to read a multi-line header properly: '%s'",
880             header);
881          break;
882       }
883
884       if (JB_ERR_OK != string_join(&header, continued_header))
885       {
886          log_error(LOG_LEVEL_FATAL,
887             "Out of memory while appending multiple headers.");
888       }
889       else
890       {
891          /* XXX: remove before next stable release. */
892          log_error(LOG_LEVEL_HEADER,
893             "Merged multiple header lines to: '%s'",
894             header);
895       }
896    }
897
898    normalize_lws(header);
899
900    return header;
901
902 }
903
904
905 /*********************************************************************
906  *
907  * Function    :  get_header_line
908  *
909  * Description :  This (odd) routine will parse the csp->iob
910  *                to get the next header line.
911  *
912  * Parameters  :
913  *          1  :  iob = The I/O buffer to parse, usually csp->iob.
914  *
915  * Returns     :  Any one of the following:
916  *
917  * 1) a pointer to a dynamically allocated string that contains a header line
918  * 2) NULL  indicating that the end of the header was reached
919  * 3) ""    indicating that the end of the iob was reached before finding
920  *          a complete header line.
921  *
922  *********************************************************************/
923 static char *get_header_line(struct iob *iob)
924 {
925    char *p, *q, *ret;
926
927    if ((iob->cur == NULL)
928       || ((p = strchr(iob->cur, '\n')) == NULL))
929    {
930       return(""); /* couldn't find a complete header */
931    }
932
933    *p = '\0';
934
935    ret = strdup(iob->cur);
936    if (ret == NULL)
937    {
938       /* FIXME No way to handle error properly */
939       log_error(LOG_LEVEL_FATAL, "Out of memory in get_header_line()");
940    }
941    assert(ret != NULL);
942
943    iob->cur = p+1;
944
945    if ((q = strchr(ret, '\r')) != NULL) *q = '\0';
946
947    /* is this a blank line (i.e. the end of the header) ? */
948    if (*ret == '\0')
949    {
950       freez(ret);
951       return NULL;
952    }
953
954    return ret;
955
956 }
957
958
959 /*********************************************************************
960  *
961  * Function    :  get_header_value
962  *
963  * Description :  Get the value of a given header from a chained list
964  *                of header lines or return NULL if no such header is
965  *                present in the list.
966  *
967  * Parameters  :
968  *          1  :  header_list = pointer to list
969  *          2  :  header_name = string with name of header to look for.
970  *                              Trailing colon required, capitalization
971  *                              doesn't matter.
972  *
973  * Returns     :  NULL if not found, else value of header
974  *
975  *********************************************************************/
976 char *get_header_value(const struct list *header_list, const char *header_name)
977 {
978    struct list_entry *cur_entry;
979    char *ret = NULL;
980    size_t length = 0;
981
982    assert(header_list);
983    assert(header_name);
984    length = strlen(header_name);
985
986    for (cur_entry = header_list->first; cur_entry ; cur_entry = cur_entry->next)
987    {
988       if (cur_entry->str)
989       {
990          if (!strncmpic(cur_entry->str, header_name, length))
991          {
992             /*
993              * Found: return pointer to start of value
994              */
995             ret = cur_entry->str + length;
996             while (*ret && ijb_isspace(*ret)) ret++;
997             return ret;
998          }
999       }
1000    }
1001
1002    /* 
1003     * Not found
1004     */
1005    return NULL;
1006
1007 }
1008
1009
1010 /*********************************************************************
1011  *
1012  * Function    :  scan_headers
1013  *
1014  * Description :  Scans headers, applies tags and updates action bits. 
1015  *
1016  * Parameters  :
1017  *          1  :  csp = Current client state (buffers, headers, etc...)
1018  *
1019  * Returns     :  JB_ERR_OK
1020  *
1021  *********************************************************************/
1022 static jb_err scan_headers(struct client_state *csp)
1023 {
1024    struct list_entry *h; /* Header */
1025    jb_err err = JB_ERR_OK;
1026
1027    for (h = csp->headers->first; (err == JB_ERR_OK) && (h != NULL) ; h = h->next)
1028    {
1029       /* Header crunch()ed in previous run? -> ignore */
1030       if (h->str == NULL) continue;
1031       log_error(LOG_LEVEL_HEADER, "scan: %s", h->str);
1032       err = header_tagger(csp, h->str);
1033    }
1034
1035    return err;
1036 }
1037
1038
1039 /*********************************************************************
1040  *
1041  * Function    :  sed
1042  *
1043  * Description :  add, delete or modify lines in the HTTP header streams.
1044  *                On entry, it receives a linked list of headers space
1045  *                that was allocated dynamically (both the list nodes
1046  *                and the header contents).
1047  *
1048  *                As a side effect it frees the space used by the original
1049  *                header lines.
1050  *
1051  * Parameters  :
1052  *          1  :  csp = Current client state (buffers, headers, etc...)
1053  *          2  :  filter_server_headers = Boolean to switch between
1054  *                                        server and header filtering.
1055  *
1056  * Returns     :  JB_ERR_OK in case off success, or
1057  *                JB_ERR_MEMORY on out-of-memory error.
1058  *
1059  *********************************************************************/
1060 jb_err sed(struct client_state *csp, int filter_server_headers)
1061 {
1062    /* XXX: use more descriptive names. */
1063    struct list_entry *p;
1064    const struct parsers *v;
1065    const add_header_func_ptr *f;
1066    jb_err err = JB_ERR_OK;
1067
1068    if (filter_server_headers)
1069    {
1070       v = server_patterns;
1071       f = add_server_headers;
1072    }
1073    else
1074    {
1075       v = client_patterns;
1076       f = add_client_headers;
1077    }
1078
1079    scan_headers(csp);
1080
1081    while ((err == JB_ERR_OK) && (v->str != NULL))
1082    {
1083       for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL); p = p->next)
1084       {
1085          /* Header crunch()ed in previous run? -> ignore */
1086          if (p->str == NULL) continue;
1087
1088          /* Does the current parser handle this header? */
1089          if ((strncmpic(p->str, v->str, v->len) == 0) ||
1090              (v->len == CHECK_EVERY_HEADER_REMAINING))
1091          {
1092             err = v->parser(csp, &(p->str));
1093          }
1094       }
1095       v++;
1096    }
1097
1098    /* place additional headers on the csp->headers list */
1099    while ((err == JB_ERR_OK) && (*f))
1100    {
1101       err = (*f)(csp);
1102       f++;
1103    }
1104
1105    return err;
1106 }
1107
1108
1109 /*********************************************************************
1110  *
1111  * Function    :  update_server_headers
1112  *
1113  * Description :  Updates server headers after the body has been modified.
1114  *
1115  * Parameters  :
1116  *          1  :  csp = Current client state (buffers, headers, etc...)
1117  *
1118  * Returns     :  JB_ERR_OK in case off success, or
1119  *                JB_ERR_MEMORY on out-of-memory error.
1120  *
1121  *********************************************************************/
1122 jb_err update_server_headers(struct client_state *csp)
1123 {
1124    jb_err err = JB_ERR_OK;
1125
1126    static const struct parsers server_patterns_light[] = {
1127       { "Content-Length:",    15, server_adjust_content_length },
1128       { "Transfer-Encoding:", 18, server_transfer_coding },
1129 #ifdef FEATURE_ZLIB
1130       { "Content-Encoding:",  17, server_content_encoding },
1131 #endif /* def FEATURE_ZLIB */
1132       { NULL,                  0, NULL }
1133    };
1134
1135    if (strncmpic(csp->http->cmd, "HEAD", 4))
1136    {
1137       const struct parsers *v;
1138       struct list_entry *p;
1139
1140       for (v = server_patterns_light; (err == JB_ERR_OK) && (v->str != NULL); v++)
1141       {
1142          for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL); p = p->next)
1143          {
1144             /* Header crunch()ed in previous run? -> ignore */
1145             if (p->str == NULL) continue;
1146
1147             /* Does the current parser handle this header? */
1148             if (strncmpic(p->str, v->str, v->len) == 0)
1149             {
1150                err = v->parser(csp, (char **)&(p->str));
1151             }
1152          }
1153       }
1154    }
1155
1156 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
1157    if ((JB_ERR_OK == err)
1158     && (csp->flags & CSP_FLAG_MODIFIED)
1159     && (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)
1160     && !(csp->flags & CSP_FLAG_SERVER_CONTENT_LENGTH_SET))
1161    {
1162       char header[50];
1163
1164       create_content_length_header(csp->content_length, header, sizeof(header));
1165       err = enlist(csp->headers, header);
1166       if (JB_ERR_OK == err)
1167       {
1168          log_error(LOG_LEVEL_HEADER,
1169             "Content modified with no Content-Length header set. "
1170             "Created: %s.", header);
1171       }
1172    }
1173 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
1174
1175    return err;
1176 }
1177
1178
1179 /*********************************************************************
1180  *
1181  * Function    :  header_tagger
1182  *
1183  * Description :  Executes all text substitutions from applying
1184  *                tag actions and saves the result as tag.
1185  *
1186  *                XXX: Shares enough code with filter_header() and
1187  *                pcrs_filter_response() to warrant some helper functions.
1188  *
1189  * Parameters  :
1190  *          1  :  csp = Current client state (buffers, headers, etc...)
1191  *          2  :  header = Header that is used as tagger input
1192  *
1193  * Returns     :  JB_ERR_OK on success and always succeeds
1194  *
1195  *********************************************************************/
1196 static jb_err header_tagger(struct client_state *csp, char *header)
1197 {
1198    int wanted_filter_type;
1199    int multi_action_index;
1200    int i;
1201    pcrs_job *job;
1202
1203    struct file_list *fl;
1204    struct re_filterfile_spec *b;
1205    struct list_entry *tag_name;
1206
1207    int found_filters = 0;
1208    const size_t header_length = strlen(header);
1209
1210    if (csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
1211    {
1212       wanted_filter_type = FT_SERVER_HEADER_TAGGER;
1213       multi_action_index = ACTION_MULTI_SERVER_HEADER_TAGGER;
1214    }
1215    else
1216    {
1217       wanted_filter_type = FT_CLIENT_HEADER_TAGGER;
1218       multi_action_index = ACTION_MULTI_CLIENT_HEADER_TAGGER;
1219    }
1220
1221    /* Check if there are any filters */
1222    for (i = 0; i < MAX_AF_FILES; i++)
1223    {
1224       fl = csp->rlist[i];
1225       if (NULL != fl)
1226       {
1227          if (NULL != fl->f)
1228          {
1229            found_filters = 1;
1230            break;
1231          }
1232       }
1233    }
1234
1235    if (0 == found_filters)
1236    {
1237       log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: "
1238          "tagging enabled, but no taggers available.");
1239       return JB_ERR_OK;
1240    }
1241
1242    for (i = 0; i < MAX_AF_FILES; i++)
1243    {
1244       fl = csp->rlist[i];
1245       if ((NULL == fl) || (NULL == fl->f))
1246       {
1247          /*
1248           * Either there are no filter files
1249           * left, or this filter file just
1250           * contains no valid filters.
1251           *
1252           * Continue to be sure we don't miss
1253           * valid filter files that are chained
1254           * after empty or invalid ones.
1255           */
1256          continue;
1257       }
1258
1259       /* For all filters, */
1260       for (b = fl->f; b; b = b->next)
1261       {
1262          if (b->type != wanted_filter_type)
1263          {
1264             /* skip the ones we don't care about, */
1265             continue;
1266          }
1267          /* leaving only taggers that could apply, of which we use the ones, */
1268          for (tag_name = csp->action->multi[multi_action_index]->first;
1269               NULL != tag_name; tag_name = tag_name->next)
1270          {
1271             /* that do apply, and */
1272             if (strcmp(b->name, tag_name->str) == 0)
1273             {
1274                char *modified_tag = NULL;
1275                char *tag = header;
1276                size_t size = header_length;
1277                pcrs_job *joblist = b->joblist;
1278
1279                if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b);
1280
1281                if (NULL == joblist)
1282                {
1283                   log_error(LOG_LEVEL_RE_FILTER,
1284                      "Tagger %s has empty joblist. Nothing to do.", b->name);
1285                   continue;
1286                }
1287
1288                /* execute their pcrs_joblist on the header. */
1289                for (job = joblist; NULL != job; job = job->next)
1290                {
1291                   const int hits = pcrs_execute(job, tag, size, &modified_tag, &size);
1292
1293                   if (0 < hits)
1294                   {
1295                      /* Success, continue with the modified version. */
1296                      if (tag != header)
1297                      {
1298                         freez(tag);
1299                      }
1300                      tag = modified_tag;
1301                   }
1302                   else
1303                   {
1304                      /* Tagger doesn't match */
1305                      if (0 > hits)
1306                      {
1307                         /* Regex failure, log it but continue anyway. */
1308                         assert(NULL != header);
1309                         log_error(LOG_LEVEL_ERROR,
1310                            "Problems with tagger \'%s\' and header \'%s\': %s",
1311                            b->name, *header, pcrs_strerror(hits));
1312                      }
1313                      freez(modified_tag);
1314                   }
1315                }
1316
1317                if (b->dynamic) pcrs_free_joblist(joblist);
1318
1319                /* If this tagger matched */
1320                if (tag != header)
1321                {
1322                   if (0 == size)
1323                   {
1324                      /*
1325                       * There is to technical limitation which makes
1326                       * it impossible to use empty tags, but I assume
1327                       * no one would do it intentionally.
1328                       */
1329                      freez(tag);
1330                      log_error(LOG_LEVEL_INFO,
1331                         "Tagger \'%s\' created an empty tag. Ignored.",
1332                         b->name);
1333                      continue;
1334                   }
1335  
1336                   if (!list_contains_item(csp->tags, tag))
1337                   {
1338                      if (JB_ERR_OK != enlist(csp->tags, tag))
1339                      {
1340                         log_error(LOG_LEVEL_ERROR,
1341                            "Insufficient memory to add tag \'%s\', "
1342                            "based on tagger \'%s\' and header \'%s\'",
1343                            tag, b->name, *header);
1344                      }
1345                      else
1346                      {
1347                         char *action_message;
1348                         /*
1349                          * update the action bits right away, to make
1350                          * tagging based on tags set by earlier taggers
1351                          * of the same kind possible.
1352                          */
1353                         if (update_action_bits_for_tag(csp, tag))
1354                         {
1355                            action_message = "Action bits updated accordingly.";
1356                         }
1357                         else
1358                         {
1359                            action_message = "No action bits update necessary.";
1360                         }
1361
1362                         log_error(LOG_LEVEL_HEADER,
1363                            "Tagger \'%s\' added tag \'%s\'. %s",
1364                            b->name, tag, action_message);
1365                      }
1366                   }
1367                   else
1368                   {
1369                      /* XXX: Is this log-worthy? */
1370                      log_error(LOG_LEVEL_HEADER,
1371                         "Tagger \'%s\' didn't add tag \'%s\'. "
1372                         "Tag already present", b->name, tag);
1373                   }
1374                   freez(tag);
1375                } /* if the tagger matched */
1376             } /* if the tagger applies */
1377          } /* for every tagger that could apply */
1378       } /* for all filters */
1379    } /* for all filter files */
1380
1381    return JB_ERR_OK;
1382 }
1383
1384 /* here begins the family of parser functions that reformat header lines */
1385
1386 /*********************************************************************
1387  *
1388  * Function    :  filter_header
1389  *
1390  * Description :  Executes all text substitutions from all applying
1391  *                +(server|client)-header-filter actions on the header.
1392  *                Most of the code was copied from pcrs_filter_response,
1393  *                including the rather short variable names
1394  *
1395  * Parameters  :
1396  *          1  :  csp = Current client state (buffers, headers, etc...)
1397  *          2  :  header = On input, pointer to header to modify.
1398  *                On output, pointer to the modified header, or NULL
1399  *                to remove the header.  This function frees the
1400  *                original string if necessary.
1401  *
1402  * Returns     :  JB_ERR_OK on success and always succeeds
1403  *
1404  *********************************************************************/
1405 static jb_err filter_header(struct client_state *csp, char **header)
1406 {
1407    int hits=0;
1408    int matches;
1409    size_t size = strlen(*header);
1410
1411    char *newheader = NULL;
1412    pcrs_job *job;
1413
1414    struct file_list *fl;
1415    struct re_filterfile_spec *b;
1416    struct list_entry *filtername;
1417
1418    int i, found_filters = 0;
1419    int wanted_filter_type;
1420    int multi_action_index;
1421
1422    if (csp->flags & CSP_FLAG_NO_FILTERING)
1423    {
1424       return JB_ERR_OK;
1425    }
1426
1427    if (csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
1428    {
1429       wanted_filter_type = FT_SERVER_HEADER_FILTER;
1430       multi_action_index = ACTION_MULTI_SERVER_HEADER_FILTER;
1431    }
1432    else
1433    {
1434       wanted_filter_type = FT_CLIENT_HEADER_FILTER;
1435       multi_action_index = ACTION_MULTI_CLIENT_HEADER_FILTER;
1436    }
1437
1438    /*
1439     * Need to check the set of re_filterfiles...
1440     */
1441    for (i = 0; i < MAX_AF_FILES; i++)
1442    {
1443       fl = csp->rlist[i];
1444       if (NULL != fl)
1445       {
1446          if (NULL != fl->f)
1447          {
1448            found_filters = 1;
1449            break;
1450          }
1451       }
1452    }
1453
1454    if (0 == found_filters)
1455    {
1456       log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: "
1457          "header filtering enabled, but no matching filters available.");
1458       return JB_ERR_OK;
1459    }
1460
1461    for (i = 0; i < MAX_AF_FILES; i++)
1462    {
1463       fl = csp->rlist[i];
1464       if ((NULL == fl) || (NULL == fl->f))
1465       {
1466          /*
1467           * Either there are no filter files
1468           * left, or this filter file just
1469           * contains no valid filters.
1470           *
1471           * Continue to be sure we don't miss
1472           * valid filter files that are chained
1473           * after empty or invalid ones.
1474           */
1475          continue;
1476       }
1477       /*
1478        * For all applying +filter actions, look if a filter by that
1479        * name exists and if yes, execute its pcrs_joblist on the
1480        * buffer.
1481        */
1482       for (b = fl->f; b; b = b->next)
1483       {
1484          if (b->type != wanted_filter_type)
1485          {
1486             /* Skip other filter types */
1487             continue;
1488          }
1489
1490          for (filtername = csp->action->multi[multi_action_index]->first;
1491               filtername ; filtername = filtername->next)
1492          {
1493             if (strcmp(b->name, filtername->str) == 0)
1494             {
1495                int current_hits = 0;
1496                pcrs_job *joblist = b->joblist;
1497
1498                if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b);
1499
1500                if (NULL == joblist)
1501                {
1502                   log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name);
1503                   continue;
1504                }
1505
1506                log_error(LOG_LEVEL_RE_FILTER, "filtering \'%s\' (size %d) with \'%s\' ...",
1507                          *header, size, b->name);
1508
1509                /* Apply all jobs from the joblist */
1510                for (job = joblist; NULL != job; job = job->next)
1511                {
1512                   matches = pcrs_execute(job, *header, size, &newheader, &size);
1513                   if ( 0 < matches )
1514                   {
1515                      current_hits += matches; 
1516                      log_error(LOG_LEVEL_HEADER, "Transforming \"%s\" to \"%s\"", *header, newheader);
1517                      freez(*header);
1518                      *header = newheader;
1519                   }
1520                   else if ( 0 == matches )
1521                   {
1522                      /* Filter doesn't change header */
1523                      freez(newheader);
1524                   }
1525                   else
1526                   {
1527                      /* RegEx failure */
1528                      log_error(LOG_LEVEL_ERROR, "Filtering \'%s\' with \'%s\' didn't work out: %s",
1529                         *header, b->name, pcrs_strerror(matches));
1530                      if (newheader != NULL)
1531                      {
1532                         log_error(LOG_LEVEL_ERROR, "Freeing what's left: %s", newheader);
1533                         freez(newheader);
1534                      }
1535                   }
1536                }
1537
1538                if (b->dynamic) pcrs_free_joblist(joblist);
1539
1540                log_error(LOG_LEVEL_RE_FILTER, "... produced %d hits (new size %d).", current_hits, size);
1541                hits += current_hits;
1542             }
1543          }
1544       }
1545    }
1546
1547    /*
1548     * Additionally checking for hits is important because if
1549     * the continue hack is triggered, server headers can
1550     * arrive empty to separate multiple heads from each other.
1551     */
1552    if ((0 == size) && hits)
1553    {
1554       log_error(LOG_LEVEL_HEADER, "Removing empty header %s", *header);
1555       freez(*header);
1556    }
1557
1558    return JB_ERR_OK;
1559 }
1560
1561
1562 /*********************************************************************
1563  *
1564  * Function    :  server_connection
1565  *
1566  * Description :  Makes sure a proper "Connection:" header is
1567  *                set and signals connection_header_adder to
1568  *                do nothing.
1569  *
1570  * Parameters  :
1571  *          1  :  csp = Current client state (buffers, headers, etc...)
1572  *          2  :  header = On input, pointer to header to modify.
1573  *                On output, pointer to the modified header, or NULL
1574  *                to remove the header.  This function frees the
1575  *                original string if necessary.
1576  *
1577  * Returns     :  JB_ERR_OK on success, or
1578  *                JB_ERR_MEMORY on out-of-memory error.
1579  *
1580  *********************************************************************/
1581 static jb_err server_connection(struct client_state *csp, char **header)
1582 {
1583    if (!strcmpic(*header, "Connection: keep-alive"))
1584    {
1585 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
1586       if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE))
1587       {
1588          csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
1589       }
1590
1591       if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE))
1592       {
1593          log_error(LOG_LEVEL_HEADER,
1594             "Keeping the server header '%s' around.", *header);
1595       }
1596       else
1597 #endif /* FEATURE_CONNECTION_KEEP_ALIVE */
1598       {
1599          char *old_header = *header;
1600
1601          *header = strdup("Connection: close");
1602          if (header == NULL)
1603          {
1604             return JB_ERR_MEMORY;
1605          }
1606          log_error(LOG_LEVEL_HEADER, "Replaced: \'%s\' with \'%s\'", old_header, *header);
1607          freez(old_header);
1608       }
1609    }
1610
1611    /* Signal server_connection_adder() to return early. */
1612    csp->flags |= CSP_FLAG_SERVER_CONNECTION_HEADER_SET;
1613
1614    return JB_ERR_OK;
1615 }
1616
1617
1618 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
1619 /*********************************************************************
1620  *
1621  * Function    :  server_keep_alive
1622  *
1623  * Description :  Stores the servers keep alive timeout.
1624  *
1625  * Parameters  :
1626  *          1  :  csp = Current client state (buffers, headers, etc...)
1627  *          2  :  header = On input, pointer to header to modify.
1628  *                On output, pointer to the modified header, or NULL
1629  *                to remove the header.  This function frees the
1630  *                original string if necessary.
1631  *
1632  * Returns     :  JB_ERR_OK.
1633  *
1634  *********************************************************************/
1635 static jb_err server_keep_alive(struct client_state *csp, char **header)
1636 {
1637    unsigned int keep_alive_timeout;
1638    const char *timeout_position = strstr(*header, "timeout=");
1639
1640    if ((NULL == timeout_position)
1641     || (1 != sscanf(timeout_position, "timeout=%u", &keep_alive_timeout)))
1642    {
1643       log_error(LOG_LEVEL_ERROR, "Couldn't parse: %s", *header);
1644    }
1645    else
1646    {
1647       if (keep_alive_timeout < csp->server_connection.keep_alive_timeout)
1648       {
1649          log_error(LOG_LEVEL_HEADER,
1650             "Reducing keep-alive timeout from %u to %u.",
1651             csp->server_connection.keep_alive_timeout, keep_alive_timeout);
1652          csp->server_connection.keep_alive_timeout = keep_alive_timeout;
1653       }
1654       else
1655       {
1656          /* XXX: Is this log worthy? */
1657          log_error(LOG_LEVEL_HEADER,
1658             "Server keep-alive timeout is %u. Sticking with %u.",
1659             keep_alive_timeout, csp->server_connection.keep_alive_timeout);
1660       }
1661    }
1662
1663    return JB_ERR_OK;
1664 }
1665 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
1666
1667
1668
1669 /*********************************************************************
1670  *
1671  * Function    :  client_connection
1672  *
1673  * Description :  Makes sure a proper "Connection:" header is
1674  *                set and signals connection_header_adder 
1675  *                to do nothing.
1676  *
1677  * Parameters  :
1678  *          1  :  csp = Current client state (buffers, headers, etc...)
1679  *          2  :  header = On input, pointer to header to modify.
1680  *                On output, pointer to the modified header, or NULL
1681  *                to remove the header.  This function frees the
1682  *                original string if necessary.
1683  *
1684  * Returns     :  JB_ERR_OK on success, or
1685  *                JB_ERR_MEMORY on out-of-memory error.
1686  *
1687  *********************************************************************/
1688 static jb_err client_connection(struct client_state *csp, char **header)
1689 {
1690    const char *wanted_header = get_appropiate_connection_header(csp);
1691
1692    if (strcmpic(*header, wanted_header))
1693    {
1694 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
1695       if (!(csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING))
1696       {
1697          log_error(LOG_LEVEL_HEADER,
1698             "Keeping the client header '%s' around. "
1699             "The connection will not be kept alive.",
1700             *header);
1701       }
1702       else
1703 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
1704       {
1705          char *old_header = *header;
1706
1707          *header = strdup(wanted_header);
1708          if (header == NULL)
1709          {
1710             return JB_ERR_MEMORY;
1711          }
1712          log_error(LOG_LEVEL_HEADER,
1713             "Replaced: \'%s\' with \'%s\'", old_header, *header);
1714          freez(old_header);
1715       }
1716    }
1717 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
1718    else
1719    {
1720       log_error(LOG_LEVEL_HEADER,
1721          "Keeping the client header '%s' around. "
1722          "The server connection will be kept alive if possible.",
1723          *header);
1724       csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
1725    }
1726 #endif  /* def FEATURE_CONNECTION_KEEP_ALIVE */
1727
1728    /* Signal client_connection_adder() to return early. */
1729    csp->flags |= CSP_FLAG_CLIENT_CONNECTION_HEADER_SET;
1730
1731    return JB_ERR_OK;
1732 }
1733
1734
1735 /*********************************************************************
1736  *
1737  * Function    :  crumble
1738  *
1739  * Description :  This is called if a header matches a pattern to "crunch"
1740  *
1741  * Parameters  :
1742  *          1  :  csp = Current client state (buffers, headers, etc...)
1743  *          2  :  header = On input, pointer to header to modify.
1744  *                On output, pointer to the modified header, or NULL
1745  *                to remove the header.  This function frees the
1746  *                original string if necessary.
1747  *
1748  * Returns     :  JB_ERR_OK on success, or
1749  *                JB_ERR_MEMORY on out-of-memory error.
1750  *
1751  *********************************************************************/
1752 static jb_err crumble(struct client_state *csp, char **header)
1753 {
1754    (void)csp;
1755    log_error(LOG_LEVEL_HEADER, "crumble crunched: %s!", *header);
1756    freez(*header);
1757    return JB_ERR_OK;
1758 }
1759
1760
1761 /*********************************************************************
1762  *
1763  * Function    :  crunch_server_header
1764  *
1765  * Description :  Crunch server header if it matches a string supplied by the
1766  *                user. Called from `sed'.
1767  *
1768  * Parameters  :
1769  *          1  :  csp = Current client state (buffers, headers, etc...)
1770  *          2  :  header = On input, pointer to header to modify.
1771  *                On output, pointer to the modified header, or NULL
1772  *                to remove the header.  This function frees the
1773  *                original string if necessary.
1774  *
1775  * Returns     :  JB_ERR_OK on success and always succeeds
1776  *
1777  *********************************************************************/
1778 static jb_err crunch_server_header(struct client_state *csp, char **header)
1779 {
1780    const char *crunch_pattern;
1781
1782    /* Do we feel like crunching? */
1783    if ((csp->action->flags & ACTION_CRUNCH_SERVER_HEADER))
1784    {
1785       crunch_pattern = csp->action->string[ACTION_STRING_SERVER_HEADER];
1786
1787       /* Is the current header the lucky one? */
1788       if (strstr(*header, crunch_pattern))
1789       {
1790          log_error(LOG_LEVEL_HEADER, "Crunching server header: %s (contains: %s)", *header, crunch_pattern);  
1791          freez(*header);
1792       }
1793    }
1794
1795    return JB_ERR_OK;
1796 }
1797
1798
1799 /*********************************************************************
1800  *
1801  * Function    :  server_content_type
1802  *
1803  * Description :  Set the content-type for filterable types (text/.*,
1804  *                .*xml.*, javascript and image/gif) unless filtering has been
1805  *                forbidden (CT_TABOO) while parsing earlier headers.
1806  *                NOTE: Since text/plain is commonly used by web servers
1807  *                      for files whose correct type is unknown, we don't
1808  *                      set CT_TEXT for it.
1809  *
1810  * Parameters  :
1811  *          1  :  csp = Current client state (buffers, headers, etc...)
1812  *          2  :  header = On input, pointer to header to modify.
1813  *                On output, pointer to the modified header, or NULL
1814  *                to remove the header.  This function frees the
1815  *                original string if necessary.
1816  *
1817  * Returns     :  JB_ERR_OK on success, or
1818  *                JB_ERR_MEMORY on out-of-memory error.
1819  *
1820  *********************************************************************/
1821 static jb_err server_content_type(struct client_state *csp, char **header)
1822 {
1823    /* Remove header if it isn't the first Content-Type header */
1824    if ((csp->content_type & CT_DECLARED))
1825    {
1826      /*
1827       * Another, slightly slower, way to see if
1828       * we already parsed another Content-Type header.
1829       */
1830       assert(NULL != get_header_value(csp->headers, "Content-Type:"));
1831
1832       log_error(LOG_LEVEL_ERROR,
1833          "Multiple Content-Type headers. Removing and ignoring: \'%s\'",
1834          *header);
1835       freez(*header);
1836
1837       return JB_ERR_OK;
1838    }
1839
1840    /*
1841     * Signal that the Content-Type has been set.
1842     */
1843    csp->content_type |= CT_DECLARED;
1844
1845    if (!(csp->content_type & CT_TABOO))
1846    {
1847       /*
1848        * XXX: The assumption that text/plain is a sign of
1849        * binary data seems to be somewhat unreasonable nowadays
1850        * and should be dropped after 3.0.8 is out.
1851        */
1852       if ((strstr(*header, "text/") && !strstr(*header, "plain"))
1853         || strstr(*header, "xml")
1854         || strstr(*header, "application/x-javascript"))
1855       {
1856          csp->content_type |= CT_TEXT;
1857       }
1858       else if (strstr(*header, "image/gif"))
1859       {
1860          csp->content_type |= CT_GIF;
1861       }
1862    }
1863
1864    /*
1865     * Are we messing with the content type?
1866     */
1867    if (csp->action->flags & ACTION_CONTENT_TYPE_OVERWRITE)
1868    {
1869       /*
1870        * Make sure the user doesn't accidently
1871        * change the content type of binary documents. 
1872        */
1873       if ((csp->content_type & CT_TEXT) || (csp->action->flags & ACTION_FORCE_TEXT_MODE))
1874       {
1875          freez(*header);
1876          *header = strdup("Content-Type: ");
1877          string_append(header, csp->action->string[ACTION_STRING_CONTENT_TYPE]);
1878
1879          if (header == NULL)
1880          {
1881             log_error(LOG_LEVEL_HEADER, "Insufficient memory to replace Content-Type!");
1882             return JB_ERR_MEMORY;
1883          }
1884          log_error(LOG_LEVEL_HEADER, "Modified: %s!", *header);
1885       }
1886       else
1887       {
1888          log_error(LOG_LEVEL_HEADER, "%s not replaced. "
1889             "It doesn't look like a content type that should be filtered. "
1890             "Enable force-text-mode if you know what you're doing.", *header);
1891       }
1892    }
1893
1894    return JB_ERR_OK;
1895 }
1896
1897
1898 /*********************************************************************
1899  *
1900  * Function    :  server_transfer_coding
1901  *
1902  * Description :  - Prohibit filtering (CT_TABOO) if transfer coding compresses
1903  *                - Raise the CSP_FLAG_CHUNKED flag if coding is "chunked"
1904  *                - Remove header if body was chunked but has been
1905  *                  de-chunked for filtering.
1906  *
1907  * Parameters  :
1908  *          1  :  csp = Current client state (buffers, headers, etc...)
1909  *          2  :  header = On input, pointer to header to modify.
1910  *                On output, pointer to the modified header, or NULL
1911  *                to remove the header.  This function frees the
1912  *                original string if necessary.
1913  *
1914  * Returns     :  JB_ERR_OK on success, or
1915  *                JB_ERR_MEMORY on out-of-memory error.
1916  *
1917  *********************************************************************/
1918 static jb_err server_transfer_coding(struct client_state *csp, char **header)
1919 {
1920    /*
1921     * Turn off pcrs and gif filtering if body compressed
1922     */
1923    if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate"))
1924    {
1925 #ifdef FEATURE_ZLIB
1926       /*
1927        * XXX: Added to test if we could use CT_GZIP and CT_DEFLATE here.
1928        */
1929       log_error(LOG_LEVEL_INFO, "Marking content type for %s as CT_TABOO because of %s.",
1930          csp->http->cmd, *header);
1931 #endif /* def FEATURE_ZLIB */
1932       csp->content_type = CT_TABOO;
1933    }
1934
1935    /*
1936     * Raise flag if body chunked
1937     */
1938    if (strstr(*header, "chunked"))
1939    {
1940       csp->flags |= CSP_FLAG_CHUNKED;
1941
1942       /*
1943        * If the body was modified, it has been de-chunked first
1944        * and the header must be removed.
1945        *
1946        * FIXME: If there is more than one transfer encoding,
1947        * only the "chunked" part should be removed here.
1948        */
1949       if (csp->flags & CSP_FLAG_MODIFIED)
1950       {
1951          log_error(LOG_LEVEL_HEADER, "Removing: %s", *header);
1952          freez(*header);
1953       }
1954    }
1955
1956    return JB_ERR_OK;
1957 }
1958
1959
1960 /*********************************************************************
1961  *
1962  * Function    :  server_content_encoding
1963  *
1964  * Description :  This function is run twice for each request,
1965  *                unless FEATURE_ZLIB and filtering are disabled.
1966  *
1967  *                The first run is used to check if the content
1968  *                is compressed, if FEATURE_ZLIB is disabled
1969  *                filtering is then disabled as well, if FEATURE_ZLIB
1970  *                is enabled the content is marked for decompression.
1971  *                
1972  *                The second run is used to remove the Content-Encoding
1973  *                header if the decompression was successful.
1974  *
1975  * Parameters  :
1976  *          1  :  csp = Current client state (buffers, headers, etc...)
1977  *          2  :  header = On input, pointer to header to modify.
1978  *                On output, pointer to the modified header, or NULL
1979  *                to remove the header.  This function frees the
1980  *                original string if necessary.
1981  *
1982  * Returns     :  JB_ERR_OK on success, or
1983  *                JB_ERR_MEMORY on out-of-memory error.
1984  *
1985  *********************************************************************/
1986 static jb_err server_content_encoding(struct client_state *csp, char **header)
1987 {
1988 #ifdef FEATURE_ZLIB
1989    if ((csp->flags & CSP_FLAG_MODIFIED)
1990     && (csp->content_type & (CT_GZIP | CT_DEFLATE)))
1991    {
1992       /*
1993        * We successfully decompressed the content,
1994        * and have to clean the header now, so the
1995        * client no longer expects compressed data..
1996        *
1997        * XXX: There is a difference between cleaning
1998        * and removing it completely.
1999        */
2000       log_error(LOG_LEVEL_HEADER, "Crunching: %s", *header);
2001       freez(*header);
2002    }
2003    else if (strstr(*header, "gzip"))
2004    {
2005       /* Mark for gzip decompression */
2006       csp->content_type |= CT_GZIP;
2007    }
2008    else if (strstr(*header, "deflate"))
2009    {
2010       /* Mark for zlib decompression */
2011       csp->content_type |= CT_DEFLATE;
2012    }
2013    else if (strstr(*header, "compress"))
2014    {
2015       /*
2016        * We can't decompress this; therefore we can't filter
2017        * it either.
2018        */
2019       csp->content_type |= CT_TABOO;
2020    }
2021 #else /* !defined(FEATURE_ZLIB) */
2022    if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate"))
2023    {
2024       /*
2025        * Body is compressed, turn off pcrs and gif filtering.
2026        */
2027       csp->content_type |= CT_TABOO;
2028
2029       /*
2030        * Log a warning if the user expects the content to be filtered.
2031        */
2032       if ((csp->rlist != NULL) &&
2033          (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER])))
2034       {
2035          log_error(LOG_LEVEL_INFO,
2036             "Compressed content detected, content filtering disabled. "
2037             "Consider recompiling Privoxy with zlib support or "
2038             "enable the prevent-compression action.");
2039       }
2040    }
2041 #endif /* defined(FEATURE_ZLIB) */
2042
2043    return JB_ERR_OK;
2044
2045 }
2046
2047
2048 /*********************************************************************
2049  *
2050  * Function    :  server_adjust_content_length
2051  *
2052  * Description :  Adjust Content-Length header if we modified
2053  *                the body.
2054  *
2055  * Parameters  :
2056  *          1  :  csp = Current client state (buffers, headers, etc...)
2057  *          2  :  header = On input, pointer to header to modify.
2058  *                On output, pointer to the modified header, or NULL
2059  *                to remove the header.  This function frees the
2060  *                original string if necessary.
2061  *
2062  * Returns     :  JB_ERR_OK on success, or
2063  *                JB_ERR_MEMORY on out-of-memory error.
2064  *
2065  *********************************************************************/
2066 static jb_err server_adjust_content_length(struct client_state *csp, char **header)
2067 {
2068    /* Regenerate header if the content was modified. */
2069    if (csp->flags & CSP_FLAG_MODIFIED)
2070    {
2071       const size_t header_length = 50;
2072       freez(*header);
2073       *header = malloc(header_length);
2074       if (*header == NULL)
2075       {
2076          return JB_ERR_MEMORY;
2077       }
2078       create_content_length_header(csp->content_length, *header, header_length);
2079       log_error(LOG_LEVEL_HEADER,
2080          "Adjusted Content-Length to %llu", csp->content_length);
2081    }
2082
2083    return JB_ERR_OK;
2084 }
2085
2086
2087 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
2088 /*********************************************************************
2089  *
2090  * Function    :  server_save_content_length
2091  *
2092  * Description :  Save the Content-Length sent by the server.
2093  *
2094  * Parameters  :
2095  *          1  :  csp = Current client state (buffers, headers, etc...)
2096  *          2  :  header = On input, pointer to header to modify.
2097  *                On output, pointer to the modified header, or NULL
2098  *                to remove the header.  This function frees the
2099  *                original string if necessary.
2100  *
2101  * Returns     :  JB_ERR_OK on success, or
2102  *                JB_ERR_MEMORY on out-of-memory error.
2103  *
2104  *********************************************************************/
2105 static jb_err server_save_content_length(struct client_state *csp, char **header)
2106 {
2107    unsigned long long content_length = 0;
2108
2109    assert(*(*header+14) == ':');
2110
2111    if (1 != sscanf(*header+14, ": %llu", &content_length))
2112    {
2113       log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header);
2114       freez(*header);
2115    }
2116    else
2117    {
2118       csp->expected_content_length = content_length;
2119       csp->flags |= CSP_FLAG_SERVER_CONTENT_LENGTH_SET;
2120       csp->flags |= CSP_FLAG_CONTENT_LENGTH_SET;
2121    }
2122
2123    return JB_ERR_OK;
2124 }
2125 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
2126
2127
2128 /*********************************************************************
2129  *
2130  * Function    :  server_content_md5
2131  *
2132  * Description :  Crumble any Content-MD5 headers if the document was
2133  *                modified. FIXME: Should we re-compute instead?
2134  *
2135  * Parameters  :
2136  *          1  :  csp = Current client state (buffers, headers, etc...)
2137  *          2  :  header = On input, pointer to header to modify.
2138  *                On output, pointer to the modified header, or NULL
2139  *                to remove the header.  This function frees the
2140  *                original string if necessary.
2141  *
2142  * Returns     :  JB_ERR_OK on success, or
2143  *                JB_ERR_MEMORY on out-of-memory error.
2144  *
2145  *********************************************************************/
2146 static jb_err server_content_md5(struct client_state *csp, char **header)
2147 {
2148    if (csp->flags & CSP_FLAG_MODIFIED)
2149    {
2150       log_error(LOG_LEVEL_HEADER, "Crunching Content-MD5");
2151       freez(*header);
2152    }
2153
2154    return JB_ERR_OK;
2155 }
2156
2157
2158 /*********************************************************************
2159  *
2160  * Function    :  server_content_disposition
2161  *
2162  * Description :  If enabled, blocks or modifies the "Content-Disposition" header.
2163  *                Called from `sed'.
2164  *
2165  * Parameters  :
2166  *          1  :  csp = Current client state (buffers, headers, etc...)
2167  *          2  :  header = On input, pointer to header to modify.
2168  *                On output, pointer to the modified header, or NULL
2169  *                to remove the header.  This function frees the
2170  *                original string if necessary.
2171  *
2172  * Returns     :  JB_ERR_OK on success, or
2173  *                JB_ERR_MEMORY on out-of-memory error.
2174  *
2175  *********************************************************************/
2176 static jb_err server_content_disposition(struct client_state *csp, char **header)
2177 {
2178    const char *newval;
2179
2180    /*
2181     * Are we messing with the Content-Disposition header?
2182     */
2183    if ((csp->action->flags & ACTION_HIDE_CONTENT_DISPOSITION) == 0)
2184    {
2185       /* Me tinks not */
2186       return JB_ERR_OK;
2187    }
2188
2189    newval = csp->action->string[ACTION_STRING_CONTENT_DISPOSITION];
2190
2191    if ((newval == NULL) || (0 == strcmpic(newval, "block")))
2192    {
2193       /*
2194        * Blocking content-disposition header
2195        */
2196       log_error(LOG_LEVEL_HEADER, "Crunching %s!", *header);
2197       freez(*header);
2198       return JB_ERR_OK;
2199    }
2200    else
2201    {  
2202       /*
2203        * Replacing Content-Disposition header
2204        */
2205       freez(*header);
2206       *header = strdup("Content-Disposition: ");
2207       string_append(header, newval);
2208
2209       if (*header != NULL)
2210       {
2211          log_error(LOG_LEVEL_HEADER,
2212             "Content-Disposition header crunched and replaced with: %s", *header);
2213       }
2214    }
2215    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2216 }
2217
2218
2219 /*********************************************************************
2220  *
2221  * Function    :  server_last_modified
2222  *
2223  * Description :  Changes Last-Modified header to the actual date
2224  *                to help hide-if-modified-since.
2225  *                Called from `sed'.
2226  *
2227  * Parameters  :
2228  *          1  :  csp = Current client state (buffers, headers, etc...)
2229  *          2  :  header = On input, pointer to header to modify.
2230  *                On output, pointer to the modified header, or NULL
2231  *                to remove the header.  This function frees the
2232  *                original string if necessary.
2233  *
2234  * Returns     :  JB_ERR_OK on success, or
2235  *                JB_ERR_MEMORY on out-of-memory error.
2236  *
2237  *********************************************************************/
2238 static jb_err server_last_modified(struct client_state *csp, char **header)
2239 {
2240    const char *newval;
2241    char buf[BUFFER_SIZE];
2242
2243    char newheader[50];
2244 #ifdef HAVE_GMTIME_R
2245    struct tm gmt;
2246 #endif
2247    struct tm *timeptr = NULL;
2248    time_t now, last_modified;                  
2249    long int days, hours, minutes, seconds;
2250    
2251    /*
2252     * Are we messing with the Last-Modified header?
2253     */
2254    if ((csp->action->flags & ACTION_OVERWRITE_LAST_MODIFIED) == 0)
2255    {
2256       /*Nope*/
2257       return JB_ERR_OK;
2258    }
2259
2260    newval = csp->action->string[ACTION_STRING_LAST_MODIFIED];
2261
2262    if (0 == strcmpic(newval, "block") )
2263    {
2264       /*
2265        * Blocking Last-Modified header. Useless but why not.
2266        */
2267       log_error(LOG_LEVEL_HEADER, "Crunching %s!", *header);
2268       freez(*header);
2269       return JB_ERR_OK;
2270    }
2271    else if (0 == strcmpic(newval, "reset-to-request-time"))
2272    {  
2273       /*
2274        * Setting Last-Modified Header to now.
2275        */
2276       get_http_time(0, buf, sizeof(buf));
2277       freez(*header);
2278       *header = strdup("Last-Modified: ");
2279       string_append(header, buf);   
2280
2281       if (*header == NULL)
2282       {
2283          log_error(LOG_LEVEL_HEADER, "Insufficient memory. Last-Modified header got lost, boohoo.");  
2284       }
2285       else
2286       {
2287          log_error(LOG_LEVEL_HEADER, "Reset to present time: %s", *header);
2288       }
2289    }
2290    else if (0 == strcmpic(newval, "randomize"))
2291    {
2292       const char *header_time = *header + sizeof("Last-Modified:");
2293
2294       log_error(LOG_LEVEL_HEADER, "Randomizing: %s", *header);
2295       now = time(NULL);
2296 #ifdef HAVE_GMTIME_R
2297       gmtime_r(&now, &gmt);
2298 #elif defined(MUTEX_LOCKS_AVAILABLE)
2299       privoxy_mutex_lock(&gmtime_mutex);
2300       gmtime(&now);
2301       privoxy_mutex_unlock(&gmtime_mutex);
2302 #else
2303       gmtime(&now);
2304 #endif
2305       if (JB_ERR_OK != parse_header_time(header_time, &last_modified))
2306       {
2307          log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s in %s (crunching!)", header_time, *header);
2308          freez(*header);
2309       }
2310       else
2311       {
2312          long int rtime = (long int)difftime(now, last_modified);
2313          if (rtime)
2314          {
2315             const int negative_delta = (rtime < 0);
2316
2317             if (negative_delta)
2318             {
2319                rtime *= -1; 
2320                log_error(LOG_LEVEL_HEADER, "Server time in the future.");
2321             }
2322             rtime = pick_from_range(rtime);
2323             if (negative_delta)
2324             {
2325                rtime *= -1;
2326             }
2327             last_modified += rtime;
2328 #ifdef HAVE_GMTIME_R
2329             timeptr = gmtime_r(&last_modified, &gmt);
2330 #elif defined(MUTEX_LOCKS_AVAILABLE)
2331             privoxy_mutex_lock(&gmtime_mutex);
2332             timeptr = gmtime(&last_modified);
2333             privoxy_mutex_unlock(&gmtime_mutex);
2334 #else
2335             timeptr = gmtime(&last_modified);
2336 #endif
2337             strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr);
2338             freez(*header);
2339             *header = strdup("Last-Modified: ");
2340             string_append(header, newheader);
2341
2342             if (*header == NULL)
2343             {
2344                log_error(LOG_LEVEL_ERROR, "Insufficient memory, header crunched without replacement.");
2345                return JB_ERR_MEMORY;  
2346             }
2347
2348             days    = rtime / (3600 * 24);
2349             hours   = rtime / 3600 % 24;
2350             minutes = rtime / 60 % 60;
2351             seconds = rtime % 60;
2352
2353             log_error(LOG_LEVEL_HEADER,
2354                "Randomized:  %s (added %d da%s %d hou%s %d minut%s %d second%s",
2355                *header, days, (days == 1) ? "y" : "ys", hours, (hours == 1) ? "r" : "rs",
2356                minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)");
2357          }
2358          else
2359          {
2360             log_error(LOG_LEVEL_HEADER, "Randomized ... or not. No time difference to work with.");
2361          }
2362       }
2363    }
2364
2365    return JB_ERR_OK;
2366 }
2367
2368
2369 /*********************************************************************
2370  *
2371  * Function    :  client_accept_encoding
2372  *
2373  * Description :  Rewrite the client's Accept-Encoding header so that
2374  *                if doesn't allow compression, if the action applies.
2375  *                Note: For HTTP/1.0 the absence of the header is enough.
2376  *
2377  * Parameters  :
2378  *          1  :  csp = Current client state (buffers, headers, etc...)
2379  *          2  :  header = On input, pointer to header to modify.
2380  *                On output, pointer to the modified header, or NULL
2381  *                to remove the header.  This function frees the
2382  *                original string if necessary.
2383  *
2384  * Returns     :  JB_ERR_OK on success, or
2385  *                JB_ERR_MEMORY on out-of-memory error.
2386  *
2387  *********************************************************************/
2388 static jb_err client_accept_encoding(struct client_state *csp, char **header)
2389 {
2390    if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
2391    {
2392       log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress content");
2393
2394       freez(*header);
2395
2396       /* Temporarily disable the correct behaviour to
2397        * work around a PHP bug. 
2398        *
2399        * if (!strcmpic(csp->http->ver, "HTTP/1.1"))
2400        * {
2401        *    *header = strdup("Accept-Encoding: identity;q=1.0, *;q=0");
2402        *    if (*header == NULL)
2403        *    {
2404        *       return JB_ERR_MEMORY;
2405        *    }
2406        * }
2407        * 
2408        */
2409    }
2410
2411    return JB_ERR_OK;
2412 }
2413
2414
2415 /*********************************************************************
2416  *
2417  * Function    :  client_te
2418  *
2419  * Description :  Rewrite the client's TE header so that
2420  *                if doesn't allow compression, if the action applies.
2421  *
2422  * Parameters  :
2423  *          1  :  csp = Current client state (buffers, headers, etc...)
2424  *          2  :  header = On input, pointer to header to modify.
2425  *                On output, pointer to the modified header, or NULL
2426  *                to remove the header.  This function frees the
2427  *                original string if necessary.
2428  *
2429  * Returns     :  JB_ERR_OK on success, or
2430  *                JB_ERR_MEMORY on out-of-memory error.
2431  *
2432  *********************************************************************/
2433 static jb_err client_te(struct client_state *csp, char **header)
2434 {
2435    if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
2436    {
2437       freez(*header);
2438       log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress transfer");
2439    }
2440
2441    return JB_ERR_OK;
2442 }
2443
2444
2445 /*********************************************************************
2446  *
2447  * Function    :  client_referrer
2448  *
2449  * Description :  Handle the "referer" config setting properly.
2450  *                Called from `sed'.
2451  *
2452  * Parameters  :
2453  *          1  :  csp = Current client state (buffers, headers, etc...)
2454  *          2  :  header = On input, pointer to header to modify.
2455  *                On output, pointer to the modified header, or NULL
2456  *                to remove the header.  This function frees the
2457  *                original string if necessary.
2458  *
2459  * Returns     :  JB_ERR_OK on success, or
2460  *                JB_ERR_MEMORY on out-of-memory error.
2461  *
2462  *********************************************************************/
2463 static jb_err client_referrer(struct client_state *csp, char **header)
2464 {
2465    const char *parameter;
2466    /* booleans for parameters we have to check multiple times */
2467    int parameter_conditional_block;
2468    int parameter_conditional_forge;
2469  
2470 #ifdef FEATURE_FORCE_LOAD
2471    /*
2472     * Since the referrer can include the prefix even
2473     * if the request itself is non-forced, we must
2474     * clean it unconditionally.
2475     *
2476     * XXX: strclean is too broad
2477     */
2478    strclean(*header, FORCE_PREFIX);
2479 #endif /* def FEATURE_FORCE_LOAD */
2480
2481    if ((csp->action->flags & ACTION_HIDE_REFERER) == 0)
2482    {
2483       /* Nothing left to do */
2484       return JB_ERR_OK;
2485    }
2486
2487    parameter = csp->action->string[ACTION_STRING_REFERER];
2488    assert(parameter != NULL);
2489    parameter_conditional_block = (0 == strcmpic(parameter, "conditional-block"));
2490    parameter_conditional_forge = (0 == strcmpic(parameter, "conditional-forge"));
2491
2492    if (!parameter_conditional_block && !parameter_conditional_forge)
2493    {
2494       /*
2495        * As conditional-block and conditional-forge are the only
2496        * parameters that rely on the original referrer, we can
2497        * remove it now for all the others.
2498        */
2499       freez(*header);
2500    }
2501
2502    if (0 == strcmpic(parameter, "block"))
2503    {
2504       log_error(LOG_LEVEL_HEADER, "Referer crunched!");
2505       return JB_ERR_OK;
2506    }
2507    else if (parameter_conditional_block || parameter_conditional_forge)
2508    {
2509       return handle_conditional_hide_referrer_parameter(header,
2510          csp->http->hostport, parameter_conditional_block);
2511    }
2512    else if (0 == strcmpic(parameter, "forge"))
2513    {
2514       return create_forged_referrer(header, csp->http->hostport);
2515    }
2516    else
2517    {
2518       /* interpret parameter as user-supplied referer to fake */
2519       return create_fake_referrer(header, parameter);
2520    }
2521 }
2522
2523
2524 /*********************************************************************
2525  *
2526  * Function    :  client_accept_language
2527  *
2528  * Description :  Handle the "Accept-Language" config setting properly.
2529  *                Called from `sed'.
2530  *
2531  * Parameters  :
2532  *          1  :  csp = Current client state (buffers, headers, etc...)
2533  *          2  :  header = On input, pointer to header to modify.
2534  *                On output, pointer to the modified header, or NULL
2535  *                to remove the header.  This function frees the
2536  *                original string if necessary.
2537  *
2538  * Returns     :  JB_ERR_OK on success, or
2539  *                JB_ERR_MEMORY on out-of-memory error.
2540  *
2541  *********************************************************************/
2542 static jb_err client_accept_language(struct client_state *csp, char **header)
2543 {
2544    const char *newval;
2545
2546    /*
2547     * Are we messing with the Accept-Language?
2548     */
2549    if ((csp->action->flags & ACTION_HIDE_ACCEPT_LANGUAGE) == 0)
2550    {
2551       /*I don't think so*/
2552       return JB_ERR_OK;
2553    }
2554
2555    newval = csp->action->string[ACTION_STRING_LANGUAGE];
2556
2557    if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
2558    {
2559       /*
2560        * Blocking Accept-Language header
2561        */
2562       log_error(LOG_LEVEL_HEADER, "Crunching Accept-Language!");
2563       freez(*header);
2564       return JB_ERR_OK;
2565    }
2566    else
2567    {  
2568       /*
2569        * Replacing Accept-Language header
2570        */
2571       freez(*header);
2572       *header = strdup("Accept-Language: ");
2573       string_append(header, newval);   
2574
2575       if (*header == NULL)
2576       {
2577          log_error(LOG_LEVEL_ERROR,
2578             "Insufficient memory. Accept-Language header crunched without replacement.");  
2579       }
2580       else
2581       {
2582          log_error(LOG_LEVEL_HEADER,
2583             "Accept-Language header crunched and replaced with: %s", *header);
2584       }
2585    }
2586    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2587 }
2588
2589
2590 /*********************************************************************
2591  *
2592  * Function    :  crunch_client_header
2593  *
2594  * Description :  Crunch client header if it matches a string supplied by the
2595  *                user. Called from `sed'.
2596  *
2597  * Parameters  :
2598  *          1  :  csp = Current client state (buffers, headers, etc...)
2599  *          2  :  header = On input, pointer to header to modify.
2600  *                On output, pointer to the modified header, or NULL
2601  *                to remove the header.  This function frees the
2602  *                original string if necessary.
2603  *
2604  * Returns     :  JB_ERR_OK on success and always succeeds
2605  *
2606  *********************************************************************/
2607 static jb_err crunch_client_header(struct client_state *csp, char **header)
2608 {
2609    const char *crunch_pattern;
2610
2611    /* Do we feel like crunching? */
2612    if ((csp->action->flags & ACTION_CRUNCH_CLIENT_HEADER))
2613    {
2614       crunch_pattern = csp->action->string[ACTION_STRING_CLIENT_HEADER];
2615
2616       /* Is the current header the lucky one? */
2617       if (strstr(*header, crunch_pattern))
2618       {
2619          log_error(LOG_LEVEL_HEADER, "Crunching client header: %s (contains: %s)", *header, crunch_pattern);  
2620          freez(*header);
2621       }
2622    }
2623    return JB_ERR_OK;
2624 }
2625
2626
2627 /*********************************************************************
2628  *
2629  * Function    :  client_uagent
2630  *
2631  * Description :  Handle the "user-agent" config setting properly
2632  *                and remember its original value to enable browser
2633  *                bug workarounds. Called from `sed'.
2634  *
2635  * Parameters  :
2636  *          1  :  csp = Current client state (buffers, headers, etc...)
2637  *          2  :  header = On input, pointer to header to modify.
2638  *                On output, pointer to the modified header, or NULL
2639  *                to remove the header.  This function frees the
2640  *                original string if necessary.
2641  *
2642  * Returns     :  JB_ERR_OK on success, or
2643  *                JB_ERR_MEMORY on out-of-memory error.
2644  *
2645  *********************************************************************/
2646 static jb_err client_uagent(struct client_state *csp, char **header)
2647 {
2648    const char *newval;
2649
2650    if ((csp->action->flags & ACTION_HIDE_USER_AGENT) == 0)
2651    {
2652       return JB_ERR_OK;
2653    }
2654
2655    newval = csp->action->string[ACTION_STRING_USER_AGENT];
2656    if (newval == NULL)
2657    {
2658       return JB_ERR_OK;
2659    }
2660
2661    freez(*header);
2662    *header = strdup("User-Agent: ");
2663    string_append(header, newval);
2664
2665    log_error(LOG_LEVEL_HEADER, "Modified: %s", *header);
2666
2667    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2668 }
2669
2670
2671 /*********************************************************************
2672  *
2673  * Function    :  client_ua
2674  *
2675  * Description :  Handle "ua-" headers properly.  Called from `sed'.
2676  *
2677  * Parameters  :
2678  *          1  :  csp = Current client state (buffers, headers, etc...)
2679  *          2  :  header = On input, pointer to header to modify.
2680  *                On output, pointer to the modified header, or NULL
2681  *                to remove the header.  This function frees the
2682  *                original string if necessary.
2683  *
2684  * Returns     :  JB_ERR_OK on success, or
2685  *                JB_ERR_MEMORY on out-of-memory error.
2686  *
2687  *********************************************************************/
2688 static jb_err client_ua(struct client_state *csp, char **header)
2689 {
2690    if ((csp->action->flags & ACTION_HIDE_USER_AGENT) != 0)
2691    {
2692       log_error(LOG_LEVEL_HEADER, "crunched User-Agent!");
2693       freez(*header);
2694    }
2695
2696    return JB_ERR_OK;
2697 }
2698
2699
2700 /*********************************************************************
2701  *
2702  * Function    :  client_from
2703  *
2704  * Description :  Handle the "from" config setting properly.
2705  *                Called from `sed'.
2706  *
2707  * Parameters  :
2708  *          1  :  csp = Current client state (buffers, headers, etc...)
2709  *          2  :  header = On input, pointer to header to modify.
2710  *                On output, pointer to the modified header, or NULL
2711  *                to remove the header.  This function frees the
2712  *                original string if necessary.
2713  *
2714  * Returns     :  JB_ERR_OK on success, or
2715  *                JB_ERR_MEMORY on out-of-memory error.
2716  *
2717  *********************************************************************/
2718 static jb_err client_from(struct client_state *csp, char **header)
2719 {
2720    const char *newval;
2721
2722    if ((csp->action->flags & ACTION_HIDE_FROM) == 0)
2723    {
2724       return JB_ERR_OK;
2725    }
2726
2727    freez(*header);
2728
2729    newval = csp->action->string[ACTION_STRING_FROM];
2730
2731    /*
2732     * Are we blocking the e-mail address?
2733     */
2734    if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
2735    {
2736       log_error(LOG_LEVEL_HEADER, "crunched From!");
2737       return JB_ERR_OK;
2738    }
2739
2740    log_error(LOG_LEVEL_HEADER, " modified");
2741
2742    *header = strdup("From: ");
2743    string_append(header, newval);
2744
2745    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2746 }
2747
2748
2749 /*********************************************************************
2750  *
2751  * Function    :  client_send_cookie
2752  *
2753  * Description :  Crunches the "cookie" header if necessary.
2754  *                Called from `sed'.
2755  *
2756  *                XXX: Stupid name, doesn't send squat.
2757  *
2758  * Parameters  :
2759  *          1  :  csp = Current client state (buffers, headers, etc...)
2760  *          2  :  header = On input, pointer to header to modify.
2761  *                On output, pointer to the modified header, or NULL
2762  *                to remove the header.  This function frees the
2763  *                original string if necessary.
2764  *
2765  * Returns     :  JB_ERR_OK on success, or
2766  *                JB_ERR_MEMORY on out-of-memory error.
2767  *
2768  *********************************************************************/
2769 static jb_err client_send_cookie(struct client_state *csp, char **header)
2770 {
2771    if (csp->action->flags & ACTION_NO_COOKIE_READ)
2772    {
2773       log_error(LOG_LEVEL_HEADER, "Crunched outgoing cookie: %s", *header);
2774       freez(*header);
2775    }
2776
2777    return JB_ERR_OK;
2778 }
2779
2780
2781 /*********************************************************************
2782  *
2783  * Function    :  client_x_forwarded
2784  *
2785  * Description :  Handle the "x-forwarded-for" config setting properly,
2786  *                also used in the add_client_headers list.  Called from `sed'.
2787  *
2788  * Parameters  :
2789  *          1  :  csp = Current client state (buffers, headers, etc...)
2790  *          2  :  header = On input, pointer to header to modify.
2791  *                On output, pointer to the modified header, or NULL
2792  *                to remove the header.  This function frees the
2793  *                original string if necessary.
2794  *
2795  * Returns     :  JB_ERR_OK on success, or
2796  *                JB_ERR_MEMORY on out-of-memory error.
2797  *
2798  *********************************************************************/
2799 jb_err client_x_forwarded(struct client_state *csp, char **header)
2800 {
2801    if (0 != (csp->action->flags & ACTION_CHANGE_X_FORWARDED_FOR))
2802    {
2803       const char *parameter = csp->action->string[ACTION_STRING_CHANGE_X_FORWARDED_FOR];
2804
2805       if (0 == strcmpic(parameter, "block"))
2806       {
2807          freez(*header);
2808          log_error(LOG_LEVEL_HEADER, "crunched x-forwarded-for!");
2809       }
2810       else if (0 == strcmpic(parameter, "add"))
2811       {
2812          string_append(header, ", ");
2813          string_append(header, csp->ip_addr_str);
2814
2815          if (*header == NULL)
2816          {
2817             return JB_ERR_MEMORY;
2818          }
2819          log_error(LOG_LEVEL_HEADER,
2820             "Appended client IP address to %s", *header);
2821          csp->flags |= CSP_FLAG_X_FORWARDED_FOR_APPENDED;
2822       }
2823       else
2824       {
2825          log_error(LOG_LEVEL_FATAL,
2826             "Invalid change-x-forwarded-for parameter: '%s'", parameter);
2827       }
2828    }
2829
2830    return JB_ERR_OK;
2831 }
2832
2833
2834 /*********************************************************************
2835  *
2836  * Function    :  client_max_forwards
2837  *
2838  * Description :  If the HTTP method is OPTIONS or TRACE, subtract one
2839  *                from the value of the Max-Forwards header field.
2840  *
2841  * Parameters  :
2842  *          1  :  csp = Current client state (buffers, headers, etc...)
2843  *          2  :  header = On input, pointer to header to modify.
2844  *                On output, pointer to the modified header, or NULL
2845  *                to remove the header.  This function frees the
2846  *                original string if necessary.
2847  *
2848  * Returns     :  JB_ERR_OK on success, or
2849  *                JB_ERR_MEMORY on out-of-memory error.
2850  *
2851  *********************************************************************/
2852 static jb_err client_max_forwards(struct client_state *csp, char **header)
2853 {
2854    int max_forwards;
2855
2856    if ((0 == strcmpic(csp->http->gpc, "trace")) ||
2857        (0 == strcmpic(csp->http->gpc, "options")))
2858    {
2859       assert(*(*header+12) == ':');
2860       if (1 == sscanf(*header+12, ": %d", &max_forwards))
2861       {
2862          if (max_forwards > 0)
2863          {
2864             snprintf(*header, strlen(*header)+1, "Max-Forwards: %d", --max_forwards);
2865             log_error(LOG_LEVEL_HEADER,
2866                "Max-Forwards value for %s request reduced to %d.",
2867                csp->http->gpc, max_forwards);
2868          }
2869          else if (max_forwards < 0)
2870          {
2871             log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header);
2872             freez(*header);
2873          }
2874       }
2875       else
2876       {
2877          log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header);
2878          freez(*header);
2879       }
2880    }
2881
2882    return JB_ERR_OK;
2883 }
2884
2885
2886 /*********************************************************************
2887  *
2888  * Function    :  client_host
2889  *
2890  * Description :  If the request URI did not contain host and
2891  *                port information, parse and evaluate the Host
2892  *                header field.
2893  *
2894  *                Also, kill ill-formed HOST: headers as sent by
2895  *                Apple's iTunes software when used with a proxy.
2896  *
2897  * Parameters  :
2898  *          1  :  csp = Current client state (buffers, headers, etc...)
2899  *          2  :  header = On input, pointer to header to modify.
2900  *                On output, pointer to the modified header, or NULL
2901  *                to remove the header.  This function frees the
2902  *                original string if necessary.
2903  *
2904  * Returns     :  JB_ERR_OK on success, or
2905  *                JB_ERR_MEMORY on out-of-memory error.
2906  *
2907  *********************************************************************/
2908 static jb_err client_host(struct client_state *csp, char **header)
2909 {
2910    char *p, *q;
2911
2912    /*
2913     * If the header field name is all upper-case, chances are that it's
2914     * an ill-formed one from iTunes. BTW, killing innocent headers here is
2915     * not a problem -- they are regenerated later.
2916     */
2917    if ((*header)[1] == 'O')
2918    {
2919       log_error(LOG_LEVEL_HEADER, "Killed all-caps Host header line: %s", *header);
2920       freez(*header);
2921       return JB_ERR_OK;
2922    }
2923
2924    if (!csp->http->hostport || (*csp->http->hostport == '*') ||  
2925        *csp->http->hostport == ' ' || *csp->http->hostport == '\0')
2926    {
2927       
2928       if (NULL == (p = strdup((*header)+6)))
2929       {
2930          return JB_ERR_MEMORY;
2931       }
2932       chomp(p);
2933       if (NULL == (q = strdup(p)))
2934       {
2935          freez(p);
2936          return JB_ERR_MEMORY;
2937       }
2938
2939       freez(csp->http->hostport);
2940       csp->http->hostport = p;
2941       freez(csp->http->host);
2942       csp->http->host = q;
2943       q = strchr(csp->http->host, ':');
2944       if (q != NULL)
2945       {
2946          /* Terminate hostname and evaluate port string */
2947          *q++ = '\0';
2948          csp->http->port = atoi(q);
2949       }
2950       else
2951       {
2952          csp->http->port = csp->http->ssl ? 443 : 80;
2953       }
2954
2955       log_error(LOG_LEVEL_HEADER, "New host and port from Host field: %s = %s:%d",
2956                 csp->http->hostport, csp->http->host, csp->http->port);
2957    }
2958
2959    /* Signal client_host_adder() to return right away */
2960    csp->flags |= CSP_FLAG_HOST_HEADER_IS_SET;
2961
2962    return JB_ERR_OK;
2963 }
2964
2965
2966 /*********************************************************************
2967  *
2968  * Function    :  client_if_modified_since
2969  *
2970  * Description :  Remove or modify the If-Modified-Since header.
2971  *
2972  * Parameters  :
2973  *          1  :  csp = Current client state (buffers, headers, etc...)
2974  *          2  :  header = On input, pointer to header to modify.
2975  *                On output, pointer to the modified header, or NULL
2976  *                to remove the header.  This function frees the
2977  *                original string if necessary.
2978  *
2979  * Returns     :  JB_ERR_OK on success, or
2980  *                JB_ERR_MEMORY on out-of-memory error.
2981  *
2982  *********************************************************************/
2983 static jb_err client_if_modified_since(struct client_state *csp, char **header)
2984 {
2985    char newheader[50];
2986 #ifdef HAVE_GMTIME_R
2987    struct tm gmt;
2988 #endif
2989    struct tm *timeptr = NULL;
2990    time_t tm = 0;                  
2991    const char *newval;
2992    long int hours, minutes, seconds;
2993    char * endptr;
2994    
2995    if ( 0 == strcmpic(*header, "If-Modified-Since: Wed, 08 Jun 1955 12:00:00 GMT"))
2996    {
2997       /* 
2998        * The client got an error message because of a temporary problem,
2999        * the problem is gone and the client now tries to revalidate our
3000        * error message on the real server. The revalidation would always
3001        * end with the transmission of the whole document and there is
3002        * no need to expose the bogus If-Modified-Since header.
3003        */
3004       log_error(LOG_LEVEL_HEADER, "Crunching useless If-Modified-Since header.");
3005       freez(*header);
3006    }
3007    else if (csp->action->flags & ACTION_HIDE_IF_MODIFIED_SINCE)
3008    {
3009       newval = csp->action->string[ACTION_STRING_IF_MODIFIED_SINCE];
3010
3011       if ((0 == strcmpic(newval, "block")))
3012       {
3013          log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
3014          freez(*header);
3015       }
3016       else /* add random value */
3017       {
3018          const char *header_time = *header + sizeof("If-Modified-Since:");
3019
3020          if (JB_ERR_OK != parse_header_time(header_time, &tm))
3021          {
3022             log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s in %s (crunching!)", header_time, *header);
3023             freez(*header);
3024          }
3025          else
3026          {
3027             long int rtime = strtol(newval, &endptr, 0);
3028             const int negative_range = (rtime < 0);
3029
3030             if (rtime)
3031             {
3032                log_error(LOG_LEVEL_HEADER, "Randomizing: %s (random range: %d minut%s)",
3033                   *header, rtime, (rtime == 1 || rtime == -1) ? "e": "es");
3034                if (negative_range)
3035                {
3036                   rtime *= -1; 
3037                }
3038                rtime *= 60;
3039                rtime = pick_from_range(rtime);
3040             }
3041             else
3042             {
3043                log_error(LOG_LEVEL_ERROR, "Random range is 0. Assuming time transformation test.",
3044                   *header);
3045             }
3046             tm += rtime * (negative_range ? -1 : 1);
3047 #ifdef HAVE_GMTIME_R
3048             timeptr = gmtime_r(&tm, &gmt);
3049 #elif defined(MUTEX_LOCKS_AVAILABLE)
3050             privoxy_mutex_lock(&gmtime_mutex);
3051             timeptr = gmtime(&tm);
3052             privoxy_mutex_unlock(&gmtime_mutex);
3053 #else
3054             timeptr = gmtime(&tm);
3055 #endif
3056             if (!strftime(newheader, sizeof(newheader),
3057                     "%a, %d %b %Y %H:%M:%S GMT", timeptr))
3058             {
3059                log_error(LOG_LEVEL_ERROR,
3060                   "Randomizing %s failed. Keeping the header unmodified.",
3061                   *header);
3062                return JB_ERR_OK;
3063             }
3064
3065             freez(*header);
3066             *header = strdup("If-Modified-Since: ");
3067             string_append(header, newheader);
3068
3069             if (*header == NULL)
3070             {
3071                log_error(LOG_LEVEL_HEADER, "Insufficient memory, header crunched without replacement.");
3072                return JB_ERR_MEMORY;  
3073             }
3074
3075             hours   = rtime / 3600;
3076             minutes = rtime / 60 % 60;
3077             seconds = rtime % 60;
3078
3079             log_error(LOG_LEVEL_HEADER,
3080                "Randomized:  %s (%s %d hou%s %d minut%s %d second%s",
3081                *header, (negative_range) ? "subtracted" : "added", hours,
3082                (hours == 1) ? "r" : "rs", minutes, (minutes == 1) ? "e" : "es",
3083                seconds, (seconds == 1) ? ")" : "s)");
3084          }
3085       }
3086    }
3087
3088    return JB_ERR_OK;
3089 }
3090
3091
3092 /*********************************************************************
3093  *
3094  * Function    :  client_if_none_match
3095  *
3096  * Description :  Remove the If-None-Match header.
3097  *
3098  * Parameters  :
3099  *          1  :  csp = Current client state (buffers, headers, etc...)
3100  *          2  :  header = On input, pointer to header to modify.
3101  *                On output, pointer to the modified header, or NULL
3102  *                to remove the header.  This function frees the
3103  *                original string if necessary.
3104  *
3105  * Returns     :  JB_ERR_OK on success, or
3106  *                JB_ERR_MEMORY on out-of-memory error.
3107  *
3108  *********************************************************************/
3109 static jb_err client_if_none_match(struct client_state *csp, char **header)
3110 {
3111    if (csp->action->flags & ACTION_CRUNCH_IF_NONE_MATCH)
3112    {  
3113       log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
3114       freez(*header);
3115    }
3116
3117    return JB_ERR_OK;
3118 }
3119
3120
3121 /*********************************************************************
3122  *
3123  * Function    :  client_x_filter
3124  *
3125  * Description :  Disables filtering if the client set "X-Filter: No".
3126  *                Called from `sed'.
3127  *
3128  * Parameters  :
3129  *          1  :  csp = Current client state (buffers, headers, etc...)
3130  *          2  :  header = On input, pointer to header to modify.
3131  *                On output, pointer to the modified header, or NULL
3132  *                to remove the header.  This function frees the
3133  *                original string if necessary.
3134  *
3135  * Returns     :  JB_ERR_OK on success
3136  *
3137  *********************************************************************/
3138 jb_err client_x_filter(struct client_state *csp, char **header)
3139 {
3140    if ( 0 == strcmpic(*header, "X-Filter: No"))
3141    {
3142       if (!(csp->config->feature_flags & RUNTIME_FEATURE_HTTP_TOGGLE))
3143       {
3144          log_error(LOG_LEVEL_INFO, "Ignored the client's request to fetch without filtering.");
3145       }
3146       else
3147       {
3148          if (csp->action->flags & ACTION_FORCE_TEXT_MODE)
3149          {
3150             log_error(LOG_LEVEL_HEADER,
3151                "force-text-mode overruled the client's request to fetch without filtering!");
3152          }
3153          else
3154          {  
3155             csp->content_type = CT_TABOO; /* XXX: This hack shouldn't be necessary */
3156             csp->flags |= CSP_FLAG_NO_FILTERING;
3157             log_error(LOG_LEVEL_HEADER, "Accepted the client's request to fetch without filtering.");
3158          }
3159          log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
3160          freez(*header);
3161       }
3162    }
3163    return JB_ERR_OK; 
3164 }
3165
3166
3167 /*********************************************************************
3168  *
3169  * Function    :  client_range
3170  *
3171  * Description :  Removes Range, Request-Range and If-Range headers if
3172  *                content filtering is enabled. If the client's version
3173  *                of the document has been altered by Privoxy, the server
3174  *                could interpret the range differently than the client
3175  *                intended in which case the user could end up with
3176  *                corrupted content.
3177  *
3178  * Parameters  :
3179  *          1  :  csp = Current client state (buffers, headers, etc...)
3180  *          2  :  header = On input, pointer to header to modify.
3181  *                On output, pointer to the modified header, or NULL
3182  *                to remove the header.  This function frees the
3183  *                original string if necessary.
3184  *
3185  * Returns     :  JB_ERR_OK
3186  *
3187  *********************************************************************/
3188 static jb_err client_range(struct client_state *csp, char **header)
3189 {
3190    if (content_filters_enabled(csp->action))
3191    {
3192       log_error(LOG_LEVEL_HEADER, "Content filtering is enabled."
3193          " Crunching: \'%s\' to prevent range-mismatch problems.", *header);
3194       freez(*header);
3195    }
3196
3197    return JB_ERR_OK; 
3198 }
3199
3200 /* the following functions add headers directly to the header list */
3201
3202 /*********************************************************************
3203  *
3204  * Function    :  client_host_adder
3205  *
3206  * Description :  Adds the Host: header field if it is missing.
3207  *                Called from `sed'.
3208  *
3209  * Parameters  :
3210  *          1  :  csp = Current client state (buffers, headers, etc...)
3211  *
3212  * Returns     :  JB_ERR_OK on success, or
3213  *                JB_ERR_MEMORY on out-of-memory error.
3214  *
3215  *********************************************************************/
3216 static jb_err client_host_adder(struct client_state *csp)
3217 {
3218    char *p;
3219    jb_err err;
3220
3221    if (csp->flags & CSP_FLAG_HOST_HEADER_IS_SET)
3222    {
3223       /* Header already set by the client, nothing to do. */
3224       return JB_ERR_OK;
3225    }
3226
3227    if ( !csp->http->hostport || !*(csp->http->hostport))
3228    {
3229       /* XXX: When does this happen and why is it OK? */
3230       log_error(LOG_LEVEL_INFO, "Weirdness in client_host_adder detected and ignored.");
3231       return JB_ERR_OK;
3232    }
3233
3234    /*
3235     * remove 'user:pass@' from 'proto://user:pass@host'
3236     */
3237    if ( (p = strchr( csp->http->hostport, '@')) != NULL )
3238    {
3239       p++;
3240    }
3241    else
3242    {
3243       p = csp->http->hostport;
3244    }
3245
3246    /* XXX: Just add it, we already made sure that it will be unique */
3247    log_error(LOG_LEVEL_HEADER, "addh-unique: Host: %s", p);
3248    err = enlist_unique_header(csp->headers, "Host", p);
3249    return err;
3250
3251 }
3252
3253
3254 #if 0
3255 /*********************************************************************
3256  *
3257  * Function    :  client_accept_encoding_adder
3258  *
3259  * Description :  Add an Accept-Encoding header to the client's request
3260  *                that disables compression if the action applies, and
3261  *                the header is not already there. Called from `sed'.
3262  *                Note: For HTTP/1.0, the absence of the header is enough.
3263  *
3264  * Parameters  :
3265  *          1  :  csp = Current client state (buffers, headers, etc...)
3266  *
3267  * Returns     :  JB_ERR_OK on success, or
3268  *                JB_ERR_MEMORY on out-of-memory error.
3269  *
3270  *********************************************************************/
3271 static jb_err client_accept_encoding_adder(struct client_state *csp)
3272 {
3273    if (   ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
3274        && (!strcmpic(csp->http->ver, "HTTP/1.1")) )
3275    {
3276       return enlist_unique(csp->headers, "Accept-Encoding: identity;q=1.0, *;q=0", 16);
3277    }
3278
3279    return JB_ERR_OK;
3280 }
3281 #endif
3282
3283
3284 /*********************************************************************
3285  *
3286  * Function    :  client_xtra_adder
3287  *
3288  * Description :  Used in the add_client_headers list.  Called from `sed'.
3289  *
3290  * Parameters  :
3291  *          1  :  csp = Current client state (buffers, headers, etc...)
3292  *
3293  * Returns     :  JB_ERR_OK on success, or
3294  *                JB_ERR_MEMORY on out-of-memory error.
3295  *
3296  *********************************************************************/
3297 static jb_err client_xtra_adder(struct client_state *csp)
3298 {
3299    struct list_entry *lst;
3300    jb_err err;
3301
3302    for (lst = csp->action->multi[ACTION_MULTI_ADD_HEADER]->first;
3303         lst ; lst = lst->next)
3304    {
3305       log_error(LOG_LEVEL_HEADER, "addh: %s", lst->str);
3306       err = enlist(csp->headers, lst->str);
3307       if (err)
3308       {
3309          return err;
3310       }
3311
3312    }
3313
3314    return JB_ERR_OK;
3315 }
3316
3317
3318 /*********************************************************************
3319  *
3320  * Function    :  client_x_forwarded_for_adder
3321  *
3322  * Description :  Used in the add_client_headers list.  Called from `sed'.
3323  *
3324  * Parameters  :
3325  *          1  :  csp = Current client state (buffers, headers, etc...)
3326  *
3327  * Returns     :  JB_ERR_OK on success, or
3328  *                JB_ERR_MEMORY on out-of-memory error.
3329  *
3330  *********************************************************************/
3331 static jb_err client_x_forwarded_for_adder(struct client_state *csp)
3332 {
3333    char *header = NULL;
3334    jb_err err;
3335
3336    if (!((csp->action->flags & ACTION_CHANGE_X_FORWARDED_FOR)
3337          && (0 == strcmpic(csp->action->string[ACTION_STRING_CHANGE_X_FORWARDED_FOR], "add")))
3338       || (csp->flags & CSP_FLAG_X_FORWARDED_FOR_APPENDED))
3339    {
3340       /*
3341        * If we aren't adding X-Forwarded-For headers,
3342        * or we already appended an existing X-Forwarded-For
3343        * header, there's nothing left to do here.
3344        */
3345       return JB_ERR_OK;
3346    }
3347
3348    header = strdup("X-Forwarded-For: ");
3349    string_append(&header, csp->ip_addr_str);
3350
3351    if (header == NULL)
3352    {
3353       return JB_ERR_MEMORY;
3354    }
3355
3356    log_error(LOG_LEVEL_HEADER, "addh: %s", header);
3357    err = enlist(csp->headers, header);
3358    freez(header);
3359
3360    return err;
3361 }
3362
3363
3364 /*********************************************************************
3365  *
3366  * Function    :  server_connection_adder
3367  *
3368  * Description :  Adds an appropiate "Connection:" header to csp->headers
3369  *                unless the header was already present. Called from `sed'.
3370  *
3371  * Parameters  :
3372  *          1  :  csp = Current client state (buffers, headers, etc...)
3373  *
3374  * Returns     :  JB_ERR_OK on success, or
3375  *                JB_ERR_MEMORY on out-of-memory error.
3376  *
3377  *********************************************************************/
3378 static jb_err server_connection_adder(struct client_state *csp)
3379 {
3380    const unsigned int flags = csp->flags;
3381    const char *response_status_line = csp->headers->first->str;
3382    const char *wanted_header = get_appropiate_connection_header(csp);
3383
3384    if ((flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
3385     && (flags & CSP_FLAG_SERVER_CONNECTION_HEADER_SET))
3386    {
3387       return JB_ERR_OK;
3388    }
3389
3390    /*
3391     * XXX: if we downgraded the response, this check will fail.
3392     */
3393    if ((csp->config->feature_flags &
3394         RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
3395     && (NULL != response_status_line)
3396     && !strncmpic(response_status_line, "HTTP/1.1", 8))
3397    {
3398       log_error(LOG_LEVEL_HEADER, "A HTTP/1.1 response "
3399          "without Connection header implies keep-alive.");
3400       csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
3401    }
3402
3403    log_error(LOG_LEVEL_HEADER, "Adding: %s", wanted_header);
3404
3405    return enlist(csp->headers, wanted_header);
3406 }
3407
3408
3409 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
3410 /*********************************************************************
3411  *
3412  * Function    :  server_proxy_connection_adder
3413  *
3414  * Description :  Adds a "Proxy-Connection: keep-alive" header to
3415  *                csp->headers if the client asked for keep-alive.
3416  *                XXX: We should reuse existant ones.
3417  *
3418  * Parameters  :
3419  *          1  :  csp = Current client state (buffers, headers, etc...)
3420  *
3421  * Returns     :  JB_ERR_OK on success, or
3422  *                JB_ERR_MEMORY on out-of-memory error.
3423  *
3424  *********************************************************************/
3425 static jb_err server_proxy_connection_adder(struct client_state *csp)
3426 {
3427    static const char proxy_connection_header[] = "Proxy-Connection: keep-alive";
3428    jb_err err = JB_ERR_OK;
3429
3430    if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE))
3431    {
3432       log_error(LOG_LEVEL_HEADER, "Adding: %s", proxy_connection_header);
3433       err = enlist(csp->headers, proxy_connection_header);
3434    }
3435
3436    return err;
3437 }
3438 #endif /* FEATURE_CONNECTION_KEEP_ALIVE */
3439
3440
3441 /*********************************************************************
3442  *
3443  * Function    :  client_connection_header_adder
3444  *
3445  * Description :  Adds a proper "Connection:" header to csp->headers
3446  *                unless the header was already present. Called from `sed'.
3447  *
3448  * Parameters  :
3449  *          1  :  csp = Current client state (buffers, headers, etc...)
3450  *
3451  * Returns     :  JB_ERR_OK on success, or
3452  *                JB_ERR_MEMORY on out-of-memory error.
3453  *
3454  *********************************************************************/
3455 static jb_err client_connection_header_adder(struct client_state *csp)
3456 {
3457    const char *wanted_header = get_appropiate_connection_header(csp);
3458
3459    if (!(csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
3460      && (csp->flags & CSP_FLAG_CLIENT_CONNECTION_HEADER_SET))
3461    {
3462       return JB_ERR_OK;
3463    }
3464
3465 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
3466    if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
3467       && (csp->http->ssl == 0))
3468    {
3469       csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
3470    }
3471 #endif /* FEATURE_CONNECTION_KEEP_ALIVE */
3472
3473    log_error(LOG_LEVEL_HEADER, "Adding: %s", wanted_header);
3474
3475    return enlist(csp->headers, wanted_header);
3476 }
3477
3478
3479 /*********************************************************************
3480  *
3481  * Function    :  server_http
3482  *
3483  * Description :  - Save the HTTP Status into csp->http->status
3484  *                - Set CT_TABOO to prevent filtering if the answer
3485  *                  is a partial range (HTTP status 206)
3486  *                - Rewrite HTTP/1.1 answers to HTTP/1.0 if +downgrade
3487  *                  action applies.
3488  *
3489  * Parameters  :
3490  *          1  :  csp = Current client state (buffers, headers, etc...)
3491  *          2  :  header = On input, pointer to header to modify.
3492  *                On output, pointer to the modified header, or NULL
3493  *                to remove the header.  This function frees the
3494  *                original string if necessary.
3495  *
3496  * Returns     :  JB_ERR_OK on success, or
3497  *                JB_ERR_MEMORY on out-of-memory error.
3498  *
3499  *********************************************************************/
3500 static jb_err server_http(struct client_state *csp, char **header)
3501 {
3502    sscanf(*header, "HTTP/%*d.%*d %d", &(csp->http->status));
3503    if (csp->http->status == 206)
3504    {
3505       csp->content_type = CT_TABOO;
3506    }
3507
3508    if ((csp->action->flags & ACTION_DOWNGRADE) != 0)
3509    {
3510       /* XXX: Should we do a real validity check here? */
3511       if (strlen(*header) > 8)
3512       {
3513          (*header)[7] = '0';
3514          log_error(LOG_LEVEL_HEADER, "Downgraded answer to HTTP/1.0");
3515       }
3516       else
3517       {
3518          /*
3519           * XXX: Should we block the request or
3520           * enlist a valid status code line here?
3521           */
3522          log_error(LOG_LEVEL_INFO, "Malformed server response detected. "
3523             "Downgrading to HTTP/1.0 impossible.");
3524       }
3525    }
3526
3527    return JB_ERR_OK;
3528 }
3529
3530
3531 /*********************************************************************
3532  *
3533  * Function    :  server_set_cookie
3534  *
3535  * Description :  Handle the server "cookie" header properly.
3536  *                Log cookie to the jar file.  Then "crunch",
3537  *                accept or rewrite it to a session cookie.
3538  *                Called from `sed'.
3539  *
3540  *                TODO: Allow the user to specify a new expiration
3541  *                time to cause the cookie to expire even before the
3542  *                browser is closed.
3543  *
3544  * Parameters  :
3545  *          1  :  csp = Current client state (buffers, headers, etc...)
3546  *          2  :  header = On input, pointer to header to modify.
3547  *                On output, pointer to the modified header, or NULL
3548  *                to remove the header.  This function frees the
3549  *                original string if necessary.
3550  *
3551  * Returns     :  JB_ERR_OK on success, or
3552  *                JB_ERR_MEMORY on out-of-memory error.
3553  *
3554  *********************************************************************/
3555 static jb_err server_set_cookie(struct client_state *csp, char **header)
3556 {
3557    time_t now;
3558    time_t cookie_time; 
3559
3560    time(&now);
3561
3562    if ((csp->action->flags & ACTION_NO_COOKIE_SET) != 0)
3563    {
3564       log_error(LOG_LEVEL_HEADER, "Crunching incoming cookie: %s", *header);
3565       freez(*header);
3566    }
3567    else if ((csp->action->flags & ACTION_NO_COOKIE_KEEP) != 0)
3568    {
3569       /* Flag whether or not to log a message */
3570       int changed = 0;
3571
3572       /* A variable to store the tag we're working on */
3573       char *cur_tag;
3574
3575       /* Skip "Set-Cookie:" (11 characters) in header */
3576       cur_tag = *header + 11;
3577
3578       /* skip whitespace between "Set-Cookie:" and value */
3579       while (*cur_tag && ijb_isspace(*cur_tag))
3580       {
3581          cur_tag++;
3582       }
3583
3584       /* Loop through each tag in the cookie */
3585       while (*cur_tag)
3586       {
3587          /* Find next tag */
3588          char *next_tag = strchr(cur_tag, ';');
3589          if (next_tag != NULL)
3590          {
3591             /* Skip the ';' character itself */
3592             next_tag++;
3593
3594             /* skip whitespace ";" and start of tag */
3595             while (*next_tag && ijb_isspace(*next_tag))
3596             {
3597                next_tag++;
3598             }
3599          }
3600          else
3601          {
3602             /* "Next tag" is the end of the string */
3603             next_tag = cur_tag + strlen(cur_tag);
3604          }
3605
3606          /*
3607           * Check the expiration date to see
3608           * if the cookie is still valid, if yes,
3609           * rewrite it to a session cookie.
3610           */
3611          if ((strncmpic(cur_tag, "expires=", 8) == 0) && *(cur_tag + 8))
3612          {
3613             char *expiration_date = cur_tag + 8; /* Skip "[Ee]xpires=" */
3614
3615             /* Did we detect the date properly? */
3616             if (JB_ERR_OK != parse_header_time(expiration_date, &cookie_time))
3617             {
3618                /*
3619                 * Nope, treat it as if it was still valid.
3620                 *
3621                 * XXX: Should we remove the whole cookie instead?
3622                 */
3623                log_error(LOG_LEVEL_ERROR,
3624                   "Can't parse \'%s\', send by %s. Unsupported time format?", cur_tag, csp->http->url);
3625                string_move(cur_tag, next_tag);
3626                changed = 1;
3627             }
3628             else
3629             {
3630                /*
3631                 * Yes. Check if the cookie is still valid.
3632                 *
3633                 * If the cookie is already expired it's probably
3634                 * a delete cookie and even if it isn't, the browser
3635                 * will discard it anyway.
3636                 */
3637
3638                /*
3639                 * XXX: timegm() isn't available on some AmigaOS
3640                 * versions and our replacement doesn't work.
3641                 *
3642                 * Our options are to either:
3643                 *
3644                 * - disable session-cookies-only completely if timegm
3645                 *   is missing,
3646                 *
3647                 * - to simply remove all expired tags, like it has
3648                 *   been done until Privoxy 3.0.6 and to live with
3649                 *    the consequence that it can cause login/logout
3650                 *   problems on servers that don't validate their
3651                 *   input properly, or
3652                 *
3653                 * - to replace it with mktime in which
3654                 *   case there is a slight chance of valid cookies
3655                 *   passing as already expired.
3656                 *
3657                 *   This is the way it's currently done and it's not
3658                 *   as bad as it sounds. If the missing GMT offset is
3659                 *   enough to change the result of the expiration check
3660                 *   the cookie will be only valid for a few hours
3661                 *   anyway, which in many cases will be shorter
3662                 *   than a browser session.
3663                 */
3664                if (cookie_time - now < 0)
3665                {
3666                   log_error(LOG_LEVEL_HEADER,
3667                      "Cookie \'%s\' is already expired and can pass unmodified.", *header);
3668                   /* Just in case some clown sets more then one expiration date */
3669                   cur_tag = next_tag;
3670                }
3671                else
3672                {
3673                   /*
3674                    * Still valid, delete expiration date by copying
3675                    * the rest of the string over it.
3676                    */
3677                   string_move(cur_tag, next_tag);
3678
3679                   /* That changed the header, need to issue a log message */
3680                   changed = 1;
3681
3682                   /*
3683                    * Note that the next tag has now been moved to *cur_tag,
3684                    * so we do not need to update the cur_tag pointer.
3685                    */
3686                }
3687             }
3688
3689          }
3690          else
3691          {
3692             /* Move on to next cookie tag */
3693             cur_tag = next_tag;
3694          }
3695       }
3696
3697       if (changed)
3698       {
3699          assert(NULL != *header);
3700          log_error(LOG_LEVEL_HEADER, "Cookie rewritten to a temporary one: %s",
3701             *header);
3702       }
3703    }
3704
3705    return JB_ERR_OK;
3706 }
3707
3708
3709 #ifdef FEATURE_FORCE_LOAD
3710 /*********************************************************************
3711  *
3712  * Function    :  strclean
3713  *
3714  * Description :  In-Situ-Eliminate all occurances of substring in
3715  *                string
3716  *
3717  * Parameters  :
3718  *          1  :  string = string to clean
3719  *          2  :  substring = substring to eliminate
3720  *
3721  * Returns     :  Number of eliminations
3722  *
3723  *********************************************************************/
3724 int strclean(char *string, const char *substring)
3725 {
3726    int hits = 0;
3727    size_t len;
3728    char *pos, *p;
3729
3730    len = strlen(substring);
3731
3732    while((pos = strstr(string, substring)) != NULL)
3733    {
3734       p = pos + len;
3735       do
3736       {
3737          *(p - len) = *p;
3738       }
3739       while (*p++ != '\0');
3740
3741       hits++;
3742    }
3743
3744    return(hits);
3745 }
3746 #endif /* def FEATURE_FORCE_LOAD */
3747
3748
3749 /*********************************************************************
3750  *
3751  * Function    :  parse_header_time
3752  *
3753  * Description :  Parses time formats used in HTTP header strings
3754  *                to get the numerical respresentation.
3755  *
3756  * Parameters  :
3757  *          1  :  header_time = HTTP header time as string. 
3758  *          2  :  result = storage for header_time in seconds
3759  *
3760  * Returns     :  JB_ERR_OK if the time format was recognized, or
3761  *                JB_ERR_PARSE otherwise.
3762  *
3763  *********************************************************************/
3764 static jb_err parse_header_time(const char *header_time, time_t *result)
3765 {
3766    struct tm gmt;
3767
3768    /*
3769     * Zero out gmt to prevent time zone offsets.
3770     *
3771     * While this is only necessary on some platforms
3772     * (mingw32 for example), I don't know how to
3773     * detect these automatically and doing it everywhere
3774     * shouldn't hurt.
3775     */
3776    memset(&gmt, 0, sizeof(gmt));
3777
3778                             /* Tue, 02 Jun 2037 20:00:00 */
3779    if ((NULL == strptime(header_time, "%a, %d %b %Y %H:%M:%S", &gmt))
3780                             /* Tue, 02-Jun-2037 20:00:00 */
3781     && (NULL == strptime(header_time, "%a, %d-%b-%Y %H:%M:%S", &gmt))
3782                             /* Tue, 02-Jun-37 20:00:00 */
3783     && (NULL == strptime(header_time, "%a, %d-%b-%y %H:%M:%S", &gmt))
3784                         /* Tuesday, 02-Jun-2037 20:00:00 */
3785     && (NULL == strptime(header_time, "%A, %d-%b-%Y %H:%M:%S", &gmt))
3786                         /* Tuesday Jun 02 20:00:00 2037 */
3787     && (NULL == strptime(header_time, "%A %b %d %H:%M:%S %Y", &gmt)))
3788    {
3789       return JB_ERR_PARSE;
3790    }
3791
3792    *result = timegm(&gmt);
3793
3794    return JB_ERR_OK;
3795
3796 }
3797
3798
3799 /*********************************************************************
3800  *
3801  * Function    :  get_destination_from_headers
3802  *
3803  * Description :  Parse the "Host:" header to get the request's destination.
3804  *                Only needed if the client's request was forcefully
3805  *                redirected into Privoxy.
3806  *
3807  *                Code mainly copied from client_host() which is currently
3808  *                run too late for this purpose.
3809  *
3810  * Parameters  :
3811  *          1  :  headers = List of headers (one of them hopefully being
3812  *                the "Host:" header)
3813  *          2  :  http = storage for the result (host, port and hostport). 
3814  *
3815  * Returns     :  JB_ERR_MEMORY in case of memory problems,
3816  *                JB_ERR_PARSE if the host header couldn't be found,
3817  *                JB_ERR_OK otherwise.
3818  *
3819  *********************************************************************/
3820 jb_err get_destination_from_headers(const struct list *headers, struct http_request *http)
3821 {
3822    char *q;
3823    char *p;
3824    char *host;
3825
3826    host = get_header_value(headers, "Host:");
3827
3828    if (NULL == host)
3829    {
3830       log_error(LOG_LEVEL_ERROR, "No \"Host:\" header found.");
3831       return JB_ERR_PARSE;
3832    }
3833
3834    if (NULL == (p = strdup((host))))
3835    {
3836       log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header");
3837       return JB_ERR_MEMORY;
3838    }
3839    chomp(p);
3840    if (NULL == (q = strdup(p)))
3841    {
3842       freez(p);
3843       log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header");
3844       return JB_ERR_MEMORY;
3845    }
3846
3847    freez(http->hostport);
3848    http->hostport = p;
3849    freez(http->host);
3850    http->host = q;
3851    q = strchr(http->host, ':');
3852    if (q != NULL)
3853    {
3854       /* Terminate hostname and evaluate port string */
3855       *q++ = '\0';
3856       http->port = atoi(q);
3857    }
3858    else
3859    {
3860       http->port = http->ssl ? 443 : 80;
3861    }
3862
3863    /* Rebuild request URL */
3864    freez(http->url);
3865    http->url = strdup(http->ssl ? "https://" : "http://");
3866    string_append(&http->url, http->hostport);
3867    string_append(&http->url, http->path);
3868    if (http->url == NULL)
3869    {
3870       return JB_ERR_MEMORY;
3871    }
3872
3873    log_error(LOG_LEVEL_HEADER, "Destination extracted from \"Host:\" header. New request URL: %s",
3874       http->url);
3875
3876    return JB_ERR_OK;
3877
3878 }
3879
3880
3881 /*********************************************************************
3882  *
3883  * Function    :  create_forged_referrer
3884  *
3885  * Description :  Helper for client_referrer to forge a referer as
3886  *                'http://[hostname:port/' to fool stupid
3887  *                checks for in-site links 
3888  *
3889  * Parameters  :
3890  *          1  :  header   = Pointer to header pointer
3891  *          2  :  hostport = Host and optionally port as string
3892  *
3893  * Returns     :  JB_ERR_OK in case of success, or
3894  *                JB_ERR_MEMORY in case of memory problems.
3895  *
3896  *********************************************************************/
3897 static jb_err create_forged_referrer(char **header, const char *hostport)
3898 {
3899     assert(NULL == *header);
3900
3901     *header = strdup("Referer: http://");
3902     string_append(header, hostport);
3903     string_append(header, "/");
3904
3905     if (NULL == *header)
3906     {
3907        return JB_ERR_MEMORY;
3908     }
3909
3910     log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header);
3911
3912     return JB_ERR_OK;
3913
3914 }
3915
3916
3917 /*********************************************************************
3918  *
3919  * Function    :  create_fake_referrer
3920  *
3921  * Description :  Helper for client_referrer to create a fake referrer
3922  *                based on a string supplied by the user.
3923  *
3924  * Parameters  :
3925  *          1  :  header   = Pointer to header pointer
3926  *          2  :  hosthost = Referrer to fake
3927  *
3928  * Returns     :  JB_ERR_OK in case of success, or
3929  *                JB_ERR_MEMORY in case of memory problems.
3930  *
3931  *********************************************************************/
3932 static jb_err create_fake_referrer(char **header, const char *fake_referrer)
3933 {
3934    assert(NULL == *header);
3935
3936    if ((0 != strncmpic(fake_referrer, "http://", 7)) && (0 != strncmpic(fake_referrer, "https://", 8)))
3937    {
3938       log_error(LOG_LEVEL_HEADER,
3939          "Parameter: +hide-referrer{%s} is a bad idea, but I don't care.", fake_referrer);
3940    }
3941    *header = strdup("Referer: ");
3942    string_append(header, fake_referrer);
3943
3944    if (NULL == *header)
3945    {
3946       return JB_ERR_MEMORY;
3947    }
3948
3949    log_error(LOG_LEVEL_HEADER, "Referer replaced with: %s", *header);
3950
3951    return JB_ERR_OK;
3952
3953 }
3954
3955
3956 /*********************************************************************
3957  *
3958  * Function    :  handle_conditional_hide_referrer_parameter
3959  *
3960  * Description :  Helper for client_referrer to crunch or forge
3961  *                the referrer header if the host has changed.
3962  *
3963  * Parameters  :
3964  *          1  :  header = Pointer to header pointer
3965  *          2  :  host   = The target host (may include the port)
3966  *          3  :  parameter_conditional_block = Boolean to signal
3967  *                if we're in conditional-block mode. If not set,
3968  *                we're in conditional-forge mode.
3969  *
3970  * Returns     :  JB_ERR_OK in case of success, or
3971  *                JB_ERR_MEMORY in case of memory problems.
3972  *
3973  *********************************************************************/
3974 static jb_err handle_conditional_hide_referrer_parameter(char **header,
3975    const char *host, const int parameter_conditional_block)
3976 {
3977    char *referer = strdup(*header);
3978    const size_t hostlenght = strlen(host);
3979    const char *referer_url = NULL;
3980
3981    if (NULL == referer)
3982    {
3983       freez(*header);
3984       return JB_ERR_MEMORY;
3985    }
3986
3987    /* referer begins with 'Referer: http[s]://' */
3988    if ((hostlenght+17) < strlen(referer))
3989    {
3990       /*
3991        * Shorten referer to make sure the referer is blocked
3992        * if www.example.org/www.example.com-shall-see-the-referer/
3993        * links to www.example.com/
3994        */
3995       referer[hostlenght+17] = '\0';
3996    }
3997    referer_url = strstr(referer, "http://");
3998    if ((NULL == referer_url) || (NULL == strstr(referer_url, host)))
3999    {
4000       /* Host has changed, Referer is invalid or a https URL. */
4001       if (parameter_conditional_block)
4002       {
4003          log_error(LOG_LEVEL_HEADER, "New host is: %s. Crunching %s!", host, *header);
4004          freez(*header);
4005       }
4006       else
4007       {
4008          freez(*header);
4009          freez(referer);
4010          return create_forged_referrer(header, host);
4011       }
4012    }
4013    freez(referer);
4014
4015    return JB_ERR_OK;
4016
4017 }
4018
4019
4020 /*********************************************************************
4021  *
4022  * Function    :  get_appropiate_connection_header
4023  *
4024  * Description :  Returns an appropiate Connection header
4025  *                depending on whether or not we try to keep
4026  *                the connection to the server alive.
4027  *
4028  * Parameters  :
4029  *          1  :  csp = Current client state (buffers, headers, etc...)
4030  *
4031  * Returns     :  Pointer to statically allocated header buffer.
4032  *
4033  *********************************************************************/
4034 static const char *get_appropiate_connection_header(const struct client_state *csp)
4035 {
4036    static const char connection_keep_alive[] = "Connection: keep-alive";
4037    static const char connection_close[] = "Connection: close";
4038
4039    if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
4040     && (csp->http->ssl == 0))
4041    {
4042       return connection_keep_alive;
4043    }
4044    return connection_close;
4045 }
4046
4047
4048 /*********************************************************************
4049  *
4050  * Function    :  create_content_length_header
4051  *
4052  * Description :  Creates a Content-Length header.
4053  *
4054  * Parameters  :
4055  *          1  :  content_length = The content length to be used in the header.
4056  *          2  :  header = Allocated space to safe the header.
4057  *          3  :  buffer_length = The length of the allocated space.
4058  *
4059  * Returns     :  void
4060  *
4061  *********************************************************************/
4062 static void create_content_length_header(unsigned long long content_length,
4063                                          char *header, size_t buffer_length)
4064 {
4065    snprintf(header, buffer_length, "Content-Length: %llu", content_length);
4066 }
4067
4068
4069 /*
4070   Local Variables:
4071   tab-width: 3
4072   end:
4073 */