Change csp->expected_content and_csp->expected_content_length from
[privoxy.git] / parsers.c
1 const char parsers_rcs[] = "$Id: parsers.c,v 1.152 2009/03/01 18:43:48 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/parsers.c,v $
5  *
6  * Purpose     :  Declares functions to parse/crunch headers and pages.
7  *                Functions declared include:
8  *                   `add_to_iob', `client_cookie_adder', `client_from',
9  *                   `client_referrer', `client_send_cookie', `client_ua',
10  *                   `client_uagent', `client_x_forwarded',
11  *                   `client_x_forwarded_adder', `client_xtra_adder',
12  *                   `content_type', `crumble', `destroy_list', `enlist',
13  *                   `flush_socket', ``get_header', `sed', `filter_header'
14  *                   `server_content_encoding', `server_content_disposition',
15  *                   `server_last_modified', `client_accept_language',
16  *                   `crunch_client_header', `client_if_modified_since',
17  *                   `client_if_none_match', `get_destination_from_headers',
18  *                   `parse_header_time', `decompress_iob' and `server_set_cookie'.
19  *
20  * Copyright   :  Written by and Copyright (C) 2001-2009 the
21  *                Privoxy team. http://www.privoxy.org/
22  *
23  *                Based on the Internet Junkbuster originally written
24  *                by and Copyright (C) 1997 Anonymous Coders and
25  *                Junkbusters Corporation.  http://www.junkbusters.com
26  *
27  *                This program is free software; you can redistribute it
28  *                and/or modify it under the terms of the GNU General
29  *                Public License as published by the Free Software
30  *                Foundation; either version 2 of the License, or (at
31  *                your option) any later version.
32  *
33  *                This program is distributed in the hope that it will
34  *                be useful, but WITHOUT ANY WARRANTY; without even the
35  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
36  *                PARTICULAR PURPOSE.  See the GNU General Public
37  *                License for more details.
38  *
39  *                The GNU General Public License should be included with
40  *                this file.  If not, you can view it at
41  *                http://www.gnu.org/copyleft/gpl.html
42  *                or write to the Free Software Foundation, Inc., 59
43  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
44  *
45  * Revisions   :
46  *    $Log: parsers.c,v $
47  *    Revision 1.152  2009/03/01 18:43:48  fabiankeil
48  *    Help clang understand that we aren't dereferencing
49  *    NULL pointers here.
50  *
51  *    Revision 1.151  2009/02/15 14:46:35  fabiankeil
52  *    Don't let hide-referrer{conditional-*}} pass
53  *    Referer headers without http URLs.
54  *
55  *    Revision 1.150  2008/12/04 18:12:19  fabiankeil
56  *    Fix some cparser warnings.
57  *
58  *    Revision 1.149  2008/11/21 18:39:53  fabiankeil
59  *    In case of CONNECT requests there's no point
60  *    in trying to keep the connection alive.
61  *
62  *    Revision 1.148  2008/11/16 12:43:49  fabiankeil
63  *    Turn keep-alive support into a runtime feature
64  *    that is disabled by setting keep-alive-timeout
65  *    to a negative value.
66  *
67  *    Revision 1.147  2008/11/04 17:20:31  fabiankeil
68  *    HTTP/1.1 responses without Connection
69  *    header imply keep-alive. Act accordingly.
70  *
71  *    Revision 1.146  2008/10/12 16:46:35  fabiankeil
72  *    Remove obsolete warning about delayed delivery with chunked
73  *    transfer encoding and FEATURE_CONNECTION_KEEP_ALIVE enabled.
74  *
75  *    Revision 1.145  2008/10/09 18:21:41  fabiankeil
76  *    Flush work-in-progress changes to keep outgoing connections
77  *    alive where possible. Incomplete and mostly #ifdef'd out.
78  *
79  *    Revision 1.144  2008/09/21 13:59:33  fabiankeil
80  *    Treat unknown change-x-forwarded-for parameters as fatal errors.
81  *
82  *    Revision 1.143  2008/09/21 13:36:52  fabiankeil
83  *    If change-x-forwarded-for{add} is used and the client
84  *    sends multiple X-Forwarded-For headers, append the client's
85  *    IP address to each one of them. "Traditionally" we would
86  *    lose all but the last one.
87  *
88  *    Revision 1.142  2008/09/20 10:04:33  fabiankeil
89  *    Remove hide-forwarded-for-headers action which has
90  *    been obsoleted by change-x-forwarded-for{block}.
91  *
92  *    Revision 1.141  2008/09/19 15:26:28  fabiankeil
93  *    Add change-x-forwarded-for{} action to block or add
94  *    X-Forwarded-For headers. Mostly based on code removed
95  *    before 3.0.7.
96  *
97  *    Revision 1.140  2008/09/12 17:51:43  fabiankeil
98  *    - A few style fixes.
99  *    - Remove a pointless cast.
100  *
101  *    Revision 1.139  2008/09/04 08:13:58  fabiankeil
102  *    Prepare for critical sections on Windows by adding a
103  *    layer of indirection before the pthread mutex functions.
104  *
105  *    Revision 1.138  2008/08/30 12:03:07  fabiankeil
106  *    Remove FEATURE_COOKIE_JAR.
107  *
108  *    Revision 1.137  2008/05/30 15:50:08  fabiankeil
109  *    Remove questionable micro-optimizations
110  *    whose usefulness has never been measured.
111  *
112  *    Revision 1.136  2008/05/26 16:02:24  fabiankeil
113  *    s@Insufficent@Insufficient@
114  *
115  *    Revision 1.135  2008/05/21 20:12:10  fabiankeil
116  *    The whole point of strclean() is to modify the
117  *    first parameter, so don't mark it immutable,
118  *    even though the compiler lets us get away with it.
119  *
120  *    Revision 1.134  2008/05/21 19:27:25  fabiankeil
121  *    As the wafer actions are gone, we can stop including encode.h.
122  *
123  *    Revision 1.133  2008/05/21 15:50:47  fabiankeil
124  *    Ditch cast from (char **) to (char **).
125  *
126  *    Revision 1.132  2008/05/21 15:47:14  fabiankeil
127  *    Streamline sed()'s prototype and declare
128  *    the header parse and add structures static.
129  *
130  *    Revision 1.131  2008/05/20 20:13:30  fabiankeil
131  *    Factor update_server_headers() out of sed(), ditch the
132  *    first_run hack and make server_patterns_light static.
133  *
134  *    Revision 1.130  2008/05/19 17:18:04  fabiankeil
135  *    Wrap memmove() calls in string_move()
136  *    to document the purpose in one place.
137  *
138  *    Revision 1.129  2008/05/17 14:02:07  fabiankeil
139  *    Normalize linear header white space.
140  *
141  *    Revision 1.128  2008/05/16 16:39:03  fabiankeil
142  *    If a header is split across multiple lines,
143  *    merge them to a single line before parsing them.
144  *
145  *    Revision 1.127  2008/05/10 13:23:38  fabiankeil
146  *    Don't provide get_header() with the whole client state
147  *    structure when it only needs access to csp->iob.
148  *
149  *    Revision 1.126  2008/05/03 16:40:45  fabiankeil
150  *    Change content_filters_enabled()'s parameter from
151  *    csp->action to action so it can be also used in the
152  *    CGI code. Don't bother checking if there are filters
153  *    loaded, as that's somewhat besides the point.
154  *
155  *    Revision 1.125  2008/04/17 14:40:49  fabiankeil
156  *    Provide get_http_time() with the buffer size so it doesn't
157  *    have to blindly assume that the buffer is big enough.
158  *
159  *    Revision 1.124  2008/04/16 16:38:21  fabiankeil
160  *    Don't pass the whole csp structure to flush_socket()
161  *    when it only needs a file descriptor and a buffer.
162  *
163  *    Revision 1.123  2008/03/29 12:13:46  fabiankeil
164  *    Remove send-wafer and send-vanilla-wafer actions.
165  *
166  *    Revision 1.122  2008/03/28 15:13:39  fabiankeil
167  *    Remove inspect-jpegs action.
168  *
169  *    Revision 1.121  2008/01/05 21:37:03  fabiankeil
170  *    Let client_range() also handle Request-Range headers
171  *    which apparently are still supported by many servers.
172  *
173  *    Revision 1.120  2008/01/04 17:43:45  fabiankeil
174  *    Improve the warning messages that get logged if the action files
175  *    "enable" filters but no filters of that type have been loaded.
176  *
177  *    Revision 1.119  2007/12/28 18:32:51  fabiankeil
178  *    In server_content_type():
179  *    - Don't require leading white space when detecting image content types.
180  *    - Change '... not replaced ...' message to sound less crazy if the text
181  *      type actually is 'text/plain'.
182  *    - Mark the 'text/plain == binary data' assumption for removal.
183  *    - Remove a bunch of trailing white space.
184  *
185  *    Revision 1.118  2007/12/28 16:56:35  fabiankeil
186  *    Minor server_content_disposition() changes:
187  *    - Don't regenerate the header name all lower-case.
188  *    - Some white space fixes.
189  *    - Remove useless log message in case of ENOMEM.
190  *
191  *    Revision 1.117  2007/12/06 18:11:50  fabiankeil
192  *    Garbage-collect the code to add a X-Forwarded-For
193  *    header as it seems to be mostly used by accident.
194  *
195  *    Revision 1.116  2007/12/01 13:04:22  fabiankeil
196  *    Fix a crash on mingw32 with some Last Modified times in the future.
197  *
198  *    Revision 1.115  2007/11/02 16:52:50  fabiankeil
199  *    Remove a "can't happen" error block which, over
200  *    time, mutated into a "guaranteed to happen" block.
201  *
202  *    Revision 1.114  2007/10/19 16:56:26  fabiankeil
203  *    - Downgrade "Buffer limit reached" message to LOG_LEVEL_INFO.
204  *    - Use shiny new content_filters_enabled() in client_range().
205  *
206  *    Revision 1.113  2007/10/10 17:29:57  fabiankeil
207  *    I forgot about Poland.
208  *
209  *    Revision 1.112  2007/10/09 16:38:40  fabiankeil
210  *    Remove Range and If-Range headers if content filtering is enabled.
211  *
212  *    Revision 1.111  2007/10/04 18:07:00  fabiankeil
213  *    Move ACTION_VANILLA_WAFER handling from jcc's chat() into
214  *    client_cookie_adder() to make sure send-vanilla-wafer can be
215  *    controlled through tags (and thus regression-tested).
216  *
217  *    Revision 1.110  2007/09/29 10:42:37  fabiankeil
218  *    - Remove "scanning headers for" log message again.
219  *    - Some more whitespace fixes.
220  *
221  *    Revision 1.109  2007/09/08 14:25:48  fabiankeil
222  *    Refactor client_referrer() and add conditional-forge parameter.
223  *
224  *    Revision 1.108  2007/08/28 18:21:03  fabiankeil
225  *    A bunch of whitespace fixes, pointy hat to me.
226  *
227  *    Revision 1.107  2007/08/28 18:16:32  fabiankeil
228  *    Fix possible memory corruption in server_http, make sure it's not
229  *    executed for ordinary server headers and mark some problems for later.
230  *
231  *    Revision 1.106  2007/08/18 14:30:32  fabiankeil
232  *    Let content-type-overwrite{} honour force-text-mode again.
233  *
234  *    Revision 1.105  2007/08/11 14:49:49  fabiankeil
235  *    - Add prototpyes for the header parsers and make them static.
236  *    - Comment out client_accept_encoding_adder() which isn't used right now.
237  *
238  *    Revision 1.104  2007/07/14 07:38:19  fabiankeil
239  *    Move the ACTION_FORCE_TEXT_MODE check out of
240  *    server_content_type(). Signal other functions
241  *    whether or not a content type has been declared.
242  *    Part of the fix for BR#1750917.
243  *
244  *    Revision 1.103  2007/06/01 16:31:54  fabiankeil
245  *    Change sed() to return a jb_err in preparation for forward-override{}.
246  *
247  *    Revision 1.102  2007/05/27 12:39:32  fabiankeil
248  *    Adjust "X-Filter: No" to disable dedicated header filters.
249  *
250  *    Revision 1.101  2007/05/14 10:16:41  fabiankeil
251  *    Streamline client_cookie_adder().
252  *
253  *    Revision 1.100  2007/04/30 15:53:11  fabiankeil
254  *    Make sure filters with dynamic jobs actually use them.
255  *
256  *    Revision 1.99  2007/04/30 15:06:26  fabiankeil
257  *    - Introduce dynamic pcrs jobs that can resolve variables.
258  *    - Remove unnecessary update_action_bits_for_all_tags() call.
259  *
260  *    Revision 1.98  2007/04/17 18:32:10  fabiankeil
261  *    - Make tagging based on tags set by earlier taggers
262  *      of the same kind possible.
263  *    - Log whether or not new tags cause action bits updates
264  *      (in which case a matching tag-pattern section exists).
265  *    - Log if the user tries to set a tag that is already set.
266  *
267  *    Revision 1.97  2007/04/15 16:39:21  fabiankeil
268  *    Introduce tags as alternative way to specify which
269  *    actions apply to a request. At the moment tags can be
270  *    created based on client and server headers.
271  *
272  *    Revision 1.96  2007/04/12 12:53:58  fabiankeil
273  *    Log a warning if the content is compressed, filtering is
274  *    enabled and Privoxy was compiled without zlib support.
275  *    Closes FR#1673938.
276  *
277  *    Revision 1.95  2007/03/25 14:26:40  fabiankeil
278  *    - Fix warnings when compiled with glibc.
279  *    - Don't use crumble() for cookie crunching.
280  *    - Move cookie time parsing into parse_header_time().
281  *    - Let parse_header_time() return a jb_err code
282  *      instead of a pointer that can only be used to
283  *      check for NULL anyway.
284  *
285  *    Revision 1.94  2007/03/21 12:23:53  fabiankeil
286  *    - Add better protection against malicious gzip headers.
287  *    - Stop logging the first hundred bytes of decompressed content.
288  *      It looks like it's working and there is always debug 16.
289  *    - Log the content size after decompression in decompress_iob()
290  *      instead of pcrs_filter_response().
291  *
292  *    Revision 1.93  2007/03/20 15:21:44  fabiankeil
293  *    - Use dedicated header filter actions instead of abusing "filter".
294  *      Replace "filter-client-headers" and "filter-client-headers"
295  *      with "server-header-filter" and "client-header-filter".
296  *    - Remove filter_client_header() and filter_client_header(),
297  *      filter_header() now checks the shiny new
298  *      CSP_FLAG_CLIENT_HEADER_PARSING_DONE flag instead.
299  *
300  *    Revision 1.92  2007/03/05 13:25:32  fabiankeil
301  *    - Cosmetical changes for LOG_LEVEL_RE_FILTER messages.
302  *    - Handle "Cookie:" and "Connection:" headers a bit smarter
303  *      (don't crunch them just to recreate them later on).
304  *    - Add another non-standard time format for the cookie
305  *      expiration date detection.
306  *    - Fix a valgrind warning.
307  *
308  *    Revision 1.91  2007/02/24 12:27:32  fabiankeil
309  *    Improve cookie expiration date detection.
310  *
311  *    Revision 1.90  2007/02/08 19:12:35  fabiankeil
312  *    Don't run server_content_length() the first time
313  *    sed() parses server headers; only adjust the
314  *    Content-Length header if the page was modified.
315  *
316  *    Revision 1.89  2007/02/07 16:52:11  fabiankeil
317  *    Fix log messages regarding the cookie time format
318  *    (cookie and request URL were mixed up).
319  *
320  *    Revision 1.88  2007/02/07 11:27:12  fabiankeil
321  *    - Let decompress_iob()
322  *      - not corrupt the content if decompression fails
323  *        early. (the first byte(s) were lost).
324  *      - use pointer arithmetics with defined outcome for
325  *        a change.
326  *    - Use a different kludge to remember a failed decompression.
327  *
328  *    Revision 1.87  2007/01/31 16:21:38  fabiankeil
329  *    Search for Max-Forwards headers case-insensitive,
330  *    don't generate the "501 unsupported" message for invalid
331  *    Max-Forwards values and don't increase negative ones.
332  *
333  *    Revision 1.86  2007/01/30 13:05:26  fabiankeil
334  *    - Let server_set_cookie() check the expiration date
335  *      of cookies and don't touch the ones that are already
336  *      expired. Fixes problems with low quality web applications
337  *      as described in BR 932612.
338  *
339  *    - Adjust comment in client_max_forwards to reality;
340  *      remove invalid Max-Forwards headers.
341  *
342  *    Revision 1.85  2007/01/26 15:33:46  fabiankeil
343  *    Stop filter_header() from unintentionally removing
344  *    empty header lines that were enlisted by the continue
345  *    hack.
346  *
347  *    Revision 1.84  2007/01/24 12:56:52  fabiankeil
348  *    - Repeat the request URL before logging any headers.
349  *      Makes reading the log easier in case of simultaneous requests.
350  *    - If there are more than one Content-Type headers in one request,
351  *      use the first one and remove the others.
352  *    - Remove "newval" variable in server_content_type().
353  *      It's only used once.
354  *
355  *    Revision 1.83  2007/01/12 15:03:02  fabiankeil
356  *    Correct a cast, check inflateEnd() exit code
357  *    to see if we have to, replace sprintf calls
358  *    with snprintf.
359  *
360  *    Revision 1.82  2007/01/01 19:36:37  fabiankeil
361  *    Integrate a modified version of Wil Mahan's
362  *    zlib patch (PR #895531).
363  *
364  *    Revision 1.81  2006/12/31 22:21:33  fabiankeil
365  *    Skip empty filter files in filter_header()
366  *    but don't ignore the ones that come afterwards.
367  *    Fixes BR 1619208, this time for real.
368  *
369  *    Revision 1.80  2006/12/29 19:08:22  fabiankeil
370  *    Reverted parts of my last commit
371  *    to keep error handling working.
372  *
373  *    Revision 1.79  2006/12/29 18:04:40  fabiankeil
374  *    Fixed gcc43 conversion warnings.
375  *
376  *    Revision 1.78  2006/12/26 17:19:20  fabiankeil
377  *    Bringing back the "useless" localtime() call
378  *    I removed in revision 1.67. On some platforms
379  *    it's necessary to prevent time zone offsets.
380  *
381  *    Revision 1.77  2006/12/07 18:44:26  fabiankeil
382  *    Rebuild request URL in get_destination_from_headers()
383  *    to make sure redirect{pcrs command} works as expected
384  *    for intercepted requests.
385  *
386  *    Revision 1.76  2006/12/06 19:52:25  fabiankeil
387  *    Added get_destination_from_headers().
388  *
389  *    Revision 1.75  2006/11/13 19:05:51  fabiankeil
390  *    Make pthread mutex locking more generic. Instead of
391  *    checking for OSX and OpenBSD, check for FEATURE_PTHREAD
392  *    and use mutex locking unless there is an _r function
393  *    available. Better safe than sorry.
394  *
395  *    Fixes "./configure --disable-pthread" and should result
396  *    in less threading-related problems on pthread-using platforms,
397  *    but it still doesn't fix BR#1122404.
398  *
399  *    Revision 1.74  2006/10/02 16:59:12  fabiankeil
400  *    The special header "X-Filter: No" now disables
401  *    header filtering as well.
402  *
403  *    Revision 1.73  2006/09/23 13:26:38  roro
404  *    Replace TABs by spaces in source code.
405  *
406  *    Revision 1.72  2006/09/23 12:37:21  fabiankeil
407  *    Don't print a log message every time filter_headers is
408  *    entered or left. It only creates noise without any real
409  *    information.
410  *
411  *    Revision 1.71  2006/09/21 19:55:17  fabiankeil
412  *    Fix +hide-if-modified-since{-n}.
413  *
414  *    Revision 1.70  2006/09/08 12:06:34  fabiankeil
415  *    Have hide-if-modified-since interpret the random
416  *    range value as minutes instead of hours. Allows
417  *    more fine-grained configuration.
418  *
419  *    Revision 1.69  2006/09/06 16:25:51  fabiankeil
420  *    Always have parse_header_time return a pointer
421  *    that actual makes sense, even though we currently
422  *    only need it to detect problems.
423  *
424  *    Revision 1.68  2006/09/06 10:43:32  fabiankeil
425  *    Added config option enable-remote-http-toggle
426  *    to specify if Privoxy should recognize special
427  *    headers (currently only X-Filter) to change its
428  *    behaviour. Disabled by default.
429  *
430  *    Revision 1.67  2006/09/04 11:01:26  fabiankeil
431  *    After filtering de-chunked instances, remove
432  *    "Transfer-Encoding" header entirely instead of changing
433  *    it to "Transfer-Encoding: identity", which is invalid.
434  *    Thanks Michael Shields <shields@msrl.com>. Fixes PR 1318658.
435  *
436  *    Don't use localtime in parse_header_time. An empty time struct
437  *    is good enough, it gets overwritten by strptime anyway.
438  *
439  *    Revision 1.66  2006/09/03 19:38:28  fabiankeil
440  *    Use gmtime_r if available, fallback to gmtime with mutex
441  *    protection for MacOSX and use vanilla gmtime for the rest.
442  *
443  *    Revision 1.65  2006/08/22 10:55:56  fabiankeil
444  *    Changed client_referrer to use the right type (size_t) for
445  *    hostlenght and to shorten the temporary referrer string with
446  *    '\0' instead of adding a useless line break.
447  *
448  *    Revision 1.64  2006/08/17 17:15:10  fabiankeil
449  *    - Back to timegm() using GnuPG's replacement if necessary.
450  *      Using mktime() and localtime() could add a on hour offset if
451  *      the randomize factor was big enough to lead to a summer/wintertime
452  *      switch.
453  *
454  *    - Removed now-useless Privoxy 3.0.3 compatibility glue.
455  *
456  *    - Moved randomization code into pick_from_range().
457  *
458  *    - Changed parse_header_time definition.
459  *      time_t isn't guaranteed to be signed and
460  *      if it isn't, -1 isn't available as error code.
461  *      Changed some variable types in client_if_modified_since()
462  *      because of the same reason.
463  *
464  *    Revision 1.63  2006/08/14 13:18:08  david__schmidt
465  *    OS/2 compilation compatibility fixups
466  *
467  *    Revision 1.62  2006/08/14 08:58:42  fabiankeil
468  *    Changed include from strptime.c to strptime.h
469  *
470  *    Revision 1.61  2006/08/14 08:25:19  fabiankeil
471  *    Split filter-headers{} into filter-client-headers{}
472  *    and filter-server-headers{}.
473  *    Added parse_header_time() to share some code.
474  *    Replaced timegm() with mktime().
475  *
476  *    Revision 1.60  2006/08/12 03:54:37  david__schmidt
477  *    Windows service integration
478  *
479  *    Revision 1.59  2006/08/03 02:46:41  david__schmidt
480  *    Incorporate Fabian Keil's patch work:\rhttp://www.fabiankeil.de/sourcecode/privoxy/
481  *
482  *    Revision 1.58  2006/07/18 14:48:47  david__schmidt
483  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
484  *    with what was really the latest development (the v_3_0_branch branch)
485  *
486  *    Revision 1.56.2.10  2006/01/21 16:16:08  david__schmidt
487  *    Thanks to  Edward Carrel for his patch to modernize OSX's\rpthreads support.  See bug #1409623.
488  *
489  *    Revision 1.56.2.9  2004/10/03 12:53:45  david__schmidt
490  *    Add the ability to check jpeg images for invalid
491  *    lengths of comment blocks.  Defensive strategy
492  *    against the exploit:
493  *       Microsoft Security Bulletin MS04-028
494  *       Buffer Overrun in JPEG Processing (GDI+) Could
495  *       Allow Code Execution (833987)
496  *    Enabled with +inspect-jpegs in actions files.
497  *
498  *    Revision 1.56.2.8  2003/07/11 13:21:25  oes
499  *    Excluded text/plain objects from filtering. This fixes a
500  *    couple of client-crashing, download corruption and
501  *    Privoxy performance issues, whose root cause lies in
502  *    web servers labelling content of unknown type as text/plain.
503  *
504  *    Revision 1.56.2.7  2003/05/06 12:07:26  oes
505  *    Fixed bug #729900: Suspicious HOST: headers are now killed and regenerated if necessary
506  *
507  *    Revision 1.56.2.6  2003/04/14 21:28:30  oes
508  *    Completing the previous change
509  *
510  *    Revision 1.56.2.5  2003/04/14 12:08:16  oes
511  *    Added temporary workaround for bug in PHP < 4.2.3
512  *
513  *    Revision 1.56.2.4  2003/03/07 03:41:05  david__schmidt
514  *    Wrapping all *_r functions (the non-_r versions of them) with mutex semaphores for OSX.  Hopefully this will take care of all of those pesky crash reports.
515  *
516  *    Revision 1.56.2.3  2002/11/10 04:20:02  hal9
517  *    Fix typo: supressed -> suppressed
518  *
519  *    Revision 1.56.2.2  2002/09/25 14:59:53  oes
520  *    Improved cookie logging
521  *
522  *    Revision 1.56.2.1  2002/09/25 14:52:45  oes
523  *    Added basic support for OPTIONS and TRACE HTTP methods:
524  *     - New parser function client_max_forwards which decrements
525  *       the Max-Forwards HTTP header field of OPTIONS and TRACE
526  *       requests by one before forwarding
527  *     - New parser function client_host which extracts the host
528  *       and port information from the HTTP header field if the
529  *       request URI was not absolute
530  *     - Don't crumble and re-add the Host: header, but only generate
531  *       and append if missing
532  *
533  *    Revision 1.56  2002/05/12 15:34:22  jongfoster
534  *    Fixing typo in a comment
535  *
536  *    Revision 1.55  2002/05/08 16:01:07  oes
537  *    Optimized add_to_iob:
538  *     - Use realloc instead of malloc(), memcpy(), free()
539  *     - Expand to powers of two if possible, to get
540  *       O(log n) reallocs instead of O(n).
541  *     - Moved check for buffer limit here from chat
542  *     - Report failure via returncode
543  *
544  *    Revision 1.54  2002/04/02 15:03:16  oes
545  *    Tiny code cosmetics
546  *
547  *    Revision 1.53  2002/03/26 22:29:55  swa
548  *    we have a new homepage!
549  *
550  *    Revision 1.52  2002/03/24 13:25:43  swa
551  *    name change related issues
552  *
553  *    Revision 1.51  2002/03/13 00:27:05  jongfoster
554  *    Killing warnings
555  *
556  *    Revision 1.50  2002/03/12 01:45:35  oes
557  *    More verbose logging
558  *
559  *    Revision 1.49  2002/03/09 20:03:52  jongfoster
560  *    - Making various functions return int rather than size_t.
561  *      (Undoing a recent change).  Since size_t is unsigned on
562  *      Windows, functions like read_socket that return -1 on
563  *      error cannot return a size_t.
564  *
565  *      THIS WAS A MAJOR BUG - it caused frequent, unpredictable
566  *      crashes, and also frequently caused JB to jump to 100%
567  *      CPU and stay there.  (Because it thought it had just
568  *      read ((unsigned)-1) == 4Gb of data...)
569  *
570  *    - The signature of write_socket has changed, it now simply
571  *      returns success=0/failure=nonzero.
572  *
573  *    - Trying to get rid of a few warnings --with-debug on
574  *      Windows, I've introduced a new type "jb_socket".  This is
575  *      used for the socket file descriptors.  On Windows, this
576  *      is SOCKET (a typedef for unsigned).  Everywhere else, it's
577  *      an int.  The error value can't be -1 any more, so it's
578  *      now JB_INVALID_SOCKET (which is -1 on UNIX, and in
579  *      Windows it maps to the #define INVALID_SOCKET.)
580  *
581  *    - The signature of bind_port has changed.
582  *
583  *    Revision 1.48  2002/03/07 03:46:53  oes
584  *    Fixed compiler warnings etc
585  *
586  *    Revision 1.47  2002/02/20 23:15:13  jongfoster
587  *    Parsing functions now handle out-of-memory gracefully by returning
588  *    an error code.
589  *
590  *    Revision 1.46  2002/01/17 21:03:47  jongfoster
591  *    Moving all our URL and URL pattern parsing code to urlmatch.c.
592  *
593  *    Revision 1.45  2002/01/09 14:33:03  oes
594  *    Added support for localtime_r.
595  *
596  *    Revision 1.44  2001/12/14 01:22:54  steudten
597  *    Remove 'user:pass@' from 'proto://user:pass@host' for the
598  *    new added header 'Host: ..'. (See Req ID 491818)
599  *
600  *    Revision 1.43  2001/11/23 00:26:38  jongfoster
601  *    Fixing two really stupid errors in my previous commit
602  *
603  *    Revision 1.42  2001/11/22 21:59:30  jongfoster
604  *    Adding code to handle +no-cookies-keep
605  *
606  *    Revision 1.41  2001/11/05 23:43:05  steudten
607  *    Add time+date to log files.
608  *
609  *    Revision 1.40  2001/10/26 20:13:09  jongfoster
610  *    ctype.h is needed in Windows, too.
611  *
612  *    Revision 1.39  2001/10/26 17:40:04  oes
613  *    Introduced get_header_value()
614  *    Removed http->user_agent, csp->referrer and csp->accept_types
615  *    Removed client_accept()
616  *
617  *    Revision 1.38  2001/10/25 03:40:48  david__schmidt
618  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
619  *    threads to call select() simultaneously.  So, it's time to do a real, live,
620  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
621  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
622  *
623  *    Revision 1.37  2001/10/23 21:36:02  jongfoster
624  *    Documenting sed()'s error behaviou (doc change only)
625  *
626  *    Revision 1.36  2001/10/13 12:51:51  joergs
627  *    Removed client_host, (was only required for the old 2.0.2-11 http://noijb.
628  *    force-load), instead crumble Host: and add it (again) in client_host_adder
629  *    (in case we get a HTTP/1.0 request without Host: header and forward it to
630  *    a HTTP/1.1 server/proxy).
631  *
632  *    Revision 1.35  2001/10/09 22:39:21  jongfoster
633  *    assert.h is also required under Win32, so moving out of #ifndef _WIN32
634  *    block.
635  *
636  *    Revision 1.34  2001/10/07 18:50:55  oes
637  *    Added server_content_encoding, renamed server_transfer_encoding
638  *
639  *    Revision 1.33  2001/10/07 18:04:49  oes
640  *    Changed server_http11 to server_http and its pattern to "HTTP".
641  *      Additional functionality: it now saves the HTTP status into
642  *      csp->http->status and sets CT_TABOO for Status 206 (partial range)
643  *
644  *    Revision 1.32  2001/10/07 15:43:28  oes
645  *    Removed FEATURE_DENY_GZIP and replaced it with client_accept_encoding,
646  *       client_te and client_accept_encoding_adder, triggered by the new
647  *       +no-compression action. For HTTP/1.1 the Accept-Encoding header is
648  *       changed to allow only identity and chunked, and the TE header is
649  *       crunched. For HTTP/1.0, Accept-Encoding is crunched.
650  *
651  *    parse_http_request no longer does anything than parsing. The rewriting
652  *      of http->cmd and version mangling are gone. It now also recognizes
653  *      the put and delete methods and saves the url in http->url. Removed
654  *      unused variable.
655  *
656  *    renamed content_type and content_length to have the server_ prefix
657  *
658  *    server_content_type now only works if csp->content_type != CT_TABOO
659  *
660  *    added server_transfer_encoding, which
661  *      - Sets CT_TABOO to prohibit filtering if encoding compresses
662  *      - Raises the CSP_FLAG_CHUNKED flag if Encoding is "chunked"
663  *      - Change from "chunked" to "identity" if body was chunked
664  *        but has been de-chunked for filtering.
665  *
666  *    added server_content_md5 which crunches any Content-MD5 headers
667  *      if the body was modified.
668  *
669  *    made server_http11 conditional on +downgrade action
670  *
671  *    Replaced 6 boolean members of csp with one bitmap (csp->flags)
672  *
673  *    Revision 1.31  2001/10/05 14:25:02  oes
674  *    Crumble Keep-Alive from Server
675  *
676  *    Revision 1.30  2001/09/29 12:56:03  joergs
677  *    IJB now changes HTTP/1.1 to HTTP/1.0 in requests and answers.
678  *
679  *    Revision 1.29  2001/09/24 21:09:24  jongfoster
680  *    Fixing 2 memory leaks that Guy spotted, where the paramater to
681  *    enlist() was not being free()d.
682  *
683  *    Revision 1.28  2001/09/22 16:32:28  jongfoster
684  *    Removing unused #includes.
685  *
686  *    Revision 1.27  2001/09/20 15:45:25  steudten
687  *
688  *    add casting from size_t to int for printf()
689  *    remove local variable shadow s2
690  *
691  *    Revision 1.26  2001/09/16 17:05:14  jongfoster
692  *    Removing unused #include showarg.h
693  *
694  *    Revision 1.25  2001/09/16 13:21:27  jongfoster
695  *    Changes to use new list functions.
696  *
697  *    Revision 1.24  2001/09/13 23:05:50  jongfoster
698  *    Changing the string paramater to the header parsers a "const".
699  *
700  *    Revision 1.23  2001/09/12 18:08:19  steudten
701  *
702  *    In parse_http_request() header rewriting miss the host value, so
703  *    from http://www.mydomain.com the result was just " / " not
704  *    http://www.mydomain.com/ in case we forward.
705  *
706  *    Revision 1.22  2001/09/10 10:58:53  oes
707  *    Silenced compiler warnings
708  *
709  *    Revision 1.21  2001/07/31 14:46:00  oes
710  *     - Persistant connections now suppressed
711  *     - sed() no longer appends empty header to csp->headers
712  *
713  *    Revision 1.20  2001/07/30 22:08:36  jongfoster
714  *    Tidying up #defines:
715  *    - All feature #defines are now of the form FEATURE_xxx
716  *    - Permanently turned off WIN_GUI_EDIT
717  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
718  *
719  *    Revision 1.19  2001/07/25 17:21:54  oes
720  *    client_uagent now saves copy of User-Agent: header value
721  *
722  *    Revision 1.18  2001/07/13 14:02:46  oes
723  *     - Included fix to repair broken HTTP requests that
724  *       don't contain a path, not even '/'.
725  *     - Removed all #ifdef PCRS
726  *     - content_type now always inspected and classified as
727  *       text, gif or other.
728  *     - formatting / comments
729  *
730  *    Revision 1.17  2001/06/29 21:45:41  oes
731  *    Indentation, CRLF->LF, Tab-> Space
732  *
733  *    Revision 1.16  2001/06/29 13:32:42  oes
734  *    - Fixed a comment
735  *    - Adapted free_http_request
736  *    - Removed logentry from cancelled commit
737  *
738  *    Revision 1.15  2001/06/03 19:12:38  oes
739  *    deleted const struct interceptors
740  *
741  *    Revision 1.14  2001/06/01 18:49:17  jongfoster
742  *    Replaced "list_share" with "list" - the tiny memory gain was not
743  *    worth the extra complexity.
744  *
745  *    Revision 1.13  2001/05/31 21:30:33  jongfoster
746  *    Removed list code - it's now in list.[ch]
747  *    Renamed "permission" to "action", and changed many features
748  *    to use the actions file rather than the global config.
749  *
750  *    Revision 1.12  2001/05/31 17:33:13  oes
751  *
752  *    CRLF -> LF
753  *
754  *    Revision 1.11  2001/05/29 20:11:19  joergs
755  *    '/ * inside comment' warning removed.
756  *
757  *    Revision 1.10  2001/05/29 09:50:24  jongfoster
758  *    Unified blocklist/imagelist/permissionslist.
759  *    File format is still under discussion, but the internal changes
760  *    are (mostly) done.
761  *
762  *    Also modified interceptor behaviour:
763  *    - We now intercept all URLs beginning with one of the following
764  *      prefixes (and *only* these prefixes):
765  *        * http://i.j.b/
766  *        * http://ijbswa.sf.net/config/
767  *        * http://ijbswa.sourceforge.net/config/
768  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
769  *    - Internal changes so that intercepted and fast redirect pages
770  *      are not replaced with an image.
771  *    - Interceptors now have the option to send a binary page direct
772  *      to the client. (i.e. ijb-send-banner uses this)
773  *    - Implemented show-url-info interceptor.  (Which is why I needed
774  *      the above interceptors changes - a typical URL is
775  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
776  *      The previous mechanism would not have intercepted that, and
777  *      if it had been intercepted then it then it would have replaced
778  *      it with an image.)
779  *
780  *    Revision 1.9  2001/05/28 17:26:33  jongfoster
781  *    Fixing segfault if last header was crunched.
782  *    Fixing Windows build (snprintf() is _snprintf() under Win32, but we
783  *    can use the cross-platform sprintf() instead.)
784  *
785  *    Revision 1.8  2001/05/27 22:17:04  oes
786  *
787  *    - re_process_buffer no longer writes the modified buffer
788  *      to the client, which was very ugly. It now returns the
789  *      buffer, which it is then written by chat.
790  *
791  *    - content_length now adjusts the Content-Length: header
792  *      for modified documents rather than crunch()ing it.
793  *      (Length info in csp->content_length, which is 0 for
794  *      unmodified documents)
795  *
796  *    - For this to work, sed() is called twice when filtering.
797  *
798  *    Revision 1.7  2001/05/27 13:19:06  oes
799  *    Patched Joergs solution for the content-length in.
800  *
801  *    Revision 1.6  2001/05/26 13:39:32  jongfoster
802  *    Only crunches Content-Length header if applying RE filtering.
803  *    Without this fix, Microsoft Windows Update wouldn't work.
804  *
805  *    Revision 1.5  2001/05/26 00:28:36  jongfoster
806  *    Automatic reloading of config file.
807  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
808  *    Most of the global variables have been moved to a new
809  *    struct configuration_spec, accessed through csp->config->globalname
810  *    Most of the globals remaining are used by the Win32 GUI.
811  *
812  *    Revision 1.4  2001/05/22 18:46:04  oes
813  *
814  *    - Enabled filtering banners by size rather than URL
815  *      by adding patterns that replace all standard banner
816  *      sizes with the "Junkbuster" gif to the re_filterfile
817  *
818  *    - Enabled filtering WebBugs by providing a pattern
819  *      which kills all 1x1 images
820  *
821  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
822  *      which is selected by the (nonstandard and therefore
823  *      capital) letter 'U' in the option string.
824  *      It causes the quantifiers to be ungreedy by default.
825  *      Appending a ? turns back to greedy (!).
826  *
827  *    - Added a new interceptor ijb-send-banner, which
828  *      sends back the "Junkbuster" gif. Without imagelist or
829  *      MSIE detection support, or if tinygif = 1, or the
830  *      URL isn't recognized as an imageurl, a lame HTML
831  *      explanation is sent instead.
832  *
833  *    - Added new feature, which permits blocking remote
834  *      script redirects and firing back a local redirect
835  *      to the browser.
836  *      The feature is conditionally compiled, i.e. it
837  *      can be disabled with --disable-fast-redirects,
838  *      plus it must be activated by a "fast-redirects"
839  *      line in the config file, has its own log level
840  *      and of course wants to be displayed by show-proxy-args
841  *      Note: Boy, all the #ifdefs in 1001 locations and
842  *      all the fumbling with configure.in and acconfig.h
843  *      were *way* more work than the feature itself :-(
844  *
845  *    - Because a generic redirect template was needed for
846  *      this, tinygif = 3 now uses the same.
847  *
848  *    - Moved GIFs, and other static HTTP response templates
849  *      to project.h
850  *
851  *    - Some minor fixes
852  *
853  *    - Removed some >400 CRs again (Jon, you really worked
854  *      a lot! ;-)
855  *
856  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
857  *    Version 2.9.4 checkin.
858  *    - Merged popupfile and cookiefile, and added control over PCRS
859  *      filtering, in new "permissionsfile".
860  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
861  *      file error you now get a message box (in the Win32 GUI) rather
862  *      than the program exiting with no explanation.
863  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
864  *      skipping.
865  *    - Removed tabs from "config"
866  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
867  *    - Bumped up version number.
868  *
869  *    Revision 1.2  2001/05/17 23:02:36  oes
870  *     - Made referrer option accept 'L' as a substitute for '§'
871  *
872  *    Revision 1.1.1.1  2001/05/15 13:59:01  oes
873  *    Initial import of version 2.9.3 source tree
874  *
875  *
876  *********************************************************************/
877 \f
878
879 #include "config.h"
880
881 #ifndef _WIN32
882 #include <stdio.h>
883 #include <sys/types.h>
884 #endif
885
886 #include <stdlib.h>
887 #include <ctype.h>
888 #include <assert.h>
889 #include <string.h>
890
891 #ifdef __GLIBC__
892 /*
893  * Convince GNU's libc to provide a strptime prototype.
894  */
895 #define __USE_XOPEN
896 #endif /*__GLIBC__ */
897 #include <time.h>
898
899 #ifdef FEATURE_ZLIB
900 #include <zlib.h>
901 #endif
902
903 #if !defined(_WIN32) && !defined(__OS2__)
904 #include <unistd.h>
905 #endif
906
907 #include "project.h"
908
909 #ifdef FEATURE_PTHREAD
910 #include "jcc.h"
911 /* jcc.h is for mutex semapores only */
912 #endif /* def FEATURE_PTHREAD */
913 #include "list.h"
914 #include "parsers.h"
915 #include "ssplit.h"
916 #include "errlog.h"
917 #include "jbsockets.h"
918 #include "miscutil.h"
919 #include "list.h"
920 #include "actions.h"
921 #include "filters.h"
922
923 #ifndef HAVE_STRPTIME
924 #include "strptime.h"
925 #endif
926
927 const char parsers_h_rcs[] = PARSERS_H_VERSION;
928
929 /* Fix a problem with Solaris.  There should be no effect on other
930  * platforms.
931  * Solaris's isspace() is a macro which uses its argument directly
932  * as an array index.  Therefore we need to make sure that high-bit
933  * characters generate +ve values, and ideally we also want to make
934  * the argument match the declared parameter type of "int".
935  *
936  * Why did they write a character function that can't take a simple
937  * "char" argument?  Doh!
938  */
939 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
940 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
941
942 static char *get_header_line(struct iob *iob);
943 static jb_err scan_headers(struct client_state *csp);
944 static jb_err header_tagger(struct client_state *csp, char *header);
945 static jb_err parse_header_time(const char *header_time, time_t *result);
946
947 static jb_err crumble                   (struct client_state *csp, char **header);
948 static jb_err filter_header             (struct client_state *csp, char **header);
949 static jb_err client_connection         (struct client_state *csp, char **header);
950 static jb_err client_referrer           (struct client_state *csp, char **header);
951 static jb_err client_uagent             (struct client_state *csp, char **header);
952 static jb_err client_ua                 (struct client_state *csp, char **header);
953 static jb_err client_from               (struct client_state *csp, char **header);
954 static jb_err client_send_cookie        (struct client_state *csp, char **header);
955 static jb_err client_x_forwarded        (struct client_state *csp, char **header);
956 static jb_err client_accept_encoding    (struct client_state *csp, char **header);
957 static jb_err client_te                 (struct client_state *csp, char **header);
958 static jb_err client_max_forwards       (struct client_state *csp, char **header);
959 static jb_err client_host               (struct client_state *csp, char **header);
960 static jb_err client_if_modified_since  (struct client_state *csp, char **header);
961 static jb_err client_accept_language    (struct client_state *csp, char **header);
962 static jb_err client_if_none_match      (struct client_state *csp, char **header);
963 static jb_err crunch_client_header      (struct client_state *csp, char **header);
964 static jb_err client_x_filter           (struct client_state *csp, char **header);
965 static jb_err client_range              (struct client_state *csp, char **header);
966 static jb_err server_set_cookie         (struct client_state *csp, char **header);
967 static jb_err server_connection         (struct client_state *csp, char **header);
968 static jb_err server_content_type       (struct client_state *csp, char **header);
969 static jb_err server_adjust_content_length(struct client_state *csp, char **header);
970 static jb_err server_content_md5        (struct client_state *csp, char **header);
971 static jb_err server_content_encoding   (struct client_state *csp, char **header);
972 static jb_err server_transfer_coding    (struct client_state *csp, char **header);
973 static jb_err server_http               (struct client_state *csp, char **header);
974 static jb_err crunch_server_header      (struct client_state *csp, char **header);
975 static jb_err server_last_modified      (struct client_state *csp, char **header);
976 static jb_err server_content_disposition(struct client_state *csp, char **header);
977
978 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
979 static jb_err server_save_content_length(struct client_state *csp, char **header);
980 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
981
982 static jb_err client_host_adder       (struct client_state *csp);
983 static jb_err client_xtra_adder       (struct client_state *csp);
984 static jb_err client_x_forwarded_for_adder(struct client_state *csp);
985 static jb_err client_connection_header_adder(struct client_state *csp);
986 static jb_err server_connection_close_adder(struct client_state *csp);
987
988 static jb_err create_forged_referrer(char **header, const char *hostport);
989 static jb_err create_fake_referrer(char **header, const char *fake_referrer);
990 static jb_err handle_conditional_hide_referrer_parameter(char **header,
991    const char *host, const int parameter_conditional_block);
992 static const char *get_appropiate_connection_header(const struct client_state *csp);
993
994 /*
995  * List of functions to run on a list of headers.
996  */
997 struct parsers
998 {
999    /** The header prefix to match */
1000    const char *str;
1001    
1002    /** The length of the prefix to match */
1003    const size_t len;
1004    
1005    /** The function to apply to this line */
1006    const parser_func_ptr parser;
1007 };
1008
1009 static const struct parsers client_patterns[] = {
1010    { "referer:",                  8,   client_referrer },
1011    { "user-agent:",              11,   client_uagent },
1012    { "ua-",                       3,   client_ua },
1013    { "from:",                     5,   client_from },
1014    { "cookie:",                   7,   client_send_cookie },
1015    { "x-forwarded-for:",         16,   client_x_forwarded },
1016    { "Accept-Encoding:",         16,   client_accept_encoding },
1017    { "TE:",                       3,   client_te },
1018    { "Host:",                     5,   client_host },
1019    { "if-modified-since:",       18,   client_if_modified_since },
1020    { "Keep-Alive:",              11,   crumble },
1021    { "connection:",              11,   client_connection },
1022    { "proxy-connection:",        17,   crumble },
1023    { "max-forwards:",            13,   client_max_forwards },
1024    { "Accept-Language:",         16,   client_accept_language },
1025    { "if-none-match:",           14,   client_if_none_match },
1026    { "Range:",                    6,   client_range },
1027    { "Request-Range:",           14,   client_range },
1028    { "If-Range:",                 9,   client_range },
1029    { "X-Filter:",                 9,   client_x_filter },
1030    { "*",                         0,   crunch_client_header },
1031    { "*",                         0,   filter_header },
1032    { NULL,                        0,   NULL }
1033 };
1034
1035 static const struct parsers server_patterns[] = {
1036    { "HTTP/",                     5, server_http },
1037    { "set-cookie:",              11, server_set_cookie },
1038    { "connection:",              11, server_connection },
1039    { "Content-Type:",            13, server_content_type },
1040    { "Content-MD5:",             12, server_content_md5 },
1041    { "Content-Encoding:",        17, server_content_encoding },
1042 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
1043    { "Content-Length:",          15, server_save_content_length },
1044 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
1045    { "Transfer-Encoding:",       18, server_transfer_coding },
1046    { "Keep-Alive:",              11, crumble },
1047    { "content-disposition:",     20, server_content_disposition },
1048    { "Last-Modified:",           14, server_last_modified },
1049    { "*",                         0, crunch_server_header },
1050    { "*",                         0, filter_header },
1051    { NULL,                        0, NULL }
1052 };
1053
1054 static const add_header_func_ptr add_client_headers[] = {
1055    client_host_adder,
1056    client_x_forwarded_for_adder,
1057    client_xtra_adder,
1058    /* Temporarily disabled:    client_accept_encoding_adder, */
1059    client_connection_header_adder,
1060    NULL
1061 };
1062
1063 static const add_header_func_ptr add_server_headers[] = {
1064    server_connection_close_adder,
1065    NULL
1066 };
1067
1068 /*********************************************************************
1069  *
1070  * Function    :  flush_socket
1071  *
1072  * Description :  Write any pending "buffered" content.
1073  *
1074  * Parameters  :
1075  *          1  :  fd = file descriptor of the socket to read
1076  *          2  :  iob = The I/O buffer to flush, usually csp->iob.
1077  *
1078  * Returns     :  On success, the number of bytes written are returned (zero
1079  *                indicates nothing was written).  On error, -1 is returned,
1080  *                and errno is set appropriately.  If count is zero and the
1081  *                file descriptor refers to a regular file, 0 will be
1082  *                returned without causing any other effect.  For a special
1083  *                file, the results are not portable.
1084  *
1085  *********************************************************************/
1086 int flush_socket(jb_socket fd, struct iob *iob)
1087 {
1088    int len = iob->eod - iob->cur;
1089
1090    if (len <= 0)
1091    {
1092       return(0);
1093    }
1094
1095    if (write_socket(fd, iob->cur, (size_t)len))
1096    {
1097       return(-1);
1098    }
1099    iob->eod = iob->cur = iob->buf;
1100    return(len);
1101
1102 }
1103
1104
1105 /*********************************************************************
1106  *
1107  * Function    :  add_to_iob
1108  *
1109  * Description :  Add content to the buffered page, expanding the
1110  *                buffer if necessary.
1111  *
1112  * Parameters  :
1113  *          1  :  csp = Current client state (buffers, headers, etc...)
1114  *          2  :  buf = holds the content to be added to the page
1115  *          3  :  n = number of bytes to be added
1116  *
1117  * Returns     :  JB_ERR_OK on success, JB_ERR_MEMORY if out-of-memory
1118  *                or buffer limit reached.
1119  *
1120  *********************************************************************/
1121 jb_err add_to_iob(struct client_state *csp, char *buf, int n)
1122 {
1123    struct iob *iob = csp->iob;
1124    size_t used, offset, need, want;
1125    char *p;
1126
1127    if (n <= 0) return JB_ERR_OK;
1128
1129    used   = (size_t)(iob->eod - iob->buf);
1130    offset = (size_t)(iob->cur - iob->buf);
1131    need   = used + (size_t)n + 1;
1132
1133    /*
1134     * If the buffer can't hold the new data, extend it first.
1135     * Use the next power of two if possible, else use the actual need.
1136     */
1137    if (need > csp->config->buffer_limit)
1138    {
1139       log_error(LOG_LEVEL_INFO,
1140          "Buffer limit reached while extending the buffer (iob). Needed: %d. Limit: %d",
1141          need, csp->config->buffer_limit);
1142       return JB_ERR_MEMORY;
1143    }
1144
1145    if (need > iob->size)
1146    {
1147       for (want = csp->iob->size ? csp->iob->size : 512; want <= need;) want *= 2;
1148       
1149       if (want <= csp->config->buffer_limit && NULL != (p = (char *)realloc(iob->buf, want)))
1150       {
1151          iob->size = want;
1152       }
1153       else if (NULL != (p = (char *)realloc(iob->buf, need)))
1154       {
1155          iob->size = need;
1156       }
1157       else
1158       {
1159          log_error(LOG_LEVEL_ERROR, "Extending the buffer (iob) failed: %E");
1160          return JB_ERR_MEMORY;
1161       }
1162
1163       /* Update the iob pointers */
1164       iob->cur = p + offset;
1165       iob->eod = p + used;
1166       iob->buf = p;
1167    }
1168
1169    /* copy the new data into the iob buffer */
1170    memcpy(iob->eod, buf, (size_t)n);
1171
1172    /* point to the end of the data */
1173    iob->eod += n;
1174
1175    /* null terminate == cheap insurance */
1176    *iob->eod = '\0';
1177
1178    return JB_ERR_OK;
1179
1180 }
1181
1182
1183 #ifdef FEATURE_ZLIB
1184 /*********************************************************************
1185  *
1186  * Function    :  decompress_iob
1187  *
1188  * Description :  Decompress buffered page, expanding the
1189  *                buffer as necessary.  csp->iob->cur
1190  *                should point to the the beginning of the
1191  *                compressed data block.
1192  *
1193  * Parameters  :
1194  *          1  :  csp = Current client state (buffers, headers, etc...)
1195  *
1196  * Returns     :  JB_ERR_OK on success,
1197  *                JB_ERR_MEMORY if out-of-memory limit reached, and
1198  *                JB_ERR_COMPRESS if error decompressing buffer.
1199  *
1200  *********************************************************************/
1201 jb_err decompress_iob(struct client_state *csp)
1202 {
1203    char  *buf;       /* new, uncompressed buffer */
1204    char  *cur;       /* Current iob position (to keep the original 
1205                       * iob->cur unmodified if we return early) */
1206    size_t bufsize;   /* allocated size of the new buffer */
1207    size_t old_size;  /* Content size before decompression */
1208    size_t skip_size; /* Number of bytes at the beginning of the iob
1209                         that we should NOT decompress. */
1210    int status;       /* return status of the inflate() call */
1211    z_stream zstr;    /* used by calls to zlib */
1212
1213    assert(csp->iob->cur - csp->iob->buf > 0);
1214    assert(csp->iob->eod - csp->iob->cur > 0);
1215
1216    bufsize = csp->iob->size;
1217    skip_size = (size_t)(csp->iob->cur - csp->iob->buf);
1218    old_size = (size_t)(csp->iob->eod - csp->iob->cur);
1219
1220    cur = csp->iob->cur;
1221
1222    if (bufsize < (size_t)10)
1223    {
1224       /*
1225        * This is to protect the parsing of gzipped data,
1226        * but it should(?) be valid for deflated data also.
1227        */
1228       log_error(LOG_LEVEL_ERROR, "Buffer too small decompressing iob");
1229       return JB_ERR_COMPRESS;
1230    }
1231
1232    if (csp->content_type & CT_GZIP)
1233    {
1234       /*
1235        * Our task is slightly complicated by the facts that data
1236        * compressed by gzip does not include a zlib header, and
1237        * that there is no easily accessible interface in zlib to
1238        * handle a gzip header. We strip off the gzip header by
1239        * hand, and later inform zlib not to expect a header.
1240        */
1241
1242       /*
1243        * Strip off the gzip header. Please see RFC 1952 for more
1244        * explanation of the appropriate fields.
1245        */
1246       if ((*cur++ != (char)0x1f)
1247        || (*cur++ != (char)0x8b)
1248        || (*cur++ != Z_DEFLATED))
1249       {
1250          log_error(LOG_LEVEL_ERROR, "Invalid gzip header when decompressing");
1251          return JB_ERR_COMPRESS;
1252       }
1253       else
1254       {
1255          int flags = *cur++;
1256          /*
1257           * XXX: These magic numbers should be replaced
1258           * with macros to give a better idea what they do.
1259           */
1260          if (flags & 0xe0)
1261          {
1262             /* The gzip header has reserved bits set; bail out. */
1263             log_error(LOG_LEVEL_ERROR, "Invalid gzip header flags when decompressing");
1264             return JB_ERR_COMPRESS;
1265          }
1266          cur += 6;
1267
1268          /* Skip extra fields if necessary. */
1269          if (flags & 0x04)
1270          {
1271             /*
1272              * Skip a given number of bytes, specified
1273              * as a 16-bit little-endian value.
1274              */
1275             /*
1276              * XXX: This code used to be:
1277              * 
1278              * csp->iob->cur += *csp->iob->cur++ + (*csp->iob->cur++ << 8);
1279              *
1280              * which I had to change into:
1281              *
1282              * cur += *cur++ + (*cur++ << 8);
1283              *
1284              * at which point gcc43 finally noticed that the value
1285              * of cur is undefined (it depends on which of the
1286              * summands is evaluated first).
1287              *
1288              * I haven't come across a site where this
1289              * code is actually executed yet, but I hope
1290              * it works anyway.
1291              */
1292             int skip_bytes;
1293             skip_bytes = *cur++;
1294             skip_bytes = *cur++ << 8;
1295
1296             assert(skip_bytes == *csp->iob->cur - 2 + ((*csp->iob->cur - 1) << 8));
1297
1298             /*
1299              * The number of bytes to skip should be positive
1300              * and we'd like to stay in the buffer.
1301              */
1302             if ((skip_bytes < 0) || (skip_bytes >= (csp->iob->eod - cur)))
1303             {
1304                log_error(LOG_LEVEL_ERROR,
1305                   "Unreasonable amount of bytes to skip (%d). Stopping decompression",
1306                   skip_bytes);
1307                return JB_ERR_COMPRESS;
1308             }
1309             log_error(LOG_LEVEL_INFO,
1310                "Skipping %d bytes for gzip compression. Does this sound right?",
1311                skip_bytes);
1312             cur += skip_bytes;
1313          }
1314
1315          /* Skip the filename if necessary. */
1316          if (flags & 0x08)
1317          {
1318             /* A null-terminated string is supposed to follow. */
1319             while (*cur++ && (cur < csp->iob->eod));
1320
1321          }
1322
1323          /* Skip the comment if necessary. */
1324          if (flags & 0x10)
1325          {
1326             /* A null-terminated string is supposed to follow. */
1327             while (*cur++ && (cur < csp->iob->eod));
1328          }
1329
1330          /* Skip the CRC if necessary. */
1331          if (flags & 0x02)
1332          {
1333             cur += 2;
1334          }
1335
1336          if (cur >= csp->iob->eod)
1337          {
1338             /*
1339              * If the current position pointer reached or passed
1340              * the buffer end, we were obviously tricked to skip
1341              * too much.
1342              */
1343             log_error(LOG_LEVEL_ERROR,
1344                "Malformed gzip header detected. Aborting decompression.");
1345             return JB_ERR_COMPRESS;
1346          }
1347       }
1348    }
1349    else if (csp->content_type & CT_DEFLATE)
1350    {
1351       /*
1352        * XXX: The debug level should be lowered
1353        * before the next stable release.
1354        */
1355       log_error(LOG_LEVEL_INFO, "Decompressing deflated iob: %d", *cur);
1356       /*
1357        * In theory (that is, according to RFC 1950), deflate-compressed
1358        * data should begin with a two-byte zlib header and have an
1359        * adler32 checksum at the end. It seems that in practice only
1360        * the raw compressed data is sent. Note that this means that
1361        * we are not RFC 1950-compliant here, but the advantage is that
1362        * this actually works. :)
1363        *
1364        * We add a dummy null byte to tell zlib where the data ends,
1365        * and later inform it not to expect a header.
1366        *
1367        * Fortunately, add_to_iob() has thoughtfully null-terminated
1368        * the buffer; we can just increment the end pointer to include
1369        * the dummy byte.  
1370        */
1371       csp->iob->eod++;
1372    }
1373    else
1374    {
1375       log_error(LOG_LEVEL_ERROR,
1376          "Unable to determine compression format for decompression");
1377       return JB_ERR_COMPRESS;
1378    }
1379
1380    /* Set up the fields required by zlib. */
1381    zstr.next_in  = (Bytef *)cur;
1382    zstr.avail_in = (unsigned int)(csp->iob->eod - cur);
1383    zstr.zalloc   = Z_NULL;
1384    zstr.zfree    = Z_NULL;
1385    zstr.opaque   = Z_NULL;
1386
1387    /*
1388     * Passing -MAX_WBITS to inflateInit2 tells the library
1389     * that there is no zlib header.
1390     */
1391    if (inflateInit2 (&zstr, -MAX_WBITS) != Z_OK)
1392    {
1393       log_error(LOG_LEVEL_ERROR, "Error initializing decompression");
1394       return JB_ERR_COMPRESS;
1395    }
1396
1397    /*
1398     * Next, we allocate new storage for the inflated data.
1399     * We don't modify the existing iob yet, so in case there
1400     * is error in decompression we can recover gracefully.
1401     */
1402    buf = zalloc(bufsize);
1403    if (NULL == buf)
1404    {
1405       log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob");
1406       return JB_ERR_MEMORY;
1407    }
1408
1409    assert(bufsize >= skip_size);
1410    memcpy(buf, csp->iob->buf, skip_size);
1411    zstr.avail_out = bufsize - skip_size;
1412    zstr.next_out  = (Bytef *)buf + skip_size;
1413
1414    /* Try to decompress the whole stream in one shot. */
1415    while (Z_BUF_ERROR == (status = inflate(&zstr, Z_FINISH)))
1416    {
1417       /* We need to allocate more memory for the output buffer. */
1418
1419       char *tmpbuf;                /* used for realloc'ing the buffer */
1420       size_t oldbufsize = bufsize; /* keep track of the old bufsize */
1421
1422       /*
1423        * If zlib wants more data then there's a problem, because
1424        * the complete compressed file should have been buffered.
1425        */
1426       if (0 == zstr.avail_in)
1427       {
1428          log_error(LOG_LEVEL_ERROR, "Unexpected end of compressed iob");
1429          return JB_ERR_COMPRESS;
1430       }
1431
1432       /*
1433        * If we tried the limit and still didn't have enough
1434        * memory, just give up.
1435        */
1436       if (bufsize == csp->config->buffer_limit)
1437       {
1438          log_error(LOG_LEVEL_ERROR, "Buffer limit reached while decompressing iob");
1439          return JB_ERR_MEMORY;
1440       }
1441
1442       /* Try doubling the buffer size each time. */
1443       bufsize *= 2;
1444
1445       /* Don't exceed the buffer limit. */
1446       if (bufsize > csp->config->buffer_limit)
1447       {
1448          bufsize = csp->config->buffer_limit;
1449       }
1450     
1451       /* Try to allocate the new buffer. */
1452       tmpbuf = realloc(buf, bufsize);
1453       if (NULL == tmpbuf)
1454       {
1455          log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob");
1456          freez(buf);
1457          return JB_ERR_MEMORY;
1458       }
1459       else
1460       {
1461          char *oldnext_out = (char *)zstr.next_out;
1462
1463          /*
1464           * Update the fields for inflate() to use the new
1465           * buffer, which may be in a location different from
1466           * the old one.
1467           */
1468          zstr.avail_out += bufsize - oldbufsize;
1469          zstr.next_out   = (Bytef *)tmpbuf + bufsize - zstr.avail_out;
1470
1471          /*
1472           * Compare with an uglier method of calculating these values
1473           * that doesn't require the extra oldbufsize variable.
1474           */
1475          assert(zstr.avail_out == tmpbuf + bufsize - (char *)zstr.next_out);
1476          assert((char *)zstr.next_out == tmpbuf + ((char *)oldnext_out - buf));
1477          assert(zstr.avail_out > 0U);
1478
1479          buf = tmpbuf;
1480       }
1481    }
1482
1483    if (Z_STREAM_ERROR == inflateEnd(&zstr))
1484    {
1485       log_error(LOG_LEVEL_ERROR,
1486          "Inconsistent stream state after decompression: %s", zstr.msg);
1487       /*
1488        * XXX: Intentionally no return.
1489        *
1490        * According to zlib.h, Z_STREAM_ERROR is returned
1491        * "if the stream state was inconsistent".
1492        *
1493        * I assume in this case inflate()'s status
1494        * would also be something different than Z_STREAM_END
1495        * so this check should be redundant, but lets see.
1496        */
1497    }
1498
1499    if (status != Z_STREAM_END)
1500    {
1501       /* We failed to decompress the stream. */
1502       log_error(LOG_LEVEL_ERROR,
1503          "Error in decompressing to the buffer (iob): %s", zstr.msg);
1504       return JB_ERR_COMPRESS;
1505    }
1506
1507    /*
1508     * Finally, we can actually update the iob, since the
1509     * decompression was successful. First, free the old
1510     * buffer.
1511     */
1512    freez(csp->iob->buf);
1513
1514    /* Now, update the iob to use the new buffer. */
1515    csp->iob->buf  = buf;
1516    csp->iob->cur  = csp->iob->buf + skip_size;
1517    csp->iob->eod  = (char *)zstr.next_out;
1518    csp->iob->size = bufsize;
1519   
1520    /*
1521     * Make sure the new uncompressed iob obeys some minimal
1522     * consistency conditions.
1523     */
1524    if ((csp->iob->buf <  csp->iob->cur)
1525     && (csp->iob->cur <= csp->iob->eod)
1526     && (csp->iob->eod <= csp->iob->buf + csp->iob->size))
1527    {
1528       const size_t new_size = (size_t)(csp->iob->eod - csp->iob->cur);
1529       if (new_size > (size_t)0)
1530       {
1531          log_error(LOG_LEVEL_RE_FILTER,
1532             "Decompression successful. Old size: %d, new size: %d.",
1533             old_size, new_size);
1534       }
1535       else
1536       {
1537          /* zlib thinks this is OK, so lets do the same. */
1538          log_error(LOG_LEVEL_INFO, "Decompression didn't result in any content.");
1539       }
1540    }
1541    else
1542    {
1543       /* It seems that zlib did something weird. */
1544       log_error(LOG_LEVEL_ERROR,
1545          "Unexpected error decompressing the buffer (iob): %d==%d, %d>%d, %d<%d",
1546          csp->iob->cur, csp->iob->buf + skip_size, csp->iob->eod, csp->iob->buf,
1547          csp->iob->eod, csp->iob->buf + csp->iob->size);
1548       return JB_ERR_COMPRESS;
1549    }
1550
1551    return JB_ERR_OK;
1552
1553 }
1554 #endif /* defined(FEATURE_ZLIB) */
1555
1556
1557 /*********************************************************************
1558  *
1559  * Function    :  string_move
1560  *
1561  * Description :  memmove wrapper to move the last part of a string
1562  *                towards the beginning, overwriting the part in
1563  *                the middle. strlcpy() can't be used here as the
1564  *                strings overlap.
1565  *
1566  * Parameters  :
1567  *          1  :  dst = Destination to overwrite
1568  *          2  :  src = Source to move.
1569  *
1570  * Returns     :  N/A
1571  *
1572  *********************************************************************/
1573 static void string_move(char *dst, char *src)
1574 {
1575    assert(dst < src);
1576
1577    /* +1 to copy the terminating nul as well. */
1578    memmove(dst, src, strlen(src)+1);
1579 }
1580
1581
1582 /*********************************************************************
1583  *
1584  * Function    :  normalize_lws
1585  *
1586  * Description :  Reduces unquoted linear white space in headers
1587  *                to a single space in accordance with RFC 2616 2.2.
1588  *                This simplifies parsing and filtering later on.
1589  *
1590  *                XXX: Remove log messages before
1591  *                     the next stable release?
1592  *
1593  * Parameters  :
1594  *          1  :  header = A header with linear white space to reduce.
1595  *
1596  * Returns     :  N/A
1597  *
1598  *********************************************************************/
1599 static void normalize_lws(char *header)
1600 {
1601    char *p = header;
1602
1603    while (*p != '\0')
1604    {
1605       if (ijb_isspace(*p) && ijb_isspace(*(p+1)))
1606       {
1607          char *q = p+1;
1608
1609          while (ijb_isspace(*q))
1610          {
1611             q++;
1612          }
1613          log_error(LOG_LEVEL_HEADER, "Reducing white space in '%s'", header);
1614          string_move(p+1, q);
1615       }
1616
1617       if (*p == '\t')
1618       {
1619          log_error(LOG_LEVEL_HEADER,
1620             "Converting tab to space in '%s'", header);
1621          *p = ' ';
1622       }
1623       else if (*p == '"')
1624       {
1625          char *end_of_token = strstr(p+1, "\"");
1626
1627          if (NULL != end_of_token)
1628          {
1629             /* Don't mess with quoted text. */
1630             p = end_of_token;
1631          }
1632          else
1633          {
1634             log_error(LOG_LEVEL_HEADER,
1635                "Ignoring single quote in '%s'", header);
1636          }
1637       }
1638       p++;
1639    }
1640
1641    p = strchr(header, ':');
1642    if ((p != NULL) && (p != header) && ijb_isspace(*(p-1)))
1643    {
1644       /*
1645        * There's still space before the colon.
1646        * We don't want it.
1647        */
1648       string_move(p-1, p);
1649    }
1650 }
1651
1652
1653 /*********************************************************************
1654  *
1655  * Function    :  get_header
1656  *
1657  * Description :  This (odd) routine will parse the csp->iob
1658  *                to get the next complete header.
1659  *
1660  * Parameters  :
1661  *          1  :  iob = The I/O buffer to parse, usually csp->iob.
1662  *
1663  * Returns     :  Any one of the following:
1664  *
1665  * 1) a pointer to a dynamically allocated string that contains a header line
1666  * 2) NULL  indicating that the end of the header was reached
1667  * 3) ""    indicating that the end of the iob was reached before finding
1668  *          a complete header line.
1669  *
1670  *********************************************************************/
1671 char *get_header(struct iob *iob)
1672 {
1673    char *header;
1674
1675    header = get_header_line(iob);
1676
1677    if ((header == NULL) || (*header == '\0'))
1678    {
1679       /*
1680        * No complete header read yet, tell the client.
1681        */
1682       return header;
1683    }
1684
1685    while ((iob->cur[0] == ' ') || (iob->cur[0] == '\t'))
1686    {
1687       /*
1688        * Header spans multiple lines, append the next one.
1689        */
1690       char *continued_header;
1691       
1692       continued_header = get_header_line(iob);
1693       if ((continued_header == NULL) || (*continued_header == '\0'))
1694       {
1695          /*
1696           * No complete header read yet, return what we got.
1697           * XXX: Should "unread" header instead.
1698           */
1699          log_error(LOG_LEVEL_INFO,
1700             "Failed to read a multi-line header properly: '%s'",
1701             header);
1702          break;
1703       }
1704
1705       if (JB_ERR_OK != string_join(&header, continued_header))
1706       {
1707          log_error(LOG_LEVEL_FATAL,
1708             "Out of memory while appending multiple headers.");
1709       }
1710       else
1711       {
1712          /* XXX: remove before next stable release. */
1713          log_error(LOG_LEVEL_HEADER,
1714             "Merged multiple header lines to: '%s'",
1715             header);
1716       }
1717    }
1718
1719    normalize_lws(header);
1720
1721    return header;
1722
1723 }
1724
1725
1726 /*********************************************************************
1727  *
1728  * Function    :  get_header_line
1729  *
1730  * Description :  This (odd) routine will parse the csp->iob
1731  *                to get the next header line.
1732  *
1733  * Parameters  :
1734  *          1  :  iob = The I/O buffer to parse, usually csp->iob.
1735  *
1736  * Returns     :  Any one of the following:
1737  *
1738  * 1) a pointer to a dynamically allocated string that contains a header line
1739  * 2) NULL  indicating that the end of the header was reached
1740  * 3) ""    indicating that the end of the iob was reached before finding
1741  *          a complete header line.
1742  *
1743  *********************************************************************/
1744 static char *get_header_line(struct iob *iob)
1745 {
1746    char *p, *q, *ret;
1747
1748    if ((iob->cur == NULL)
1749       || ((p = strchr(iob->cur, '\n')) == NULL))
1750    {
1751       return(""); /* couldn't find a complete header */
1752    }
1753
1754    *p = '\0';
1755
1756    ret = strdup(iob->cur);
1757    if (ret == NULL)
1758    {
1759       /* FIXME No way to handle error properly */
1760       log_error(LOG_LEVEL_FATAL, "Out of memory in get_header_line()");
1761    }
1762    assert(ret != NULL);
1763
1764    iob->cur = p+1;
1765
1766    if ((q = strchr(ret, '\r')) != NULL) *q = '\0';
1767
1768    /* is this a blank line (i.e. the end of the header) ? */
1769    if (*ret == '\0')
1770    {
1771       freez(ret);
1772       return NULL;
1773    }
1774
1775    return ret;
1776
1777 }
1778
1779
1780 /*********************************************************************
1781  *
1782  * Function    :  get_header_value
1783  *
1784  * Description :  Get the value of a given header from a chained list
1785  *                of header lines or return NULL if no such header is
1786  *                present in the list.
1787  *
1788  * Parameters  :
1789  *          1  :  header_list = pointer to list
1790  *          2  :  header_name = string with name of header to look for.
1791  *                              Trailing colon required, capitalization
1792  *                              doesn't matter.
1793  *
1794  * Returns     :  NULL if not found, else value of header
1795  *
1796  *********************************************************************/
1797 char *get_header_value(const struct list *header_list, const char *header_name)
1798 {
1799    struct list_entry *cur_entry;
1800    char *ret = NULL;
1801    size_t length = 0;
1802
1803    assert(header_list);
1804    assert(header_name);
1805    length = strlen(header_name);
1806
1807    for (cur_entry = header_list->first; cur_entry ; cur_entry = cur_entry->next)
1808    {
1809       if (cur_entry->str)
1810       {
1811          if (!strncmpic(cur_entry->str, header_name, length))
1812          {
1813             /*
1814              * Found: return pointer to start of value
1815              */
1816             ret = cur_entry->str + length;
1817             while (*ret && ijb_isspace(*ret)) ret++;
1818             return ret;
1819          }
1820       }
1821    }
1822
1823    /* 
1824     * Not found
1825     */
1826    return NULL;
1827
1828 }
1829
1830
1831 /*********************************************************************
1832  *
1833  * Function    :  scan_headers
1834  *
1835  * Description :  Scans headers, applies tags and updates action bits. 
1836  *
1837  * Parameters  :
1838  *          1  :  csp = Current client state (buffers, headers, etc...)
1839  *
1840  * Returns     :  JB_ERR_OK
1841  *
1842  *********************************************************************/
1843 static jb_err scan_headers(struct client_state *csp)
1844 {
1845    struct list_entry *h; /* Header */
1846    jb_err err = JB_ERR_OK;
1847
1848    for (h = csp->headers->first; (err == JB_ERR_OK) && (h != NULL) ; h = h->next)
1849    {
1850       /* Header crunch()ed in previous run? -> ignore */
1851       if (h->str == NULL) continue;
1852       log_error(LOG_LEVEL_HEADER, "scan: %s", h->str);
1853       err = header_tagger(csp, h->str);
1854    }
1855
1856    return err;
1857 }
1858
1859
1860 /*********************************************************************
1861  *
1862  * Function    :  sed
1863  *
1864  * Description :  add, delete or modify lines in the HTTP header streams.
1865  *                On entry, it receives a linked list of headers space
1866  *                that was allocated dynamically (both the list nodes
1867  *                and the header contents).
1868  *
1869  *                As a side effect it frees the space used by the original
1870  *                header lines.
1871  *
1872  * Parameters  :
1873  *          1  :  csp = Current client state (buffers, headers, etc...)
1874  *          2  :  filter_server_headers = Boolean to switch between
1875  *                                        server and header filtering.
1876  *
1877  * Returns     :  JB_ERR_OK in case off success, or
1878  *                JB_ERR_MEMORY on out-of-memory error.
1879  *
1880  *********************************************************************/
1881 jb_err sed(struct client_state *csp, int filter_server_headers)
1882 {
1883    /* XXX: use more descriptive names. */
1884    struct list_entry *p;
1885    const struct parsers *v;
1886    const add_header_func_ptr *f;
1887    jb_err err = JB_ERR_OK;
1888
1889    if (filter_server_headers)
1890    {
1891       v = server_patterns;
1892       f = add_server_headers;
1893    }
1894    else
1895    {
1896       v = client_patterns;
1897       f = add_client_headers;
1898    }
1899
1900    scan_headers(csp);
1901
1902    while ((err == JB_ERR_OK) && (v->str != NULL))
1903    {
1904       for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL); p = p->next)
1905       {
1906          /* Header crunch()ed in previous run? -> ignore */
1907          if (p->str == NULL) continue;
1908
1909          /* Does the current parser handle this header? */
1910          if ((strncmpic(p->str, v->str, v->len) == 0) ||
1911              (v->len == CHECK_EVERY_HEADER_REMAINING))
1912          {
1913             err = v->parser(csp, &(p->str));
1914          }
1915       }
1916       v++;
1917    }
1918
1919    /* place additional headers on the csp->headers list */
1920    while ((err == JB_ERR_OK) && (*f))
1921    {
1922       err = (*f)(csp);
1923       f++;
1924    }
1925
1926    return err;
1927 }
1928
1929
1930 /*********************************************************************
1931  *
1932  * Function    :  update_server_headers
1933  *
1934  * Description :  Updates server headers after the body has been modified.
1935  *
1936  * Parameters  :
1937  *          1  :  csp = Current client state (buffers, headers, etc...)
1938  *
1939  * Returns     :  JB_ERR_OK in case off success, or
1940  *                JB_ERR_MEMORY on out-of-memory error.
1941  *
1942  *********************************************************************/
1943 jb_err update_server_headers(struct client_state *csp)
1944 {
1945    jb_err err = JB_ERR_OK;
1946
1947    static const struct parsers server_patterns_light[] = {
1948       { "Content-Length:",    15, server_adjust_content_length },
1949       { "Transfer-Encoding:", 18, server_transfer_coding },
1950 #ifdef FEATURE_ZLIB
1951       { "Content-Encoding:",  17, server_content_encoding },
1952 #endif /* def FEATURE_ZLIB */
1953       { NULL,                  0, NULL }
1954    };
1955
1956    if (strncmpic(csp->http->cmd, "HEAD", 4))
1957    {
1958       const struct parsers *v;
1959       struct list_entry *p;
1960
1961       for (v = server_patterns_light; (err == JB_ERR_OK) && (v->str != NULL); v++)
1962       {
1963          for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL); p = p->next)
1964          {
1965             /* Header crunch()ed in previous run? -> ignore */
1966             if (p->str == NULL) continue;
1967
1968             /* Does the current parser handle this header? */
1969             if (strncmpic(p->str, v->str, v->len) == 0)
1970             {
1971                err = v->parser(csp, (char **)&(p->str));
1972             }
1973          }
1974       }
1975    }
1976
1977    return err;
1978 }
1979
1980
1981 /*********************************************************************
1982  *
1983  * Function    :  header_tagger
1984  *
1985  * Description :  Executes all text substitutions from applying
1986  *                tag actions and saves the result as tag.
1987  *
1988  *                XXX: Shares enough code with filter_header() and
1989  *                pcrs_filter_response() to warrant some helper functions.
1990  *
1991  * Parameters  :
1992  *          1  :  csp = Current client state (buffers, headers, etc...)
1993  *          2  :  header = Header that is used as tagger input
1994  *
1995  * Returns     :  JB_ERR_OK on success and always succeeds
1996  *
1997  *********************************************************************/
1998 static jb_err header_tagger(struct client_state *csp, char *header)
1999 {
2000    int wanted_filter_type;
2001    int multi_action_index;
2002    int i;
2003    pcrs_job *job;
2004
2005    struct file_list *fl;
2006    struct re_filterfile_spec *b;
2007    struct list_entry *tag_name;
2008
2009    int found_filters = 0;
2010    const size_t header_length = strlen(header);
2011
2012    if (csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
2013    {
2014       wanted_filter_type = FT_SERVER_HEADER_TAGGER;
2015       multi_action_index = ACTION_MULTI_SERVER_HEADER_TAGGER;
2016    }
2017    else
2018    {
2019       wanted_filter_type = FT_CLIENT_HEADER_TAGGER;
2020       multi_action_index = ACTION_MULTI_CLIENT_HEADER_TAGGER;
2021    }
2022
2023    /* Check if there are any filters */
2024    for (i = 0; i < MAX_AF_FILES; i++)
2025    {
2026       fl = csp->rlist[i];
2027       if (NULL != fl)
2028       {
2029          if (NULL != fl->f)
2030          {
2031            found_filters = 1;
2032            break;
2033          }
2034       }
2035    }
2036
2037    if (0 == found_filters)
2038    {
2039       log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: "
2040          "tagging enabled, but no taggers available.");
2041       return JB_ERR_OK;
2042    }
2043
2044    for (i = 0; i < MAX_AF_FILES; i++)
2045    {
2046       fl = csp->rlist[i];
2047       if ((NULL == fl) || (NULL == fl->f))
2048       {
2049          /*
2050           * Either there are no filter files
2051           * left, or this filter file just
2052           * contains no valid filters.
2053           *
2054           * Continue to be sure we don't miss
2055           * valid filter files that are chained
2056           * after empty or invalid ones.
2057           */
2058          continue;
2059       }
2060
2061       /* For all filters, */
2062       for (b = fl->f; b; b = b->next)
2063       {
2064          if (b->type != wanted_filter_type)
2065          {
2066             /* skip the ones we don't care about, */
2067             continue;
2068          }
2069          /* leaving only taggers that could apply, of which we use the ones, */
2070          for (tag_name = csp->action->multi[multi_action_index]->first;
2071               NULL != tag_name; tag_name = tag_name->next)
2072          {
2073             /* that do apply, and */
2074             if (strcmp(b->name, tag_name->str) == 0)
2075             {
2076                char *modified_tag = NULL;
2077                char *tag = header;
2078                size_t size = header_length;
2079                pcrs_job *joblist = b->joblist;
2080
2081                if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b);
2082
2083                if (NULL == joblist)
2084                {
2085                   log_error(LOG_LEVEL_RE_FILTER,
2086                      "Tagger %s has empty joblist. Nothing to do.", b->name);
2087                   continue;
2088                }
2089
2090                /* execute their pcrs_joblist on the header. */
2091                for (job = joblist; NULL != job; job = job->next)
2092                {
2093                   const int hits = pcrs_execute(job, tag, size, &modified_tag, &size);
2094
2095                   if (0 < hits)
2096                   {
2097                      /* Success, continue with the modified version. */
2098                      if (tag != header)
2099                      {
2100                         freez(tag);
2101                      }
2102                      tag = modified_tag;
2103                   }
2104                   else
2105                   {
2106                      /* Tagger doesn't match */
2107                      if (0 > hits)
2108                      {
2109                         /* Regex failure, log it but continue anyway. */
2110                         assert(NULL != header);
2111                         log_error(LOG_LEVEL_ERROR,
2112                            "Problems with tagger \'%s\' and header \'%s\': %s",
2113                            b->name, *header, pcrs_strerror(hits));
2114                      }
2115                      freez(modified_tag);
2116                   }
2117                }
2118
2119                if (b->dynamic) pcrs_free_joblist(joblist);
2120
2121                /* If this tagger matched */
2122                if (tag != header)
2123                {
2124                   if (0 == size)
2125                   {
2126                      /*
2127                       * There is to technical limitation which makes
2128                       * it impossible to use empty tags, but I assume
2129                       * no one would do it intentionally.
2130                       */
2131                      freez(tag);
2132                      log_error(LOG_LEVEL_INFO,
2133                         "Tagger \'%s\' created an empty tag. Ignored.",
2134                         b->name);
2135                      continue;
2136                   }
2137  
2138                   if (!list_contains_item(csp->tags, tag))
2139                   {
2140                      if (JB_ERR_OK != enlist(csp->tags, tag))
2141                      {
2142                         log_error(LOG_LEVEL_ERROR,
2143                            "Insufficient memory to add tag \'%s\', "
2144                            "based on tagger \'%s\' and header \'%s\'",
2145                            tag, b->name, *header);
2146                      }
2147                      else
2148                      {
2149                         char *action_message;
2150                         /*
2151                          * update the action bits right away, to make
2152                          * tagging based on tags set by earlier taggers
2153                          * of the same kind possible.
2154                          */
2155                         if (update_action_bits_for_tag(csp, tag))
2156                         {
2157                            action_message = "Action bits updated accordingly.";
2158                         }
2159                         else
2160                         {
2161                            action_message = "No action bits update necessary.";
2162                         }
2163
2164                         log_error(LOG_LEVEL_HEADER,
2165                            "Tagger \'%s\' added tag \'%s\'. %s",
2166                            b->name, tag, action_message);
2167                      }
2168                   }
2169                   else
2170                   {
2171                      /* XXX: Is this log-worthy? */
2172                      log_error(LOG_LEVEL_HEADER,
2173                         "Tagger \'%s\' didn't add tag \'%s\'. "
2174                         "Tag already present", b->name, tag);
2175                   }
2176                   freez(tag);
2177                } /* if the tagger matched */
2178             } /* if the tagger applies */
2179          } /* for every tagger that could apply */
2180       } /* for all filters */
2181    } /* for all filter files */
2182
2183    return JB_ERR_OK;
2184 }
2185
2186 /* here begins the family of parser functions that reformat header lines */
2187
2188 /*********************************************************************
2189  *
2190  * Function    :  filter_header
2191  *
2192  * Description :  Executes all text substitutions from all applying
2193  *                +(server|client)-header-filter actions on the header.
2194  *                Most of the code was copied from pcrs_filter_response,
2195  *                including the rather short variable names
2196  *
2197  * Parameters  :
2198  *          1  :  csp = Current client state (buffers, headers, etc...)
2199  *          2  :  header = On input, pointer to header to modify.
2200  *                On output, pointer to the modified header, or NULL
2201  *                to remove the header.  This function frees the
2202  *                original string if necessary.
2203  *
2204  * Returns     :  JB_ERR_OK on success and always succeeds
2205  *
2206  *********************************************************************/
2207 static jb_err filter_header(struct client_state *csp, char **header)
2208 {
2209    int hits=0;
2210    int matches;
2211    size_t size = strlen(*header);
2212
2213    char *newheader = NULL;
2214    pcrs_job *job;
2215
2216    struct file_list *fl;
2217    struct re_filterfile_spec *b;
2218    struct list_entry *filtername;
2219
2220    int i, found_filters = 0;
2221    int wanted_filter_type;
2222    int multi_action_index;
2223
2224    if (csp->flags & CSP_FLAG_NO_FILTERING)
2225    {
2226       return JB_ERR_OK;
2227    }
2228
2229    if (csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
2230    {
2231       wanted_filter_type = FT_SERVER_HEADER_FILTER;
2232       multi_action_index = ACTION_MULTI_SERVER_HEADER_FILTER;
2233    }
2234    else
2235    {
2236       wanted_filter_type = FT_CLIENT_HEADER_FILTER;
2237       multi_action_index = ACTION_MULTI_CLIENT_HEADER_FILTER;
2238    }
2239
2240    /*
2241     * Need to check the set of re_filterfiles...
2242     */
2243    for (i = 0; i < MAX_AF_FILES; i++)
2244    {
2245       fl = csp->rlist[i];
2246       if (NULL != fl)
2247       {
2248          if (NULL != fl->f)
2249          {
2250            found_filters = 1;
2251            break;
2252          }
2253       }
2254    }
2255
2256    if (0 == found_filters)
2257    {
2258       log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: "
2259          "header filtering enabled, but no matching filters available.");
2260       return JB_ERR_OK;
2261    }
2262
2263    for (i = 0; i < MAX_AF_FILES; i++)
2264    {
2265       fl = csp->rlist[i];
2266       if ((NULL == fl) || (NULL == fl->f))
2267       {
2268          /*
2269           * Either there are no filter files
2270           * left, or this filter file just
2271           * contains no valid filters.
2272           *
2273           * Continue to be sure we don't miss
2274           * valid filter files that are chained
2275           * after empty or invalid ones.
2276           */
2277          continue;
2278       }
2279       /*
2280        * For all applying +filter actions, look if a filter by that
2281        * name exists and if yes, execute its pcrs_joblist on the
2282        * buffer.
2283        */
2284       for (b = fl->f; b; b = b->next)
2285       {
2286          if (b->type != wanted_filter_type)
2287          {
2288             /* Skip other filter types */
2289             continue;
2290          }
2291
2292          for (filtername = csp->action->multi[multi_action_index]->first;
2293               filtername ; filtername = filtername->next)
2294          {
2295             if (strcmp(b->name, filtername->str) == 0)
2296             {
2297                int current_hits = 0;
2298                pcrs_job *joblist = b->joblist;
2299
2300                if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b);
2301
2302                if (NULL == joblist)
2303                {
2304                   log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name);
2305                   continue;
2306                }
2307
2308                log_error(LOG_LEVEL_RE_FILTER, "filtering \'%s\' (size %d) with \'%s\' ...",
2309                          *header, size, b->name);
2310
2311                /* Apply all jobs from the joblist */
2312                for (job = joblist; NULL != job; job = job->next)
2313                {
2314                   matches = pcrs_execute(job, *header, size, &newheader, &size);
2315                   if ( 0 < matches )
2316                   {
2317                      current_hits += matches; 
2318                      log_error(LOG_LEVEL_HEADER, "Transforming \"%s\" to \"%s\"", *header, newheader);
2319                      freez(*header);
2320                      *header = newheader;
2321                   }
2322                   else if ( 0 == matches )
2323                   {
2324                      /* Filter doesn't change header */
2325                      freez(newheader);
2326                   }
2327                   else
2328                   {
2329                      /* RegEx failure */
2330                      log_error(LOG_LEVEL_ERROR, "Filtering \'%s\' with \'%s\' didn't work out: %s",
2331                         *header, b->name, pcrs_strerror(matches));
2332                      if (newheader != NULL)
2333                      {
2334                         log_error(LOG_LEVEL_ERROR, "Freeing what's left: %s", newheader);
2335                         freez(newheader);
2336                      }
2337                   }
2338                }
2339
2340                if (b->dynamic) pcrs_free_joblist(joblist);
2341
2342                log_error(LOG_LEVEL_RE_FILTER, "... produced %d hits (new size %d).", current_hits, size);
2343                hits += current_hits;
2344             }
2345          }
2346       }
2347    }
2348
2349    /*
2350     * Additionally checking for hits is important because if
2351     * the continue hack is triggered, server headers can
2352     * arrive empty to separate multiple heads from each other.
2353     */
2354    if ((0 == size) && hits)
2355    {
2356       log_error(LOG_LEVEL_HEADER, "Removing empty header %s", *header);
2357       freez(*header);
2358    }
2359
2360    return JB_ERR_OK;
2361 }
2362
2363
2364 /*********************************************************************
2365  *
2366  * Function    :  server_connection
2367  *
2368  * Description :  Makes sure that the value of the Connection: header
2369  *                is "close" and signals server_connection_close_adder 
2370  *                to do nothing.
2371  *
2372  * Parameters  :
2373  *          1  :  csp = Current client state (buffers, headers, etc...)
2374  *          2  :  header = On input, pointer to header to modify.
2375  *                On output, pointer to the modified header, or NULL
2376  *                to remove the header.  This function frees the
2377  *                original string if necessary.
2378  *
2379  * Returns     :  JB_ERR_OK on success, or
2380  *                JB_ERR_MEMORY on out-of-memory error.
2381  *
2382  *********************************************************************/
2383 static jb_err server_connection(struct client_state *csp, char **header)
2384 {
2385    char *old_header = *header;
2386
2387    /* Do we have a 'Connection: close' header? */
2388    if (strcmpic(*header, "Connection: close"))
2389    {
2390 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
2391       if ((csp->config->feature_flags &
2392            RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
2393          && !strcmpic(*header, "Connection: keep-alive"))
2394       {
2395          /* Remember to keep the connection alive. */
2396          csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
2397       }
2398 #endif /* FEATURE_CONNECTION_KEEP_ALIVE */
2399
2400       *header = strdup("Connection: close");
2401       if (header == NULL)
2402       { 
2403          return JB_ERR_MEMORY;
2404       }
2405       log_error(LOG_LEVEL_HEADER, "Replaced: \'%s\' with \'%s\'", old_header, *header);
2406       freez(old_header);
2407    }
2408
2409    /* Signal server_connection_close_adder() to return early. */
2410    csp->flags |= CSP_FLAG_SERVER_CONNECTION_CLOSE_SET;
2411
2412    return JB_ERR_OK;
2413 }
2414
2415 /*********************************************************************
2416  *
2417  * Function    :  client_connection
2418  *
2419  * Description :  Makes sure a proper "Connection:" header is
2420  *                set and signals connection_header_adder 
2421  *                to do nothing.
2422  *
2423  * Parameters  :
2424  *          1  :  csp = Current client state (buffers, headers, etc...)
2425  *          2  :  header = On input, pointer to header to modify.
2426  *                On output, pointer to the modified header, or NULL
2427  *                to remove the header.  This function frees the
2428  *                original string if necessary.
2429  *
2430  * Returns     :  JB_ERR_OK on success, or
2431  *                JB_ERR_MEMORY on out-of-memory error.
2432  *
2433  *********************************************************************/
2434 static jb_err client_connection(struct client_state *csp, char **header)
2435 {
2436    char *old_header = *header;
2437    const char *wanted_header = get_appropiate_connection_header(csp);
2438
2439    if (strcmpic(*header, wanted_header))
2440    {
2441       *header = strdup(wanted_header);
2442       if (header == NULL)
2443       { 
2444          return JB_ERR_MEMORY;
2445       }
2446       log_error(LOG_LEVEL_HEADER,
2447          "Replaced: \'%s\' with \'%s\'", old_header, *header);
2448       freez(old_header);
2449    }
2450
2451    /* Signal client_connection_close_adder() to return early. */
2452    csp->flags |= CSP_FLAG_CLIENT_CONNECTION_HEADER_SET;
2453
2454    return JB_ERR_OK;
2455 }
2456
2457
2458 /*********************************************************************
2459  *
2460  * Function    :  crumble
2461  *
2462  * Description :  This is called if a header matches a pattern to "crunch"
2463  *
2464  * Parameters  :
2465  *          1  :  csp = Current client state (buffers, headers, etc...)
2466  *          2  :  header = On input, pointer to header to modify.
2467  *                On output, pointer to the modified header, or NULL
2468  *                to remove the header.  This function frees the
2469  *                original string if necessary.
2470  *
2471  * Returns     :  JB_ERR_OK on success, or
2472  *                JB_ERR_MEMORY on out-of-memory error.
2473  *
2474  *********************************************************************/
2475 static jb_err crumble(struct client_state *csp, char **header)
2476 {
2477    (void)csp;
2478    log_error(LOG_LEVEL_HEADER, "crumble crunched: %s!", *header);
2479    freez(*header);
2480    return JB_ERR_OK;
2481 }
2482
2483
2484 /*********************************************************************
2485  *
2486  * Function    :  crunch_server_header
2487  *
2488  * Description :  Crunch server header if it matches a string supplied by the
2489  *                user. Called from `sed'.
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 and always succeeds
2499  *
2500  *********************************************************************/
2501 static jb_err crunch_server_header(struct client_state *csp, char **header)
2502 {
2503    const char *crunch_pattern;
2504
2505    /* Do we feel like crunching? */
2506    if ((csp->action->flags & ACTION_CRUNCH_SERVER_HEADER))
2507    {
2508       crunch_pattern = csp->action->string[ACTION_STRING_SERVER_HEADER];
2509
2510       /* Is the current header the lucky one? */
2511       if (strstr(*header, crunch_pattern))
2512       {
2513          log_error(LOG_LEVEL_HEADER, "Crunching server header: %s (contains: %s)", *header, crunch_pattern);  
2514          freez(*header);
2515       }
2516    }
2517
2518    return JB_ERR_OK;
2519 }
2520
2521
2522 /*********************************************************************
2523  *
2524  * Function    :  server_content_type
2525  *
2526  * Description :  Set the content-type for filterable types (text/.*,
2527  *                .*xml.*, javascript and image/gif) unless filtering has been
2528  *                forbidden (CT_TABOO) while parsing earlier headers.
2529  *                NOTE: Since text/plain is commonly used by web servers
2530  *                      for files whose correct type is unknown, we don't
2531  *                      set CT_TEXT for it.
2532  *
2533  * Parameters  :
2534  *          1  :  csp = Current client state (buffers, headers, etc...)
2535  *          2  :  header = On input, pointer to header to modify.
2536  *                On output, pointer to the modified header, or NULL
2537  *                to remove the header.  This function frees the
2538  *                original string if necessary.
2539  *
2540  * Returns     :  JB_ERR_OK on success, or
2541  *                JB_ERR_MEMORY on out-of-memory error.
2542  *
2543  *********************************************************************/
2544 static jb_err server_content_type(struct client_state *csp, char **header)
2545 {
2546    /* Remove header if it isn't the first Content-Type header */
2547    if ((csp->content_type & CT_DECLARED))
2548    {
2549      /*
2550       * Another, slightly slower, way to see if
2551       * we already parsed another Content-Type header.
2552       */
2553       assert(NULL != get_header_value(csp->headers, "Content-Type:"));
2554
2555       log_error(LOG_LEVEL_ERROR,
2556          "Multiple Content-Type headers. Removing and ignoring: \'%s\'",
2557          *header);
2558       freez(*header);
2559
2560       return JB_ERR_OK;
2561    }
2562
2563    /*
2564     * Signal that the Content-Type has been set.
2565     */
2566    csp->content_type |= CT_DECLARED;
2567
2568    if (!(csp->content_type & CT_TABOO))
2569    {
2570       /*
2571        * XXX: The assumption that text/plain is a sign of
2572        * binary data seems to be somewhat unreasonable nowadays
2573        * and should be dropped after 3.0.8 is out.
2574        */
2575       if ((strstr(*header, "text/") && !strstr(*header, "plain"))
2576         || strstr(*header, "xml")
2577         || strstr(*header, "application/x-javascript"))
2578       {
2579          csp->content_type |= CT_TEXT;
2580       }
2581       else if (strstr(*header, "image/gif"))
2582       {
2583          csp->content_type |= CT_GIF;
2584       }
2585    }
2586
2587    /*
2588     * Are we messing with the content type?
2589     */
2590    if (csp->action->flags & ACTION_CONTENT_TYPE_OVERWRITE)
2591    {
2592       /*
2593        * Make sure the user doesn't accidently
2594        * change the content type of binary documents. 
2595        */
2596       if ((csp->content_type & CT_TEXT) || (csp->action->flags & ACTION_FORCE_TEXT_MODE))
2597       {
2598          freez(*header);
2599          *header = strdup("Content-Type: ");
2600          string_append(header, csp->action->string[ACTION_STRING_CONTENT_TYPE]);
2601
2602          if (header == NULL)
2603          {
2604             log_error(LOG_LEVEL_HEADER, "Insufficient memory to replace Content-Type!");
2605             return JB_ERR_MEMORY;
2606          }
2607          log_error(LOG_LEVEL_HEADER, "Modified: %s!", *header);
2608       }
2609       else
2610       {
2611          log_error(LOG_LEVEL_HEADER, "%s not replaced. "
2612             "It doesn't look like a content type that should be filtered. "
2613             "Enable force-text-mode if you know what you're doing.", *header);
2614       }
2615    }
2616
2617    return JB_ERR_OK;
2618 }
2619
2620
2621 /*********************************************************************
2622  *
2623  * Function    :  server_transfer_coding
2624  *
2625  * Description :  - Prohibit filtering (CT_TABOO) if transfer coding compresses
2626  *                - Raise the CSP_FLAG_CHUNKED flag if coding is "chunked"
2627  *                - Remove header if body was chunked but has been
2628  *                  de-chunked for filtering.
2629  *
2630  * Parameters  :
2631  *          1  :  csp = Current client state (buffers, headers, etc...)
2632  *          2  :  header = On input, pointer to header to modify.
2633  *                On output, pointer to the modified header, or NULL
2634  *                to remove the header.  This function frees the
2635  *                original string if necessary.
2636  *
2637  * Returns     :  JB_ERR_OK on success, or
2638  *                JB_ERR_MEMORY on out-of-memory error.
2639  *
2640  *********************************************************************/
2641 static jb_err server_transfer_coding(struct client_state *csp, char **header)
2642 {
2643    /*
2644     * Turn off pcrs and gif filtering if body compressed
2645     */
2646    if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate"))
2647    {
2648 #ifdef FEATURE_ZLIB
2649       /*
2650        * XXX: Added to test if we could use CT_GZIP and CT_DEFLATE here.
2651        */
2652       log_error(LOG_LEVEL_INFO, "Marking content type for %s as CT_TABOO because of %s.",
2653          csp->http->cmd, *header);
2654 #endif /* def FEATURE_ZLIB */
2655       csp->content_type = CT_TABOO;
2656    }
2657
2658    /*
2659     * Raise flag if body chunked
2660     */
2661    if (strstr(*header, "chunked"))
2662    {
2663       csp->flags |= CSP_FLAG_CHUNKED;
2664
2665       /*
2666        * If the body was modified, it has been de-chunked first
2667        * and the header must be removed.
2668        *
2669        * FIXME: If there is more than one transfer encoding,
2670        * only the "chunked" part should be removed here.
2671        */
2672       if (csp->flags & CSP_FLAG_MODIFIED)
2673       {
2674          log_error(LOG_LEVEL_HEADER, "Removing: %s", *header);
2675          freez(*header);
2676       }
2677    }
2678
2679    return JB_ERR_OK;
2680 }
2681
2682
2683 /*********************************************************************
2684  *
2685  * Function    :  server_content_encoding
2686  *
2687  * Description :  This function is run twice for each request,
2688  *                unless FEATURE_ZLIB and filtering are disabled.
2689  *
2690  *                The first run is used to check if the content
2691  *                is compressed, if FEATURE_ZLIB is disabled
2692  *                filtering is then disabled as well, if FEATURE_ZLIB
2693  *                is enabled the content is marked for decompression.
2694  *                
2695  *                The second run is used to remove the Content-Encoding
2696  *                header if the decompression was successful.
2697  *
2698  * Parameters  :
2699  *          1  :  csp = Current client state (buffers, headers, etc...)
2700  *          2  :  header = On input, pointer to header to modify.
2701  *                On output, pointer to the modified header, or NULL
2702  *                to remove the header.  This function frees the
2703  *                original string if necessary.
2704  *
2705  * Returns     :  JB_ERR_OK on success, or
2706  *                JB_ERR_MEMORY on out-of-memory error.
2707  *
2708  *********************************************************************/
2709 static jb_err server_content_encoding(struct client_state *csp, char **header)
2710 {
2711 #ifdef FEATURE_ZLIB
2712    if ((csp->flags & CSP_FLAG_MODIFIED)
2713     && (csp->content_type & (CT_GZIP | CT_DEFLATE)))
2714    {
2715       /*
2716        * We successfully decompressed the content,
2717        * and have to clean the header now, so the
2718        * client no longer expects compressed data..
2719        *
2720        * XXX: There is a difference between cleaning
2721        * and removing it completely.
2722        */
2723       log_error(LOG_LEVEL_HEADER, "Crunching: %s", *header);
2724       freez(*header);
2725    }
2726    else if (strstr(*header, "gzip"))
2727    {
2728       /* Mark for gzip decompression */
2729       csp->content_type |= CT_GZIP;
2730    }
2731    else if (strstr(*header, "deflate"))
2732    {
2733       /* Mark for zlib decompression */
2734       csp->content_type |= CT_DEFLATE;
2735    }
2736    else if (strstr(*header, "compress"))
2737    {
2738       /*
2739        * We can't decompress this; therefore we can't filter
2740        * it either.
2741        */
2742       csp->content_type |= CT_TABOO;
2743    }
2744 #else /* !defined(FEATURE_ZLIB) */
2745    if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate"))
2746    {
2747       /*
2748        * Body is compressed, turn off pcrs and gif filtering.
2749        */
2750       csp->content_type |= CT_TABOO;
2751
2752       /*
2753        * Log a warning if the user expects the content to be filtered.
2754        */
2755       if ((csp->rlist != NULL) &&
2756          (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER])))
2757       {
2758          log_error(LOG_LEVEL_INFO,
2759             "Compressed content detected, content filtering disabled. "
2760             "Consider recompiling Privoxy with zlib support or "
2761             "enable the prevent-compression action.");
2762       }
2763    }
2764 #endif /* defined(FEATURE_ZLIB) */
2765
2766    return JB_ERR_OK;
2767
2768 }
2769
2770
2771 /*********************************************************************
2772  *
2773  * Function    :  server_adjust_content_length
2774  *
2775  * Description :  Adjust Content-Length header if we modified
2776  *                the body.
2777  *
2778  * Parameters  :
2779  *          1  :  csp = Current client state (buffers, headers, etc...)
2780  *          2  :  header = On input, pointer to header to modify.
2781  *                On output, pointer to the modified header, or NULL
2782  *                to remove the header.  This function frees the
2783  *                original string if necessary.
2784  *
2785  * Returns     :  JB_ERR_OK on success, or
2786  *                JB_ERR_MEMORY on out-of-memory error.
2787  *
2788  *********************************************************************/
2789 static jb_err server_adjust_content_length(struct client_state *csp, char **header)
2790 {
2791    const size_t max_header_length = 80;
2792
2793    /* Regenerate header if the content was modified. */
2794    if (csp->flags & CSP_FLAG_MODIFIED)
2795    {
2796       freez(*header);
2797       *header = (char *) zalloc(max_header_length);
2798       if (*header == NULL)
2799       {
2800          return JB_ERR_MEMORY;
2801       }
2802
2803       snprintf(*header, max_header_length, "Content-Length: %d",
2804          (int)csp->content_length);
2805       log_error(LOG_LEVEL_HEADER, "Adjusted Content-Length to %d",
2806          (int)csp->content_length);
2807    }
2808
2809    return JB_ERR_OK;
2810 }
2811
2812
2813 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
2814 /*********************************************************************
2815  *
2816  * Function    :  server_save_content_length
2817  *
2818  * Description :  Save the Content-Length sent by the server.
2819  *
2820  * Parameters  :
2821  *          1  :  csp = Current client state (buffers, headers, etc...)
2822  *          2  :  header = On input, pointer to header to modify.
2823  *                On output, pointer to the modified header, or NULL
2824  *                to remove the header.  This function frees the
2825  *                original string if necessary.
2826  *
2827  * Returns     :  JB_ERR_OK on success, or
2828  *                JB_ERR_MEMORY on out-of-memory error.
2829  *
2830  *********************************************************************/
2831 static jb_err server_save_content_length(struct client_state *csp, char **header)
2832 {
2833    unsigned long long content_length = 0;
2834
2835    assert(*(*header+14) == ':');
2836
2837    if (1 != sscanf(*header+14, ": %llu", &content_length))
2838    {
2839       log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header);
2840       freez(*header);
2841    }
2842    else
2843    {
2844       csp->expected_content_length = content_length;
2845       csp->flags |= CSP_FLAG_CONTENT_LENGTH_SET;
2846    }
2847
2848    return JB_ERR_OK;
2849 }
2850 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
2851
2852
2853 /*********************************************************************
2854  *
2855  * Function    :  server_content_md5
2856  *
2857  * Description :  Crumble any Content-MD5 headers if the document was
2858  *                modified. FIXME: Should we re-compute instead?
2859  *
2860  * Parameters  :
2861  *          1  :  csp = Current client state (buffers, headers, etc...)
2862  *          2  :  header = On input, pointer to header to modify.
2863  *                On output, pointer to the modified header, or NULL
2864  *                to remove the header.  This function frees the
2865  *                original string if necessary.
2866  *
2867  * Returns     :  JB_ERR_OK on success, or
2868  *                JB_ERR_MEMORY on out-of-memory error.
2869  *
2870  *********************************************************************/
2871 static jb_err server_content_md5(struct client_state *csp, char **header)
2872 {
2873    if (csp->flags & CSP_FLAG_MODIFIED)
2874    {
2875       log_error(LOG_LEVEL_HEADER, "Crunching Content-MD5");
2876       freez(*header);
2877    }
2878
2879    return JB_ERR_OK;
2880 }
2881
2882
2883 /*********************************************************************
2884  *
2885  * Function    :  server_content_disposition
2886  *
2887  * Description :  If enabled, blocks or modifies the "Content-Disposition" header.
2888  *                Called from `sed'.
2889  *
2890  * Parameters  :
2891  *          1  :  csp = Current client state (buffers, headers, etc...)
2892  *          2  :  header = On input, pointer to header to modify.
2893  *                On output, pointer to the modified header, or NULL
2894  *                to remove the header.  This function frees the
2895  *                original string if necessary.
2896  *
2897  * Returns     :  JB_ERR_OK on success, or
2898  *                JB_ERR_MEMORY on out-of-memory error.
2899  *
2900  *********************************************************************/
2901 static jb_err server_content_disposition(struct client_state *csp, char **header)
2902 {
2903    const char *newval;
2904
2905    /*
2906     * Are we messing with the Content-Disposition header?
2907     */
2908    if ((csp->action->flags & ACTION_HIDE_CONTENT_DISPOSITION) == 0)
2909    {
2910       /* Me tinks not */
2911       return JB_ERR_OK;
2912    }
2913
2914    newval = csp->action->string[ACTION_STRING_CONTENT_DISPOSITION];
2915
2916    if ((newval == NULL) || (0 == strcmpic(newval, "block")))
2917    {
2918       /*
2919        * Blocking content-disposition header
2920        */
2921       log_error(LOG_LEVEL_HEADER, "Crunching %s!", *header);
2922       freez(*header);
2923       return JB_ERR_OK;
2924    }
2925    else
2926    {  
2927       /*
2928        * Replacing Content-Disposition header
2929        */
2930       freez(*header);
2931       *header = strdup("Content-Disposition: ");
2932       string_append(header, newval);
2933
2934       if (*header != NULL)
2935       {
2936          log_error(LOG_LEVEL_HEADER,
2937             "Content-Disposition header crunched and replaced with: %s", *header);
2938       }
2939    }
2940    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2941 }
2942
2943
2944 /*********************************************************************
2945  *
2946  * Function    :  server_last_modified
2947  *
2948  * Description :  Changes Last-Modified header to the actual date
2949  *                to help hide-if-modified-since.
2950  *                Called from `sed'.
2951  *
2952  * Parameters  :
2953  *          1  :  csp = Current client state (buffers, headers, etc...)
2954  *          2  :  header = On input, pointer to header to modify.
2955  *                On output, pointer to the modified header, or NULL
2956  *                to remove the header.  This function frees the
2957  *                original string if necessary.
2958  *
2959  * Returns     :  JB_ERR_OK on success, or
2960  *                JB_ERR_MEMORY on out-of-memory error.
2961  *
2962  *********************************************************************/
2963 static jb_err server_last_modified(struct client_state *csp, char **header)
2964 {
2965    const char *newval;
2966    char buf[BUFFER_SIZE];
2967
2968    char newheader[50];
2969 #ifdef HAVE_GMTIME_R
2970    struct tm gmt;
2971 #endif
2972    struct tm *timeptr = NULL;
2973    time_t now, last_modified;                  
2974    long int rtime;
2975    long int days, hours, minutes, seconds;
2976    
2977    /*
2978     * Are we messing with the Last-Modified header?
2979     */
2980    if ((csp->action->flags & ACTION_OVERWRITE_LAST_MODIFIED) == 0)
2981    {
2982       /*Nope*/
2983       return JB_ERR_OK;
2984    }
2985
2986    newval = csp->action->string[ACTION_STRING_LAST_MODIFIED];
2987
2988    if (0 == strcmpic(newval, "block") )
2989    {
2990       /*
2991        * Blocking Last-Modified header. Useless but why not.
2992        */
2993       log_error(LOG_LEVEL_HEADER, "Crunching %s!", *header);
2994       freez(*header);
2995       return JB_ERR_OK;
2996    }
2997    else if (0 == strcmpic(newval, "reset-to-request-time"))
2998    {  
2999       /*
3000        * Setting Last-Modified Header to now.
3001        */
3002       get_http_time(0, buf, sizeof(buf));
3003       freez(*header);
3004       *header = strdup("Last-Modified: ");
3005       string_append(header, buf);   
3006
3007       if (*header == NULL)
3008       {
3009          log_error(LOG_LEVEL_HEADER, "Insufficient memory. Last-Modified header got lost, boohoo.");  
3010       }
3011       else
3012       {
3013          log_error(LOG_LEVEL_HEADER, "Reset to present time: %s", *header);
3014       }
3015    }
3016    else if (0 == strcmpic(newval, "randomize"))
3017    {
3018       const char *header_time = *header + sizeof("Last-Modified:");
3019
3020       log_error(LOG_LEVEL_HEADER, "Randomizing: %s", *header);
3021       now = time(NULL);
3022 #ifdef HAVE_GMTIME_R
3023       timeptr = gmtime_r(&now, &gmt);
3024 #elif FEATURE_PTHREAD
3025       privoxy_mutex_lock(&gmtime_mutex);
3026       timeptr = gmtime(&now);
3027       privoxy_mutex_unlock(&gmtime_mutex);
3028 #else
3029       timeptr = gmtime(&now);
3030 #endif
3031       if (JB_ERR_OK != parse_header_time(header_time, &last_modified))
3032       {
3033          log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s in %s (crunching!)", header_time, *header);
3034          freez(*header);
3035       }
3036       else
3037       {
3038          rtime = (long int)difftime(now, last_modified);
3039          if (rtime)
3040          {
3041             int negative = 0;
3042
3043             if (rtime < 0)
3044             {
3045                rtime *= -1; 
3046                negative = 1;
3047                log_error(LOG_LEVEL_HEADER, "Server time in the future.");
3048             }
3049             rtime = pick_from_range(rtime);
3050             if (negative) rtime *= -1;
3051             last_modified += rtime;
3052 #ifdef HAVE_GMTIME_R
3053             timeptr = gmtime_r(&last_modified, &gmt);
3054 #elif FEATURE_PTHREAD
3055             privoxy_mutex_lock(&gmtime_mutex);
3056             timeptr = gmtime(&last_modified);
3057             privoxy_mutex_unlock(&gmtime_mutex);
3058 #else
3059             timeptr = gmtime(&last_modified);
3060 #endif
3061             strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr);
3062             freez(*header);
3063             *header = strdup("Last-Modified: ");
3064             string_append(header, newheader);
3065
3066             if (*header == NULL)
3067             {
3068                log_error(LOG_LEVEL_ERROR, "Insufficient memory, header crunched without replacement.");
3069                return JB_ERR_MEMORY;  
3070             }
3071
3072             days    = rtime / (3600 * 24);
3073             hours   = rtime / 3600 % 24;
3074             minutes = rtime / 60 % 60;
3075             seconds = rtime % 60;
3076
3077             log_error(LOG_LEVEL_HEADER,
3078                "Randomized:  %s (added %d da%s %d hou%s %d minut%s %d second%s",
3079                *header, days, (days == 1) ? "y" : "ys", hours, (hours == 1) ? "r" : "rs",
3080                minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)");
3081          }
3082          else
3083          {
3084             log_error(LOG_LEVEL_HEADER, "Randomized ... or not. No time difference to work with.");
3085          }
3086       }
3087    }
3088
3089    return JB_ERR_OK;
3090 }
3091
3092
3093 /*********************************************************************
3094  *
3095  * Function    :  client_accept_encoding
3096  *
3097  * Description :  Rewrite the client's Accept-Encoding header so that
3098  *                if doesn't allow compression, if the action applies.
3099  *                Note: For HTTP/1.0 the absence of the header is enough.
3100  *
3101  * Parameters  :
3102  *          1  :  csp = Current client state (buffers, headers, etc...)
3103  *          2  :  header = On input, pointer to header to modify.
3104  *                On output, pointer to the modified header, or NULL
3105  *                to remove the header.  This function frees the
3106  *                original string if necessary.
3107  *
3108  * Returns     :  JB_ERR_OK on success, or
3109  *                JB_ERR_MEMORY on out-of-memory error.
3110  *
3111  *********************************************************************/
3112 static jb_err client_accept_encoding(struct client_state *csp, char **header)
3113 {
3114    if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
3115    {
3116       log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress content");
3117
3118       freez(*header);
3119
3120       /* Temporarily disable the correct behaviour to
3121        * work around a PHP bug. 
3122        *
3123        * if (!strcmpic(csp->http->ver, "HTTP/1.1"))
3124        * {
3125        *    *header = strdup("Accept-Encoding: identity;q=1.0, *;q=0");
3126        *    if (*header == NULL)
3127        *    {
3128        *       return JB_ERR_MEMORY;
3129        *    }
3130        * }
3131        * 
3132        */
3133    }
3134
3135    return JB_ERR_OK;
3136 }
3137
3138
3139 /*********************************************************************
3140  *
3141  * Function    :  client_te
3142  *
3143  * Description :  Rewrite the client's TE header so that
3144  *                if doesn't allow compression, if the action applies.
3145  *
3146  * Parameters  :
3147  *          1  :  csp = Current client state (buffers, headers, etc...)
3148  *          2  :  header = On input, pointer to header to modify.
3149  *                On output, pointer to the modified header, or NULL
3150  *                to remove the header.  This function frees the
3151  *                original string if necessary.
3152  *
3153  * Returns     :  JB_ERR_OK on success, or
3154  *                JB_ERR_MEMORY on out-of-memory error.
3155  *
3156  *********************************************************************/
3157 static jb_err client_te(struct client_state *csp, char **header)
3158 {
3159    if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
3160    {
3161       freez(*header);
3162       log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress transfer");
3163    }
3164
3165    return JB_ERR_OK;
3166 }
3167
3168
3169 /*********************************************************************
3170  *
3171  * Function    :  client_referrer
3172  *
3173  * Description :  Handle the "referer" config setting properly.
3174  *                Called from `sed'.
3175  *
3176  * Parameters  :
3177  *          1  :  csp = Current client state (buffers, headers, etc...)
3178  *          2  :  header = On input, pointer to header to modify.
3179  *                On output, pointer to the modified header, or NULL
3180  *                to remove the header.  This function frees the
3181  *                original string if necessary.
3182  *
3183  * Returns     :  JB_ERR_OK on success, or
3184  *                JB_ERR_MEMORY on out-of-memory error.
3185  *
3186  *********************************************************************/
3187 static jb_err client_referrer(struct client_state *csp, char **header)
3188 {
3189    const char *parameter;
3190    /* booleans for parameters we have to check multiple times */
3191    int parameter_conditional_block;
3192    int parameter_conditional_forge;
3193  
3194 #ifdef FEATURE_FORCE_LOAD
3195    /*
3196     * Since the referrer can include the prefix even
3197     * if the request itself is non-forced, we must
3198     * clean it unconditionally.
3199     *
3200     * XXX: strclean is too broad
3201     */
3202    strclean(*header, FORCE_PREFIX);
3203 #endif /* def FEATURE_FORCE_LOAD */
3204
3205    if ((csp->action->flags & ACTION_HIDE_REFERER) == 0)
3206    {
3207       /* Nothing left to do */
3208       return JB_ERR_OK;
3209    }
3210
3211    parameter = csp->action->string[ACTION_STRING_REFERER];
3212    assert(parameter != NULL);
3213    parameter_conditional_block = (0 == strcmpic(parameter, "conditional-block"));
3214    parameter_conditional_forge = (0 == strcmpic(parameter, "conditional-forge"));
3215
3216    if (!parameter_conditional_block && !parameter_conditional_forge)
3217    {
3218       /*
3219        * As conditional-block and conditional-forge are the only
3220        * parameters that rely on the original referrer, we can
3221        * remove it now for all the others.
3222        */
3223       freez(*header);
3224    }
3225
3226    if (0 == strcmpic(parameter, "block"))
3227    {
3228       log_error(LOG_LEVEL_HEADER, "Referer crunched!");
3229       return JB_ERR_OK;
3230    }
3231    else if (parameter_conditional_block || parameter_conditional_forge)
3232    {
3233       return handle_conditional_hide_referrer_parameter(header,
3234          csp->http->hostport, parameter_conditional_block);
3235    }
3236    else if (0 == strcmpic(parameter, "forge"))
3237    {
3238       return create_forged_referrer(header, csp->http->hostport);
3239    }
3240    else
3241    {
3242       /* interpret parameter as user-supplied referer to fake */
3243       return create_fake_referrer(header, parameter);
3244    }
3245 }
3246
3247
3248 /*********************************************************************
3249  *
3250  * Function    :  client_accept_language
3251  *
3252  * Description :  Handle the "Accept-Language" config setting properly.
3253  *                Called from `sed'.
3254  *
3255  * Parameters  :
3256  *          1  :  csp = Current client state (buffers, headers, etc...)
3257  *          2  :  header = On input, pointer to header to modify.
3258  *                On output, pointer to the modified header, or NULL
3259  *                to remove the header.  This function frees the
3260  *                original string if necessary.
3261  *
3262  * Returns     :  JB_ERR_OK on success, or
3263  *                JB_ERR_MEMORY on out-of-memory error.
3264  *
3265  *********************************************************************/
3266 static jb_err client_accept_language(struct client_state *csp, char **header)
3267 {
3268    const char *newval;
3269
3270    /*
3271     * Are we messing with the Accept-Language?
3272     */
3273    if ((csp->action->flags & ACTION_HIDE_ACCEPT_LANGUAGE) == 0)
3274    {
3275       /*I don't think so*/
3276       return JB_ERR_OK;
3277    }
3278
3279    newval = csp->action->string[ACTION_STRING_LANGUAGE];
3280
3281    if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
3282    {
3283       /*
3284        * Blocking Accept-Language header
3285        */
3286       log_error(LOG_LEVEL_HEADER, "Crunching Accept-Language!");
3287       freez(*header);
3288       return JB_ERR_OK;
3289    }
3290    else
3291    {  
3292       /*
3293        * Replacing Accept-Language header
3294        */
3295       freez(*header);
3296       *header = strdup("Accept-Language: ");
3297       string_append(header, newval);   
3298
3299       if (*header == NULL)
3300       {
3301          log_error(LOG_LEVEL_ERROR,
3302             "Insufficient memory. Accept-Language header crunched without replacement.");  
3303       }
3304       else
3305       {
3306          log_error(LOG_LEVEL_HEADER,
3307             "Accept-Language header crunched and replaced with: %s", *header);
3308       }
3309    }
3310    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
3311 }
3312
3313
3314 /*********************************************************************
3315  *
3316  * Function    :  crunch_client_header
3317  *
3318  * Description :  Crunch client header if it matches a string supplied by the
3319  *                user. Called from `sed'.
3320  *
3321  * Parameters  :
3322  *          1  :  csp = Current client state (buffers, headers, etc...)
3323  *          2  :  header = On input, pointer to header to modify.
3324  *                On output, pointer to the modified header, or NULL
3325  *                to remove the header.  This function frees the
3326  *                original string if necessary.
3327  *
3328  * Returns     :  JB_ERR_OK on success and always succeeds
3329  *
3330  *********************************************************************/
3331 static jb_err crunch_client_header(struct client_state *csp, char **header)
3332 {
3333    const char *crunch_pattern;
3334
3335    /* Do we feel like crunching? */
3336    if ((csp->action->flags & ACTION_CRUNCH_CLIENT_HEADER))
3337    {
3338       crunch_pattern = csp->action->string[ACTION_STRING_CLIENT_HEADER];
3339
3340       /* Is the current header the lucky one? */
3341       if (strstr(*header, crunch_pattern))
3342       {
3343          log_error(LOG_LEVEL_HEADER, "Crunching client header: %s (contains: %s)", *header, crunch_pattern);  
3344          freez(*header);
3345       }
3346    }
3347    return JB_ERR_OK;
3348 }
3349
3350
3351 /*********************************************************************
3352  *
3353  * Function    :  client_uagent
3354  *
3355  * Description :  Handle the "user-agent" config setting properly
3356  *                and remember its original value to enable browser
3357  *                bug workarounds. Called from `sed'.
3358  *
3359  * Parameters  :
3360  *          1  :  csp = Current client state (buffers, headers, etc...)
3361  *          2  :  header = On input, pointer to header to modify.
3362  *                On output, pointer to the modified header, or NULL
3363  *                to remove the header.  This function frees the
3364  *                original string if necessary.
3365  *
3366  * Returns     :  JB_ERR_OK on success, or
3367  *                JB_ERR_MEMORY on out-of-memory error.
3368  *
3369  *********************************************************************/
3370 static jb_err client_uagent(struct client_state *csp, char **header)
3371 {
3372    const char *newval;
3373
3374    if ((csp->action->flags & ACTION_HIDE_USER_AGENT) == 0)
3375    {
3376       return JB_ERR_OK;
3377    }
3378
3379    newval = csp->action->string[ACTION_STRING_USER_AGENT];
3380    if (newval == NULL)
3381    {
3382       return JB_ERR_OK;
3383    }
3384
3385    freez(*header);
3386    *header = strdup("User-Agent: ");
3387    string_append(header, newval);
3388
3389    log_error(LOG_LEVEL_HEADER, "Modified: %s", *header);
3390
3391    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
3392 }
3393
3394
3395 /*********************************************************************
3396  *
3397  * Function    :  client_ua
3398  *
3399  * Description :  Handle "ua-" headers properly.  Called from `sed'.
3400  *
3401  * Parameters  :
3402  *          1  :  csp = Current client state (buffers, headers, etc...)
3403  *          2  :  header = On input, pointer to header to modify.
3404  *                On output, pointer to the modified header, or NULL
3405  *                to remove the header.  This function frees the
3406  *                original string if necessary.
3407  *
3408  * Returns     :  JB_ERR_OK on success, or
3409  *                JB_ERR_MEMORY on out-of-memory error.
3410  *
3411  *********************************************************************/
3412 static jb_err client_ua(struct client_state *csp, char **header)
3413 {
3414    if ((csp->action->flags & ACTION_HIDE_USER_AGENT) != 0)
3415    {
3416       log_error(LOG_LEVEL_HEADER, "crunched User-Agent!");
3417       freez(*header);
3418    }
3419
3420    return JB_ERR_OK;
3421 }
3422
3423
3424 /*********************************************************************
3425  *
3426  * Function    :  client_from
3427  *
3428  * Description :  Handle the "from" config setting properly.
3429  *                Called from `sed'.
3430  *
3431  * Parameters  :
3432  *          1  :  csp = Current client state (buffers, headers, etc...)
3433  *          2  :  header = On input, pointer to header to modify.
3434  *                On output, pointer to the modified header, or NULL
3435  *                to remove the header.  This function frees the
3436  *                original string if necessary.
3437  *
3438  * Returns     :  JB_ERR_OK on success, or
3439  *                JB_ERR_MEMORY on out-of-memory error.
3440  *
3441  *********************************************************************/
3442 static jb_err client_from(struct client_state *csp, char **header)
3443 {
3444    const char *newval;
3445
3446    if ((csp->action->flags & ACTION_HIDE_FROM) == 0)
3447    {
3448       return JB_ERR_OK;
3449    }
3450
3451    freez(*header);
3452
3453    newval = csp->action->string[ACTION_STRING_FROM];
3454
3455    /*
3456     * Are we blocking the e-mail address?
3457     */
3458    if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
3459    {
3460       log_error(LOG_LEVEL_HEADER, "crunched From!");
3461       return JB_ERR_OK;
3462    }
3463
3464    log_error(LOG_LEVEL_HEADER, " modified");
3465
3466    *header = strdup("From: ");
3467    string_append(header, newval);
3468
3469    return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
3470 }
3471
3472
3473 /*********************************************************************
3474  *
3475  * Function    :  client_send_cookie
3476  *
3477  * Description :  Crunches the "cookie" header if necessary.
3478  *                Called from `sed'.
3479  *
3480  *                XXX: Stupid name, doesn't send squat.
3481  *
3482  * Parameters  :
3483  *          1  :  csp = Current client state (buffers, headers, etc...)
3484  *          2  :  header = On input, pointer to header to modify.
3485  *                On output, pointer to the modified header, or NULL
3486  *                to remove the header.  This function frees the
3487  *                original string if necessary.
3488  *
3489  * Returns     :  JB_ERR_OK on success, or
3490  *                JB_ERR_MEMORY on out-of-memory error.
3491  *
3492  *********************************************************************/
3493 static jb_err client_send_cookie(struct client_state *csp, char **header)
3494 {
3495    if (csp->action->flags & ACTION_NO_COOKIE_READ)
3496    {
3497       log_error(LOG_LEVEL_HEADER, "Crunched outgoing cookie: %s", *header);
3498       freez(*header);
3499    }
3500
3501    return JB_ERR_OK;
3502 }
3503
3504
3505 /*********************************************************************
3506  *
3507  * Function    :  client_x_forwarded
3508  *
3509  * Description :  Handle the "x-forwarded-for" config setting properly,
3510  *                also used in the add_client_headers list.  Called from `sed'.
3511  *
3512  * Parameters  :
3513  *          1  :  csp = Current client state (buffers, headers, etc...)
3514  *          2  :  header = On input, pointer to header to modify.
3515  *                On output, pointer to the modified header, or NULL
3516  *                to remove the header.  This function frees the
3517  *                original string if necessary.
3518  *
3519  * Returns     :  JB_ERR_OK on success, or
3520  *                JB_ERR_MEMORY on out-of-memory error.
3521  *
3522  *********************************************************************/
3523 jb_err client_x_forwarded(struct client_state *csp, char **header)
3524 {
3525    if (0 != (csp->action->flags & ACTION_CHANGE_X_FORWARDED_FOR))
3526    {
3527       const char *parameter = csp->action->string[ACTION_STRING_CHANGE_X_FORWARDED_FOR];
3528
3529       if (0 == strcmpic(parameter, "block"))
3530       {
3531          freez(*header);
3532          log_error(LOG_LEVEL_HEADER, "crunched x-forwarded-for!");
3533       }
3534       else if (0 == strcmpic(parameter, "add"))
3535       {
3536          string_append(header, ", ");
3537          string_append(header, csp->ip_addr_str);
3538
3539          if (*header == NULL)
3540          {
3541             return JB_ERR_MEMORY;
3542          }
3543          log_error(LOG_LEVEL_HEADER,
3544             "Appended client IP address to %s", *header);
3545          csp->flags |= CSP_FLAG_X_FORWARDED_FOR_APPENDED;
3546       }
3547       else
3548       {
3549          log_error(LOG_LEVEL_FATAL,
3550             "Invalid change-x-forwarded-for parameter: '%s'", parameter);
3551       }
3552    }
3553
3554    return JB_ERR_OK;
3555 }
3556
3557
3558 /*********************************************************************
3559  *
3560  * Function    :  client_max_forwards
3561  *
3562  * Description :  If the HTTP method is OPTIONS or TRACE, subtract one
3563  *                from the value of the Max-Forwards header field.
3564  *
3565  * Parameters  :
3566  *          1  :  csp = Current client state (buffers, headers, etc...)
3567  *          2  :  header = On input, pointer to header to modify.
3568  *                On output, pointer to the modified header, or NULL
3569  *                to remove the header.  This function frees the
3570  *                original string if necessary.
3571  *
3572  * Returns     :  JB_ERR_OK on success, or
3573  *                JB_ERR_MEMORY on out-of-memory error.
3574  *
3575  *********************************************************************/
3576 static jb_err client_max_forwards(struct client_state *csp, char **header)
3577 {
3578    int max_forwards;
3579
3580    if ((0 == strcmpic(csp->http->gpc, "trace")) ||
3581        (0 == strcmpic(csp->http->gpc, "options")))
3582    {
3583       assert(*(*header+12) == ':');
3584       if (1 == sscanf(*header+12, ": %d", &max_forwards))
3585       {
3586          if (max_forwards > 0)
3587          {
3588             snprintf(*header, strlen(*header)+1, "Max-Forwards: %d", --max_forwards);
3589             log_error(LOG_LEVEL_HEADER,
3590                "Max-Forwards value for %s request reduced to %d.",
3591                csp->http->gpc, max_forwards);
3592          }
3593          else if (max_forwards < 0)
3594          {
3595             log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header);
3596             freez(*header);
3597          }
3598       }
3599       else
3600       {
3601          log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header);
3602          freez(*header);
3603       }
3604    }
3605
3606    return JB_ERR_OK;
3607 }
3608
3609
3610 /*********************************************************************
3611  *
3612  * Function    :  client_host
3613  *
3614  * Description :  If the request URI did not contain host and
3615  *                port information, parse and evaluate the Host
3616  *                header field.
3617  *
3618  *                Also, kill ill-formed HOST: headers as sent by
3619  *                Apple's iTunes software when used with a proxy.
3620  *
3621  * Parameters  :
3622  *          1  :  csp = Current client state (buffers, headers, etc...)
3623  *          2  :  header = On input, pointer to header to modify.
3624  *                On output, pointer to the modified header, or NULL
3625  *                to remove the header.  This function frees the
3626  *                original string if necessary.
3627  *
3628  * Returns     :  JB_ERR_OK on success, or
3629  *                JB_ERR_MEMORY on out-of-memory error.
3630  *
3631  *********************************************************************/
3632 static jb_err client_host(struct client_state *csp, char **header)
3633 {
3634    char *p, *q;
3635
3636    /*
3637     * If the header field name is all upper-case, chances are that it's
3638     * an ill-formed one from iTunes. BTW, killing innocent headers here is
3639     * not a problem -- they are regenerated later.
3640     */
3641    if ((*header)[1] == 'O')
3642    {
3643       log_error(LOG_LEVEL_HEADER, "Killed all-caps Host header line: %s", *header);
3644       freez(*header);
3645       return JB_ERR_OK;
3646    }
3647
3648    if (!csp->http->hostport || (*csp->http->hostport == '*') ||  
3649        *csp->http->hostport == ' ' || *csp->http->hostport == '\0')
3650    {
3651       
3652       if (NULL == (p = strdup((*header)+6)))
3653       {
3654          return JB_ERR_MEMORY;
3655       }
3656       chomp(p);
3657       if (NULL == (q = strdup(p)))
3658       {
3659          freez(p);
3660          return JB_ERR_MEMORY;
3661       }
3662
3663       freez(csp->http->hostport);
3664       csp->http->hostport = p;
3665       freez(csp->http->host);
3666       csp->http->host = q;
3667       q = strchr(csp->http->host, ':');
3668       if (q != NULL)
3669       {
3670          /* Terminate hostname and evaluate port string */
3671          *q++ = '\0';
3672          csp->http->port = atoi(q);
3673       }
3674       else
3675       {
3676          csp->http->port = csp->http->ssl ? 443 : 80;
3677       }
3678
3679       log_error(LOG_LEVEL_HEADER, "New host and port from Host field: %s = %s:%d",
3680                 csp->http->hostport, csp->http->host, csp->http->port);
3681    }
3682
3683    /* Signal client_host_adder() to return right away */
3684    csp->flags |= CSP_FLAG_HOST_HEADER_IS_SET;
3685
3686    return JB_ERR_OK;
3687 }
3688
3689
3690 /*********************************************************************
3691  *
3692  * Function    :  client_if_modified_since
3693  *
3694  * Description :  Remove or modify the If-Modified-Since header.
3695  *
3696  * Parameters  :
3697  *          1  :  csp = Current client state (buffers, headers, etc...)
3698  *          2  :  header = On input, pointer to header to modify.
3699  *                On output, pointer to the modified header, or NULL
3700  *                to remove the header.  This function frees the
3701  *                original string if necessary.
3702  *
3703  * Returns     :  JB_ERR_OK on success, or
3704  *                JB_ERR_MEMORY on out-of-memory error.
3705  *
3706  *********************************************************************/
3707 static jb_err client_if_modified_since(struct client_state *csp, char **header)
3708 {
3709    char newheader[50];
3710 #ifdef HAVE_GMTIME_R
3711    struct tm gmt;
3712 #endif
3713    struct tm *timeptr = NULL;
3714    time_t tm = 0;                  
3715    const char *newval;
3716    long int rtime;
3717    long int hours, minutes, seconds;
3718    int negative = 0;
3719    char * endptr;
3720    
3721    if ( 0 == strcmpic(*header, "If-Modified-Since: Wed, 08 Jun 1955 12:00:00 GMT"))
3722    {
3723       /* 
3724        * The client got an error message because of a temporary problem,
3725        * the problem is gone and the client now tries to revalidate our
3726        * error message on the real server. The revalidation would always
3727        * end with the transmission of the whole document and there is
3728        * no need to expose the bogus If-Modified-Since header.
3729        */
3730       log_error(LOG_LEVEL_HEADER, "Crunching useless If-Modified-Since header.");
3731       freez(*header);
3732    }
3733    else if (csp->action->flags & ACTION_HIDE_IF_MODIFIED_SINCE)
3734    {
3735       newval = csp->action->string[ACTION_STRING_IF_MODIFIED_SINCE];
3736
3737       if ((0 == strcmpic(newval, "block")))
3738       {
3739          log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
3740          freez(*header);
3741       }
3742       else /* add random value */
3743       {
3744          const char *header_time = *header + sizeof("If-Modified-Since:");
3745
3746          if (JB_ERR_OK != parse_header_time(header_time, &tm))
3747          {
3748             log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s in %s (crunching!)", header_time, *header);
3749             freez(*header);
3750          }
3751          else
3752          {
3753             rtime = strtol(newval, &endptr, 0);
3754             if (rtime)
3755             {
3756                log_error(LOG_LEVEL_HEADER, "Randomizing: %s (random range: %d minut%s)",
3757                   *header, rtime, (rtime == 1 || rtime == -1) ? "e": "es");
3758                if (rtime < 0)
3759                {
3760                   rtime *= -1; 
3761                   negative = 1;
3762                }
3763                rtime *= 60;
3764                rtime = pick_from_range(rtime);
3765             }
3766             else
3767             {
3768                log_error(LOG_LEVEL_ERROR, "Random range is 0. Assuming time transformation test.",
3769                   *header);
3770             }
3771             tm += rtime * (negative ? -1 : 1);
3772 #ifdef HAVE_GMTIME_R
3773             timeptr = gmtime_r(&tm, &gmt);
3774 #elif FEATURE_PTHREAD
3775             privoxy_mutex_lock(&gmtime_mutex);
3776             timeptr = gmtime(&tm);
3777             privoxy_mutex_unlock(&gmtime_mutex);
3778 #else
3779             timeptr = gmtime(&tm);
3780 #endif
3781             strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr);
3782
3783             freez(*header);
3784             *header = strdup("If-Modified-Since: ");
3785             string_append(header, newheader);
3786
3787             if (*header == NULL)
3788             {
3789                log_error(LOG_LEVEL_HEADER, "Insufficient memory, header crunched without replacement.");
3790                return JB_ERR_MEMORY;  
3791             }
3792
3793             hours   = rtime / 3600;
3794             minutes = rtime / 60 % 60;
3795             seconds = rtime % 60;
3796
3797             log_error(LOG_LEVEL_HEADER,
3798                "Randomized:  %s (%s %d hou%s %d minut%s %d second%s",
3799                *header, (negative) ? "subtracted" : "added", hours,
3800                (hours == 1) ? "r" : "rs", minutes, (minutes == 1) ? "e" : "es",
3801                seconds, (seconds == 1) ? ")" : "s)");
3802          }
3803       }
3804    }
3805
3806    return JB_ERR_OK;
3807 }
3808
3809
3810 /*********************************************************************
3811  *
3812  * Function    :  client_if_none_match
3813  *
3814  * Description :  Remove the If-None-Match header.
3815  *
3816  * Parameters  :
3817  *          1  :  csp = Current client state (buffers, headers, etc...)
3818  *          2  :  header = On input, pointer to header to modify.
3819  *                On output, pointer to the modified header, or NULL
3820  *                to remove the header.  This function frees the
3821  *                original string if necessary.
3822  *
3823  * Returns     :  JB_ERR_OK on success, or
3824  *                JB_ERR_MEMORY on out-of-memory error.
3825  *
3826  *********************************************************************/
3827 static jb_err client_if_none_match(struct client_state *csp, char **header)
3828 {
3829    if (csp->action->flags & ACTION_CRUNCH_IF_NONE_MATCH)
3830    {  
3831       log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
3832       freez(*header);
3833    }
3834
3835    return JB_ERR_OK;
3836 }
3837
3838
3839 /*********************************************************************
3840  *
3841  * Function    :  client_x_filter
3842  *
3843  * Description :  Disables filtering if the client set "X-Filter: No".
3844  *                Called from `sed'.
3845  *
3846  * Parameters  :
3847  *          1  :  csp = Current client state (buffers, headers, etc...)
3848  *          2  :  header = On input, pointer to header to modify.
3849  *                On output, pointer to the modified header, or NULL
3850  *                to remove the header.  This function frees the
3851  *                original string if necessary.
3852  *
3853  * Returns     :  JB_ERR_OK on success
3854  *
3855  *********************************************************************/
3856 jb_err client_x_filter(struct client_state *csp, char **header)
3857 {
3858    if ( 0 == strcmpic(*header, "X-Filter: No"))
3859    {
3860       if (!(csp->config->feature_flags & RUNTIME_FEATURE_HTTP_TOGGLE))
3861       {
3862          log_error(LOG_LEVEL_INFO, "Ignored the client's request to fetch without filtering.");
3863       }
3864       else
3865       {
3866          if (csp->action->flags & ACTION_FORCE_TEXT_MODE)
3867          {
3868             log_error(LOG_LEVEL_HEADER,
3869                "force-text-mode overruled the client's request to fetch without filtering!");
3870          }
3871          else
3872          {  
3873             csp->content_type = CT_TABOO; /* XXX: This hack shouldn't be necessary */
3874             csp->flags |= CSP_FLAG_NO_FILTERING;
3875             log_error(LOG_LEVEL_HEADER, "Accepted the client's request to fetch without filtering.");
3876          }
3877          log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
3878          freez(*header);
3879       }
3880    }
3881    return JB_ERR_OK; 
3882 }
3883
3884
3885 /*********************************************************************
3886  *
3887  * Function    :  client_range
3888  *
3889  * Description :  Removes Range, Request-Range and If-Range headers if
3890  *                content filtering is enabled. If the client's version
3891  *                of the document has been altered by Privoxy, the server
3892  *                could interpret the range differently than the client
3893  *                intended in which case the user could end up with
3894  *                corrupted content.
3895  *
3896  * Parameters  :
3897  *          1  :  csp = Current client state (buffers, headers, etc...)
3898  *          2  :  header = On input, pointer to header to modify.
3899  *                On output, pointer to the modified header, or NULL
3900  *                to remove the header.  This function frees the
3901  *                original string if necessary.
3902  *
3903  * Returns     :  JB_ERR_OK
3904  *
3905  *********************************************************************/
3906 static jb_err client_range(struct client_state *csp, char **header)
3907 {
3908    if (content_filters_enabled(csp->action))
3909    {
3910       log_error(LOG_LEVEL_HEADER, "Content filtering is enabled."
3911          " Crunching: \'%s\' to prevent range-mismatch problems.", *header);
3912       freez(*header);
3913    }
3914
3915    return JB_ERR_OK; 
3916 }
3917
3918 /* the following functions add headers directly to the header list */
3919
3920 /*********************************************************************
3921  *
3922  * Function    :  client_host_adder
3923  *
3924  * Description :  Adds the Host: header field if it is missing.
3925  *                Called from `sed'.
3926  *
3927  * Parameters  :
3928  *          1  :  csp = Current client state (buffers, headers, etc...)
3929  *
3930  * Returns     :  JB_ERR_OK on success, or
3931  *                JB_ERR_MEMORY on out-of-memory error.
3932  *
3933  *********************************************************************/
3934 static jb_err client_host_adder(struct client_state *csp)
3935 {
3936    char *p;
3937    jb_err err;
3938
3939    if (csp->flags & CSP_FLAG_HOST_HEADER_IS_SET)
3940    {
3941       /* Header already set by the client, nothing to do. */
3942       return JB_ERR_OK;
3943    }
3944
3945    if ( !csp->http->hostport || !*(csp->http->hostport))
3946    {
3947       /* XXX: When does this happen and why is it OK? */
3948       log_error(LOG_LEVEL_INFO, "Weirdness in client_host_adder detected and ignored.");
3949       return JB_ERR_OK;
3950    }
3951
3952    /*
3953     * remove 'user:pass@' from 'proto://user:pass@host'
3954     */
3955    if ( (p = strchr( csp->http->hostport, '@')) != NULL )
3956    {
3957       p++;
3958    }
3959    else
3960    {
3961       p = csp->http->hostport;
3962    }
3963
3964    /* XXX: Just add it, we already made sure that it will be unique */
3965    log_error(LOG_LEVEL_HEADER, "addh-unique: Host: %s", p);
3966    err = enlist_unique_header(csp->headers, "Host", p);
3967    return err;
3968
3969 }
3970
3971
3972 #if 0
3973 /*********************************************************************
3974  *
3975  * Function    :  client_accept_encoding_adder
3976  *
3977  * Description :  Add an Accept-Encoding header to the client's request
3978  *                that disables compression if the action applies, and
3979  *                the header is not already there. Called from `sed'.
3980  *                Note: For HTTP/1.0, the absence of the header is enough.
3981  *
3982  * Parameters  :
3983  *          1  :  csp = Current client state (buffers, headers, etc...)
3984  *
3985  * Returns     :  JB_ERR_OK on success, or
3986  *                JB_ERR_MEMORY on out-of-memory error.
3987  *
3988  *********************************************************************/
3989 static jb_err client_accept_encoding_adder(struct client_state *csp)
3990 {
3991    if (   ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
3992        && (!strcmpic(csp->http->ver, "HTTP/1.1")) )
3993    {
3994       return enlist_unique(csp->headers, "Accept-Encoding: identity;q=1.0, *;q=0", 16);
3995    }
3996
3997    return JB_ERR_OK;
3998 }
3999 #endif
4000
4001
4002 /*********************************************************************
4003  *
4004  * Function    :  client_xtra_adder
4005  *
4006  * Description :  Used in the add_client_headers list.  Called from `sed'.
4007  *
4008  * Parameters  :
4009  *          1  :  csp = Current client state (buffers, headers, etc...)
4010  *
4011  * Returns     :  JB_ERR_OK on success, or
4012  *                JB_ERR_MEMORY on out-of-memory error.
4013  *
4014  *********************************************************************/
4015 static jb_err client_xtra_adder(struct client_state *csp)
4016 {
4017    struct list_entry *lst;
4018    jb_err err;
4019
4020    for (lst = csp->action->multi[ACTION_MULTI_ADD_HEADER]->first;
4021         lst ; lst = lst->next)
4022    {
4023       log_error(LOG_LEVEL_HEADER, "addh: %s", lst->str);
4024       err = enlist(csp->headers, lst->str);
4025       if (err)
4026       {
4027          return err;
4028       }
4029
4030    }
4031
4032    return JB_ERR_OK;
4033 }
4034
4035
4036 /*********************************************************************
4037  *
4038  * Function    :  client_x_forwarded_for_adder
4039  *
4040  * Description :  Used in the add_client_headers list.  Called from `sed'.
4041  *
4042  * Parameters  :
4043  *          1  :  csp = Current client state (buffers, headers, etc...)
4044  *
4045  * Returns     :  JB_ERR_OK on success, or
4046  *                JB_ERR_MEMORY on out-of-memory error.
4047  *
4048  *********************************************************************/
4049 static jb_err client_x_forwarded_for_adder(struct client_state *csp)
4050 {
4051    char *header = NULL;
4052    jb_err err;
4053
4054    if (!((csp->action->flags & ACTION_CHANGE_X_FORWARDED_FOR)
4055          && (0 == strcmpic(csp->action->string[ACTION_STRING_CHANGE_X_FORWARDED_FOR], "add")))
4056       || (csp->flags & CSP_FLAG_X_FORWARDED_FOR_APPENDED))
4057    {
4058       /*
4059        * If we aren't adding X-Forwarded-For headers,
4060        * or we already appended an existing X-Forwarded-For
4061        * header, there's nothing left to do here.
4062        */
4063       return JB_ERR_OK;
4064    }
4065
4066    header = strdup("X-Forwarded-For: ");
4067    string_append(&header, csp->ip_addr_str);
4068
4069    if (header == NULL)
4070    {
4071       return JB_ERR_MEMORY;
4072    }
4073
4074    log_error(LOG_LEVEL_HEADER, "addh: %s", header);
4075    err = enlist(csp->headers, header);
4076    freez(header);
4077
4078    return err;
4079 }
4080
4081
4082 /*********************************************************************
4083  *
4084  * Function    :  server_connection_close_adder
4085  *
4086  * Description :  "Temporary" fix for the needed but missing HTTP/1.1
4087  *                support. Adds a "Connection: close" header to csp->headers
4088  *                unless the header was already present. Called from `sed'.
4089  *
4090  *                FIXME: This whole function shouldn't be neccessary!
4091  *
4092  * Parameters  :
4093  *          1  :  csp = Current client state (buffers, headers, etc...)
4094  *
4095  * Returns     :  JB_ERR_OK on success, or
4096  *                JB_ERR_MEMORY on out-of-memory error.
4097  *
4098  *********************************************************************/
4099 static jb_err server_connection_close_adder(struct client_state *csp)
4100 {
4101    const unsigned int flags = csp->flags;
4102    const char *response_status_line = csp->headers->first->str;
4103
4104    if ((flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
4105     && (flags & CSP_FLAG_SERVER_CONNECTION_CLOSE_SET))
4106    {
4107       return JB_ERR_OK;
4108    }
4109
4110    /*
4111     * XXX: if we downgraded the response, this check will fail.
4112     */
4113    if ((csp->config->feature_flags &
4114         RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
4115     && (NULL != response_status_line)
4116     && !strncmpic(response_status_line, "HTTP/1.1", 8))
4117    {
4118       log_error(LOG_LEVEL_HEADER, "A HTTP/1.1 response "
4119          "without Connection header implies keep-alive.");
4120       csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
4121    }
4122
4123    log_error(LOG_LEVEL_HEADER, "Adding: Connection: close");
4124
4125    return enlist(csp->headers, "Connection: close");
4126 }
4127
4128
4129 /*********************************************************************
4130  *
4131  * Function    :  client_connection_header_adder
4132  *
4133  * Description :  Adds a proper "Connection:" header to csp->headers
4134  *                unless the header was already present. Called from `sed'.
4135  *
4136  * Parameters  :
4137  *          1  :  csp = Current client state (buffers, headers, etc...)
4138  *
4139  * Returns     :  JB_ERR_OK on success, or
4140  *                JB_ERR_MEMORY on out-of-memory error.
4141  *
4142  *********************************************************************/
4143 static jb_err client_connection_header_adder(struct client_state *csp)
4144 {
4145    const unsigned int flags = csp->flags;
4146    const char *wanted_header = get_appropiate_connection_header(csp);
4147
4148    if (!(flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
4149      && (flags & CSP_FLAG_CLIENT_CONNECTION_HEADER_SET))
4150    {
4151       return JB_ERR_OK;
4152    }
4153
4154    log_error(LOG_LEVEL_HEADER, "Adding: %s", wanted_header);
4155
4156    return enlist(csp->headers, wanted_header);
4157 }
4158
4159
4160 /*********************************************************************
4161  *
4162  * Function    :  server_http
4163  *
4164  * Description :  - Save the HTTP Status into csp->http->status
4165  *                - Set CT_TABOO to prevent filtering if the answer
4166  *                  is a partial range (HTTP status 206)
4167  *                - Rewrite HTTP/1.1 answers to HTTP/1.0 if +downgrade
4168  *                  action applies.
4169  *
4170  * Parameters  :
4171  *          1  :  csp = Current client state (buffers, headers, etc...)
4172  *          2  :  header = On input, pointer to header to modify.
4173  *                On output, pointer to the modified header, or NULL
4174  *                to remove the header.  This function frees the
4175  *                original string if necessary.
4176  *
4177  * Returns     :  JB_ERR_OK on success, or
4178  *                JB_ERR_MEMORY on out-of-memory error.
4179  *
4180  *********************************************************************/
4181 static jb_err server_http(struct client_state *csp, char **header)
4182 {
4183    sscanf(*header, "HTTP/%*d.%*d %d", &(csp->http->status));
4184    if (csp->http->status == 206)
4185    {
4186       csp->content_type = CT_TABOO;
4187    }
4188
4189    if ((csp->action->flags & ACTION_DOWNGRADE) != 0)
4190    {
4191       /* XXX: Should we do a real validity check here? */
4192       if (strlen(*header) > 8)
4193       {
4194          (*header)[7] = '0';
4195          log_error(LOG_LEVEL_HEADER, "Downgraded answer to HTTP/1.0");
4196       }
4197       else
4198       {
4199          /*
4200           * XXX: Should we block the request or
4201           * enlist a valid status code line here?
4202           */
4203          log_error(LOG_LEVEL_INFO, "Malformed server response detected. "
4204             "Downgrading to HTTP/1.0 impossible.");
4205       }
4206    }
4207
4208    return JB_ERR_OK;
4209 }
4210
4211
4212 /*********************************************************************
4213  *
4214  * Function    :  server_set_cookie
4215  *
4216  * Description :  Handle the server "cookie" header properly.
4217  *                Log cookie to the jar file.  Then "crunch",
4218  *                accept or rewrite it to a session cookie.
4219  *                Called from `sed'.
4220  *
4221  *                TODO: Allow the user to specify a new expiration
4222  *                time to cause the cookie to expire even before the
4223  *                browser is closed.
4224  *
4225  * Parameters  :
4226  *          1  :  csp = Current client state (buffers, headers, etc...)
4227  *          2  :  header = On input, pointer to header to modify.
4228  *                On output, pointer to the modified header, or NULL
4229  *                to remove the header.  This function frees the
4230  *                original string if necessary.
4231  *
4232  * Returns     :  JB_ERR_OK on success, or
4233  *                JB_ERR_MEMORY on out-of-memory error.
4234  *
4235  *********************************************************************/
4236 static jb_err server_set_cookie(struct client_state *csp, char **header)
4237 {
4238    time_t now;
4239    time_t cookie_time; 
4240
4241    time(&now);
4242
4243    if ((csp->action->flags & ACTION_NO_COOKIE_SET) != 0)
4244    {
4245       log_error(LOG_LEVEL_HEADER, "Crunching incoming cookie: %s", *header);
4246       freez(*header);
4247    }
4248    else if ((csp->action->flags & ACTION_NO_COOKIE_KEEP) != 0)
4249    {
4250       /* Flag whether or not to log a message */
4251       int changed = 0;
4252
4253       /* A variable to store the tag we're working on */
4254       char *cur_tag;
4255
4256       /* Skip "Set-Cookie:" (11 characters) in header */
4257       cur_tag = *header + 11;
4258
4259       /* skip whitespace between "Set-Cookie:" and value */
4260       while (*cur_tag && ijb_isspace(*cur_tag))
4261       {
4262          cur_tag++;
4263       }
4264
4265       /* Loop through each tag in the cookie */
4266       while (*cur_tag)
4267       {
4268          /* Find next tag */
4269          char *next_tag = strchr(cur_tag, ';');
4270          if (next_tag != NULL)
4271          {
4272             /* Skip the ';' character itself */
4273             next_tag++;
4274
4275             /* skip whitespace ";" and start of tag */
4276             while (*next_tag && ijb_isspace(*next_tag))
4277             {
4278                next_tag++;
4279             }
4280          }
4281          else
4282          {
4283             /* "Next tag" is the end of the string */
4284             next_tag = cur_tag + strlen(cur_tag);
4285          }
4286
4287          /*
4288           * Check the expiration date to see
4289           * if the cookie is still valid, if yes,
4290           * rewrite it to a session cookie.
4291           */
4292          if ((strncmpic(cur_tag, "expires=", 8) == 0) && *(cur_tag + 8))
4293          {
4294             char *expiration_date = cur_tag + 8; /* Skip "[Ee]xpires=" */
4295
4296             /* Did we detect the date properly? */
4297             if (JB_ERR_OK != parse_header_time(expiration_date, &cookie_time))
4298             {
4299                /*
4300                 * Nope, treat it as if it was still valid.
4301                 *
4302                 * XXX: Should we remove the whole cookie instead?
4303                 */
4304                log_error(LOG_LEVEL_ERROR,
4305                   "Can't parse \'%s\', send by %s. Unsupported time format?", cur_tag, csp->http->url);
4306                string_move(cur_tag, next_tag);
4307                changed = 1;
4308             }
4309             else
4310             {
4311                /*
4312                 * Yes. Check if the cookie is still valid.
4313                 *
4314                 * If the cookie is already expired it's probably
4315                 * a delete cookie and even if it isn't, the browser
4316                 * will discard it anyway.
4317                 */
4318
4319                /*
4320                 * XXX: timegm() isn't available on some AmigaOS
4321                 * versions and our replacement doesn't work.
4322                 *
4323                 * Our options are to either:
4324                 *
4325                 * - disable session-cookies-only completely if timegm
4326                 *   is missing,
4327                 *
4328                 * - to simply remove all expired tags, like it has
4329                 *   been done until Privoxy 3.0.6 and to live with
4330                 *    the consequence that it can cause login/logout
4331                 *   problems on servers that don't validate their
4332                 *   input properly, or
4333                 *
4334                 * - to replace it with mktime in which
4335                 *   case there is a slight chance of valid cookies
4336                 *   passing as already expired.
4337                 *
4338                 *   This is the way it's currently done and it's not
4339                 *   as bad as it sounds. If the missing GMT offset is
4340                 *   enough to change the result of the expiration check
4341                 *   the cookie will be only valid for a few hours
4342                 *   anyway, which in many cases will be shorter
4343                 *   than a browser session.
4344                 */
4345                if (cookie_time - now < 0)
4346                {
4347                   log_error(LOG_LEVEL_HEADER,
4348                      "Cookie \'%s\' is already expired and can pass unmodified.", *header);
4349                   /* Just in case some clown sets more then one expiration date */
4350                   cur_tag = next_tag;
4351                }
4352                else
4353                {
4354                   /*
4355                    * Still valid, delete expiration date by copying
4356                    * the rest of the string over it.
4357                    */
4358                   string_move(cur_tag, next_tag);
4359
4360                   /* That changed the header, need to issue a log message */
4361                   changed = 1;
4362
4363                   /*
4364                    * Note that the next tag has now been moved to *cur_tag,
4365                    * so we do not need to update the cur_tag pointer.
4366                    */
4367                }
4368             }
4369
4370          }
4371          else
4372          {
4373             /* Move on to next cookie tag */
4374             cur_tag = next_tag;
4375          }
4376       }
4377
4378       if (changed)
4379       {
4380          assert(NULL != *header);
4381          log_error(LOG_LEVEL_HEADER, "Cookie rewritten to a temporary one: %s",
4382             *header);
4383       }
4384    }
4385
4386    return JB_ERR_OK;
4387 }
4388
4389
4390 #ifdef FEATURE_FORCE_LOAD
4391 /*********************************************************************
4392  *
4393  * Function    :  strclean
4394  *
4395  * Description :  In-Situ-Eliminate all occurances of substring in
4396  *                string
4397  *
4398  * Parameters  :
4399  *          1  :  string = string to clean
4400  *          2  :  substring = substring to eliminate
4401  *
4402  * Returns     :  Number of eliminations
4403  *
4404  *********************************************************************/
4405 int strclean(char *string, const char *substring)
4406 {
4407    int hits = 0;
4408    size_t len;
4409    char *pos, *p;
4410
4411    len = strlen(substring);
4412
4413    while((pos = strstr(string, substring)) != NULL)
4414    {
4415       p = pos + len;
4416       do
4417       {
4418          *(p - len) = *p;
4419       }
4420       while (*p++ != '\0');
4421
4422       hits++;
4423    }
4424
4425    return(hits);
4426 }
4427 #endif /* def FEATURE_FORCE_LOAD */
4428
4429
4430 /*********************************************************************
4431  *
4432  * Function    :  parse_header_time
4433  *
4434  * Description :  Parses time formats used in HTTP header strings
4435  *                to get the numerical respresentation.
4436  *
4437  * Parameters  :
4438  *          1  :  header_time = HTTP header time as string. 
4439  *          2  :  result = storage for header_time in seconds
4440  *
4441  * Returns     :  JB_ERR_OK if the time format was recognized, or
4442  *                JB_ERR_PARSE otherwise.
4443  *
4444  *********************************************************************/
4445 static jb_err parse_header_time(const char *header_time, time_t *result)
4446 {
4447    struct tm gmt;
4448
4449    /*
4450     * Zero out gmt to prevent time zone offsets.
4451     *
4452     * While this is only necessary on some platforms
4453     * (mingw32 for example), I don't know how to
4454     * detect these automatically and doing it everywhere
4455     * shouldn't hurt.
4456     */
4457    memset(&gmt, 0, sizeof(gmt));
4458
4459                             /* Tue, 02 Jun 2037 20:00:00 */
4460    if ((NULL == strptime(header_time, "%a, %d %b %Y %H:%M:%S", &gmt))
4461                             /* Tue, 02-Jun-2037 20:00:00 */
4462     && (NULL == strptime(header_time, "%a, %d-%b-%Y %H:%M:%S", &gmt))
4463                             /* Tue, 02-Jun-37 20:00:00 */
4464     && (NULL == strptime(header_time, "%a, %d-%b-%y %H:%M:%S", &gmt))
4465                         /* Tuesday, 02-Jun-2037 20:00:00 */
4466     && (NULL == strptime(header_time, "%A, %d-%b-%Y %H:%M:%S", &gmt))
4467                         /* Tuesday Jun 02 20:00:00 2037 */
4468     && (NULL == strptime(header_time, "%A %b %d %H:%M:%S %Y", &gmt)))
4469    {
4470       return JB_ERR_PARSE;
4471    }
4472
4473    *result = timegm(&gmt);
4474
4475    return JB_ERR_OK;
4476
4477 }
4478
4479
4480 /*********************************************************************
4481  *
4482  * Function    :  get_destination_from_headers
4483  *
4484  * Description :  Parse the "Host:" header to get the request's destination.
4485  *                Only needed if the client's request was forcefully
4486  *                redirected into Privoxy.
4487  *
4488  *                Code mainly copied from client_host() which is currently
4489  *                run too late for this purpose.
4490  *
4491  * Parameters  :
4492  *          1  :  headers = List of headers (one of them hopefully being
4493  *                the "Host:" header)
4494  *          2  :  http = storage for the result (host, port and hostport). 
4495  *
4496  * Returns     :  JB_ERR_MEMORY in case of memory problems,
4497  *                JB_ERR_PARSE if the host header couldn't be found,
4498  *                JB_ERR_OK otherwise.
4499  *
4500  *********************************************************************/
4501 jb_err get_destination_from_headers(const struct list *headers, struct http_request *http)
4502 {
4503    char *q;
4504    char *p;
4505    char *host;
4506
4507    host = get_header_value(headers, "Host:");
4508
4509    if (NULL == host)
4510    {
4511       log_error(LOG_LEVEL_ERROR, "No \"Host:\" header found.");
4512       return JB_ERR_PARSE;
4513    }
4514
4515    if (NULL == (p = strdup((host))))
4516    {
4517       log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header");
4518       return JB_ERR_MEMORY;
4519    }
4520    chomp(p);
4521    if (NULL == (q = strdup(p)))
4522    {
4523       freez(p);
4524       log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header");
4525       return JB_ERR_MEMORY;
4526    }
4527
4528    freez(http->hostport);
4529    http->hostport = p;
4530    freez(http->host);
4531    http->host = q;
4532    q = strchr(http->host, ':');
4533    if (q != NULL)
4534    {
4535       /* Terminate hostname and evaluate port string */
4536       *q++ = '\0';
4537       http->port = atoi(q);
4538    }
4539    else
4540    {
4541       http->port = http->ssl ? 443 : 80;
4542    }
4543
4544    /* Rebuild request URL */
4545    freez(http->url);
4546    http->url = strdup(http->ssl ? "https://" : "http://");
4547    string_append(&http->url, http->hostport);
4548    string_append(&http->url, http->path);
4549    if (http->url == NULL)
4550    {
4551       return JB_ERR_MEMORY;
4552    }
4553
4554    log_error(LOG_LEVEL_HEADER, "Destination extracted from \"Host:\" header. New request URL: %s",
4555       http->url);
4556
4557    return JB_ERR_OK;
4558
4559 }
4560
4561
4562 /*********************************************************************
4563  *
4564  * Function    :  create_forged_referrer
4565  *
4566  * Description :  Helper for client_referrer to forge a referer as
4567  *                'http://[hostname:port/' to fool stupid
4568  *                checks for in-site links 
4569  *
4570  * Parameters  :
4571  *          1  :  header   = Pointer to header pointer
4572  *          2  :  hostport = Host and optionally port as string
4573  *
4574  * Returns     :  JB_ERR_OK in case of success, or
4575  *                JB_ERR_MEMORY in case of memory problems.
4576  *
4577  *********************************************************************/
4578 static jb_err create_forged_referrer(char **header, const char *hostport)
4579 {
4580     assert(NULL == *header);
4581
4582     *header = strdup("Referer: http://");
4583     string_append(header, hostport);
4584     string_append(header, "/");
4585
4586     if (NULL == *header)
4587     {
4588        return JB_ERR_MEMORY;
4589     }
4590
4591     log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header);
4592
4593     return JB_ERR_OK;
4594
4595 }
4596
4597
4598 /*********************************************************************
4599  *
4600  * Function    :  create_fake_referrer
4601  *
4602  * Description :  Helper for client_referrer to create a fake referrer
4603  *                based on a string supplied by the user.
4604  *
4605  * Parameters  :
4606  *          1  :  header   = Pointer to header pointer
4607  *          2  :  hosthost = Referrer to fake
4608  *
4609  * Returns     :  JB_ERR_OK in case of success, or
4610  *                JB_ERR_MEMORY in case of memory problems.
4611  *
4612  *********************************************************************/
4613 static jb_err create_fake_referrer(char **header, const char *fake_referrer)
4614 {
4615    assert(NULL == *header);
4616
4617    if ((0 != strncmpic(fake_referrer, "http://", 7)) && (0 != strncmpic(fake_referrer, "https://", 8)))
4618    {
4619       log_error(LOG_LEVEL_HEADER,
4620          "Parameter: +hide-referrer{%s} is a bad idea, but I don't care.", fake_referrer);
4621    }
4622    *header = strdup("Referer: ");
4623    string_append(header, fake_referrer);
4624
4625    if (NULL == *header)
4626    {
4627       return JB_ERR_MEMORY;
4628    }
4629
4630    log_error(LOG_LEVEL_HEADER, "Referer replaced with: %s", *header);
4631
4632    return JB_ERR_OK;
4633
4634 }
4635
4636
4637 /*********************************************************************
4638  *
4639  * Function    :  handle_conditional_hide_referrer_parameter
4640  *
4641  * Description :  Helper for client_referrer to crunch or forge
4642  *                the referrer header if the host has changed.
4643  *
4644  * Parameters  :
4645  *          1  :  header = Pointer to header pointer
4646  *          2  :  host   = The target host (may include the port)
4647  *          3  :  parameter_conditional_block = Boolean to signal
4648  *                if we're in conditional-block mode. If not set,
4649  *                we're in conditional-forge mode.
4650  *
4651  * Returns     :  JB_ERR_OK in case of success, or
4652  *                JB_ERR_MEMORY in case of memory problems.
4653  *
4654  *********************************************************************/
4655 static jb_err handle_conditional_hide_referrer_parameter(char **header,
4656    const char *host, const int parameter_conditional_block)
4657 {
4658    char *referer = strdup(*header);
4659    const size_t hostlenght = strlen(host);
4660    const char *referer_url = NULL;
4661
4662    if (NULL == referer)
4663    {
4664       freez(*header);
4665       return JB_ERR_MEMORY;
4666    }
4667
4668    /* referer begins with 'Referer: http[s]://' */
4669    if ((hostlenght+17) < strlen(referer))
4670    {
4671       /*
4672        * Shorten referer to make sure the referer is blocked
4673        * if www.example.org/www.example.com-shall-see-the-referer/
4674        * links to www.example.com/
4675        */
4676       referer[hostlenght+17] = '\0';
4677    }
4678    referer_url = strstr(referer, "http://");
4679    if ((NULL == referer_url) || (NULL == strstr(referer_url, host)))
4680    {
4681       /* Host has changed, Referer is invalid or a https URL. */
4682       if (parameter_conditional_block)
4683       {
4684          log_error(LOG_LEVEL_HEADER, "New host is: %s. Crunching %s!", host, *header);
4685          freez(*header);
4686       }
4687       else
4688       {
4689          freez(*header);
4690          freez(referer);
4691          return create_forged_referrer(header, host);
4692       }
4693    }
4694    freez(referer);
4695
4696    return JB_ERR_OK;
4697
4698 }
4699
4700
4701 /*********************************************************************
4702  *
4703  * Function    :  get_appropiate_connection_header
4704  *
4705  * Description :  Returns an appropiate Connection header
4706  *                depending on whether or not we try to keep
4707  *                the connection to the server alive.
4708  *
4709  * Parameters  :
4710  *          1  :  csp = Current client state (buffers, headers, etc...)
4711  *
4712  * Returns     :  Pointer to statically allocated header buffer.
4713  *
4714  *********************************************************************/
4715 static const char *get_appropiate_connection_header(const struct client_state *csp)
4716 {
4717    static const char connection_keep_alive[] = "Connection: keep-alive";
4718    static const char connection_close[] = "Connection: close";
4719
4720    if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
4721     && (csp->http->ssl == 0))
4722    {
4723       return connection_keep_alive;
4724    }
4725    return connection_close;
4726 }
4727 /*
4728   Local Variables:
4729   tab-width: 3
4730   end:
4731 */