1 const char parsers_rcs[] = "$Id: parsers.c,v 1.84 2007/01/24 12:56:52 fabiankeil Exp $";
2 /*********************************************************************
4 * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $
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_server_header'
14 * `filter_client_header', `filter_header', `crunch_server_header',
15 * `server_content_encoding', `server_content_disposition',
16 * `server_last_modified', `client_accept_language',
17 * `crunch_client_header', `client_if_modified_since',
18 * `client_if_none_match', `get_destination_from_headers',
19 * `parse_header_time' and `server_set_cookie'.
21 * Copyright : Written by and Copyright (C) 2001-2007 the SourceForge
22 * Privoxy team. http://www.privoxy.org/
24 * Based on the Internet Junkbuster originally written
25 * by and Copyright (C) 1997 Anonymous Coders and
26 * Junkbusters Corporation. http://www.junkbusters.com
28 * This program is free software; you can redistribute it
29 * and/or modify it under the terms of the GNU General
30 * Public License as published by the Free Software
31 * Foundation; either version 2 of the License, or (at
32 * your option) any later version.
34 * This program is distributed in the hope that it will
35 * be useful, but WITHOUT ANY WARRANTY; without even the
36 * implied warranty of MERCHANTABILITY or FITNESS FOR A
37 * PARTICULAR PURPOSE. See the GNU General Public
38 * License for more details.
40 * The GNU General Public License should be included with
41 * this file. If not, you can view it at
42 * http://www.gnu.org/copyleft/gpl.html
43 * or write to the Free Software Foundation, Inc., 59
44 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
48 * Revision 1.84 2007/01/24 12:56:52 fabiankeil
49 * - Repeat the request URL before logging any headers.
50 * Makes reading the log easier in case of simultaneous requests.
51 * - If there are more than one Content-Type headers in one request,
52 * use the first one and remove the others.
53 * - Remove "newval" variable in server_content_type().
54 * It's only used once.
56 * Revision 1.83 2007/01/12 15:03:02 fabiankeil
57 * Correct a cast, check inflateEnd() exit code
58 * to see if we have to, replace sprintf calls
61 * Revision 1.82 2007/01/01 19:36:37 fabiankeil
62 * Integrate a modified version of Wil Mahan's
63 * zlib patch (PR #895531).
65 * Revision 1.81 2006/12/31 22:21:33 fabiankeil
66 * Skip empty filter files in filter_header()
67 * but don't ignore the ones that come afterwards.
68 * Fixes BR 1619208, this time for real.
70 * Revision 1.80 2006/12/29 19:08:22 fabiankeil
71 * Reverted parts of my last commit
72 * to keep error handling working.
74 * Revision 1.79 2006/12/29 18:04:40 fabiankeil
75 * Fixed gcc43 conversion warnings.
77 * Revision 1.78 2006/12/26 17:19:20 fabiankeil
78 * Bringing back the "useless" localtime() call
79 * I removed in revision 1.67. On some platforms
80 * it's necessary to prevent time zone offsets.
82 * Revision 1.77 2006/12/07 18:44:26 fabiankeil
83 * Rebuild request URL in get_destination_from_headers()
84 * to make sure redirect{pcrs command} works as expected
85 * for intercepted requests.
87 * Revision 1.76 2006/12/06 19:52:25 fabiankeil
88 * Added get_destination_from_headers().
90 * Revision 1.75 2006/11/13 19:05:51 fabiankeil
91 * Make pthread mutex locking more generic. Instead of
92 * checking for OSX and OpenBSD, check for FEATURE_PTHREAD
93 * and use mutex locking unless there is an _r function
94 * available. Better safe than sorry.
96 * Fixes "./configure --disable-pthread" and should result
97 * in less threading-related problems on pthread-using platforms,
98 * but it still doesn't fix BR#1122404.
100 * Revision 1.74 2006/10/02 16:59:12 fabiankeil
101 * The special header "X-Filter: No" now disables
102 * header filtering as well.
104 * Revision 1.73 2006/09/23 13:26:38 roro
105 * Replace TABs by spaces in source code.
107 * Revision 1.72 2006/09/23 12:37:21 fabiankeil
108 * Don't print a log message every time filter_headers is
109 * entered or left. It only creates noise without any real
112 * Revision 1.71 2006/09/21 19:55:17 fabiankeil
113 * Fix +hide-if-modified-since{-n}.
115 * Revision 1.70 2006/09/08 12:06:34 fabiankeil
116 * Have hide-if-modified-since interpret the random
117 * range value as minutes instead of hours. Allows
118 * more fine-grained configuration.
120 * Revision 1.69 2006/09/06 16:25:51 fabiankeil
121 * Always have parse_header_time return a pointer
122 * that actual makes sense, even though we currently
123 * only need it to detect problems.
125 * Revision 1.68 2006/09/06 10:43:32 fabiankeil
126 * Added config option enable-remote-http-toggle
127 * to specify if Privoxy should recognize special
128 * headers (currently only X-Filter) to change its
129 * behaviour. Disabled by default.
131 * Revision 1.67 2006/09/04 11:01:26 fabiankeil
132 * After filtering de-chunked instances, remove
133 * "Transfer-Encoding" header entirely instead of changing
134 * it to "Transfer-Encoding: identity", which is invalid.
135 * Thanks Michael Shields <shields@msrl.com>. Fixes PR 1318658.
137 * Don't use localtime in parse_header_time. An empty time struct
138 * is good enough, it gets overwritten by strptime anyway.
140 * Revision 1.66 2006/09/03 19:38:28 fabiankeil
141 * Use gmtime_r if available, fallback to gmtime with mutex
142 * protection for MacOSX and use vanilla gmtime for the rest.
144 * Revision 1.65 2006/08/22 10:55:56 fabiankeil
145 * Changed client_referrer to use the right type (size_t) for
146 * hostlenght and to shorten the temporary referrer string with
147 * '\0' instead of adding a useless line break.
149 * Revision 1.64 2006/08/17 17:15:10 fabiankeil
150 * - Back to timegm() using GnuPG's replacement if necessary.
151 * Using mktime() and localtime() could add a on hour offset if
152 * the randomize factor was big enough to lead to a summer/wintertime
155 * - Removed now-useless Privoxy 3.0.3 compatibility glue.
157 * - Moved randomization code into pick_from_range().
159 * - Changed parse_header_time definition.
160 * time_t isn't guaranteed to be signed and
161 * if it isn't, -1 isn't available as error code.
162 * Changed some variable types in client_if_modified_since()
163 * because of the same reason.
165 * Revision 1.63 2006/08/14 13:18:08 david__schmidt
166 * OS/2 compilation compatibility fixups
168 * Revision 1.62 2006/08/14 08:58:42 fabiankeil
169 * Changed include from strptime.c to strptime.h
171 * Revision 1.61 2006/08/14 08:25:19 fabiankeil
172 * Split filter-headers{} into filter-client-headers{}
173 * and filter-server-headers{}.
174 * Added parse_header_time() to share some code.
175 * Replaced timegm() with mktime().
177 * Revision 1.60 2006/08/12 03:54:37 david__schmidt
178 * Windows service integration
180 * Revision 1.59 2006/08/03 02:46:41 david__schmidt
181 * Incorporate Fabian Keil's patch work:
\rhttp://www.fabiankeil.de/sourcecode/privoxy/
183 * Revision 1.58 2006/07/18 14:48:47 david__schmidt
184 * Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
185 * with what was really the latest development (the v_3_0_branch branch)
187 * Revision 1.56.2.10 2006/01/21 16:16:08 david__schmidt
188 * Thanks to Edward Carrel for his patch to modernize OSX's
\rpthreads support. See bug #1409623.
190 * Revision 1.56.2.9 2004/10/03 12:53:45 david__schmidt
191 * Add the ability to check jpeg images for invalid
192 * lengths of comment blocks. Defensive strategy
193 * against the exploit:
194 * Microsoft Security Bulletin MS04-028
195 * Buffer Overrun in JPEG Processing (GDI+) Could
196 * Allow Code Execution (833987)
197 * Enabled with +inspect-jpegs in actions files.
199 * Revision 1.56.2.8 2003/07/11 13:21:25 oes
200 * Excluded text/plain objects from filtering. This fixes a
201 * couple of client-crashing, download corruption and
202 * Privoxy performance issues, whose root cause lies in
203 * web servers labelling content of unknown type as text/plain.
205 * Revision 1.56.2.7 2003/05/06 12:07:26 oes
206 * Fixed bug #729900: Suspicious HOST: headers are now killed and regenerated if necessary
208 * Revision 1.56.2.6 2003/04/14 21:28:30 oes
209 * Completing the previous change
211 * Revision 1.56.2.5 2003/04/14 12:08:16 oes
212 * Added temporary workaround for bug in PHP < 4.2.3
214 * Revision 1.56.2.4 2003/03/07 03:41:05 david__schmidt
215 * 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.
217 * Revision 1.56.2.3 2002/11/10 04:20:02 hal9
218 * Fix typo: supressed -> suppressed
220 * Revision 1.56.2.2 2002/09/25 14:59:53 oes
221 * Improved cookie logging
223 * Revision 1.56.2.1 2002/09/25 14:52:45 oes
224 * Added basic support for OPTIONS and TRACE HTTP methods:
225 * - New parser function client_max_forwards which decrements
226 * the Max-Forwards HTTP header field of OPTIONS and TRACE
227 * requests by one before forwarding
228 * - New parser function client_host which extracts the host
229 * and port information from the HTTP header field if the
230 * request URI was not absolute
231 * - Don't crumble and re-add the Host: header, but only generate
232 * and append if missing
234 * Revision 1.56 2002/05/12 15:34:22 jongfoster
235 * Fixing typo in a comment
237 * Revision 1.55 2002/05/08 16:01:07 oes
238 * Optimized add_to_iob:
239 * - Use realloc instead of malloc(), memcpy(), free()
240 * - Expand to powers of two if possible, to get
241 * O(log n) reallocs instead of O(n).
242 * - Moved check for buffer limit here from chat
243 * - Report failure via returncode
245 * Revision 1.54 2002/04/02 15:03:16 oes
246 * Tiny code cosmetics
248 * Revision 1.53 2002/03/26 22:29:55 swa
249 * we have a new homepage!
251 * Revision 1.52 2002/03/24 13:25:43 swa
252 * name change related issues
254 * Revision 1.51 2002/03/13 00:27:05 jongfoster
257 * Revision 1.50 2002/03/12 01:45:35 oes
258 * More verbose logging
260 * Revision 1.49 2002/03/09 20:03:52 jongfoster
261 * - Making various functions return int rather than size_t.
262 * (Undoing a recent change). Since size_t is unsigned on
263 * Windows, functions like read_socket that return -1 on
264 * error cannot return a size_t.
266 * THIS WAS A MAJOR BUG - it caused frequent, unpredictable
267 * crashes, and also frequently caused JB to jump to 100%
268 * CPU and stay there. (Because it thought it had just
269 * read ((unsigned)-1) == 4Gb of data...)
271 * - The signature of write_socket has changed, it now simply
272 * returns success=0/failure=nonzero.
274 * - Trying to get rid of a few warnings --with-debug on
275 * Windows, I've introduced a new type "jb_socket". This is
276 * used for the socket file descriptors. On Windows, this
277 * is SOCKET (a typedef for unsigned). Everywhere else, it's
278 * an int. The error value can't be -1 any more, so it's
279 * now JB_INVALID_SOCKET (which is -1 on UNIX, and in
280 * Windows it maps to the #define INVALID_SOCKET.)
282 * - The signature of bind_port has changed.
284 * Revision 1.48 2002/03/07 03:46:53 oes
285 * Fixed compiler warnings etc
287 * Revision 1.47 2002/02/20 23:15:13 jongfoster
288 * Parsing functions now handle out-of-memory gracefully by returning
291 * Revision 1.46 2002/01/17 21:03:47 jongfoster
292 * Moving all our URL and URL pattern parsing code to urlmatch.c.
294 * Revision 1.45 2002/01/09 14:33:03 oes
295 * Added support for localtime_r.
297 * Revision 1.44 2001/12/14 01:22:54 steudten
298 * Remove 'user:pass@' from 'proto://user:pass@host' for the
299 * new added header 'Host: ..'. (See Req ID 491818)
301 * Revision 1.43 2001/11/23 00:26:38 jongfoster
302 * Fixing two really stupid errors in my previous commit
304 * Revision 1.42 2001/11/22 21:59:30 jongfoster
305 * Adding code to handle +no-cookies-keep
307 * Revision 1.41 2001/11/05 23:43:05 steudten
308 * Add time+date to log files.
310 * Revision 1.40 2001/10/26 20:13:09 jongfoster
311 * ctype.h is needed in Windows, too.
313 * Revision 1.39 2001/10/26 17:40:04 oes
314 * Introduced get_header_value()
315 * Removed http->user_agent, csp->referrer and csp->accept_types
316 * Removed client_accept()
318 * Revision 1.38 2001/10/25 03:40:48 david__schmidt
319 * Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
320 * threads to call select() simultaneously. So, it's time to do a real, live,
321 * native OS/2 port. See defines for __EMX__ (the porting layer) vs. __OS2__
322 * (native). Both versions will work, but using __OS2__ offers multi-threading.
324 * Revision 1.37 2001/10/23 21:36:02 jongfoster
325 * Documenting sed()'s error behaviou (doc change only)
327 * Revision 1.36 2001/10/13 12:51:51 joergs
328 * Removed client_host, (was only required for the old 2.0.2-11 http://noijb.
329 * force-load), instead crumble Host: and add it (again) in client_host_adder
330 * (in case we get a HTTP/1.0 request without Host: header and forward it to
331 * a HTTP/1.1 server/proxy).
333 * Revision 1.35 2001/10/09 22:39:21 jongfoster
334 * assert.h is also required under Win32, so moving out of #ifndef _WIN32
337 * Revision 1.34 2001/10/07 18:50:55 oes
338 * Added server_content_encoding, renamed server_transfer_encoding
340 * Revision 1.33 2001/10/07 18:04:49 oes
341 * Changed server_http11 to server_http and its pattern to "HTTP".
342 * Additional functionality: it now saves the HTTP status into
343 * csp->http->status and sets CT_TABOO for Status 206 (partial range)
345 * Revision 1.32 2001/10/07 15:43:28 oes
346 * Removed FEATURE_DENY_GZIP and replaced it with client_accept_encoding,
347 * client_te and client_accept_encoding_adder, triggered by the new
348 * +no-compression action. For HTTP/1.1 the Accept-Encoding header is
349 * changed to allow only identity and chunked, and the TE header is
350 * crunched. For HTTP/1.0, Accept-Encoding is crunched.
352 * parse_http_request no longer does anything than parsing. The rewriting
353 * of http->cmd and version mangling are gone. It now also recognizes
354 * the put and delete methods and saves the url in http->url. Removed
357 * renamed content_type and content_length to have the server_ prefix
359 * server_content_type now only works if csp->content_type != CT_TABOO
361 * added server_transfer_encoding, which
362 * - Sets CT_TABOO to prohibit filtering if encoding compresses
363 * - Raises the CSP_FLAG_CHUNKED flag if Encoding is "chunked"
364 * - Change from "chunked" to "identity" if body was chunked
365 * but has been de-chunked for filtering.
367 * added server_content_md5 which crunches any Content-MD5 headers
368 * if the body was modified.
370 * made server_http11 conditional on +downgrade action
372 * Replaced 6 boolean members of csp with one bitmap (csp->flags)
374 * Revision 1.31 2001/10/05 14:25:02 oes
375 * Crumble Keep-Alive from Server
377 * Revision 1.30 2001/09/29 12:56:03 joergs
378 * IJB now changes HTTP/1.1 to HTTP/1.0 in requests and answers.
380 * Revision 1.29 2001/09/24 21:09:24 jongfoster
381 * Fixing 2 memory leaks that Guy spotted, where the paramater to
382 * enlist() was not being free()d.
384 * Revision 1.28 2001/09/22 16:32:28 jongfoster
385 * Removing unused #includes.
387 * Revision 1.27 2001/09/20 15:45:25 steudten
389 * add casting from size_t to int for printf()
390 * remove local variable shadow s2
392 * Revision 1.26 2001/09/16 17:05:14 jongfoster
393 * Removing unused #include showarg.h
395 * Revision 1.25 2001/09/16 13:21:27 jongfoster
396 * Changes to use new list functions.
398 * Revision 1.24 2001/09/13 23:05:50 jongfoster
399 * Changing the string paramater to the header parsers a "const".
401 * Revision 1.23 2001/09/12 18:08:19 steudten
403 * In parse_http_request() header rewriting miss the host value, so
404 * from http://www.mydomain.com the result was just " / " not
405 * http://www.mydomain.com/ in case we forward.
407 * Revision 1.22 2001/09/10 10:58:53 oes
408 * Silenced compiler warnings
410 * Revision 1.21 2001/07/31 14:46:00 oes
411 * - Persistant connections now suppressed
412 * - sed() no longer appends empty header to csp->headers
414 * Revision 1.20 2001/07/30 22:08:36 jongfoster
415 * Tidying up #defines:
416 * - All feature #defines are now of the form FEATURE_xxx
417 * - Permanently turned off WIN_GUI_EDIT
418 * - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
420 * Revision 1.19 2001/07/25 17:21:54 oes
421 * client_uagent now saves copy of User-Agent: header value
423 * Revision 1.18 2001/07/13 14:02:46 oes
424 * - Included fix to repair broken HTTP requests that
425 * don't contain a path, not even '/'.
426 * - Removed all #ifdef PCRS
427 * - content_type now always inspected and classified as
428 * text, gif or other.
429 * - formatting / comments
431 * Revision 1.17 2001/06/29 21:45:41 oes
432 * Indentation, CRLF->LF, Tab-> Space
434 * Revision 1.16 2001/06/29 13:32:42 oes
436 * - Adapted free_http_request
437 * - Removed logentry from cancelled commit
439 * Revision 1.15 2001/06/03 19:12:38 oes
440 * deleted const struct interceptors
442 * Revision 1.14 2001/06/01 18:49:17 jongfoster
443 * Replaced "list_share" with "list" - the tiny memory gain was not
444 * worth the extra complexity.
446 * Revision 1.13 2001/05/31 21:30:33 jongfoster
447 * Removed list code - it's now in list.[ch]
448 * Renamed "permission" to "action", and changed many features
449 * to use the actions file rather than the global config.
451 * Revision 1.12 2001/05/31 17:33:13 oes
455 * Revision 1.11 2001/05/29 20:11:19 joergs
456 * '/ * inside comment' warning removed.
458 * Revision 1.10 2001/05/29 09:50:24 jongfoster
459 * Unified blocklist/imagelist/permissionslist.
460 * File format is still under discussion, but the internal changes
463 * Also modified interceptor behaviour:
464 * - We now intercept all URLs beginning with one of the following
465 * prefixes (and *only* these prefixes):
467 * * http://ijbswa.sf.net/config/
468 * * http://ijbswa.sourceforge.net/config/
469 * - New interceptors "home page" - go to http://i.j.b/ to see it.
470 * - Internal changes so that intercepted and fast redirect pages
471 * are not replaced with an image.
472 * - Interceptors now have the option to send a binary page direct
473 * to the client. (i.e. ijb-send-banner uses this)
474 * - Implemented show-url-info interceptor. (Which is why I needed
475 * the above interceptors changes - a typical URL is
476 * "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
477 * The previous mechanism would not have intercepted that, and
478 * if it had been intercepted then it then it would have replaced
481 * Revision 1.9 2001/05/28 17:26:33 jongfoster
482 * Fixing segfault if last header was crunched.
483 * Fixing Windows build (snprintf() is _snprintf() under Win32, but we
484 * can use the cross-platform sprintf() instead.)
486 * Revision 1.8 2001/05/27 22:17:04 oes
488 * - re_process_buffer no longer writes the modified buffer
489 * to the client, which was very ugly. It now returns the
490 * buffer, which it is then written by chat.
492 * - content_length now adjusts the Content-Length: header
493 * for modified documents rather than crunch()ing it.
494 * (Length info in csp->content_length, which is 0 for
495 * unmodified documents)
497 * - For this to work, sed() is called twice when filtering.
499 * Revision 1.7 2001/05/27 13:19:06 oes
500 * Patched Joergs solution for the content-length in.
502 * Revision 1.6 2001/05/26 13:39:32 jongfoster
503 * Only crunches Content-Length header if applying RE filtering.
504 * Without this fix, Microsoft Windows Update wouldn't work.
506 * Revision 1.5 2001/05/26 00:28:36 jongfoster
507 * Automatic reloading of config file.
508 * Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
509 * Most of the global variables have been moved to a new
510 * struct configuration_spec, accessed through csp->config->globalname
511 * Most of the globals remaining are used by the Win32 GUI.
513 * Revision 1.4 2001/05/22 18:46:04 oes
515 * - Enabled filtering banners by size rather than URL
516 * by adding patterns that replace all standard banner
517 * sizes with the "Junkbuster" gif to the re_filterfile
519 * - Enabled filtering WebBugs by providing a pattern
520 * which kills all 1x1 images
522 * - Added support for PCRE_UNGREEDY behaviour to pcrs,
523 * which is selected by the (nonstandard and therefore
524 * capital) letter 'U' in the option string.
525 * It causes the quantifiers to be ungreedy by default.
526 * Appending a ? turns back to greedy (!).
528 * - Added a new interceptor ijb-send-banner, which
529 * sends back the "Junkbuster" gif. Without imagelist or
530 * MSIE detection support, or if tinygif = 1, or the
531 * URL isn't recognized as an imageurl, a lame HTML
532 * explanation is sent instead.
534 * - Added new feature, which permits blocking remote
535 * script redirects and firing back a local redirect
537 * The feature is conditionally compiled, i.e. it
538 * can be disabled with --disable-fast-redirects,
539 * plus it must be activated by a "fast-redirects"
540 * line in the config file, has its own log level
541 * and of course wants to be displayed by show-proxy-args
542 * Note: Boy, all the #ifdefs in 1001 locations and
543 * all the fumbling with configure.in and acconfig.h
544 * were *way* more work than the feature itself :-(
546 * - Because a generic redirect template was needed for
547 * this, tinygif = 3 now uses the same.
549 * - Moved GIFs, and other static HTTP response templates
554 * - Removed some >400 CRs again (Jon, you really worked
557 * Revision 1.3 2001/05/20 01:21:20 jongfoster
558 * Version 2.9.4 checkin.
559 * - Merged popupfile and cookiefile, and added control over PCRS
560 * filtering, in new "permissionsfile".
561 * - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
562 * file error you now get a message box (in the Win32 GUI) rather
563 * than the program exiting with no explanation.
564 * - Made killpopup use the PCRS MIME-type checking and HTTP-header
566 * - Removed tabs from "config"
567 * - Moved duplicated url parsing code in "loaders.c" to a new funcition.
568 * - Bumped up version number.
570 * Revision 1.2 2001/05/17 23:02:36 oes
571 * - Made referrer option accept 'L' as a substitute for '§'
573 * Revision 1.1.1.1 2001/05/15 13:59:01 oes
574 * Initial import of version 2.9.3 source tree
577 *********************************************************************/
584 #include <sys/types.h>
597 #if !defined(_WIN32) && !defined(__OS2__)
603 #ifdef FEATURE_PTHREAD
605 /* jcc.h is for mutex semapores only */
606 #endif /* def FEATURE_PTHREAD */
612 #include "jbsockets.h"
613 #include "miscutil.h"
616 #ifndef HAVE_STRPTIME
617 #include "strptime.h"
620 const char parsers_h_rcs[] = PARSERS_H_VERSION;
622 /* Fix a problem with Solaris. There should be no effect on other
624 * Solaris's isspace() is a macro which uses it's argument directly
625 * as an array index. Therefore we need to make sure that high-bit
626 * characters generate +ve values, and ideally we also want to make
627 * the argument match the declared parameter type of "int".
629 * Why did they write a character function that can't take a simple
630 * "char" argument? Doh!
632 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
633 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
636 const struct parsers client_patterns[] = {
637 { "referer:", 8, client_referrer },
638 { "user-agent:", 11, client_uagent },
639 { "ua-", 3, client_ua },
640 { "from:", 5, client_from },
641 { "cookie:", 7, client_send_cookie },
642 { "x-forwarded-for:", 16, client_x_forwarded },
643 { "Accept-Encoding:", 16, client_accept_encoding },
644 { "TE:", 3, client_te },
645 { "Host:", 5, client_host },
646 { "if-modified-since:", 18, client_if_modified_since },
647 { "Keep-Alive:", 11, crumble },
648 { "connection:", 11, crumble },
649 { "proxy-connection:", 17, crumble },
650 { "max-forwards:", 13, client_max_forwards },
651 { "Accept-Language:", 16, client_accept_language },
652 { "if-none-match:", 14, client_if_none_match },
653 { "X-Filter:", 9, client_x_filter },
654 { "*", 0, crunch_client_header },
655 { "*", 0, filter_client_header },
659 const struct parsers server_patterns[] = {
660 { "HTTP", 4, server_http },
661 { "set-cookie:", 11, server_set_cookie },
662 { "connection:", 11, crumble },
663 { "Content-Type:", 13, server_content_type },
664 { "Content-Length:", 15, server_content_length },
665 { "Content-MD5:", 12, server_content_md5 },
666 { "Content-Encoding:", 17, server_content_encoding },
667 { "Transfer-Encoding:", 18, server_transfer_coding },
668 { "Keep-Alive:", 11, crumble },
669 { "content-disposition:", 20, server_content_disposition },
670 { "Last-Modified:", 14, server_last_modified },
671 { "*", 0, crunch_server_header },
672 { "*", 0, filter_server_header },
676 const struct parsers server_patterns_light[] = {
677 { "Content-Length:", 15, server_content_length },
678 { "Transfer-Encoding:", 18, server_transfer_coding },
680 { "Content-Encoding:", 17, server_content_encoding },
681 #endif /* def FEATURE_ZLIB */
685 const add_header_func_ptr add_client_headers[] = {
688 client_x_forwarded_adder,
690 /* Temporarily disabled: client_accept_encoding_adder, */
691 connection_close_adder,
696 const add_header_func_ptr add_server_headers[] = {
697 connection_close_adder,
701 /*********************************************************************
703 * Function : flush_socket
705 * Description : Write any pending "buffered" content.
708 * 1 : fd = file descriptor of the socket to read
709 * 2 : csp = Current client state (buffers, headers, etc...)
711 * Returns : On success, the number of bytes written are returned (zero
712 * indicates nothing was written). On error, -1 is returned,
713 * and errno is set appropriately. If count is zero and the
714 * file descriptor refers to a regular file, 0 will be
715 * returned without causing any other effect. For a special
716 * file, the results are not portable.
718 *********************************************************************/
719 int flush_socket(jb_socket fd, struct client_state *csp)
721 struct iob *iob = csp->iob;
722 int len = iob->eod - iob->cur;
729 if (write_socket(fd, iob->cur, (size_t)len))
733 iob->eod = iob->cur = iob->buf;
739 /*********************************************************************
741 * Function : add_to_iob
743 * Description : Add content to the buffered page, expanding the
744 * buffer if necessary.
747 * 1 : csp = Current client state (buffers, headers, etc...)
748 * 2 : buf = holds the content to be added to the page
749 * 3 : n = number of bytes to be added
751 * Returns : JB_ERR_OK on success, JB_ERR_MEMORY if out-of-memory
752 * or buffer limit reached.
754 *********************************************************************/
755 jb_err add_to_iob(struct client_state *csp, char *buf, int n)
757 struct iob *iob = csp->iob;
758 size_t used, offset, need, want;
761 if (n <= 0) return JB_ERR_OK;
763 used = (size_t)(iob->eod - iob->buf);
764 offset = (size_t)(iob->cur - iob->buf);
765 need = used + (size_t)n + 1;
768 * If the buffer can't hold the new data, extend it first.
769 * Use the next power of two if possible, else use the actual need.
771 if (need > csp->config->buffer_limit)
773 log_error(LOG_LEVEL_ERROR, "Buffer limit reached while extending the buffer (iob)");
774 return JB_ERR_MEMORY;
777 if (need > iob->size)
779 for (want = csp->iob->size ? csp->iob->size : 512; want <= need;) want *= 2;
781 if (want <= csp->config->buffer_limit && NULL != (p = (char *)realloc(iob->buf, want)))
785 else if (NULL != (p = (char *)realloc(iob->buf, need)))
791 log_error(LOG_LEVEL_ERROR, "Extending the buffer (iob) failed: %E");
792 return JB_ERR_MEMORY;
795 /* Update the iob pointers */
796 iob->cur = p + offset;
801 /* copy the new data into the iob buffer */
802 memcpy(iob->eod, buf, (size_t)n);
804 /* point to the end of the data */
807 /* null terminate == cheap insurance */
816 /*********************************************************************
818 * Function : decompress_iob
820 * Description : Decompress buffered page, expanding the
821 * buffer as necessary. csp->iob->cur
822 * should point to the the beginning of the
823 * compressed data block.
826 * 1 : csp = Current client state (buffers, headers, etc...)
828 * Returns : JB_ERR_OK on success,
829 * JB_ERR_MEMORY if out-of-memory limit reached, and
830 * JB_ERR_COMPRESS if error decompressing buffer.
832 *********************************************************************/
833 jb_err decompress_iob(struct client_state *csp)
835 char *buf; /* new, uncompressed buffer */
836 size_t bufsize; /* allocated size of the new buffer */
837 size_t skip_size; /* Number of bytes at the beginning of the iob
838 that we should NOT decompress. */
839 int status; /* return status of the inflate() call */
840 z_stream zstr; /* used by calls to zlib */
842 bufsize = csp->iob->size;
843 skip_size = (size_t)(csp->iob->cur - csp->iob->buf);
848 * This is to protect the parsing of gzipped data,
849 * but it should(?) be valid for deflated data also.
851 log_error (LOG_LEVEL_ERROR, "Buffer too small decompressing iob");
852 return JB_ERR_COMPRESS;
855 if (csp->content_type & CT_GZIP)
858 * Our task is slightly complicated by the facts that data
859 * compressed by gzip does not include a zlib header, and
860 * that there is no easily accessible interface in zlib to
861 * handle a gzip header. We strip off the gzip header by
862 * hand, and later inform zlib not to expect a header.
866 * Strip off the gzip header. Please see RFC 1952 for more
867 * explanation of the appropriate fields.
869 if ((*csp->iob->cur++ != (char)0x1f)
870 || (*csp->iob->cur++ != (char)0x8b)
871 || (*csp->iob->cur++ != Z_DEFLATED))
873 log_error (LOG_LEVEL_ERROR, "Invalid gzip header when decompressing");
874 return JB_ERR_COMPRESS;
878 int flags = *csp->iob->cur++;
880 * XXX: These magic numbers should be replaced
881 * with macros to give a better idea what they do.
885 /* The gzip header has reserved bits set; bail out. */
886 log_error (LOG_LEVEL_ERROR, "Invalid gzip header when decompressing");
887 return JB_ERR_COMPRESS;
891 /* Skip extra fields if necessary. */
895 * Skip a given number of bytes, specified
896 * as a 16-bit little-endian value.
898 csp->iob->cur += *csp->iob->cur++ + (*csp->iob->cur++ << 8);
901 /* Skip the filename if necessary. */
904 /* A null-terminated string follows. */
905 while (*csp->iob->cur++);
908 /* Skip the comment if necessary. */
911 while (*csp->iob->cur++);
914 /* Skip the CRC if necessary. */
921 else if (csp->content_type & CT_DEFLATE)
924 * XXX: The debug level should be lowered
925 * before the next stable release.
927 log_error (LOG_LEVEL_INFO, "Decompressing deflated iob: %d", *csp->iob->cur);
929 * In theory (that is, according to RFC 1950), deflate-compressed
930 * data should begin with a two-byte zlib header and have an
931 * adler32 checksum at the end. It seems that in practice only
932 * the raw compressed data is sent. Note that this means that
933 * we are not RFC 1950-compliant here, but the advantage is that
934 * this actually works. :)
936 * We add a dummy null byte to tell zlib where the data ends,
937 * and later inform it not to expect a header.
939 * Fortunately, add_to_iob() has thoughtfully null-terminated
940 * the buffer; we can just increment the end pointer to include
947 log_error (LOG_LEVEL_ERROR,
948 "Unable to determine compression format for decompression");
949 return JB_ERR_COMPRESS;
952 /* Set up the fields required by zlib. */
953 zstr.next_in = (Bytef *)csp->iob->cur;
954 zstr.avail_in = (unsigned int)(csp->iob->eod - csp->iob->cur);
955 zstr.zalloc = Z_NULL;
957 zstr.opaque = Z_NULL;
960 * Passing -MAX_WBITS to inflateInit2 tells the library
961 * that there is no zlib header.
963 if (inflateInit2 (&zstr, -MAX_WBITS) != Z_OK)
965 log_error (LOG_LEVEL_ERROR, "Error initializing decompression");
966 return JB_ERR_COMPRESS;
970 * Next, we allocate new storage for the inflated data.
971 * We don't modify the existing iob yet, so in case there
972 * is error in decompression we can recover gracefully.
974 buf = zalloc (bufsize);
977 log_error (LOG_LEVEL_ERROR, "Out of memory decompressing iob");
978 return JB_ERR_MEMORY;
981 assert(bufsize >= skip_size);
982 memcpy(buf, csp->iob->buf, skip_size);
983 zstr.avail_out = bufsize - skip_size;
984 zstr.next_out = (Bytef *)buf + skip_size;
986 /* Try to decompress the whole stream in one shot. */
987 while (Z_BUF_ERROR == (status = inflate(&zstr, Z_FINISH)))
989 /* We need to allocate more memory for the output buffer. */
991 char *tmpbuf; /* used for realloc'ing the buffer */
992 size_t oldbufsize = bufsize; /* keep track of the old bufsize */
995 * If zlib wants more data then there's a problem, because
996 * the complete compressed file should have been buffered.
998 if (0 == zstr.avail_in)
1000 log_error(LOG_LEVEL_ERROR, "Unexpected end of compressed iob");
1001 return JB_ERR_COMPRESS;
1005 * If we tried the limit and still didn't have enough
1006 * memory, just give up.
1008 if (bufsize == csp->config->buffer_limit)
1010 log_error(LOG_LEVEL_ERROR, "Buffer limit reached while decompressing iob");
1011 return JB_ERR_MEMORY;
1014 /* Try doubling the buffer size each time. */
1017 /* Don't exceed the buffer limit. */
1018 if (bufsize > csp->config->buffer_limit)
1020 bufsize = csp->config->buffer_limit;
1023 /* Try to allocate the new buffer. */
1024 tmpbuf = realloc(buf, bufsize);
1027 log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob");
1029 return JB_ERR_MEMORY;
1033 char *oldnext_out = (char *)zstr.next_out;
1036 * Update the fields for inflate() to use the new
1037 * buffer, which may be in a location different from
1040 zstr.avail_out += bufsize - oldbufsize;
1041 zstr.next_out = (Bytef *)tmpbuf + bufsize - zstr.avail_out;
1044 * Compare with an uglier method of calculating these values
1045 * that doesn't require the extra oldbufsize variable.
1047 assert(zstr.avail_out == tmpbuf + bufsize - (char *)zstr.next_out);
1048 assert((char *)zstr.next_out == tmpbuf + ((char *)oldnext_out - buf));
1049 assert(zstr.avail_out > 0);
1055 if (Z_STREAM_ERROR == inflateEnd(&zstr))
1057 log_error(LOG_LEVEL_ERROR,
1058 "Inconsistent stream state after decompression: %s", zstr.msg);
1060 * XXX: Intentionally no return.
1062 * According to zlib.h, Z_STREAM_ERROR is returned
1063 * "if the stream state was inconsistent".
1065 * I assume in this case inflate()'s status
1066 * would also be something different than Z_STREAM_END
1067 * so this check should be redundant, but lets see.
1071 if (status != Z_STREAM_END)
1073 /* We failed to decompress the stream. */
1074 log_error(LOG_LEVEL_ERROR,
1075 "Error in decompressing to the buffer (iob): %s", zstr.msg);
1076 return JB_ERR_COMPRESS;
1080 * Finally, we can actually update the iob, since the
1081 * decompression was successful. First, free the old
1084 freez(csp->iob->buf);
1086 /* Now, update the iob to use the new buffer. */
1087 csp->iob->buf = buf;
1088 csp->iob->cur = csp->iob->buf + skip_size;
1089 csp->iob->eod = (char *)zstr.next_out;
1090 csp->iob->size = bufsize;
1093 * Make sure the new uncompressed iob obeys some minimal
1094 * consistency conditions.
1096 if ((csp->iob->buf < csp->iob->cur)
1097 && (csp->iob->cur <= csp->iob->eod)
1098 && (csp->iob->eod <= csp->iob->buf + csp->iob->size))
1100 char t = csp->iob->cur[100];
1101 csp->iob->cur[100] = '\0';
1103 * XXX: The debug level should be lowered
1104 * before the next stable release.
1106 log_error(LOG_LEVEL_INFO, "Sucessfully decompressed: %s", csp->iob->cur);
1107 csp->iob->cur[100] = t;
1112 /* It seems that zlib did something weird. */
1113 log_error(LOG_LEVEL_ERROR,
1114 "Unexpected error decompressing the buffer (iob): %d==%d, %d>%d, %d<%d",
1115 csp->iob->cur, csp->iob->buf + skip_size, csp->iob->eod, csp->iob->buf,
1116 csp->iob->eod, csp->iob->buf + csp->iob->size);
1117 return JB_ERR_COMPRESS;
1121 #endif /* defined(FEATURE_ZLIB) */
1124 /*********************************************************************
1126 * Function : get_header
1128 * Description : This (odd) routine will parse the csp->iob
1131 * 1 : csp = Current client state (buffers, headers, etc...)
1133 * Returns : Any one of the following:
1135 * 1) a pointer to a dynamically allocated string that contains a header line
1136 * 2) NULL indicating that the end of the header was reached
1137 * 3) "" indicating that the end of the iob was reached before finding
1138 * a complete header line.
1140 *********************************************************************/
1141 char *get_header(struct client_state *csp)
1147 if ((iob->cur == NULL)
1148 || ((p = strchr(iob->cur, '\n')) == NULL))
1150 return(""); /* couldn't find a complete header */
1155 ret = strdup(iob->cur);
1158 /* FIXME No way to handle error properly */
1159 log_error(LOG_LEVEL_FATAL, "Out of memory in get_header()");
1164 if ((q = strchr(ret, '\r')) != NULL) *q = '\0';
1166 /* is this a blank line (i.e. the end of the header) ? */
1178 /*********************************************************************
1180 * Function : get_header_value
1182 * Description : Get the value of a given header from a chained list
1183 * of header lines or return NULL if no such header is
1184 * present in the list.
1187 * 1 : header_list = pointer to list
1188 * 2 : header_name = string with name of header to look for.
1189 * Trailing colon required, capitalization
1192 * Returns : NULL if not found, else value of header
1194 *********************************************************************/
1195 char *get_header_value(const struct list *header_list, const char *header_name)
1197 struct list_entry *cur_entry;
1201 assert(header_list);
1202 assert(header_name);
1203 length = strlen(header_name);
1205 for (cur_entry = header_list->first; cur_entry ; cur_entry = cur_entry->next)
1209 if (!strncmpic(cur_entry->str, header_name, length))
1212 * Found: return pointer to start of value
1214 ret = (char *) (cur_entry->str + length);
1215 while (*ret && ijb_isspace(*ret)) ret++;
1228 /*********************************************************************
1232 * Description : add, delete or modify lines in the HTTP header streams.
1233 * On entry, it receives a linked list of headers space
1234 * that was allocated dynamically (both the list nodes
1235 * and the header contents).
1237 * As a side effect it frees the space used by the original
1241 * 1 : pats = list of patterns to match against headers
1242 * 2 : more_headers = list of functions to add more
1243 * headers (client or server)
1244 * 3 : csp = Current client state (buffers, headers, etc...)
1246 * Returns : Single pointer to a fully formed header, or NULL
1247 * on out-of-memory error.
1249 *********************************************************************/
1250 char *sed(const struct parsers pats[],
1251 const add_header_func_ptr more_headers[],
1252 struct client_state *csp)
1254 struct list_entry *p;
1255 const struct parsers *v;
1256 const add_header_func_ptr *f;
1257 jb_err err = JB_ERR_OK;
1261 * If filtering is enabled, sed is run twice,
1262 * but most of the work needs to be done only once.
1264 first_run = (more_headers != NULL ) ? 1 : 0;
1266 if (first_run) /* Parse and print */
1268 log_error(LOG_LEVEL_HEADER, "scanning headers for: %s", csp->http->url);
1269 for (v = pats; (err == JB_ERR_OK) && (v->str != NULL) ; v++)
1271 for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL) ; p = p->next)
1273 /* Header crunch()ed in previous run? -> ignore */
1274 if (p->str == NULL) continue;
1276 if (v == pats) log_error(LOG_LEVEL_HEADER, "scan: %s", p->str);
1278 /* Does the current parser handle this header? */
1279 if ((strncmpic(p->str, v->str, v->len) == 0) || (v->len == CHECK_EVERY_HEADER_REMAINING))
1281 err = v->parser(csp, (char **)&(p->str));
1285 /* place any additional headers on the csp->headers list */
1286 for (f = more_headers; (err == JB_ERR_OK) && (*f) ; f++)
1291 else /* Parse only */
1294 * The second run is only needed if the body was modified
1295 * and the content-lenght has changed.
1297 if (strncmpic(csp->http->cmd, "HEAD", 4))
1299 /*XXX: Code duplication */
1300 for (v = pats; (err == JB_ERR_OK) && (v->str != NULL) ; v++)
1302 for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL) ; p = p->next)
1304 /* Header crunch()ed in previous run? -> ignore */
1305 if (p->str == NULL) continue;
1307 /* Does the current parser handle this header? */
1308 if (strncmpic(p->str, v->str, v->len) == 0)
1310 err = v->parser(csp, (char **)&(p->str));
1317 if (err != JB_ERR_OK)
1322 return list_to_text(csp->headers);
1326 /* here begins the family of parser functions that reformat header lines */
1328 /*********************************************************************
1330 * Function : filter_server_header
1332 * Description : Checks if server header filtering is enabled.
1333 * If it is, filter_header is called to do the work.
1336 * 1 : csp = Current client state (buffers, headers, etc...)
1337 * 2 : header = On input, pointer to header to modify.
1338 * On output, pointer to the modified header, or NULL
1339 * to remove the header. This function frees the
1340 * original string if necessary.
1342 * Returns : JB_ERR_OK on success and always succeeds
1344 *********************************************************************/
1345 jb_err filter_server_header(struct client_state *csp, char **header)
1347 if (csp->action->flags & ACTION_FILTER_SERVER_HEADERS)
1349 filter_header(csp, header);
1354 /*********************************************************************
1356 * Function : filter_client_header
1358 * Description : Checks if client header filtering is enabled.
1359 * If it is, filter_header is called to do the work.
1362 * 1 : csp = Current client state (buffers, headers, etc...)
1363 * 2 : header = On input, pointer to header to modify.
1364 * On output, pointer to the modified header, or NULL
1365 * to remove the header. This function frees the
1366 * original string if necessary.
1368 * Returns : JB_ERR_OK on success and always succeeds
1370 *********************************************************************/
1371 jb_err filter_client_header(struct client_state *csp, char **header)
1373 if (csp->action->flags & ACTION_FILTER_CLIENT_HEADERS)
1375 filter_header(csp, header);
1380 /*********************************************************************
1382 * Function : filter_header
1384 * Description : Executes all text substitutions from all applying
1385 * +filter actions on the header.
1386 * Most of the code was copied from pcrs_filter_response,
1387 * including the rather short variable names
1390 * 1 : csp = Current client state (buffers, headers, etc...)
1391 * 2 : header = On input, pointer to header to modify.
1392 * On output, pointer to the modified header, or NULL
1393 * to remove the header. This function frees the
1394 * original string if necessary.
1396 * Returns : JB_ERR_OK on success and always succeeds
1398 *********************************************************************/
1399 jb_err filter_header(struct client_state *csp, char **header)
1403 size_t size = strlen(*header);
1405 char *newheader = NULL;
1408 struct file_list *fl;
1409 struct re_filterfile_spec *b;
1410 struct list_entry *filtername;
1412 int i, found_filters = 0;
1415 * Need to check the set of re_filterfiles...
1417 for (i = 0; i < MAX_AF_FILES; i++)
1430 if (0 == found_filters)
1432 log_error(LOG_LEVEL_ERROR, "Unable to get current state of regexp filtering.");
1436 for (i = 0; i < MAX_AF_FILES; i++)
1439 if ((NULL == fl) || (NULL == fl->f))
1442 * Either there are no filter files
1443 * left, or this filter file just
1444 * contains no valid filters.
1446 * Continue to be sure we don't miss
1447 * valid filter files that are chained
1448 * after empty or invalid ones.
1453 * For all applying +filter actions, look if a filter by that
1454 * name exists and if yes, execute its pcrs_joblist on the
1457 for (b = fl->f; b; b = b->next)
1459 for (filtername = csp->action->multi[ACTION_MULTI_FILTER]->first;
1460 filtername ; filtername = filtername->next)
1462 if (strcmp(b->name, filtername->str) == 0)
1464 int current_hits = 0;
1466 if ( NULL == b->joblist )
1468 log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name);
1472 log_error(LOG_LEVEL_RE_FILTER, "re_filtering %s (size %d) with filter %s...",
1473 *header, size, b->name);
1475 /* Apply all jobs from the joblist */
1476 for (job = b->joblist; NULL != job; job = job->next)
1478 matches = pcrs_execute(job, *header, size, &newheader, &size);
1481 current_hits += matches;
1482 log_error(LOG_LEVEL_HEADER, "Transforming \"%s\" to \"%s\"", *header, newheader);
1484 *header = newheader;
1486 else if ( 0 == matches )
1488 /* Filter doesn't change header */
1494 log_error(LOG_LEVEL_ERROR, "Filtering \'%s\' with \'%s\' didn't work out: %s",
1495 *header, b->name, pcrs_strerror(matches));
1496 if( newheader != NULL)
1498 log_error(LOG_LEVEL_ERROR, "Freeing what's left: %s", newheader);
1503 log_error(LOG_LEVEL_RE_FILTER, " ...produced %d hits (new size %d).", current_hits, size);
1504 hits += current_hits;
1511 * Additionally checking for hits is important because if
1512 * the continue hack is triggered, server headers can
1513 * arrive empty to separate multiple heads from each other.
1515 if ((0 == size) && hits)
1517 log_error(LOG_LEVEL_HEADER, "Removing empty header %s", *header);
1525 /*********************************************************************
1527 * Function : crumble
1529 * Description : This is called if a header matches a pattern to "crunch"
1532 * 1 : csp = Current client state (buffers, headers, etc...)
1533 * 2 : header = On input, pointer to header to modify.
1534 * On output, pointer to the modified header, or NULL
1535 * to remove the header. This function frees the
1536 * original string if necessary.
1538 * Returns : JB_ERR_OK on success, or
1539 * JB_ERR_MEMORY on out-of-memory error.
1541 *********************************************************************/
1542 jb_err crumble(struct client_state *csp, char **header)
1544 log_error(LOG_LEVEL_HEADER, "crumble crunched: %s!", *header);
1549 /*********************************************************************
1551 * Function : crunch_server_header
1553 * Description : Crunch server header if it matches a string supplied by the
1554 * user. Called from `sed'.
1557 * 1 : csp = Current client state (buffers, headers, etc...)
1558 * 2 : header = On input, pointer to header to modify.
1559 * On output, pointer to the modified header, or NULL
1560 * to remove the header. This function frees the
1561 * original string if necessary.
1563 * Returns : JB_ERR_OK on success and always succeeds
1565 *********************************************************************/
1566 jb_err crunch_server_header(struct client_state *csp, char **header)
1568 const char *crunch_pattern;
1569 /*Is there a header to crunch*/
1571 if ((csp->action->flags & ACTION_CRUNCH_SERVER_HEADER))
1573 crunch_pattern = csp->action->string[ACTION_STRING_SERVER_HEADER];
1575 /*Is the current header the lucky one?*/
1576 if (strstr(*header, crunch_pattern))
1578 log_error(LOG_LEVEL_HEADER, "Crunching server header: %s (contains: %s)", *header, crunch_pattern);
1587 /*********************************************************************
1589 * Function : server_content_type
1591 * Description : Set the content-type for filterable types (text/.*,
1592 * .*xml.*, javascript and image/gif) unless filtering has been
1593 * forbidden (CT_TABOO) while parsing earlier headers.
1594 * NOTE: Since text/plain is commonly used by web servers
1595 * for files whose correct type is unknown, we don't
1596 * set CT_TEXT for it.
1599 * 1 : csp = Current client state (buffers, headers, etc...)
1600 * 2 : header = On input, pointer to header to modify.
1601 * On output, pointer to the modified header, or NULL
1602 * to remove the header. This function frees the
1603 * original string if necessary.
1605 * Returns : JB_ERR_OK on success, or
1606 * JB_ERR_MEMORY on out-of-memory error.
1608 *********************************************************************/
1609 jb_err server_content_type(struct client_state *csp, char **header)
1611 /* Remove header if it isn't the first Content-Type header */
1612 if(csp->content_type && (csp->content_type != CT_TABOO))
1615 * Another, slightly slower, way to see if
1616 * we already parsed another Content-Type header.
1618 assert(NULL != get_header_value(csp->headers, "Content-Type:"));
1620 log_error(LOG_LEVEL_ERROR,
1621 "Multiple Content-Type headers. Removing and ignoring: \'%s\'",
1628 if (!(csp->content_type & CT_TABOO))
1630 if ((strstr(*header, " text/") && !strstr(*header, "plain"))
1631 || strstr(*header, "xml")
1632 || strstr(*header, "application/x-javascript"))
1634 csp->content_type |= CT_TEXT;
1636 else if (strstr(*header, " image/gif"))
1638 csp->content_type |= CT_GIF;
1640 else if (strstr(*header, " image/jpeg"))
1642 csp->content_type |= CT_JPEG;
1646 csp->content_type = 0;
1650 * Are we enabling text mode by force?
1652 if (csp->action->flags & ACTION_FORCE_TEXT_MODE)
1655 * Do we really have to?
1657 if (csp->content_type & CT_TEXT)
1659 log_error(LOG_LEVEL_HEADER, "Text mode is already enabled.");
1663 csp->content_type |= CT_TEXT;
1664 log_error(LOG_LEVEL_HEADER, "Text mode enabled by force. Take cover!");
1668 * Are we messing with the content type?
1670 if (csp->action->flags & ACTION_CONTENT_TYPE_OVERWRITE)
1673 * Make sure the user doesn't accidently
1674 * change the content type of binary documents.
1676 if (csp->content_type & CT_TEXT)
1679 *header = strdup("Content-Type: ");
1680 string_append(header, csp->action->string[ACTION_STRING_CONTENT_TYPE]);
1684 log_error(LOG_LEVEL_HEADER, "Insufficient memory to replace Content-Type!");
1685 return JB_ERR_MEMORY;
1687 log_error(LOG_LEVEL_HEADER, "Modified: %s!", *header);
1691 log_error(LOG_LEVEL_HEADER, "%s not replaced. It doesn't look like text. "
1692 "Enable force-text-mode if you know what you're doing.", *header);
1699 /*********************************************************************
1701 * Function : server_transfer_coding
1703 * Description : - Prohibit filtering (CT_TABOO) if transfer coding compresses
1704 * - Raise the CSP_FLAG_CHUNKED flag if coding is "chunked"
1705 * - Remove header if body was chunked but has been
1706 * de-chunked for filtering.
1709 * 1 : csp = Current client state (buffers, headers, etc...)
1710 * 2 : header = On input, pointer to header to modify.
1711 * On output, pointer to the modified header, or NULL
1712 * to remove the header. This function frees the
1713 * original string if necessary.
1715 * Returns : JB_ERR_OK on success, or
1716 * JB_ERR_MEMORY on out-of-memory error.
1718 *********************************************************************/
1719 jb_err server_transfer_coding(struct client_state *csp, char **header)
1722 * Turn off pcrs and gif filtering if body compressed
1724 if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate"))
1728 * XXX: Added to test if we could use CT_GZIP and CT_DEFLATE here.
1730 log_error(LOG_LEVEL_INFO, "Marking content type for %s as CT_TABOO because of %s.",
1731 csp->http->cmd, *header);
1732 #endif /* def FEATURE_ZLIB */
1733 csp->content_type = CT_TABOO;
1737 * Raise flag if body chunked
1739 if (strstr(*header, "chunked"))
1741 csp->flags |= CSP_FLAG_CHUNKED;
1744 * If the body was modified, it has been de-chunked first
1745 * and the header must be removed.
1747 * FIXME: If there is more than one transfer encoding,
1748 * only the "chunked" part should be removed here.
1750 if (csp->flags & CSP_FLAG_MODIFIED)
1752 log_error(LOG_LEVEL_HEADER, "Removing: %s", *header);
1761 /*********************************************************************
1763 * Function : server_content_encoding
1765 * Description : This function is run twice for each request,
1766 * unless FEATURE_ZLIB and filtering are disabled.
1768 * The first run is used to check if the content
1769 * is compressed, if FEATURE_ZLIB is disabled
1770 * filtering is then disabled as well, if FEATURE_ZLIB
1771 * is enabled the content is marked for decompression.
1773 * The second run is used to remove the Content-Encoding
1774 * header if the decompression was successful.
1777 * 1 : csp = Current client state (buffers, headers, etc...)
1778 * 2 : header = On input, pointer to header to modify.
1779 * On output, pointer to the modified header, or NULL
1780 * to remove the header. This function frees the
1781 * original string if necessary.
1783 * Returns : JB_ERR_OK on success, or
1784 * JB_ERR_MEMORY on out-of-memory error.
1786 *********************************************************************/
1787 jb_err server_content_encoding(struct client_state *csp, char **header)
1790 /* XXX: Why would we modify the content if it was taboo? */
1791 if ((csp->flags & CSP_FLAG_MODIFIED) && !(csp->content_type & CT_TABOO))
1794 * We successfully decompressed the content,
1795 * and have to clean the header now, so the
1796 * client no longer expects compressed data..
1798 * XXX: There is a difference between cleaning
1799 * and removing it completely.
1801 log_error(LOG_LEVEL_HEADER, "Crunching: %s", *header);
1804 else if (strstr(*header, "gzip"))
1806 /* Mark for gzip decompression */
1807 csp->content_type |= CT_GZIP;
1809 else if (strstr(*header, "deflate"))
1811 /* Mark for zlib decompression */
1812 csp->content_type |= CT_DEFLATE;
1814 else if (strstr(*header, "compress"))
1817 * We can't decompress this; therefore we can't filter
1820 csp->content_type |= CT_TABOO;
1822 #else /* !defined(FEATURE_ZLIB) */
1823 if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate"))
1826 * Body is compressed, turn off pcrs and gif filtering.
1828 csp->content_type |= CT_TABOO;
1830 #endif /* !defined(FEATURE_ZLIB) */
1837 /*********************************************************************
1839 * Function : server_content_length
1841 * Description : Adjust Content-Length header if we modified
1845 * 1 : csp = Current client state (buffers, headers, etc...)
1846 * 2 : header = On input, pointer to header to modify.
1847 * On output, pointer to the modified header, or NULL
1848 * to remove the header. This function frees the
1849 * original string if necessary.
1851 * Returns : JB_ERR_OK on success, or
1852 * JB_ERR_MEMORY on out-of-memory error.
1854 *********************************************************************/
1855 jb_err server_content_length(struct client_state *csp, char **header)
1857 const size_t max_header_length = 80;
1858 if (csp->content_length != 0) /* Content length could have been modified */
1861 * XXX: Shouldn't we check if csp->content_length
1862 * is different than the original value?
1865 *header = (char *) zalloc(max_header_length);
1866 if (*header == NULL)
1868 return JB_ERR_MEMORY;
1871 snprintf(*header, max_header_length, "Content-Length: %d",
1872 (int)csp->content_length);
1873 log_error(LOG_LEVEL_HEADER, "Adjusted Content-Length to %d",
1874 (int)csp->content_length);
1881 /*********************************************************************
1883 * Function : server_content_md5
1885 * Description : Crumble any Content-MD5 headers if the document was
1886 * modified. FIXME: Should we re-compute instead?
1889 * 1 : csp = Current client state (buffers, headers, etc...)
1890 * 2 : header = On input, pointer to header to modify.
1891 * On output, pointer to the modified header, or NULL
1892 * to remove the header. This function frees the
1893 * original string if necessary.
1895 * Returns : JB_ERR_OK on success, or
1896 * JB_ERR_MEMORY on out-of-memory error.
1898 *********************************************************************/
1899 jb_err server_content_md5(struct client_state *csp, char **header)
1901 if (csp->flags & CSP_FLAG_MODIFIED)
1903 log_error(LOG_LEVEL_HEADER, "Crunching Content-MD5");
1910 /*********************************************************************
1912 * Function : server_content_disposition
1914 * Description : If enabled, blocks or modifies the "content-disposition" header.
1915 * Called from `sed'.
1918 * 1 : csp = Current client state (buffers, headers, etc...)
1919 * 2 : header = On input, pointer to header to modify.
1920 * On output, pointer to the modified header, or NULL
1921 * to remove the header. This function frees the
1922 * original string if necessary.
1924 * Returns : JB_ERR_OK on success, or
1925 * JB_ERR_MEMORY on out-of-memory error.
1927 *********************************************************************/
1928 jb_err server_content_disposition(struct client_state *csp, char **header)
1933 * Are we messing with the content-disposition header?
1935 if ((csp->action->flags & ACTION_HIDE_CONTENT_DISPOSITION) == 0)
1941 newval = csp->action->string[ACTION_STRING_CONTENT_DISPOSITION];
1943 if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
1946 * Blocking content-disposition header
1948 log_error(LOG_LEVEL_HEADER, "Crunching %s!", *header);
1955 * Replacing content-disposition header
1958 *header = strdup("content-disposition: ");
1959 string_append(header, newval);
1961 if (*header == NULL)
1963 log_error(LOG_LEVEL_HEADER, "Insufficent memory. content-disposition header not fully replaced.");
1967 log_error(LOG_LEVEL_HEADER, "content-disposition header crunched and replaced with: %s", *header);
1970 return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
1973 /*********************************************************************
1975 * Function : server_last_modified
1977 * Description : Changes Last-Modified header to the actual date
1978 * to help hide-if-modified-since.
1979 * Called from `sed'.
1982 * 1 : csp = Current client state (buffers, headers, etc...)
1983 * 2 : header = On input, pointer to header to modify.
1984 * On output, pointer to the modified header, or NULL
1985 * to remove the header. This function frees the
1986 * original string if necessary.
1988 * Returns : JB_ERR_OK on success, or
1989 * JB_ERR_MEMORY on out-of-memory error.
1991 *********************************************************************/
1992 jb_err server_last_modified(struct client_state *csp, char **header)
1995 char buf[BUFFER_SIZE];
1998 #ifdef HAVE_GMTIME_R
2001 struct tm *timeptr = NULL;
2002 time_t now, last_modified;
2004 long int days, hours, minutes, seconds;
2007 * Are we messing with the Last-Modified header?
2009 if ((csp->action->flags & ACTION_OVERWRITE_LAST_MODIFIED) == 0)
2015 newval = csp->action->string[ACTION_STRING_LAST_MODIFIED];
2017 if (0 == strcmpic(newval, "block") )
2020 * Blocking Last-Modified header. Useless but why not.
2022 log_error(LOG_LEVEL_HEADER, "Crunching %s!", *header);
2026 else if (0 == strcmpic(newval, "reset-to-request-time"))
2029 * Setting Last-Modified Header to now.
2031 get_http_time(0, buf);
2033 *header = strdup("Last-Modified: ");
2034 string_append(header, buf);
2036 if (*header == NULL)
2038 log_error(LOG_LEVEL_HEADER, "Insufficent memory. Last-Modified header got lost, boohoo.");
2042 log_error(LOG_LEVEL_HEADER, "Reset to present time: %s", *header);
2045 else if (0 == strcmpic(newval, "randomize"))
2047 log_error(LOG_LEVEL_HEADER, "Randomizing: %s", *header);
2049 #ifdef HAVE_GMTIME_R
2050 timeptr = gmtime_r(&now, &gmt);
2051 #elif FEATURE_PTHREAD
2052 pthread_mutex_lock(&gmtime_mutex);
2053 timeptr = gmtime(&now);
2054 pthread_mutex_unlock(&gmtime_mutex);
2056 timeptr = gmtime(&now);
2058 if ((timeptr = parse_header_time(*header, &last_modified)) == NULL)
2060 log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s (crunching!)", *header);
2065 rtime = (long int)difftime(now, last_modified);
2068 rtime = pick_from_range(rtime);
2069 last_modified += rtime;
2070 #ifdef HAVE_GMTIME_R
2071 timeptr = gmtime_r(&last_modified, &gmt);
2072 #elif FEATURE_PTHREAD
2073 pthread_mutex_lock(&gmtime_mutex);
2074 timeptr = gmtime(&last_modified);
2075 pthread_mutex_unlock(&gmtime_mutex);
2077 timeptr = gmtime(&last_modified);
2079 strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr);
2081 *header = strdup("Last-Modified: ");
2082 string_append(header, newheader);
2084 if (*header == NULL)
2086 log_error(LOG_LEVEL_ERROR, "Insufficent memory, header crunched without replacement.");
2087 return JB_ERR_MEMORY;
2090 if(LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */
2092 days = rtime / (3600 * 24);
2093 hours = rtime / 3600 % 24;
2094 minutes = rtime / 60 % 60;
2095 seconds = rtime % 60;
2097 log_error(LOG_LEVEL_HEADER, "Randomized: %s (added %d da%s %d hou%s %d minut%s %d second%s",
2098 *header, days, (days == 1) ? "y" : "ys", hours, (hours == 1) ? "r" : "rs",
2099 minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)");
2104 log_error(LOG_LEVEL_HEADER, "Randomized ... or not. No time difference to work with.");
2112 /*********************************************************************
2114 * Function : client_accept_encoding
2116 * Description : Rewrite the client's Accept-Encoding header so that
2117 * if doesn't allow compression, if the action applies.
2118 * Note: For HTTP/1.0 the absence of the header is enough.
2121 * 1 : csp = Current client state (buffers, headers, etc...)
2122 * 2 : header = On input, pointer to header to modify.
2123 * On output, pointer to the modified header, or NULL
2124 * to remove the header. This function frees the
2125 * original string if necessary.
2127 * Returns : JB_ERR_OK on success, or
2128 * JB_ERR_MEMORY on out-of-memory error.
2130 *********************************************************************/
2131 jb_err client_accept_encoding(struct client_state *csp, char **header)
2133 if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
2135 log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress content");
2139 /* Temporarily disable the correct behaviour to
2140 * work around a PHP bug.
2142 * if (!strcmpic(csp->http->ver, "HTTP/1.1"))
2144 * *header = strdup("Accept-Encoding: identity;q=1.0, *;q=0");
2145 * if (*header == NULL)
2147 * return JB_ERR_MEMORY;
2158 /*********************************************************************
2160 * Function : client_te
2162 * Description : Rewrite the client's TE header so that
2163 * if doesn't allow compression, if the action applies.
2166 * 1 : csp = Current client state (buffers, headers, etc...)
2167 * 2 : header = On input, pointer to header to modify.
2168 * On output, pointer to the modified header, or NULL
2169 * to remove the header. This function frees the
2170 * original string if necessary.
2172 * Returns : JB_ERR_OK on success, or
2173 * JB_ERR_MEMORY on out-of-memory error.
2175 *********************************************************************/
2176 jb_err client_te(struct client_state *csp, char **header)
2178 if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
2181 log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress transfer");
2187 /*********************************************************************
2189 * Function : client_referrer
2191 * Description : Handle the "referer" config setting properly.
2192 * Called from `sed'.
2195 * 1 : csp = Current client state (buffers, headers, etc...)
2196 * 2 : header = On input, pointer to header to modify.
2197 * On output, pointer to the modified header, or NULL
2198 * to remove the header. This function frees the
2199 * original string if necessary.
2201 * Returns : JB_ERR_OK on success, or
2202 * JB_ERR_MEMORY on out-of-memory error.
2204 *********************************************************************/
2205 jb_err client_referrer(struct client_state *csp, char **header)
2212 #ifdef FEATURE_FORCE_LOAD
2213 /* Since the referrer can include the prefix even
2214 * if the request itself is non-forced, we must
2215 * clean it unconditionally
2217 strclean(*header, FORCE_PREFIX);
2218 #endif /* def FEATURE_FORCE_LOAD */
2221 * Are we sending referer?
2223 if ((csp->action->flags & ACTION_HIDE_REFERER) == 0)
2228 newval = csp->action->string[ACTION_STRING_REFERER];
2230 if ((0 != strcmpic(newval, "conditional-block")))
2234 if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
2239 log_error(LOG_LEVEL_HEADER, "Referer crunched!");
2242 else if (0 == strcmpic(newval, "conditional-block"))
2245 * Block referer if host has changed.
2248 if (NULL == (host = strdup(csp->http->hostport)))
2251 log_error(LOG_LEVEL_HEADER, "Referer crunched! Couldn't allocate memory for temporary host copy.");
2252 return JB_ERR_MEMORY;
2254 if (NULL == (referer = strdup(*header)))
2258 log_error(LOG_LEVEL_HEADER, "Referer crunched! Couldn't allocate memory for temporary referer copy.");
2259 return JB_ERR_MEMORY;
2261 hostlenght = strlen(host);
2262 if ( hostlenght < (strlen(referer)-17) ) /*referer begins with 'Referer: http[s]://'*/
2264 /*Shorten referer to make sure the referer is blocked
2265 *if www.example.org/www.example.com-shall-see-the-referer/
2266 *links to www.example.com/
2268 referer[hostlenght+17] = '\0';
2270 if ( 0 == strstr(referer, host)) /*Host has changed*/
2272 log_error(LOG_LEVEL_HEADER, "New host is: %s. Crunching %s!", host, *header);
2277 log_error(LOG_LEVEL_HEADER, "%s (not modified, still on %s)", *header, host);
2283 else if (0 != strcmpic(newval, "forge"))
2286 * We have a specific (fixed) referer we want to send.
2288 if ((0 != strncmpic(newval, "http://", 7)) && (0 != strncmpic(newval, "https://", 8)))
2290 log_error(LOG_LEVEL_HEADER, "Parameter: +referrer{%s} is a bad idea, but I don't care.", newval);
2292 *header = strdup("Referer: ");
2293 string_append(header, newval);
2294 log_error(LOG_LEVEL_HEADER, "Referer overwritten with: %s", *header);
2296 return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2301 * Forge a referer as http://[hostname:port of REQUEST]/
2302 * to fool stupid checks for in-site links
2305 *header = strdup("Referer: http://");
2306 string_append(header, csp->http->hostport);
2307 string_append(header, "/");
2308 log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header);
2310 return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2314 /*********************************************************************
2316 * Function : client_accept_language
2318 * Description : Handle the "Accept-Language" config setting properly.
2319 * Called from `sed'.
2322 * 1 : csp = Current client state (buffers, headers, etc...)
2323 * 2 : header = On input, pointer to header to modify.
2324 * On output, pointer to the modified header, or NULL
2325 * to remove the header. This function frees the
2326 * original string if necessary.
2328 * Returns : JB_ERR_OK on success, or
2329 * JB_ERR_MEMORY on out-of-memory error.
2331 *********************************************************************/
2332 jb_err client_accept_language(struct client_state *csp, char **header)
2337 * Are we messing with the Accept-Language?
2339 if ((csp->action->flags & ACTION_HIDE_ACCEPT_LANGUAGE) == 0)
2341 /*I don't think so*/
2345 newval = csp->action->string[ACTION_STRING_LANGUAGE];
2347 if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
2350 * Blocking Accept-Language header
2352 log_error(LOG_LEVEL_HEADER, "Crunching Accept-Language!");
2359 * Replacing Accept-Language header
2362 *header = strdup("Accept-Language: ");
2363 string_append(header, newval);
2365 if (*header == NULL)
2367 log_error(LOG_LEVEL_ERROR,
2368 "Insufficent memory. Accept-Language header crunched without replacement.");
2372 log_error(LOG_LEVEL_HEADER,
2373 "Accept-Language header crunched and replaced with: %s", *header);
2376 return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2379 /*********************************************************************
2381 * Function : crunch_client_header
2383 * Description : Crunch client header if it matches a string supplied by the
2384 * user. Called from `sed'.
2387 * 1 : csp = Current client state (buffers, headers, etc...)
2388 * 2 : header = On input, pointer to header to modify.
2389 * On output, pointer to the modified header, or NULL
2390 * to remove the header. This function frees the
2391 * original string if necessary.
2393 * Returns : JB_ERR_OK on success and always succeeds
2395 *********************************************************************/
2396 jb_err crunch_client_header(struct client_state *csp, char **header)
2398 const char *crunch_pattern;
2399 /*Is there a header to crunch*/
2401 if ((csp->action->flags & ACTION_CRUNCH_CLIENT_HEADER))
2403 crunch_pattern = csp->action->string[ACTION_STRING_CLIENT_HEADER];
2405 /*Is the current header the lucky one?*/
2406 if (strstr(*header, crunch_pattern))
2408 log_error(LOG_LEVEL_HEADER, "Crunching client header: %s (contains: %s)", *header, crunch_pattern);
2416 /*********************************************************************
2418 * Function : client_uagent
2420 * Description : Handle the "user-agent" config setting properly
2421 * and remember its original value to enable browser
2422 * bug workarounds. Called from `sed'.
2425 * 1 : csp = Current client state (buffers, headers, etc...)
2426 * 2 : header = On input, pointer to header to modify.
2427 * On output, pointer to the modified header, or NULL
2428 * to remove the header. This function frees the
2429 * original string if necessary.
2431 * Returns : JB_ERR_OK on success, or
2432 * JB_ERR_MEMORY on out-of-memory error.
2434 *********************************************************************/
2435 jb_err client_uagent(struct client_state *csp, char **header)
2439 if ((csp->action->flags & ACTION_HIDE_USER_AGENT) == 0)
2444 newval = csp->action->string[ACTION_STRING_USER_AGENT];
2451 *header = strdup("User-Agent: ");
2452 string_append(header, newval);
2454 log_error(LOG_LEVEL_HEADER, "Modified: %s", *header);
2456 return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2459 /*********************************************************************
2461 * Function : client_ua
2463 * Description : Handle "ua-" headers properly. Called from `sed'.
2466 * 1 : csp = Current client state (buffers, headers, etc...)
2467 * 2 : header = On input, pointer to header to modify.
2468 * On output, pointer to the modified header, or NULL
2469 * to remove the header. This function frees the
2470 * original string if necessary.
2472 * Returns : JB_ERR_OK on success, or
2473 * JB_ERR_MEMORY on out-of-memory error.
2475 *********************************************************************/
2476 jb_err client_ua(struct client_state *csp, char **header)
2478 if ((csp->action->flags & ACTION_HIDE_USER_AGENT) != 0)
2480 log_error(LOG_LEVEL_HEADER, "crunched User-Agent!");
2488 /*********************************************************************
2490 * Function : client_from
2492 * Description : Handle the "from" config setting properly.
2493 * Called from `sed'.
2496 * 1 : csp = Current client state (buffers, headers, etc...)
2497 * 2 : header = On input, pointer to header to modify.
2498 * On output, pointer to the modified header, or NULL
2499 * to remove the header. This function frees the
2500 * original string if necessary.
2502 * Returns : JB_ERR_OK on success, or
2503 * JB_ERR_MEMORY on out-of-memory error.
2505 *********************************************************************/
2506 jb_err client_from(struct client_state *csp, char **header)
2510 if ((csp->action->flags & ACTION_HIDE_FROM) == 0)
2517 newval = csp->action->string[ACTION_STRING_FROM];
2520 * Are we blocking the e-mail address?
2522 if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
2524 log_error(LOG_LEVEL_HEADER, "crunched From!");
2528 log_error(LOG_LEVEL_HEADER, " modified");
2530 *header = strdup("From: ");
2531 string_append(header, newval);
2533 return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
2537 /*********************************************************************
2539 * Function : client_send_cookie
2541 * Description : Handle the "cookie" header properly. Called from `sed'.
2542 * If cookie is accepted, add it to the cookie_list,
2543 * else we crunch it. Mmmmmmmmmmm ... cookie ......
2546 * 1 : csp = Current client state (buffers, headers, etc...)
2547 * 2 : header = On input, pointer to header to modify.
2548 * On output, pointer to the modified header, or NULL
2549 * to remove the header. This function frees the
2550 * original string if necessary.
2552 * Returns : JB_ERR_OK on success, or
2553 * JB_ERR_MEMORY on out-of-memory error.
2555 *********************************************************************/
2556 jb_err client_send_cookie(struct client_state *csp, char **header)
2558 jb_err result = JB_ERR_OK;
2560 if ((csp->action->flags & ACTION_NO_COOKIE_READ) == 0)
2562 /* strlen("cookie: ") == 8 */
2563 result = enlist(csp->cookie_list, *header + 8);
2567 log_error(LOG_LEVEL_HEADER, "Crunched outgoing cookie -- yum!");
2571 * Always remove the cookie here. The cookie header
2572 * will be sent at the end of the header.
2580 /*********************************************************************
2582 * Function : client_x_forwarded
2584 * Description : Handle the "x-forwarded-for" config setting properly,
2585 * also used in the add_client_headers list. Called from `sed'.
2588 * 1 : csp = Current client state (buffers, headers, etc...)
2589 * 2 : header = On input, pointer to header to modify.
2590 * On output, pointer to the modified header, or NULL
2591 * to remove the header. This function frees the
2592 * original string if necessary.
2594 * Returns : JB_ERR_OK on success, or
2595 * JB_ERR_MEMORY on out-of-memory error.
2597 *********************************************************************/
2598 jb_err client_x_forwarded(struct client_state *csp, char **header)
2600 if ((csp->action->flags & ACTION_HIDE_FORWARDED) == 0)
2602 /* Save it so we can re-add it later */
2603 freez(csp->x_forwarded);
2604 csp->x_forwarded = *header;
2607 * Always set *header = NULL, since this information
2608 * will be sent at the end of the header.
2615 log_error(LOG_LEVEL_HEADER, "crunched x-forwarded-for!");
2622 /*********************************************************************
2624 * Function : client_max_forwards
2626 * Description : If the HTTP method is OPTIONS or TRACE, subtract one
2627 * from the value of the Max-Forwards header field.
2630 * 1 : csp = Current client state (buffers, headers, etc...)
2631 * 2 : header = On input, pointer to header to modify.
2632 * On output, pointer to the modified header, or NULL
2633 * to remove the header. This function frees the
2634 * original string if necessary.
2636 * Returns : JB_ERR_OK on success, or
2637 * JB_ERR_MEMORY on out-of-memory error.
2639 *********************************************************************/
2640 jb_err client_max_forwards(struct client_state *csp, char **header)
2642 unsigned int max_forwards;
2644 if ((0 == strcmpic(csp->http->gpc, "trace")) ||
2645 (0 == strcmpic(csp->http->gpc, "options")))
2647 if (1 == sscanf(*header, "Max-Forwards: %u", &max_forwards))
2649 if (max_forwards-- > 0)
2651 snprintf(*header, strlen(*header)+1, "Max-Forwards: %u", max_forwards);
2652 log_error(LOG_LEVEL_HEADER, "Max-Forwards header for %s request replaced with: %s",
2653 csp->http->gpc, *header);
2657 /* FIXME: Follow spec and intercept the request. */
2658 log_error(LOG_LEVEL_ERROR,
2659 "Non-intercepted %s request with Max-Forwards zero!", csp->http->gpc);
2668 /*********************************************************************
2670 * Function : client_host
2672 * Description : If the request URI did not contain host and
2673 * port information, parse and evaluate the Host
2676 * Also, kill ill-formed HOST: headers as sent by
2677 * Apple's iTunes software when used with a proxy.
2680 * 1 : csp = Current client state (buffers, headers, etc...)
2681 * 2 : header = On input, pointer to header to modify.
2682 * On output, pointer to the modified header, or NULL
2683 * to remove the header. This function frees the
2684 * original string if necessary.
2686 * Returns : JB_ERR_OK on success, or
2687 * JB_ERR_MEMORY on out-of-memory error.
2689 *********************************************************************/
2690 jb_err client_host(struct client_state *csp, char **header)
2695 * If the header field name is all upper-case, chances are that it's
2696 * an ill-formed one from iTunes. BTW, killing innocent headers here is
2697 * not a problem -- they are regenerated later.
2699 if ((*header)[1] == 'O')
2701 log_error(LOG_LEVEL_HEADER, "Killed all-caps Host header line: %s", *header);
2706 if (!csp->http->hostport || (*csp->http->hostport == '*') ||
2707 *csp->http->hostport == ' ' || *csp->http->hostport == '\0')
2710 if (NULL == (p = strdup((*header)+6)))
2712 return JB_ERR_MEMORY;
2715 if (NULL == (q = strdup(p)))
2718 return JB_ERR_MEMORY;
2721 freez(csp->http->hostport);
2722 csp->http->hostport = p;
2723 freez(csp->http->host);
2724 csp->http->host = q;
2725 q = strchr(csp->http->host, ':');
2728 /* Terminate hostname and evaluate port string */
2730 csp->http->port = atoi(q);
2734 csp->http->port = csp->http->ssl ? 443 : 80;
2737 log_error(LOG_LEVEL_HEADER, "New host and port from Host field: %s = %s:%d",
2738 csp->http->hostport, csp->http->host, csp->http->port);
2744 /*********************************************************************
2746 * Function : client_if_modified_since
2748 * Description : Remove or modify the If-Modified-Since header.
2751 * 1 : csp = Current client state (buffers, headers, etc...)
2752 * 2 : header = On input, pointer to header to modify.
2753 * On output, pointer to the modified header, or NULL
2754 * to remove the header. This function frees the
2755 * original string if necessary.
2757 * Returns : JB_ERR_OK on success, or
2758 * JB_ERR_MEMORY on out-of-memory error.
2760 *********************************************************************/
2761 jb_err client_if_modified_since(struct client_state *csp, char **header)
2764 #ifdef HAVE_GMTIME_R
2767 struct tm *timeptr = NULL;
2771 long int hours, minutes, seconds;
2775 if ( 0 == strcmpic(*header, "If-Modified-Since: Wed, 08 Jun 1955 12:00:00 GMT"))
2778 * The client got an error message because of a temporary problem,
2779 * the problem is gone and the client now tries to revalidate our
2780 * error message on the real server. The revalidation would always
2781 * end with the transmission of the whole document and there is
2782 * no need to expose the bogus If-Modified-Since header.
2784 log_error(LOG_LEVEL_HEADER, "Crunching useless If-Modified-Since header.");
2787 else if (csp->action->flags & ACTION_HIDE_IF_MODIFIED_SINCE)
2789 newval = csp->action->string[ACTION_STRING_IF_MODIFIED_SINCE];
2791 if ((0 == strcmpic(newval, "block")))
2793 log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
2796 else /* add random value */
2798 if ((timeptr = parse_header_time(*header, &tm)) == NULL)
2800 log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s (crunching!)", *header);
2805 rtime = strtol(newval, &endptr, 0);
2808 log_error(LOG_LEVEL_HEADER, "Randomizing: %s (random range: %d minut%s)",
2809 *header, rtime, (rtime == 1 || rtime == -1) ? "e": "es");
2816 rtime = pick_from_range(rtime);
2820 log_error(LOG_LEVEL_ERROR, "Random range is 0. Assuming time transformation test.",
2823 tm += rtime * (negative ? -1 : 1);
2824 #ifdef HAVE_GMTIME_R
2825 timeptr = gmtime_r(&tm, &gmt);
2826 #elif FEATURE_PTHREAD
2827 pthread_mutex_lock(&gmtime_mutex);
2828 timeptr = gmtime(&tm);
2829 pthread_mutex_unlock(&gmtime_mutex);
2831 timeptr = gmtime(&tm);
2833 strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr);
2836 *header = strdup("If-Modified-Since: ");
2837 string_append(header, newheader);
2839 if (*header == NULL)
2841 log_error(LOG_LEVEL_HEADER, "Insufficent memory, header crunched without replacement.");
2842 return JB_ERR_MEMORY;
2845 if(LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */
2847 hours = rtime / 3600;
2848 minutes = rtime / 60 % 60;
2849 seconds = rtime % 60;
2851 log_error(LOG_LEVEL_HEADER, "Randomized: %s (%s %d hou%s %d minut%s %d second%s",
2852 *header, (negative) ? "subtracted" : "added", hours, (hours == 1) ? "r" : "rs",
2853 minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)");
2862 /*********************************************************************
2864 * Function : client_if_none_match
2866 * Description : Remove the If-None-Match header.
2869 * 1 : csp = Current client state (buffers, headers, etc...)
2870 * 2 : header = On input, pointer to header to modify.
2871 * On output, pointer to the modified header, or NULL
2872 * to remove the header. This function frees the
2873 * original string if necessary.
2875 * Returns : JB_ERR_OK on success, or
2876 * JB_ERR_MEMORY on out-of-memory error.
2878 *********************************************************************/
2879 jb_err client_if_none_match(struct client_state *csp, char **header)
2881 if (csp->action->flags & ACTION_CRUNCH_IF_NONE_MATCH)
2883 log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
2890 /*********************************************************************
2892 * Function : client_x_filter
2894 * Description : Disables filtering if the client set "X-Filter: No".
2895 * Called from `sed'.
2898 * 1 : csp = Current client state (buffers, headers, etc...)
2899 * 2 : header = On input, pointer to header to modify.
2900 * On output, pointer to the modified header, or NULL
2901 * to remove the header. This function frees the
2902 * original string if necessary.
2904 * Returns : JB_ERR_OK on success
2906 *********************************************************************/
2907 jb_err client_x_filter(struct client_state *csp, char **header)
2909 if ( 0 == strcmpic(*header, "X-Filter: No"))
2911 if (!(csp->config->feature_flags & RUNTIME_FEATURE_HTTP_TOGGLE))
2913 log_error(LOG_LEVEL_INFO, "Ignored the client's request to fetch without filtering.");
2917 if (csp->action->flags & ACTION_FORCE_TEXT_MODE)
2919 log_error(LOG_LEVEL_HEADER,
2920 "force-text-mode overruled the client's request to fetch without filtering!");
2924 csp->content_type = CT_TABOO;
2925 csp->action->flags &= ~ACTION_FILTER_SERVER_HEADERS;
2926 csp->action->flags &= ~ACTION_FILTER_CLIENT_HEADERS;
2927 log_error(LOG_LEVEL_HEADER, "Accepted the client's request to fetch without filtering.");
2929 log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
2936 /* the following functions add headers directly to the header list */
2938 /*********************************************************************
2940 * Function : client_host_adder
2942 * Description : Adds the Host: header field if it is missing.
2943 * Called from `sed'.
2946 * 1 : csp = Current client state (buffers, headers, etc...)
2948 * Returns : JB_ERR_OK on success, or
2949 * JB_ERR_MEMORY on out-of-memory error.
2951 *********************************************************************/
2952 jb_err client_host_adder(struct client_state *csp)
2957 if ( !csp->http->hostport || !*(csp->http->hostport))
2963 * remove 'user:pass@' from 'proto://user:pass@host'
2965 if ( (p = strchr( csp->http->hostport, '@')) != NULL )
2971 p = csp->http->hostport;
2974 log_error(LOG_LEVEL_HEADER, "addh-unique: Host: %s", p);
2975 err = enlist_unique_header(csp->headers, "Host", p);
2981 /*********************************************************************
2983 * Function : client_cookie_adder
2985 * Description : Used in the add_client_headers list. Called from `sed'.
2988 * 1 : csp = Current client state (buffers, headers, etc...)
2990 * Returns : JB_ERR_OK on success, or
2991 * JB_ERR_MEMORY on out-of-memory error.
2993 *********************************************************************/
2994 jb_err client_cookie_adder(struct client_state *csp)
2996 struct list_entry *lst;
2998 struct list_entry *list1 = csp->cookie_list->first;
2999 struct list_entry *list2 = csp->action->multi[ACTION_MULTI_WAFER]->first;
3000 int first_cookie = 1;
3003 if ((list1 == NULL) && (list2 == NULL))
3009 tmp = strdup("Cookie: ");
3011 for (lst = list1; lst ; lst = lst->next)
3019 string_append(&tmp, "; ");
3021 string_append(&tmp, lst->str);
3024 for (lst = list2; lst ; lst = lst->next)
3032 string_append(&tmp, "; ");
3034 string_join(&tmp, cookie_encode(lst->str));
3039 return JB_ERR_MEMORY;
3042 log_error(LOG_LEVEL_HEADER, "addh: %s", tmp);
3043 err = enlist(csp->headers, tmp);
3049 /*********************************************************************
3051 * Function : client_accept_encoding_adder
3053 * Description : Add an Accept-Encoding header to the client's request
3054 * that disables compression if the action applies, and
3055 * the header is not already there. Called from `sed'.
3056 * Note: For HTTP/1.0, the absence of the header is enough.
3059 * 1 : csp = Current client state (buffers, headers, etc...)
3061 * Returns : JB_ERR_OK on success, or
3062 * JB_ERR_MEMORY on out-of-memory error.
3064 *********************************************************************/
3065 jb_err client_accept_encoding_adder(struct client_state *csp)
3067 if ( ((csp->action->flags & ACTION_NO_COMPRESSION) != 0)
3068 && (!strcmpic(csp->http->ver, "HTTP/1.1")) )
3070 return enlist_unique(csp->headers, "Accept-Encoding: identity;q=1.0, *;q=0", 16);
3077 /*********************************************************************
3079 * Function : client_xtra_adder
3081 * Description : Used in the add_client_headers list. Called from `sed'.
3084 * 1 : csp = Current client state (buffers, headers, etc...)
3086 * Returns : JB_ERR_OK on success, or
3087 * JB_ERR_MEMORY on out-of-memory error.
3089 *********************************************************************/
3090 jb_err client_xtra_adder(struct client_state *csp)
3092 struct list_entry *lst;
3095 for (lst = csp->action->multi[ACTION_MULTI_ADD_HEADER]->first;
3096 lst ; lst = lst->next)
3098 log_error(LOG_LEVEL_HEADER, "addh: %s", lst->str);
3099 err = enlist(csp->headers, lst->str);
3111 /*********************************************************************
3113 * Function : client_x_forwarded_adder
3115 * Description : Used in the add_client_headers list. Called from `sed'.
3118 * 1 : csp = Current client state (buffers, headers, etc...)
3120 * Returns : JB_ERR_OK on success, or
3121 * JB_ERR_MEMORY on out-of-memory error.
3123 *********************************************************************/
3124 jb_err client_x_forwarded_adder(struct client_state *csp)
3129 if ((csp->action->flags & ACTION_HIDE_FORWARDED) != 0)
3134 if (csp->x_forwarded)
3136 p = strdup(csp->x_forwarded);
3137 string_append(&p, ", ");
3141 p = strdup("X-Forwarded-For: ");
3143 string_append(&p, csp->ip_addr_str);
3147 return JB_ERR_MEMORY;
3150 log_error(LOG_LEVEL_HEADER, "addh: %s", p);
3151 err = enlist(csp->headers, p);
3158 /*********************************************************************
3160 * Function : connection_close_adder
3162 * Description : Adds a "Connection: close" header to csp->headers
3163 * as a temporary fix for the needed but missing HTTP/1.1
3164 * support. Called from `sed'.
3165 * FIXME: This whole function shouldn't be neccessary!
3168 * 1 : csp = Current client state (buffers, headers, etc...)
3170 * Returns : JB_ERR_OK on success, or
3171 * JB_ERR_MEMORY on out-of-memory error.
3173 *********************************************************************/
3174 jb_err connection_close_adder(struct client_state *csp)
3176 log_error(LOG_LEVEL_HEADER, "Adding: Connection: close");
3177 return enlist(csp->headers, "Connection: close");
3181 /*********************************************************************
3183 * Function : server_http
3185 * Description : - Save the HTTP Status into csp->http->status
3186 * - Set CT_TABOO to prevent filtering if the answer
3187 * is a partial range (HTTP status 206)
3188 * - Rewrite HTTP/1.1 answers to HTTP/1.0 if +downgrade
3192 * 1 : csp = Current client state (buffers, headers, etc...)
3193 * 2 : header = On input, pointer to header to modify.
3194 * On output, pointer to the modified header, or NULL
3195 * to remove the header. This function frees the
3196 * original string if necessary.
3198 * Returns : JB_ERR_OK on success, or
3199 * JB_ERR_MEMORY on out-of-memory error.
3201 *********************************************************************/
3202 jb_err server_http(struct client_state *csp, char **header)
3204 sscanf(*header, "HTTP/%*d.%*d %d", &(csp->http->status));
3205 if (csp->http->status == 206)
3207 csp->content_type = CT_TABOO;
3210 if ((csp->action->flags & ACTION_DOWNGRADE) != 0)
3213 log_error(LOG_LEVEL_HEADER, "Downgraded answer to HTTP/1.0");
3220 /*********************************************************************
3222 * Function : server_set_cookie
3224 * Description : Handle the server "cookie" header properly.
3225 * Log cookie to the jar file. Then "crunch" it,
3226 * or accept it. Called from `sed'.
3229 * 1 : csp = Current client state (buffers, headers, etc...)
3230 * 2 : header = On input, pointer to header to modify.
3231 * On output, pointer to the modified header, or NULL
3232 * to remove the header. This function frees the
3233 * original string if necessary.
3235 * Returns : JB_ERR_OK on success, or
3236 * JB_ERR_MEMORY on out-of-memory error.
3238 *********************************************************************/
3239 jb_err server_set_cookie(struct client_state *csp, char **header)
3241 #ifdef FEATURE_COOKIE_JAR
3242 if (csp->config->jar)
3245 * Write timestamp into outbuf.
3247 * Complex because not all OSs have tm_gmtoff or
3248 * the %z field in strftime()
3250 char tempbuf[ BUFFER_SIZE ];
3254 #ifdef HAVE_LOCALTIME_R
3255 tm_now = *localtime_r(&now, &tm_now);
3256 #elif FEATURE_PTHREAD
3257 pthread_mutex_lock(&localtime_mutex);
3258 tm_now = *localtime (&now);
3259 pthread_mutex_unlock(&localtime_mutex);
3261 tm_now = *localtime (&now);
3263 strftime(tempbuf, BUFFER_SIZE-6, "%b %d %H:%M:%S ", &tm_now);
3265 /* strlen("set-cookie: ") = 12 */
3266 fprintf(csp->config->jar, "%s %s\t%s\n", tempbuf, csp->http->host, *header + 12);
3268 #endif /* def FEATURE_COOKIE_JAR */
3270 if ((csp->action->flags & ACTION_NO_COOKIE_SET) != 0)
3272 log_error(LOG_LEVEL_HEADER, "Crunched incoming cookie -- yum!");
3273 return crumble(csp, header);
3275 else if ((csp->action->flags & ACTION_NO_COOKIE_KEEP) != 0)
3277 /* Flag whether or not to log a message */
3280 /* A variable to store the tag we're working on */
3283 /* Skip "Set-Cookie:" (11 characters) in header */
3284 cur_tag = *header + 11;
3286 /* skip whitespace between "Set-Cookie:" and value */
3287 while (*cur_tag && ijb_isspace(*cur_tag))
3292 /* Loop through each tag in the cookie */
3296 char *next_tag = strchr(cur_tag, ';');
3297 if (next_tag != NULL)
3299 /* Skip the ';' character itself */
3302 /* skip whitespace ";" and start of tag */
3303 while (*next_tag && ijb_isspace(*next_tag))
3310 /* "Next tag" is the end of the string */
3311 next_tag = cur_tag + strlen(cur_tag);
3314 /* Is this the "Expires" tag? */
3315 if (strncmpic(cur_tag, "expires=", 8) == 0)
3317 /* Delete the tag by copying the rest of the string over it.
3318 * (Note that we cannot just use "strcpy(cur_tag, next_tag)",
3319 * since the behaviour of strcpy is undefined for overlapping
3322 memmove(cur_tag, next_tag, strlen(next_tag) + 1);
3324 /* That changed the header, need to issue a log message */
3327 /* Note that the next tag has now been moved to *cur_tag,
3328 * so we do not need to update the cur_tag pointer.
3333 /* Move on to next cookie tag */
3340 log_error(LOG_LEVEL_HEADER, "Changed cookie to a temporary one.");
3348 #ifdef FEATURE_FORCE_LOAD
3349 /*********************************************************************
3351 * Function : strclean
3353 * Description : In-Situ-Eliminate all occurances of substring in
3357 * 1 : string = string to clean
3358 * 2 : substring = substring to eliminate
3360 * Returns : Number of eliminations
3362 *********************************************************************/
3363 int strclean(const char *string, const char *substring)
3369 len = strlen(substring);
3371 while((pos = strstr(string, substring)) != NULL)
3378 while (*p++ != '\0');
3385 #endif /* def FEATURE_FORCE_LOAD */
3387 /*********************************************************************
3389 * Function : parse_header_time
3391 * Description : Transforms time inside a HTTP header into
3392 * the usual time format.
3395 * 1 : header = header to parse
3396 * 2 : tm = storage for the resulting time in seconds
3398 * Returns : Time struct containing the header time, or
3399 * NULL in case of a parsing problems.
3401 *********************************************************************/
3402 struct tm *parse_header_time(char *header, time_t *tm) {
3406 struct tm * timeptr;
3409 * Initializing gmt to prevent time zone offsets.
3411 * While this is only necessary on some platforms
3412 * (mingw32 for example), I don't know how to
3413 * detect these automatically and doing it everywhere
3417 #ifdef HAVE_LOCALTIME_R
3418 gmt = *localtime_r(tm, &gmt);
3419 #elif FEATURE_PTHREAD
3420 pthread_mutex_lock(&localtime_mutex);
3421 gmt = *localtime(tm);
3422 pthread_mutex_unlock(&localtime_mutex);
3424 gmt = *localtime(tm);
3427 /* Skipping header name */
3428 timestring = strstr(header, ": ");
3429 if (strptime(timestring, ": %a, %d %b %Y %H:%M:%S", &gmt) == NULL)
3442 /*********************************************************************
3444 * Function : get_destination_from_headers
3446 * Description : Parse the "Host:" header to get the request's destination.
3447 * Only needed if the client's request was forcefully
3448 * redirected into Privoxy.
3450 * Code mainly copied from client_host() which is currently
3451 * run too late for this purpose.
3454 * 1 : headers = List of headers (one of them hopefully being
3455 * the "Host:" header)
3456 * 2 : http = storage for the result (host, port and hostport).
3458 * Returns : JB_ERR_MEMORY in case of memory problems,
3459 * JB_ERR_PARSE if the host header couldn't be found,
3460 * JB_ERR_OK otherwise.
3462 *********************************************************************/
3463 jb_err get_destination_from_headers(const struct list *headers, struct http_request *http)
3469 host = get_header_value(headers, "Host:");
3473 log_error(LOG_LEVEL_ERROR, "No \"Host:\" header found.");
3474 return JB_ERR_PARSE;
3477 if (NULL == (p = strdup((host))))
3479 log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header");
3480 return JB_ERR_MEMORY;
3483 if (NULL == (q = strdup(p)))
3486 log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header");
3487 return JB_ERR_MEMORY;
3490 freez(http->hostport);
3494 q = strchr(http->host, ':');
3497 /* Terminate hostname and evaluate port string */
3499 http->port = atoi(q);
3503 http->port = http->ssl ? 443 : 80;
3506 /* Rebuild request URL */
3508 http->url = strdup(http->ssl ? "https://" : "http://");
3509 string_append(&http->url, http->hostport);
3510 string_append(&http->url, http->path);
3511 if (http->url == NULL)
3513 return JB_ERR_MEMORY;
3516 log_error(LOG_LEVEL_HEADER, "Destination extracted from \"Host:\" header. New request URL: %s",