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