Check for strftime() failures in server_last_modified(), too.
[privoxy.git] / parsers.c
1 const char parsers_rcs[] = "$Id: parsers.c,v 1.180 2009/06/17 14:50:55 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             if (!strftime(newheader, sizeof(newheader),
2338                     "%a, %d %b %Y %H:%M:%S GMT", timeptr))
2339             {
2340                log_error(LOG_LEVEL_ERROR,
2341                   "Randomizing %s failed. Keeping the header unmodified.",
2342                   *header);
2343                return JB_ERR_OK;
2344             }
2345
2346             freez(*header);
2347             *header = strdup("Last-Modified: ");
2348             string_append(header, newheader);
2349
2350             if (*header == NULL)
2351             {
2352                log_error(LOG_LEVEL_ERROR, "Insufficient memory, header crunched without replacement.");
2353                return JB_ERR_MEMORY;  
2354             }
2355
2356             days    = rtime / (3600 * 24);
2357             hours   = rtime / 3600 % 24;
2358             minutes = rtime / 60 % 60;
2359             seconds = rtime % 60;
2360
2361             log_error(LOG_LEVEL_HEADER,
2362                "Randomized:  %s (added %d da%s %d hou%s %d minut%s %d second%s",
2363                *header, days, (days == 1) ? "y" : "ys", hours, (hours == 1) ? "r" : "rs",
2364                minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)");
2365          }
2366          else
2367          {
2368             log_error(LOG_LEVEL_HEADER, "Randomized ... or not. No time difference to work with.");
2369          }
2370       }
2371    }
2372
2373    return JB_ERR_OK;
2374 }
2375
2376
2377 /*********************************************************************
2378  *
2379  * Function    :  client_accept_encoding
2380  *
2381  * Description :  Rewrite the client's Accept-Encoding header so that
2382  *                if doesn't allow compression, if the action applies.
2383  *                Note: For HTTP/1.0 the absence of the header is enough.
2384  *
2385  * Parameters  :
2386  *          1  :  csp = Current client state (buffers, headers, etc...)
2387  *          2  :  header = On input, pointer to header to modify.
2388  *                On output, pointer to the modified header, or NULL
2389  *                to remove the header.  This function frees the
2390  *                original string if necessary.
2391  *
2392  * Returns     :  JB_ERR_OK on success, or
2393  *                JB_ERR_MEMORY on out-of-memory error.
2394  *
2395  *********************************************************************/
2396 static jb_err client_accept_encoding(struct client_state *csp, char **header)
2397 {
2398    if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
2399    {
2400       log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress content");
2401
2402       freez(*header);
2403
2404       /* Temporarily disable the correct behaviour to
2405        * work around a PHP bug. 
2406        *
2407        * if (!strcmpic(csp->http->ver, "HTTP/1.1"))
2408        * {
2409        *    *header = strdup("Accept-Encoding: identity;q=1.0, *;q=0");
2410        *    if (*header == NULL)
2411        *    {
2412        *       return JB_ERR_MEMORY;
2413        *    }
2414        * }
2415        * 
2416        */
2417    }
2418
2419    return JB_ERR_OK;
2420 }
2421
2422
2423 /*********************************************************************
2424  *
2425  * Function    :  client_te
2426  *
2427  * Description :  Rewrite the client's TE header so that
2428  *                if doesn't allow compression, if the action applies.
2429  *
2430  * Parameters  :
2431  *          1  :  csp = Current client state (buffers, headers, etc...)
2432  *          2  :  header = On input, pointer to header to modify.
2433  *                On output, pointer to the modified header, or NULL
2434  *                to remove the header.  This function frees the
2435  *                original string if necessary.
2436  *
2437  * Returns     :  JB_ERR_OK on success, or
2438  *                JB_ERR_MEMORY on out-of-memory error.
2439  *
2440  *********************************************************************/
2441 static jb_err client_te(struct client_state *csp, char **header)
2442 {
2443    if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
2444    {
2445       freez(*header);
2446       log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress transfer");
2447    }
2448
2449    return JB_ERR_OK;
2450 }
2451
2452
2453 /*********************************************************************
2454  *
2455  * Function    :  client_referrer
2456  *
2457  * Description :  Handle the "referer" config setting properly.
2458  *                Called from `sed'.
2459  *
2460  * Parameters  :
2461  *          1  :  csp = Current client state (buffers, headers, etc...)
2462  *          2  :  header = On input, pointer to header to modify.
2463  *                On output, pointer to the modified header, or NULL
2464  *                to remove the header.  This function frees the
2465  *                original string if necessary.
2466  *
2467  * Returns     :  JB_ERR_OK on success, or
2468  *                JB_ERR_MEMORY on out-of-memory error.
2469  *
2470  *********************************************************************/
2471 static jb_err client_referrer(struct client_state *csp, char **header)
2472 {
2473    const char *parameter;
2474    /* booleans for parameters we have to check multiple times */
2475    int parameter_conditional_block;
2476    int parameter_conditional_forge;
2477  
2478 #ifdef FEATURE_FORCE_LOAD
2479    /*
2480     * Since the referrer can include the prefix even
2481     * if the request itself is non-forced, we must
2482     * clean it unconditionally.
2483     *
2484     * XXX: strclean is too broad
2485     */
2486    strclean(*header, FORCE_PREFIX);
2487 #endif /* def FEATURE_FORCE_LOAD */
2488
2489    if ((csp->action->flags & ACTION_HIDE_REFERER) == 0)
2490    {
2491       /* Nothing left to do */
2492       return JB_ERR_OK;
2493    }
2494
2495    parameter = csp->action->string[ACTION_STRING_REFERER];
2496    assert(parameter != NULL);
2497    parameter_conditional_block = (0 == strcmpic(parameter, "conditional-block"));
2498    parameter_conditional_forge = (0 == strcmpic(parameter, "conditional-forge"));
2499
2500    if (!parameter_conditional_block && !parameter_conditional_forge)
2501    {
2502       /*
2503        * As conditional-block and conditional-forge are the only
2504        * parameters that rely on the original referrer, we can
2505        * remove it now for all the others.
2506        */
2507       freez(*header);
2508    }
2509
2510    if (0 == strcmpic(parameter, "block"))
2511    {
2512       log_error(LOG_LEVEL_HEADER, "Referer crunched!");
2513       return JB_ERR_OK;
2514    }
2515    else if (parameter_conditional_block || parameter_conditional_forge)
2516    {
2517       return handle_conditional_hide_referrer_parameter(header,
2518          csp->http->hostport, parameter_conditional_block);
2519    }
2520    else if (0 == strcmpic(parameter, "forge"))
2521    {
2522       return create_forged_referrer(header, csp->http->hostport);
2523    }
2524    else
2525    {
2526       /* interpret parameter as user-supplied referer to fake */
2527       return create_fake_referrer(header, parameter);
2528    }
2529 }
2530
2531
2532 /*********************************************************************
2533  *
2534  * Function    :  client_accept_language
2535  *
2536  * Description :  Handle the "Accept-Language" config setting properly.
2537  *                Called from `sed'.
2538  *
2539  * Parameters  :
2540  *          1  :  csp = Current client state (buffers, headers, etc...)
2541  *          2  :  header = On input, pointer to header to modify.
2542  *                On output, pointer to the modified header, or NULL
2543  *                to remove the header.  This function frees the
2544  *                original string if necessary.
2545  *
2546  * Returns     :  JB_ERR_OK on success, or
2547  *                JB_ERR_MEMORY on out-of-memory error.
2548  *
2549  *********************************************************************/
2550 static jb_err client_accept_language(struct client_state *csp, char **header)
2551 {
2552    const char *newval;
2553
2554    /*
2555     * Are we messing with the Accept-Language?
2556     */
2557    if ((csp->action->flags & ACTION_HIDE_ACCEPT_LANGUAGE) == 0)
2558    {
2559       /*I don't think so*/
2560       return JB_ERR_OK;
2561    }
2562
2563    newval = csp->action->string[ACTION_STRING_LANGUAGE];
2564
2565    if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
2566    {
2567       /*
2568        * Blocking Accept-Language header
2569        */
2570       log_error(LOG_LEVEL_HEADER, "Crunching Accept-Language!");
2571       freez(*header);
2572       return JB_ERR_OK;
2573    }
2574    else
2575    {  
2576       /*
2577        * Replacing Accept-Language header
2578        */
2579       freez(*header);
2580       *header = strdup("Accept-Language: ");
2581       string_append(header, newval);   
2582
2583       if (*header == NULL)
2584       {
2585          log_error(LOG_LEVEL_ERROR,
2586             "Insufficient memory. Accept-Language header crunched without replacement.");  
2587       }
2588       else
2589       {
2590          log_error(LOG_LEVEL_HEADER,
2591             "Accept-Language header crunched and replaced with: %s", *header);
2592       }
2593    }
2594    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2595 }
2596
2597
2598 /*********************************************************************
2599  *
2600  * Function    :  crunch_client_header
2601  *
2602  * Description :  Crunch client header if it matches a string supplied by the
2603  *                user. Called from `sed'.
2604  *
2605  * Parameters  :
2606  *          1  :  csp = Current client state (buffers, headers, etc...)
2607  *          2  :  header = On input, pointer to header to modify.
2608  *                On output, pointer to the modified header, or NULL
2609  *                to remove the header.  This function frees the
2610  *                original string if necessary.
2611  *
2612  * Returns     :  JB_ERR_OK on success and always succeeds
2613  *
2614  *********************************************************************/
2615 static jb_err crunch_client_header(struct client_state *csp, char **header)
2616 {
2617    const char *crunch_pattern;
2618
2619    /* Do we feel like crunching? */
2620    if ((csp->action->flags & ACTION_CRUNCH_CLIENT_HEADER))
2621    {
2622       crunch_pattern = csp->action->string[ACTION_STRING_CLIENT_HEADER];
2623
2624       /* Is the current header the lucky one? */
2625       if (strstr(*header, crunch_pattern))
2626       {
2627          log_error(LOG_LEVEL_HEADER, "Crunching client header: %s (contains: %s)", *header, crunch_pattern);  
2628          freez(*header);
2629       }
2630    }
2631    return JB_ERR_OK;
2632 }
2633
2634
2635 /*********************************************************************
2636  *
2637  * Function    :  client_uagent
2638  *
2639  * Description :  Handle the "user-agent" config setting properly
2640  *                and remember its original value to enable browser
2641  *                bug workarounds. Called from `sed'.
2642  *
2643  * Parameters  :
2644  *          1  :  csp = Current client state (buffers, headers, etc...)
2645  *          2  :  header = On input, pointer to header to modify.
2646  *                On output, pointer to the modified header, or NULL
2647  *                to remove the header.  This function frees the
2648  *                original string if necessary.
2649  *
2650  * Returns     :  JB_ERR_OK on success, or
2651  *                JB_ERR_MEMORY on out-of-memory error.
2652  *
2653  *********************************************************************/
2654 static jb_err client_uagent(struct client_state *csp, char **header)
2655 {
2656    const char *newval;
2657
2658    if ((csp->action->flags & ACTION_HIDE_USER_AGENT) == 0)
2659    {
2660       return JB_ERR_OK;
2661    }
2662
2663    newval = csp->action->string[ACTION_STRING_USER_AGENT];
2664    if (newval == NULL)
2665    {
2666       return JB_ERR_OK;
2667    }
2668
2669    freez(*header);
2670    *header = strdup("User-Agent: ");
2671    string_append(header, newval);
2672
2673    log_error(LOG_LEVEL_HEADER, "Modified: %s", *header);
2674
2675    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2676 }
2677
2678
2679 /*********************************************************************
2680  *
2681  * Function    :  client_ua
2682  *
2683  * Description :  Handle "ua-" headers properly.  Called from `sed'.
2684  *
2685  * Parameters  :
2686  *          1  :  csp = Current client state (buffers, headers, etc...)
2687  *          2  :  header = On input, pointer to header to modify.
2688  *                On output, pointer to the modified header, or NULL
2689  *                to remove the header.  This function frees the
2690  *                original string if necessary.
2691  *
2692  * Returns     :  JB_ERR_OK on success, or
2693  *                JB_ERR_MEMORY on out-of-memory error.
2694  *
2695  *********************************************************************/
2696 static jb_err client_ua(struct client_state *csp, char **header)
2697 {
2698    if ((csp->action->flags & ACTION_HIDE_USER_AGENT) != 0)
2699    {
2700       log_error(LOG_LEVEL_HEADER, "crunched User-Agent!");
2701       freez(*header);
2702    }
2703
2704    return JB_ERR_OK;
2705 }
2706
2707
2708 /*********************************************************************
2709  *
2710  * Function    :  client_from
2711  *
2712  * Description :  Handle the "from" config setting properly.
2713  *                Called from `sed'.
2714  *
2715  * Parameters  :
2716  *          1  :  csp = Current client state (buffers, headers, etc...)
2717  *          2  :  header = On input, pointer to header to modify.
2718  *                On output, pointer to the modified header, or NULL
2719  *                to remove the header.  This function frees the
2720  *                original string if necessary.
2721  *
2722  * Returns     :  JB_ERR_OK on success, or
2723  *                JB_ERR_MEMORY on out-of-memory error.
2724  *
2725  *********************************************************************/
2726 static jb_err client_from(struct client_state *csp, char **header)
2727 {
2728    const char *newval;
2729
2730    if ((csp->action->flags & ACTION_HIDE_FROM) == 0)
2731    {
2732       return JB_ERR_OK;
2733    }
2734
2735    freez(*header);
2736
2737    newval = csp->action->string[ACTION_STRING_FROM];
2738
2739    /*
2740     * Are we blocking the e-mail address?
2741     */
2742    if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
2743    {
2744       log_error(LOG_LEVEL_HEADER, "crunched From!");
2745       return JB_ERR_OK;
2746    }
2747
2748    log_error(LOG_LEVEL_HEADER, " modified");
2749
2750    *header = strdup("From: ");
2751    string_append(header, newval);
2752
2753    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2754 }
2755
2756
2757 /*********************************************************************
2758  *
2759  * Function    :  client_send_cookie
2760  *
2761  * Description :  Crunches the "cookie" header if necessary.
2762  *                Called from `sed'.
2763  *
2764  *                XXX: Stupid name, doesn't send squat.
2765  *
2766  * Parameters  :
2767  *          1  :  csp = Current client state (buffers, headers, etc...)
2768  *          2  :  header = On input, pointer to header to modify.
2769  *                On output, pointer to the modified header, or NULL
2770  *                to remove the header.  This function frees the
2771  *                original string if necessary.
2772  *
2773  * Returns     :  JB_ERR_OK on success, or
2774  *                JB_ERR_MEMORY on out-of-memory error.
2775  *
2776  *********************************************************************/
2777 static jb_err client_send_cookie(struct client_state *csp, char **header)
2778 {
2779    if (csp->action->flags & ACTION_NO_COOKIE_READ)
2780    {
2781       log_error(LOG_LEVEL_HEADER, "Crunched outgoing cookie: %s", *header);
2782       freez(*header);
2783    }
2784
2785    return JB_ERR_OK;
2786 }
2787
2788
2789 /*********************************************************************
2790  *
2791  * Function    :  client_x_forwarded
2792  *
2793  * Description :  Handle the "x-forwarded-for" config setting properly,
2794  *                also used in the add_client_headers list.  Called from `sed'.
2795  *
2796  * Parameters  :
2797  *          1  :  csp = Current client state (buffers, headers, etc...)
2798  *          2  :  header = On input, pointer to header to modify.
2799  *                On output, pointer to the modified header, or NULL
2800  *                to remove the header.  This function frees the
2801  *                original string if necessary.
2802  *
2803  * Returns     :  JB_ERR_OK on success, or
2804  *                JB_ERR_MEMORY on out-of-memory error.
2805  *
2806  *********************************************************************/
2807 jb_err client_x_forwarded(struct client_state *csp, char **header)
2808 {
2809    if (0 != (csp->action->flags & ACTION_CHANGE_X_FORWARDED_FOR))
2810    {
2811       const char *parameter = csp->action->string[ACTION_STRING_CHANGE_X_FORWARDED_FOR];
2812
2813       if (0 == strcmpic(parameter, "block"))
2814       {
2815          freez(*header);
2816          log_error(LOG_LEVEL_HEADER, "crunched x-forwarded-for!");
2817       }
2818       else if (0 == strcmpic(parameter, "add"))
2819       {
2820          string_append(header, ", ");
2821          string_append(header, csp->ip_addr_str);
2822
2823          if (*header == NULL)
2824          {
2825             return JB_ERR_MEMORY;
2826          }
2827          log_error(LOG_LEVEL_HEADER,
2828             "Appended client IP address to %s", *header);
2829          csp->flags |= CSP_FLAG_X_FORWARDED_FOR_APPENDED;
2830       }
2831       else
2832       {
2833          log_error(LOG_LEVEL_FATAL,
2834             "Invalid change-x-forwarded-for parameter: '%s'", parameter);
2835       }
2836    }
2837
2838    return JB_ERR_OK;
2839 }
2840
2841
2842 /*********************************************************************
2843  *
2844  * Function    :  client_max_forwards
2845  *
2846  * Description :  If the HTTP method is OPTIONS or TRACE, subtract one
2847  *                from the value of the Max-Forwards header field.
2848  *
2849  * Parameters  :
2850  *          1  :  csp = Current client state (buffers, headers, etc...)
2851  *          2  :  header = On input, pointer to header to modify.
2852  *                On output, pointer to the modified header, or NULL
2853  *                to remove the header.  This function frees the
2854  *                original string if necessary.
2855  *
2856  * Returns     :  JB_ERR_OK on success, or
2857  *                JB_ERR_MEMORY on out-of-memory error.
2858  *
2859  *********************************************************************/
2860 static jb_err client_max_forwards(struct client_state *csp, char **header)
2861 {
2862    int max_forwards;
2863
2864    if ((0 == strcmpic(csp->http->gpc, "trace")) ||
2865        (0 == strcmpic(csp->http->gpc, "options")))
2866    {
2867       assert(*(*header+12) == ':');
2868       if (1 == sscanf(*header+12, ": %d", &max_forwards))
2869       {
2870          if (max_forwards > 0)
2871          {
2872             snprintf(*header, strlen(*header)+1, "Max-Forwards: %d", --max_forwards);
2873             log_error(LOG_LEVEL_HEADER,
2874                "Max-Forwards value for %s request reduced to %d.",
2875                csp->http->gpc, max_forwards);
2876          }
2877          else if (max_forwards < 0)
2878          {
2879             log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header);
2880             freez(*header);
2881          }
2882       }
2883       else
2884       {
2885          log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header);
2886          freez(*header);
2887       }
2888    }
2889
2890    return JB_ERR_OK;
2891 }
2892
2893
2894 /*********************************************************************
2895  *
2896  * Function    :  client_host
2897  *
2898  * Description :  If the request URI did not contain host and
2899  *                port information, parse and evaluate the Host
2900  *                header field.
2901  *
2902  *                Also, kill ill-formed HOST: headers as sent by
2903  *                Apple's iTunes software when used with a proxy.
2904  *
2905  * Parameters  :
2906  *          1  :  csp = Current client state (buffers, headers, etc...)
2907  *          2  :  header = On input, pointer to header to modify.
2908  *                On output, pointer to the modified header, or NULL
2909  *                to remove the header.  This function frees the
2910  *                original string if necessary.
2911  *
2912  * Returns     :  JB_ERR_OK on success, or
2913  *                JB_ERR_MEMORY on out-of-memory error.
2914  *
2915  *********************************************************************/
2916 static jb_err client_host(struct client_state *csp, char **header)
2917 {
2918    char *p, *q;
2919
2920    /*
2921     * If the header field name is all upper-case, chances are that it's
2922     * an ill-formed one from iTunes. BTW, killing innocent headers here is
2923     * not a problem -- they are regenerated later.
2924     */
2925    if ((*header)[1] == 'O')
2926    {
2927       log_error(LOG_LEVEL_HEADER, "Killed all-caps Host header line: %s", *header);
2928       freez(*header);
2929       return JB_ERR_OK;
2930    }
2931
2932    if (!csp->http->hostport || (*csp->http->hostport == '*') ||  
2933        *csp->http->hostport == ' ' || *csp->http->hostport == '\0')
2934    {
2935       
2936       if (NULL == (p = strdup((*header)+6)))
2937       {
2938          return JB_ERR_MEMORY;
2939       }
2940       chomp(p);
2941       if (NULL == (q = strdup(p)))
2942       {
2943          freez(p);
2944          return JB_ERR_MEMORY;
2945       }
2946
2947       freez(csp->http->hostport);
2948       csp->http->hostport = p;
2949       freez(csp->http->host);
2950       csp->http->host = q;
2951       q = strchr(csp->http->host, ':');
2952       if (q != NULL)
2953       {
2954          /* Terminate hostname and evaluate port string */
2955          *q++ = '\0';
2956          csp->http->port = atoi(q);
2957       }
2958       else
2959       {
2960          csp->http->port = csp->http->ssl ? 443 : 80;
2961       }
2962
2963       log_error(LOG_LEVEL_HEADER, "New host and port from Host field: %s = %s:%d",
2964                 csp->http->hostport, csp->http->host, csp->http->port);
2965    }
2966
2967    /* Signal client_host_adder() to return right away */
2968    csp->flags |= CSP_FLAG_HOST_HEADER_IS_SET;
2969
2970    return JB_ERR_OK;
2971 }
2972
2973
2974 /*********************************************************************
2975  *
2976  * Function    :  client_if_modified_since
2977  *
2978  * Description :  Remove or modify the If-Modified-Since header.
2979  *
2980  * Parameters  :
2981  *          1  :  csp = Current client state (buffers, headers, etc...)
2982  *          2  :  header = On input, pointer to header to modify.
2983  *                On output, pointer to the modified header, or NULL
2984  *                to remove the header.  This function frees the
2985  *                original string if necessary.
2986  *
2987  * Returns     :  JB_ERR_OK on success, or
2988  *                JB_ERR_MEMORY on out-of-memory error.
2989  *
2990  *********************************************************************/
2991 static jb_err client_if_modified_since(struct client_state *csp, char **header)
2992 {
2993    char newheader[50];
2994 #ifdef HAVE_GMTIME_R
2995    struct tm gmt;
2996 #endif
2997    struct tm *timeptr = NULL;
2998    time_t tm = 0;                  
2999    const char *newval;
3000    long int hours, minutes, seconds;
3001    char * endptr;
3002    
3003    if ( 0 == strcmpic(*header, "If-Modified-Since: Wed, 08 Jun 1955 12:00:00 GMT"))
3004    {
3005       /* 
3006        * The client got an error message because of a temporary problem,
3007        * the problem is gone and the client now tries to revalidate our
3008        * error message on the real server. The revalidation would always
3009        * end with the transmission of the whole document and there is
3010        * no need to expose the bogus If-Modified-Since header.
3011        */
3012       log_error(LOG_LEVEL_HEADER, "Crunching useless If-Modified-Since header.");
3013       freez(*header);
3014    }
3015    else if (csp->action->flags & ACTION_HIDE_IF_MODIFIED_SINCE)
3016    {
3017       newval = csp->action->string[ACTION_STRING_IF_MODIFIED_SINCE];
3018
3019       if ((0 == strcmpic(newval, "block")))
3020       {
3021          log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
3022          freez(*header);
3023       }
3024       else /* add random value */
3025       {
3026          const char *header_time = *header + sizeof("If-Modified-Since:");
3027
3028          if (JB_ERR_OK != parse_header_time(header_time, &tm))
3029          {
3030             log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s in %s (crunching!)", header_time, *header);
3031             freez(*header);
3032          }
3033          else
3034          {
3035             long int rtime = strtol(newval, &endptr, 0);
3036             const int negative_range = (rtime < 0);
3037
3038             if (rtime)
3039             {
3040                log_error(LOG_LEVEL_HEADER, "Randomizing: %s (random range: %d minut%s)",
3041                   *header, rtime, (rtime == 1 || rtime == -1) ? "e": "es");
3042                if (negative_range)
3043                {
3044                   rtime *= -1; 
3045                }
3046                rtime *= 60;
3047                rtime = pick_from_range(rtime);
3048             }
3049             else
3050             {
3051                log_error(LOG_LEVEL_ERROR, "Random range is 0. Assuming time transformation test.",
3052                   *header);
3053             }
3054             tm += rtime * (negative_range ? -1 : 1);
3055 #ifdef HAVE_GMTIME_R
3056             timeptr = gmtime_r(&tm, &gmt);
3057 #elif defined(MUTEX_LOCKS_AVAILABLE)
3058             privoxy_mutex_lock(&gmtime_mutex);
3059             timeptr = gmtime(&tm);
3060             privoxy_mutex_unlock(&gmtime_mutex);
3061 #else
3062             timeptr = gmtime(&tm);
3063 #endif
3064             if (!strftime(newheader, sizeof(newheader),
3065                     "%a, %d %b %Y %H:%M:%S GMT", timeptr))
3066             {
3067                log_error(LOG_LEVEL_ERROR,
3068                   "Randomizing %s failed. Keeping the header unmodified.",
3069                   *header);
3070                return JB_ERR_OK;
3071             }
3072
3073             freez(*header);
3074             *header = strdup("If-Modified-Since: ");
3075             string_append(header, newheader);
3076
3077             if (*header == NULL)
3078             {
3079                log_error(LOG_LEVEL_HEADER, "Insufficient memory, header crunched without replacement.");
3080                return JB_ERR_MEMORY;  
3081             }
3082
3083             hours   = rtime / 3600;
3084             minutes = rtime / 60 % 60;
3085             seconds = rtime % 60;
3086
3087             log_error(LOG_LEVEL_HEADER,
3088                "Randomized:  %s (%s %d hou%s %d minut%s %d second%s",
3089                *header, (negative_range) ? "subtracted" : "added", hours,
3090                (hours == 1) ? "r" : "rs", minutes, (minutes == 1) ? "e" : "es",
3091                seconds, (seconds == 1) ? ")" : "s)");
3092          }
3093       }
3094    }
3095
3096    return JB_ERR_OK;
3097 }
3098
3099
3100 /*********************************************************************
3101  *
3102  * Function    :  client_if_none_match
3103  *
3104  * Description :  Remove the If-None-Match header.
3105  *
3106  * Parameters  :
3107  *          1  :  csp = Current client state (buffers, headers, etc...)
3108  *          2  :  header = On input, pointer to header to modify.
3109  *                On output, pointer to the modified header, or NULL
3110  *                to remove the header.  This function frees the
3111  *                original string if necessary.
3112  *
3113  * Returns     :  JB_ERR_OK on success, or
3114  *                JB_ERR_MEMORY on out-of-memory error.
3115  *
3116  *********************************************************************/
3117 static jb_err client_if_none_match(struct client_state *csp, char **header)
3118 {
3119    if (csp->action->flags & ACTION_CRUNCH_IF_NONE_MATCH)
3120    {  
3121       log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
3122       freez(*header);
3123    }
3124
3125    return JB_ERR_OK;
3126 }
3127
3128
3129 /*********************************************************************
3130  *
3131  * Function    :  client_x_filter
3132  *
3133  * Description :  Disables filtering if the client set "X-Filter: No".
3134  *                Called from `sed'.
3135  *
3136  * Parameters  :
3137  *          1  :  csp = Current client state (buffers, headers, etc...)
3138  *          2  :  header = On input, pointer to header to modify.
3139  *                On output, pointer to the modified header, or NULL
3140  *                to remove the header.  This function frees the
3141  *                original string if necessary.
3142  *
3143  * Returns     :  JB_ERR_OK on success
3144  *
3145  *********************************************************************/
3146 jb_err client_x_filter(struct client_state *csp, char **header)
3147 {
3148    if ( 0 == strcmpic(*header, "X-Filter: No"))
3149    {
3150       if (!(csp->config->feature_flags & RUNTIME_FEATURE_HTTP_TOGGLE))
3151       {
3152          log_error(LOG_LEVEL_INFO, "Ignored the client's request to fetch without filtering.");
3153       }
3154       else
3155       {
3156          if (csp->action->flags & ACTION_FORCE_TEXT_MODE)
3157          {
3158             log_error(LOG_LEVEL_HEADER,
3159                "force-text-mode overruled the client's request to fetch without filtering!");
3160          }
3161          else
3162          {  
3163             csp->content_type = CT_TABOO; /* XXX: This hack shouldn't be necessary */
3164             csp->flags |= CSP_FLAG_NO_FILTERING;
3165             log_error(LOG_LEVEL_HEADER, "Accepted the client's request to fetch without filtering.");
3166          }
3167          log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
3168          freez(*header);
3169       }
3170    }
3171    return JB_ERR_OK; 
3172 }
3173
3174
3175 /*********************************************************************
3176  *
3177  * Function    :  client_range
3178  *
3179  * Description :  Removes Range, Request-Range and If-Range headers if
3180  *                content filtering is enabled. If the client's version
3181  *                of the document has been altered by Privoxy, the server
3182  *                could interpret the range differently than the client
3183  *                intended in which case the user could end up with
3184  *                corrupted content.
3185  *
3186  * Parameters  :
3187  *          1  :  csp = Current client state (buffers, headers, etc...)
3188  *          2  :  header = On input, pointer to header to modify.
3189  *                On output, pointer to the modified header, or NULL
3190  *                to remove the header.  This function frees the
3191  *                original string if necessary.
3192  *
3193  * Returns     :  JB_ERR_OK
3194  *
3195  *********************************************************************/
3196 static jb_err client_range(struct client_state *csp, char **header)
3197 {
3198    if (content_filters_enabled(csp->action))
3199    {
3200       log_error(LOG_LEVEL_HEADER, "Content filtering is enabled."
3201          " Crunching: \'%s\' to prevent range-mismatch problems.", *header);
3202       freez(*header);
3203    }
3204
3205    return JB_ERR_OK; 
3206 }
3207
3208 /* the following functions add headers directly to the header list */
3209
3210 /*********************************************************************
3211  *
3212  * Function    :  client_host_adder
3213  *
3214  * Description :  Adds the Host: header field if it is missing.
3215  *                Called from `sed'.
3216  *
3217  * Parameters  :
3218  *          1  :  csp = Current client state (buffers, headers, etc...)
3219  *
3220  * Returns     :  JB_ERR_OK on success, or
3221  *                JB_ERR_MEMORY on out-of-memory error.
3222  *
3223  *********************************************************************/
3224 static jb_err client_host_adder(struct client_state *csp)
3225 {
3226    char *p;
3227    jb_err err;
3228
3229    if (csp->flags & CSP_FLAG_HOST_HEADER_IS_SET)
3230    {
3231       /* Header already set by the client, nothing to do. */
3232       return JB_ERR_OK;
3233    }
3234
3235    if ( !csp->http->hostport || !*(csp->http->hostport))
3236    {
3237       /* XXX: When does this happen and why is it OK? */
3238       log_error(LOG_LEVEL_INFO, "Weirdness in client_host_adder detected and ignored.");
3239       return JB_ERR_OK;
3240    }
3241
3242    /*
3243     * remove 'user:pass@' from 'proto://user:pass@host'
3244     */
3245    if ( (p = strchr( csp->http->hostport, '@')) != NULL )
3246    {
3247       p++;
3248    }
3249    else
3250    {
3251       p = csp->http->hostport;
3252    }
3253
3254    /* XXX: Just add it, we already made sure that it will be unique */
3255    log_error(LOG_LEVEL_HEADER, "addh-unique: Host: %s", p);
3256    err = enlist_unique_header(csp->headers, "Host", p);
3257    return err;
3258
3259 }
3260
3261
3262 #if 0
3263 /*********************************************************************
3264  *
3265  * Function    :  client_accept_encoding_adder
3266  *
3267  * Description :  Add an Accept-Encoding header to the client's request
3268  *                that disables compression if the action applies, and
3269  *                the header is not already there. Called from `sed'.
3270  *                Note: For HTTP/1.0, the absence of the header is enough.
3271  *
3272  * Parameters  :
3273  *          1  :  csp = Current client state (buffers, headers, etc...)
3274  *
3275  * Returns     :  JB_ERR_OK on success, or
3276  *                JB_ERR_MEMORY on out-of-memory error.
3277  *
3278  *********************************************************************/
3279 static jb_err client_accept_encoding_adder(struct client_state *csp)
3280 {
3281    if (   ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
3282        && (!strcmpic(csp->http->ver, "HTTP/1.1")) )
3283    {
3284       return enlist_unique(csp->headers, "Accept-Encoding: identity;q=1.0, *;q=0", 16);
3285    }
3286
3287    return JB_ERR_OK;
3288 }
3289 #endif
3290
3291
3292 /*********************************************************************
3293  *
3294  * Function    :  client_xtra_adder
3295  *
3296  * Description :  Used in the add_client_headers list.  Called from `sed'.
3297  *
3298  * Parameters  :
3299  *          1  :  csp = Current client state (buffers, headers, etc...)
3300  *
3301  * Returns     :  JB_ERR_OK on success, or
3302  *                JB_ERR_MEMORY on out-of-memory error.
3303  *
3304  *********************************************************************/
3305 static jb_err client_xtra_adder(struct client_state *csp)
3306 {
3307    struct list_entry *lst;
3308    jb_err err;
3309
3310    for (lst = csp->action->multi[ACTION_MULTI_ADD_HEADER]->first;
3311         lst ; lst = lst->next)
3312    {
3313       log_error(LOG_LEVEL_HEADER, "addh: %s", lst->str);
3314       err = enlist(csp->headers, lst->str);
3315       if (err)
3316       {
3317          return err;
3318       }
3319
3320    }
3321
3322    return JB_ERR_OK;
3323 }
3324
3325
3326 /*********************************************************************
3327  *
3328  * Function    :  client_x_forwarded_for_adder
3329  *
3330  * Description :  Used in the add_client_headers list.  Called from `sed'.
3331  *
3332  * Parameters  :
3333  *          1  :  csp = Current client state (buffers, headers, etc...)
3334  *
3335  * Returns     :  JB_ERR_OK on success, or
3336  *                JB_ERR_MEMORY on out-of-memory error.
3337  *
3338  *********************************************************************/
3339 static jb_err client_x_forwarded_for_adder(struct client_state *csp)
3340 {
3341    char *header = NULL;
3342    jb_err err;
3343
3344    if (!((csp->action->flags & ACTION_CHANGE_X_FORWARDED_FOR)
3345          && (0 == strcmpic(csp->action->string[ACTION_STRING_CHANGE_X_FORWARDED_FOR], "add")))
3346       || (csp->flags & CSP_FLAG_X_FORWARDED_FOR_APPENDED))
3347    {
3348       /*
3349        * If we aren't adding X-Forwarded-For headers,
3350        * or we already appended an existing X-Forwarded-For
3351        * header, there's nothing left to do here.
3352        */
3353       return JB_ERR_OK;
3354    }
3355
3356    header = strdup("X-Forwarded-For: ");
3357    string_append(&header, csp->ip_addr_str);
3358
3359    if (header == NULL)
3360    {
3361       return JB_ERR_MEMORY;
3362    }
3363
3364    log_error(LOG_LEVEL_HEADER, "addh: %s", header);
3365    err = enlist(csp->headers, header);
3366    freez(header);
3367
3368    return err;
3369 }
3370
3371
3372 /*********************************************************************
3373  *
3374  * Function    :  server_connection_adder
3375  *
3376  * Description :  Adds an appropiate "Connection:" header to csp->headers
3377  *                unless the header was already present. Called from `sed'.
3378  *
3379  * Parameters  :
3380  *          1  :  csp = Current client state (buffers, headers, etc...)
3381  *
3382  * Returns     :  JB_ERR_OK on success, or
3383  *                JB_ERR_MEMORY on out-of-memory error.
3384  *
3385  *********************************************************************/
3386 static jb_err server_connection_adder(struct client_state *csp)
3387 {
3388    const unsigned int flags = csp->flags;
3389    const char *response_status_line = csp->headers->first->str;
3390    const char *wanted_header = get_appropiate_connection_header(csp);
3391
3392    if ((flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
3393     && (flags & CSP_FLAG_SERVER_CONNECTION_HEADER_SET))
3394    {
3395       return JB_ERR_OK;
3396    }
3397
3398    /*
3399     * XXX: if we downgraded the response, this check will fail.
3400     */
3401    if ((csp->config->feature_flags &
3402         RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
3403     && (NULL != response_status_line)
3404     && !strncmpic(response_status_line, "HTTP/1.1", 8))
3405    {
3406       log_error(LOG_LEVEL_HEADER, "A HTTP/1.1 response "
3407          "without Connection header implies keep-alive.");
3408       csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
3409    }
3410
3411    log_error(LOG_LEVEL_HEADER, "Adding: %s", wanted_header);
3412
3413    return enlist(csp->headers, wanted_header);
3414 }
3415
3416
3417 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
3418 /*********************************************************************
3419  *
3420  * Function    :  server_proxy_connection_adder
3421  *
3422  * Description :  Adds a "Proxy-Connection: keep-alive" header to
3423  *                csp->headers if the client asked for keep-alive.
3424  *                XXX: We should reuse existant ones.
3425  *
3426  * Parameters  :
3427  *          1  :  csp = Current client state (buffers, headers, etc...)
3428  *
3429  * Returns     :  JB_ERR_OK on success, or
3430  *                JB_ERR_MEMORY on out-of-memory error.
3431  *
3432  *********************************************************************/
3433 static jb_err server_proxy_connection_adder(struct client_state *csp)
3434 {
3435    static const char proxy_connection_header[] = "Proxy-Connection: keep-alive";
3436    jb_err err = JB_ERR_OK;
3437
3438    if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE))
3439    {
3440       log_error(LOG_LEVEL_HEADER, "Adding: %s", proxy_connection_header);
3441       err = enlist(csp->headers, proxy_connection_header);
3442    }
3443
3444    return err;
3445 }
3446 #endif /* FEATURE_CONNECTION_KEEP_ALIVE */
3447
3448
3449 /*********************************************************************
3450  *
3451  * Function    :  client_connection_header_adder
3452  *
3453  * Description :  Adds a proper "Connection:" header to csp->headers
3454  *                unless the header was already present. Called from `sed'.
3455  *
3456  * Parameters  :
3457  *          1  :  csp = Current client state (buffers, headers, etc...)
3458  *
3459  * Returns     :  JB_ERR_OK on success, or
3460  *                JB_ERR_MEMORY on out-of-memory error.
3461  *
3462  *********************************************************************/
3463 static jb_err client_connection_header_adder(struct client_state *csp)
3464 {
3465    const char *wanted_header = get_appropiate_connection_header(csp);
3466
3467    if (!(csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
3468      && (csp->flags & CSP_FLAG_CLIENT_CONNECTION_HEADER_SET))
3469    {
3470       return JB_ERR_OK;
3471    }
3472
3473 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
3474    if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
3475       && (csp->http->ssl == 0))
3476    {
3477       csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
3478    }
3479 #endif /* FEATURE_CONNECTION_KEEP_ALIVE */
3480
3481    log_error(LOG_LEVEL_HEADER, "Adding: %s", wanted_header);
3482
3483    return enlist(csp->headers, wanted_header);
3484 }
3485
3486
3487 /*********************************************************************
3488  *
3489  * Function    :  server_http
3490  *
3491  * Description :  - Save the HTTP Status into csp->http->status
3492  *                - Set CT_TABOO to prevent filtering if the answer
3493  *                  is a partial range (HTTP status 206)
3494  *                - Rewrite HTTP/1.1 answers to HTTP/1.0 if +downgrade
3495  *                  action applies.
3496  *
3497  * Parameters  :
3498  *          1  :  csp = Current client state (buffers, headers, etc...)
3499  *          2  :  header = On input, pointer to header to modify.
3500  *                On output, pointer to the modified header, or NULL
3501  *                to remove the header.  This function frees the
3502  *                original string if necessary.
3503  *
3504  * Returns     :  JB_ERR_OK on success, or
3505  *                JB_ERR_MEMORY on out-of-memory error.
3506  *
3507  *********************************************************************/
3508 static jb_err server_http(struct client_state *csp, char **header)
3509 {
3510    sscanf(*header, "HTTP/%*d.%*d %d", &(csp->http->status));
3511    if (csp->http->status == 206)
3512    {
3513       csp->content_type = CT_TABOO;
3514    }
3515
3516    if ((csp->action->flags & ACTION_DOWNGRADE) != 0)
3517    {
3518       /* XXX: Should we do a real validity check here? */
3519       if (strlen(*header) > 8)
3520       {
3521          (*header)[7] = '0';
3522          log_error(LOG_LEVEL_HEADER, "Downgraded answer to HTTP/1.0");
3523       }
3524       else
3525       {
3526          /*
3527           * XXX: Should we block the request or
3528           * enlist a valid status code line here?
3529           */
3530          log_error(LOG_LEVEL_INFO, "Malformed server response detected. "
3531             "Downgrading to HTTP/1.0 impossible.");
3532       }
3533    }
3534
3535    return JB_ERR_OK;
3536 }
3537
3538
3539 /*********************************************************************
3540  *
3541  * Function    :  server_set_cookie
3542  *
3543  * Description :  Handle the server "cookie" header properly.
3544  *                Log cookie to the jar file.  Then "crunch",
3545  *                accept or rewrite it to a session cookie.
3546  *                Called from `sed'.
3547  *
3548  *                TODO: Allow the user to specify a new expiration
3549  *                time to cause the cookie to expire even before the
3550  *                browser is closed.
3551  *
3552  * Parameters  :
3553  *          1  :  csp = Current client state (buffers, headers, etc...)
3554  *          2  :  header = On input, pointer to header to modify.
3555  *                On output, pointer to the modified header, or NULL
3556  *                to remove the header.  This function frees the
3557  *                original string if necessary.
3558  *
3559  * Returns     :  JB_ERR_OK on success, or
3560  *                JB_ERR_MEMORY on out-of-memory error.
3561  *
3562  *********************************************************************/
3563 static jb_err server_set_cookie(struct client_state *csp, char **header)
3564 {
3565    time_t now;
3566    time_t cookie_time; 
3567
3568    time(&now);
3569
3570    if ((csp->action->flags & ACTION_NO_COOKIE_SET) != 0)
3571    {
3572       log_error(LOG_LEVEL_HEADER, "Crunching incoming cookie: %s", *header);
3573       freez(*header);
3574    }
3575    else if ((csp->action->flags & ACTION_NO_COOKIE_KEEP) != 0)
3576    {
3577       /* Flag whether or not to log a message */
3578       int changed = 0;
3579
3580       /* A variable to store the tag we're working on */
3581       char *cur_tag;
3582
3583       /* Skip "Set-Cookie:" (11 characters) in header */
3584       cur_tag = *header + 11;
3585
3586       /* skip whitespace between "Set-Cookie:" and value */
3587       while (*cur_tag && ijb_isspace(*cur_tag))
3588       {
3589          cur_tag++;
3590       }
3591
3592       /* Loop through each tag in the cookie */
3593       while (*cur_tag)
3594       {
3595          /* Find next tag */
3596          char *next_tag = strchr(cur_tag, ';');
3597          if (next_tag != NULL)
3598          {
3599             /* Skip the ';' character itself */
3600             next_tag++;
3601
3602             /* skip whitespace ";" and start of tag */
3603             while (*next_tag && ijb_isspace(*next_tag))
3604             {
3605                next_tag++;
3606             }
3607          }
3608          else
3609          {
3610             /* "Next tag" is the end of the string */
3611             next_tag = cur_tag + strlen(cur_tag);
3612          }
3613
3614          /*
3615           * Check the expiration date to see
3616           * if the cookie is still valid, if yes,
3617           * rewrite it to a session cookie.
3618           */
3619          if ((strncmpic(cur_tag, "expires=", 8) == 0) && *(cur_tag + 8))
3620          {
3621             char *expiration_date = cur_tag + 8; /* Skip "[Ee]xpires=" */
3622
3623             /* Did we detect the date properly? */
3624             if (JB_ERR_OK != parse_header_time(expiration_date, &cookie_time))
3625             {
3626                /*
3627                 * Nope, treat it as if it was still valid.
3628                 *
3629                 * XXX: Should we remove the whole cookie instead?
3630                 */
3631                log_error(LOG_LEVEL_ERROR,
3632                   "Can't parse \'%s\', send by %s. Unsupported time format?", cur_tag, csp->http->url);
3633                string_move(cur_tag, next_tag);
3634                changed = 1;
3635             }
3636             else
3637             {
3638                /*
3639                 * Yes. Check if the cookie is still valid.
3640                 *
3641                 * If the cookie is already expired it's probably
3642                 * a delete cookie and even if it isn't, the browser
3643                 * will discard it anyway.
3644                 */
3645
3646                /*
3647                 * XXX: timegm() isn't available on some AmigaOS
3648                 * versions and our replacement doesn't work.
3649                 *
3650                 * Our options are to either:
3651                 *
3652                 * - disable session-cookies-only completely if timegm
3653                 *   is missing,
3654                 *
3655                 * - to simply remove all expired tags, like it has
3656                 *   been done until Privoxy 3.0.6 and to live with
3657                 *    the consequence that it can cause login/logout
3658                 *   problems on servers that don't validate their
3659                 *   input properly, or
3660                 *
3661                 * - to replace it with mktime in which
3662                 *   case there is a slight chance of valid cookies
3663                 *   passing as already expired.
3664                 *
3665                 *   This is the way it's currently done and it's not
3666                 *   as bad as it sounds. If the missing GMT offset is
3667                 *   enough to change the result of the expiration check
3668                 *   the cookie will be only valid for a few hours
3669                 *   anyway, which in many cases will be shorter
3670                 *   than a browser session.
3671                 */
3672                if (cookie_time - now < 0)
3673                {
3674                   log_error(LOG_LEVEL_HEADER,
3675                      "Cookie \'%s\' is already expired and can pass unmodified.", *header);
3676                   /* Just in case some clown sets more then one expiration date */
3677                   cur_tag = next_tag;
3678                }
3679                else
3680                {
3681                   /*
3682                    * Still valid, delete expiration date by copying
3683                    * the rest of the string over it.
3684                    */
3685                   string_move(cur_tag, next_tag);
3686
3687                   /* That changed the header, need to issue a log message */
3688                   changed = 1;
3689
3690                   /*
3691                    * Note that the next tag has now been moved to *cur_tag,
3692                    * so we do not need to update the cur_tag pointer.
3693                    */
3694                }
3695             }
3696
3697          }
3698          else
3699          {
3700             /* Move on to next cookie tag */
3701             cur_tag = next_tag;
3702          }
3703       }
3704
3705       if (changed)
3706       {
3707          assert(NULL != *header);
3708          log_error(LOG_LEVEL_HEADER, "Cookie rewritten to a temporary one: %s",
3709             *header);
3710       }
3711    }
3712
3713    return JB_ERR_OK;
3714 }
3715
3716
3717 #ifdef FEATURE_FORCE_LOAD
3718 /*********************************************************************
3719  *
3720  * Function    :  strclean
3721  *
3722  * Description :  In-Situ-Eliminate all occurances of substring in
3723  *                string
3724  *
3725  * Parameters  :
3726  *          1  :  string = string to clean
3727  *          2  :  substring = substring to eliminate
3728  *
3729  * Returns     :  Number of eliminations
3730  *
3731  *********************************************************************/
3732 int strclean(char *string, const char *substring)
3733 {
3734    int hits = 0;
3735    size_t len;
3736    char *pos, *p;
3737
3738    len = strlen(substring);
3739
3740    while((pos = strstr(string, substring)) != NULL)
3741    {
3742       p = pos + len;
3743       do
3744       {
3745          *(p - len) = *p;
3746       }
3747       while (*p++ != '\0');
3748
3749       hits++;
3750    }
3751
3752    return(hits);
3753 }
3754 #endif /* def FEATURE_FORCE_LOAD */
3755
3756
3757 /*********************************************************************
3758  *
3759  * Function    :  parse_header_time
3760  *
3761  * Description :  Parses time formats used in HTTP header strings
3762  *                to get the numerical respresentation.
3763  *
3764  * Parameters  :
3765  *          1  :  header_time = HTTP header time as string. 
3766  *          2  :  result = storage for header_time in seconds
3767  *
3768  * Returns     :  JB_ERR_OK if the time format was recognized, or
3769  *                JB_ERR_PARSE otherwise.
3770  *
3771  *********************************************************************/
3772 static jb_err parse_header_time(const char *header_time, time_t *result)
3773 {
3774    struct tm gmt;
3775
3776    /*
3777     * Zero out gmt to prevent time zone offsets.
3778     *
3779     * While this is only necessary on some platforms
3780     * (mingw32 for example), I don't know how to
3781     * detect these automatically and doing it everywhere
3782     * shouldn't hurt.
3783     */
3784    memset(&gmt, 0, sizeof(gmt));
3785
3786                             /* Tue, 02 Jun 2037 20:00:00 */
3787    if ((NULL == strptime(header_time, "%a, %d %b %Y %H:%M:%S", &gmt))
3788                             /* Tue, 02-Jun-2037 20:00:00 */
3789     && (NULL == strptime(header_time, "%a, %d-%b-%Y %H:%M:%S", &gmt))
3790                             /* Tue, 02-Jun-37 20:00:00 */
3791     && (NULL == strptime(header_time, "%a, %d-%b-%y %H:%M:%S", &gmt))
3792                         /* Tuesday, 02-Jun-2037 20:00:00 */
3793     && (NULL == strptime(header_time, "%A, %d-%b-%Y %H:%M:%S", &gmt))
3794                         /* Tuesday Jun 02 20:00:00 2037 */
3795     && (NULL == strptime(header_time, "%A %b %d %H:%M:%S %Y", &gmt)))
3796    {
3797       return JB_ERR_PARSE;
3798    }
3799
3800    *result = timegm(&gmt);
3801
3802    return JB_ERR_OK;
3803
3804 }
3805
3806
3807 /*********************************************************************
3808  *
3809  * Function    :  get_destination_from_headers
3810  *
3811  * Description :  Parse the "Host:" header to get the request's destination.
3812  *                Only needed if the client's request was forcefully
3813  *                redirected into Privoxy.
3814  *
3815  *                Code mainly copied from client_host() which is currently
3816  *                run too late for this purpose.
3817  *
3818  * Parameters  :
3819  *          1  :  headers = List of headers (one of them hopefully being
3820  *                the "Host:" header)
3821  *          2  :  http = storage for the result (host, port and hostport). 
3822  *
3823  * Returns     :  JB_ERR_MEMORY in case of memory problems,
3824  *                JB_ERR_PARSE if the host header couldn't be found,
3825  *                JB_ERR_OK otherwise.
3826  *
3827  *********************************************************************/
3828 jb_err get_destination_from_headers(const struct list *headers, struct http_request *http)
3829 {
3830    char *q;
3831    char *p;
3832    char *host;
3833
3834    host = get_header_value(headers, "Host:");
3835
3836    if (NULL == host)
3837    {
3838       log_error(LOG_LEVEL_ERROR, "No \"Host:\" header found.");
3839       return JB_ERR_PARSE;
3840    }
3841
3842    if (NULL == (p = strdup((host))))
3843    {
3844       log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header");
3845       return JB_ERR_MEMORY;
3846    }
3847    chomp(p);
3848    if (NULL == (q = strdup(p)))
3849    {
3850       freez(p);
3851       log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header");
3852       return JB_ERR_MEMORY;
3853    }
3854
3855    freez(http->hostport);
3856    http->hostport = p;
3857    freez(http->host);
3858    http->host = q;
3859    q = strchr(http->host, ':');
3860    if (q != NULL)
3861    {
3862       /* Terminate hostname and evaluate port string */
3863       *q++ = '\0';
3864       http->port = atoi(q);
3865    }
3866    else
3867    {
3868       http->port = http->ssl ? 443 : 80;
3869    }
3870
3871    /* Rebuild request URL */
3872    freez(http->url);
3873    http->url = strdup(http->ssl ? "https://" : "http://");
3874    string_append(&http->url, http->hostport);
3875    string_append(&http->url, http->path);
3876    if (http->url == NULL)
3877    {
3878       return JB_ERR_MEMORY;
3879    }
3880
3881    log_error(LOG_LEVEL_HEADER, "Destination extracted from \"Host:\" header. New request URL: %s",
3882       http->url);
3883
3884    return JB_ERR_OK;
3885
3886 }
3887
3888
3889 /*********************************************************************
3890  *
3891  * Function    :  create_forged_referrer
3892  *
3893  * Description :  Helper for client_referrer to forge a referer as
3894  *                'http://[hostname:port/' to fool stupid
3895  *                checks for in-site links 
3896  *
3897  * Parameters  :
3898  *          1  :  header   = Pointer to header pointer
3899  *          2  :  hostport = Host and optionally port as string
3900  *
3901  * Returns     :  JB_ERR_OK in case of success, or
3902  *                JB_ERR_MEMORY in case of memory problems.
3903  *
3904  *********************************************************************/
3905 static jb_err create_forged_referrer(char **header, const char *hostport)
3906 {
3907     assert(NULL == *header);
3908
3909     *header = strdup("Referer: http://");
3910     string_append(header, hostport);
3911     string_append(header, "/");
3912
3913     if (NULL == *header)
3914     {
3915        return JB_ERR_MEMORY;
3916     }
3917
3918     log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header);
3919
3920     return JB_ERR_OK;
3921
3922 }
3923
3924
3925 /*********************************************************************
3926  *
3927  * Function    :  create_fake_referrer
3928  *
3929  * Description :  Helper for client_referrer to create a fake referrer
3930  *                based on a string supplied by the user.
3931  *
3932  * Parameters  :
3933  *          1  :  header   = Pointer to header pointer
3934  *          2  :  hosthost = Referrer to fake
3935  *
3936  * Returns     :  JB_ERR_OK in case of success, or
3937  *                JB_ERR_MEMORY in case of memory problems.
3938  *
3939  *********************************************************************/
3940 static jb_err create_fake_referrer(char **header, const char *fake_referrer)
3941 {
3942    assert(NULL == *header);
3943
3944    if ((0 != strncmpic(fake_referrer, "http://", 7)) && (0 != strncmpic(fake_referrer, "https://", 8)))
3945    {
3946       log_error(LOG_LEVEL_HEADER,
3947          "Parameter: +hide-referrer{%s} is a bad idea, but I don't care.", fake_referrer);
3948    }
3949    *header = strdup("Referer: ");
3950    string_append(header, fake_referrer);
3951
3952    if (NULL == *header)
3953    {
3954       return JB_ERR_MEMORY;
3955    }
3956
3957    log_error(LOG_LEVEL_HEADER, "Referer replaced with: %s", *header);
3958
3959    return JB_ERR_OK;
3960
3961 }
3962
3963
3964 /*********************************************************************
3965  *
3966  * Function    :  handle_conditional_hide_referrer_parameter
3967  *
3968  * Description :  Helper for client_referrer to crunch or forge
3969  *                the referrer header if the host has changed.
3970  *
3971  * Parameters  :
3972  *          1  :  header = Pointer to header pointer
3973  *          2  :  host   = The target host (may include the port)
3974  *          3  :  parameter_conditional_block = Boolean to signal
3975  *                if we're in conditional-block mode. If not set,
3976  *                we're in conditional-forge mode.
3977  *
3978  * Returns     :  JB_ERR_OK in case of success, or
3979  *                JB_ERR_MEMORY in case of memory problems.
3980  *
3981  *********************************************************************/
3982 static jb_err handle_conditional_hide_referrer_parameter(char **header,
3983    const char *host, const int parameter_conditional_block)
3984 {
3985    char *referer = strdup(*header);
3986    const size_t hostlenght = strlen(host);
3987    const char *referer_url = NULL;
3988
3989    if (NULL == referer)
3990    {
3991       freez(*header);
3992       return JB_ERR_MEMORY;
3993    }
3994
3995    /* referer begins with 'Referer: http[s]://' */
3996    if ((hostlenght+17) < strlen(referer))
3997    {
3998       /*
3999        * Shorten referer to make sure the referer is blocked
4000        * if www.example.org/www.example.com-shall-see-the-referer/
4001        * links to www.example.com/
4002        */
4003       referer[hostlenght+17] = '\0';
4004    }
4005    referer_url = strstr(referer, "http://");
4006    if ((NULL == referer_url) || (NULL == strstr(referer_url, host)))
4007    {
4008       /* Host has changed, Referer is invalid or a https URL. */
4009       if (parameter_conditional_block)
4010       {
4011          log_error(LOG_LEVEL_HEADER, "New host is: %s. Crunching %s!", host, *header);
4012          freez(*header);
4013       }
4014       else
4015       {
4016          freez(*header);
4017          freez(referer);
4018          return create_forged_referrer(header, host);
4019       }
4020    }
4021    freez(referer);
4022
4023    return JB_ERR_OK;
4024
4025 }
4026
4027
4028 /*********************************************************************
4029  *
4030  * Function    :  get_appropiate_connection_header
4031  *
4032  * Description :  Returns an appropiate Connection header
4033  *                depending on whether or not we try to keep
4034  *                the connection to the server alive.
4035  *
4036  * Parameters  :
4037  *          1  :  csp = Current client state (buffers, headers, etc...)
4038  *
4039  * Returns     :  Pointer to statically allocated header buffer.
4040  *
4041  *********************************************************************/
4042 static const char *get_appropiate_connection_header(const struct client_state *csp)
4043 {
4044    static const char connection_keep_alive[] = "Connection: keep-alive";
4045    static const char connection_close[] = "Connection: close";
4046
4047    if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
4048     && (csp->http->ssl == 0))
4049    {
4050       return connection_keep_alive;
4051    }
4052    return connection_close;
4053 }
4054
4055
4056 /*********************************************************************
4057  *
4058  * Function    :  create_content_length_header
4059  *
4060  * Description :  Creates a Content-Length header.
4061  *
4062  * Parameters  :
4063  *          1  :  content_length = The content length to be used in the header.
4064  *          2  :  header = Allocated space to safe the header.
4065  *          3  :  buffer_length = The length of the allocated space.
4066  *
4067  * Returns     :  void
4068  *
4069  *********************************************************************/
4070 static void create_content_length_header(unsigned long long content_length,
4071                                          char *header, size_t buffer_length)
4072 {
4073    snprintf(header, buffer_length, "Content-Length: %llu", content_length);
4074 }
4075
4076
4077 /*
4078   Local Variables:
4079   tab-width: 3
4080   end:
4081 */