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