-const char parsers_rcs[] = "$Id: parsers.c,v 1.312 2017/06/08 13:13:26 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/parsers.c,v $
*
* Purpose : Declares functions to parse/crunch headers and pages.
*
- * Copyright : Written by and Copyright (C) 2001-2016 the
- * Privoxy team. http://www.privoxy.org/
+ * Copyright : Written by and Copyright (C) 2001-2020 the
+ * Privoxy team. https://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
* by and Copyright (C) 1997 Anonymous Coders and
#define GZIP_FLAG_COMMENT 0x10
#define GZIP_FLAG_RESERVED_BITS 0xe0
#endif
+#ifdef FEATURE_BROTLI
+#include <brotli/decode.h>
+#endif
-#if !defined(_WIN32) && !defined(__OS2__)
+#if !defined(_WIN32)
#include <unistd.h>
#endif
#include "list.h"
#include "actions.h"
#include "filters.h"
+#ifdef FEATURE_HTTPS_INSPECTION
+#include "ssl.h"
+#endif
#ifndef HAVE_STRPTIME
#include "strptime.h"
#endif
-const char parsers_h_rcs[] = PARSERS_H_VERSION;
-
static char *get_header_line(struct iob *iob);
static jb_err scan_headers(struct client_state *csp);
static jb_err header_tagger(struct client_state *csp, char *header);
static jb_err server_keep_alive(struct client_state *csp, char **header);
static jb_err server_proxy_connection(struct client_state *csp, char **header);
static jb_err client_keep_alive(struct client_state *csp, char **header);
-static jb_err client_save_content_length(struct client_state *csp, char **header);
static jb_err client_proxy_connection(struct client_state *csp, char **header);
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+static jb_err client_save_content_length(struct client_state *csp, char **header);
static jb_err client_host_adder (struct client_state *csp);
static jb_err client_xtra_adder (struct client_state *csp);
static jb_err client_x_forwarded_for_adder(struct client_state *csp);
{ "TE:", 3, client_te },
{ "Host:", 5, client_host },
{ "if-modified-since:", 18, client_if_modified_since },
+ { "Content-Length:", 15, client_save_content_length },
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
{ "Keep-Alive:", 11, client_keep_alive },
- { "Content-Length:", 15, client_save_content_length },
{ "Proxy-Connection:", 17, client_proxy_connection },
#else
{ "Keep-Alive:", 11, crumble },
/*********************************************************************
*
- * Function : flush_socket
+ * Function : flush_iob
*
* Description : Write any pending "buffered" content.
*
* Parameters :
* 1 : fd = file descriptor of the socket to read
* 2 : iob = The I/O buffer to flush, usually csp->iob.
+ * 3 : delay = Number of milliseconds to delay the writes
*
* Returns : On success, the number of bytes written are returned (zero
* indicates nothing was written). On error, -1 is returned,
* file, the results are not portable.
*
*********************************************************************/
-long flush_socket(jb_socket fd, struct iob *iob)
+long flush_iob(jb_socket fd, struct iob *iob, unsigned int delay)
{
long len = iob->eod - iob->cur;
return(0);
}
- if (write_socket(fd, iob->cur, (size_t)len))
+ if (write_socket_delayed(fd, iob->cur, (size_t)len, delay))
{
return(-1);
}
if (need > buffer_limit)
{
log_error(LOG_LEVEL_INFO,
- "Buffer limit reached while extending the buffer (iob). Needed: %d. Limit: %d",
+ "Buffer limit reached while extending the buffer (iob). Needed: %lu. Limit: %lu",
need, buffer_limit);
return JB_ERR_MEMORY;
}
* Parameters :
* 1 : iob = I/O buffer to clear.
*
- * Returns : JB_ERR_OK on success, JB_ERR_MEMORY if out-of-memory
- * or buffer limit reached.
+ * Returns : N/A
*
*********************************************************************/
void clear_iob(struct iob *iob)
#ifdef FEATURE_ZLIB
+#ifdef FEATURE_BROTLI
+/*********************************************************************
+ *
+ * Function : decompress_iob_with_brotli
+ *
+ * Description : Decompress buffered page using Brotli.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : JB_ERR_OK on success,
+ * JB_ERR_MEMORY if out-of-memory limit reached, and
+ * JB_ERR_COMPRESS if error decompressing buffer.
+ *
+ *********************************************************************/
+static jb_err decompress_iob_with_brotli(struct client_state *csp)
+{
+ BrotliDecoderResult result;
+ char *decoded_buffer;
+ size_t decoded_size;
+ size_t decoded_buffer_size;
+ size_t encoded_size;
+ enum { MAX_COMPRESSION_FACTOR = 15 };
+
+ encoded_size = (size_t)(csp->iob->eod - csp->iob->cur);
+ /*
+ * The BrotliDecoderDecompress() api is a bit unfortunate
+ * and requires the caller to reserve enough memory for
+ * the decompressed content. Hopefully reserving
+ * MAX_COMPRESSION_FACTOR times the original size is
+ * sufficient. If not, BrotliDecoderDecompress() will fail.
+ */
+ decoded_buffer_size = encoded_size * MAX_COMPRESSION_FACTOR;
+
+ if (decoded_buffer_size > csp->config->buffer_limit)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Buffer limit reached before decompressing iob with Brotli");
+ return JB_ERR_MEMORY;
+ }
+
+ decoded_buffer = malloc(decoded_buffer_size);
+ if (decoded_buffer == NULL)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Failed to allocate %lu bytes for Brotli decompression",
+ decoded_buffer_size);
+ return JB_ERR_MEMORY;
+ }
+
+ decoded_size = decoded_buffer_size;
+ result = BrotliDecoderDecompress(encoded_size,
+ (const uint8_t *)csp->iob->cur, &decoded_size,
+ (uint8_t *)decoded_buffer);
+ if (result == BROTLI_DECODER_RESULT_SUCCESS)
+ {
+ /*
+ * Update the iob, since the decompression was successful.
+ */
+ freez(csp->iob->buf);
+ csp->iob->buf = decoded_buffer;
+ csp->iob->cur = csp->iob->buf;
+ csp->iob->eod = csp->iob->cur + decoded_size;
+ csp->iob->size = decoded_buffer_size;
+
+ log_error(LOG_LEVEL_RE_FILTER,
+ "Decompression successful. Old size: %lu, new size: %lu.",
+ encoded_size, decoded_size);
+
+ return JB_ERR_OK;
+ }
+ else
+ {
+ log_error(LOG_LEVEL_ERROR, "Failed to decompress buffer with Brotli");
+ freez(decoded_buffer);
+
+ return JB_ERR_COMPRESS;
+ }
+}
+#endif
+
/*********************************************************************
*
* Function : decompress_iob
* but it should(?) be valid for deflated data also.
*/
log_error(LOG_LEVEL_ERROR,
- "Insufficient data to start decompression. Bytes in buffer: %d",
+ "Insufficient data to start decompression. Bytes in buffer: %ld",
csp->iob->eod - csp->iob->cur);
return JB_ERR_COMPRESS;
}
+#ifdef FEATURE_BROTLI
+ if (csp->content_type & CT_BROTLI)
+ {
+ return decompress_iob_with_brotli(csp);
+ }
+#endif
+
if (csp->content_type & CT_GZIP)
{
/*
if (bufsize >= csp->config->buffer_limit)
{
log_error(LOG_LEVEL_ERROR, "Buffer limit reached while decompressing iob");
+ freez(buf);
+ inflateEnd(&zstr);
return JB_ERR_MEMORY;
}
{
log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob");
freez(buf);
+ inflateEnd(&zstr);
return JB_ERR_MEMORY;
}
else
* Make sure the new uncompressed iob obeys some minimal
* consistency conditions.
*/
- if ((csp->iob->buf <= csp->iob->cur)
+ if ((csp->iob->buf <= csp->iob->cur)
&& (csp->iob->cur <= csp->iob->eod)
&& (csp->iob->eod <= csp->iob->buf + csp->iob->size))
{
if (new_size > (size_t)0)
{
log_error(LOG_LEVEL_RE_FILTER,
- "Decompression successful. Old size: %d, new size: %d.",
+ "Decompression successful. Old size: %lu, new size: %lu.",
old_size, new_size);
}
else
{
- /* zlib thinks this is OK, so lets do the same. */
- log_error(LOG_LEVEL_INFO, "Decompression didn't result in any content.");
+ /* zlib thinks this is OK, so let's do the same. */
+ log_error(LOG_LEVEL_RE_FILTER,
+ "Decompression didn't result in any content.");
}
}
else
{
/* It seems that zlib did something weird. */
- log_error(LOG_LEVEL_ERROR,
- "Unexpected error decompressing the buffer (iob): %d==%d, %d>%d, %d<%d",
- csp->iob->cur, csp->iob->buf + skip_size, csp->iob->eod, csp->iob->buf,
- csp->iob->eod, csp->iob->buf + csp->iob->size);
+ log_error(LOG_LEVEL_ERROR, "Inconsistent buffer after decompression");
return JB_ERR_COMPRESS;
}
}
+#ifdef FEATURE_HTTPS_INSPECTION
+/*********************************************************************
+ *
+ * Function : sed_https
+ *
+ * Description : add, delete or modify lines in the HTTPS client
+ * header streams. Wrapper around sed().
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : JB_ERR_OK in case off success, or
+ * JB_ERR_MEMORY on some out-of-memory errors, or
+ * JB_ERR_PARSE in case of fatal parse errors.
+ *
+ *********************************************************************/
+jb_err sed_https(struct client_state *csp)
+{
+ jb_err err;
+ struct list headers;
+
+ /*
+ * Temporarily replace csp->headers with csp->https_headers
+ * to trick sed() into filtering the https headers.
+ */
+ headers.first = csp->headers->first;
+ headers.last = csp->headers->last;
+ csp->headers->first = csp->https_headers->first;
+ csp->headers->last = csp->https_headers->last;
+
+ /*
+ * Start with fresh tags. Already existing tags may
+ * be set again. This is necessary to overrule
+ * URL-based patterns.
+ */
+ destroy_list(csp->tags);
+
+ /*
+ * We want client header filters and taggers
+ * so temporarily remove the flag.
+ */
+ csp->flags &= ~CSP_FLAG_CLIENT_HEADER_PARSING_DONE;
+ err = sed(csp, FILTER_CLIENT_HEADERS);
+ csp->flags |= CSP_FLAG_CLIENT_HEADER_PARSING_DONE;
+
+ /*
+ * Update the last header which may have changed
+ * due to header additions,
+ */
+ csp->https_headers->last = csp->headers->last;
+
+ csp->headers->first = headers.first;
+ csp->headers->last = headers.last;
+
+ return err;
+}
+#endif /* def FEATURE_HTTPS_INSPECTION */
+
+
/*********************************************************************
*
* Function : update_server_headers
assert(NULL != header);
log_error(LOG_LEVEL_ERROR,
"Problems with tagger \'%s\' and header \'%s\': %s",
- b->name, *header, pcrs_strerror(hits));
+ b->name, header, pcrs_strerror(hits));
}
freez(modified_tag);
}
continue;
}
+ if (list_contains_item(csp->action->multi[ACTION_MULTI_SUPPRESS_TAG], tag))
+ {
+ log_error(LOG_LEVEL_HEADER,
+ "Tagger \'%s\' didn't add tag \'%s\': suppressed",
+ b->name, tag);
+ freez(tag);
+ continue;
+ }
+
if (!list_contains_item(csp->tags, tag))
{
if (JB_ERR_OK != enlist(csp->tags, tag))
log_error(LOG_LEVEL_ERROR,
"Insufficient memory to add tag \'%s\', "
"based on tagger \'%s\' and header \'%s\'",
- tag, b->name, *header);
+ tag, b->name, header);
}
else
{
continue;
}
- log_error(LOG_LEVEL_RE_FILTER, "filtering \'%s\' (size %d) with \'%s\' ...",
+ log_error(LOG_LEVEL_RE_FILTER, "filtering \'%s\' (size %lu) with \'%s\' ...",
*header, size, b->name);
/* Apply all jobs from the joblist */
if (b->dynamic) pcrs_free_joblist(joblist);
- log_error(LOG_LEVEL_RE_FILTER, "... produced %d hits (new size %d).", current_hits, size);
+ log_error(LOG_LEVEL_RE_FILTER,
+ "... produced %d hits (new size %lu).", current_hits, size);
hits += current_hits;
}
csp->flags |= CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET;
return JB_ERR_OK;
}
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
/*********************************************************************
}
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
/*********************************************************************
*
* Function : client_keep_alive
return JB_ERR_OK;
}
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
/*********************************************************************
return JB_ERR_OK;
}
-#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
-
/*********************************************************************
{
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)
- && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED))
+ && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
+#ifdef FEATURE_HTTPS_INSPECTION
+ && !client_use_ssl(csp)
+#endif
+ )
{
- if (!strcmpic(csp->http->ver, "HTTP/1.1"))
+ if (!strcmpic(csp->http->version, "HTTP/1.1"))
{
log_error(LOG_LEVEL_HEADER,
"Removing \'%s\' to imply keep-alive.", *header);
/* Mark for zlib decompression */
csp->content_type |= CT_DEFLATE;
}
+ else if (strstr(*header, "br"))
+ {
+#ifdef FEATURE_BROTLI
+ /* Mark for Brotli decompression */
+ csp->content_type |= CT_BROTLI;
+#else
+ csp->content_type |= CT_TABOO;
+#endif
+ }
else if (strstr(*header, "compress"))
{
/*
*
* Description : Remove the Content-Encoding header if the
* decompression was successful and the content
- * has been modifed.
+ * has been modified.
*
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
static jb_err server_adjust_content_encoding(struct client_state *csp, char **header)
{
if ((csp->flags & CSP_FLAG_MODIFIED)
- && (csp->content_type & (CT_GZIP | CT_DEFLATE)))
+ && ((csp->content_type & (CT_GZIP | CT_DEFLATE))
+#ifdef FEATURE_BROTLI
+ || (csp->content_type & CT_BROTLI)
+#endif
+ )
+ )
{
/*
* We successfully decompressed the content,
time_t now;
struct tm *timeptr = NULL;
long int rtime;
-#ifdef HAVE_GMTIME_R
struct tm gmt;
-#endif
+
now = time(NULL);
rtime = (long int)difftime(now, last_modified);
if (rtime)
rtime *= -1;
}
last_modified += rtime;
-#ifdef HAVE_GMTIME_R
- timeptr = gmtime_r(&last_modified, &gmt);
-#elif defined(MUTEX_LOCKS_AVAILABLE)
- privoxy_mutex_lock(&gmtime_mutex);
- timeptr = gmtime(&last_modified);
- privoxy_mutex_unlock(&gmtime_mutex);
-#else
- timeptr = gmtime(&last_modified);
-#endif
+ timeptr = privoxy_gmtime_r(&last_modified, &gmt);
if ((NULL == timeptr) || !strftime(newheader,
sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr))
{
freez(*header);
return JB_ERR_OK;
}
-
freez(*header);
*header = strdup("Last-Modified: ");
string_append(header, newheader);
seconds = rtime % 60;
log_error(LOG_LEVEL_HEADER,
- "Randomized: %s (added %d da%s %d hou%s %d minut%s %d second%s",
+ "Randomized: %s (added %ld da%s %ld hou%s %ld minut%s %ld second%s",
*header, days, (days == 1) ? "y" : "ys", hours, (hours == 1) ? "r" : "rs",
minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)");
}
static jb_err client_if_modified_since(struct client_state *csp, char **header)
{
char newheader[50];
-#ifdef HAVE_GMTIME_R
struct tm gmt;
-#endif
struct tm *timeptr = NULL;
time_t tm = 0;
const char *newval;
if (rtime)
{
- log_error(LOG_LEVEL_HEADER, "Randomizing: %s (random range: %d minut%s)",
+ log_error(LOG_LEVEL_HEADER, "Randomizing: %s (random range: %ld minut%s)",
*header, rtime, (rtime == 1 || rtime == -1) ? "e": "es");
if (negative_range)
{
}
else
{
- log_error(LOG_LEVEL_ERROR, "Random range is 0. Assuming time transformation test.",
- *header);
+ log_error(LOG_LEVEL_ERROR,
+ "Random range is 0. Assuming time transformation test.");
}
tm += rtime * (negative_range ? -1 : 1);
-#ifdef HAVE_GMTIME_R
- timeptr = gmtime_r(&tm, &gmt);
-#elif defined(MUTEX_LOCKS_AVAILABLE)
- privoxy_mutex_lock(&gmtime_mutex);
- timeptr = gmtime(&tm);
- privoxy_mutex_unlock(&gmtime_mutex);
-#else
- timeptr = gmtime(&tm);
-#endif
+ timeptr = privoxy_gmtime_r(&tm, &gmt);
if ((NULL == timeptr) || !strftime(newheader,
sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr))
{
freez(*header);
return JB_ERR_OK;
}
-
freez(*header);
*header = strdup("If-Modified-Since: ");
string_append(header, newheader);
seconds = rtime % 60;
log_error(LOG_LEVEL_HEADER,
- "Randomized: %s (%s %d hou%s %d minut%s %d second%s",
+ "Randomized: %s (%s %ld hou%s %ld minut%s %ld second%s",
*header, (negative_range) ? "subtracted" : "added", hours,
(hours == 1) ? "r" : "rs", minutes, (minutes == 1) ? "e" : "es",
seconds, (seconds == 1) ? ")" : "s)");
&& !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
&& !(csp->flags & CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET)
&& ((csp->flags & CSP_FLAG_SERVER_CONTENT_LENGTH_SET)
- || (csp->flags & CSP_FLAG_CHUNKED)))
+ || (csp->flags & CSP_FLAG_CHUNKED))
+#ifdef FEATURE_HTTPS_INSPECTION
+ && !client_use_ssl(csp)
+ && !csp->http->ssl
+#endif
+ )
{
log_error(LOG_LEVEL_HEADER, "Adding: %s", proxy_connection_header);
err = enlist(csp->headers, proxy_connection_header);
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
&& !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
- && !strcmpic(csp->http->ver, "HTTP/1.1"))
+ && !strcmpic(csp->http->version, "HTTP/1.1"))
{
csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
return JB_ERR_OK;
return JB_ERR_PARSE;
}
- if (csp->http->status == 206)
+ if (csp->http->status == 101 ||
+ csp->http->status == 206)
{
csp->content_type = CT_TABOO;
}
char tmp[50];
struct tm *timeptr = NULL;
time_t expiry_date = time(NULL) + lifetime;
-#ifdef HAVE_GMTIME_R
struct tm gmt;
- timeptr = gmtime_r(&expiry_date, &gmt);
-#elif defined(MUTEX_LOCKS_AVAILABLE)
- privoxy_mutex_lock(&gmtime_mutex);
- timeptr = gmtime(&expiry_date);
- privoxy_mutex_unlock(&gmtime_mutex);
-#else
- timeptr = gmtime(&expiry_date);
-#endif
-
+ timeptr = privoxy_gmtime_r(&expiry_date, &gmt);
if (NULL == timeptr)
{
log_error(LOG_LEVEL_FATAL,
{
char recreated_date[100];
struct tm *tm;
+ struct tm storage;
time_t result2;
- tm = gmtime(result);
+ tm = privoxy_gmtime_r(result, &storage);
if (!strftime(recreated_date, sizeof(recreated_date),
time_formats[i], tm))
{
if (*result != result2)
{
log_error(LOG_LEVEL_ERROR, "strftime() and strptime() disagree. "
- "Format: '%s'. In: '%s', out: '%s'. %d != %d. Rejecting.",
+ "Format: '%s'. In: '%s', out: '%s'. %ld != %ld. Rejecting.",
time_formats[i], header_time, recreated_date, *result, result2);
continue;
}
char *p;
char *host;
- assert(!http->ssl);
-
host = get_header_value(headers, "Host:");
if (NULL == host)
return JB_ERR_PARSE;
}
- p = strdup_or_die(host);
+ p = string_tolower(host);
+ if (p == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
chomp(p);
q = strdup_or_die(p);
string_append(&http->cmd, " ");
string_append(&http->cmd, http->url);
string_append(&http->cmd, " ");
- string_append(&http->cmd, http->ver);
+ string_append(&http->cmd, http->version);
+ if (http->cmd == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
+
+ return JB_ERR_OK;
+
+}
+
+
+#ifdef FEATURE_HTTPS_INSPECTION
+/*********************************************************************
+ *
+ * Function : get_destination_from_https_headers
+ *
+ * Description : Parse the previously encrypted "Host:" header to
+ * get the request's destination.
+ *
+ * Parameters :
+ * 1 : headers = List of headers (one of them hopefully being
+ * the "Host:" header)
+ * 2 : http = storage for the result (host, port and hostport).
+ *
+ * Returns : JB_ERR_MEMORY (or terminates) in case of memory problems,
+ * JB_ERR_PARSE if the host header couldn't be found,
+ * JB_ERR_OK otherwise.
+ *
+ *********************************************************************/
+jb_err get_destination_from_https_headers(const struct list *headers, struct http_request *http)
+{
+ char *q;
+ char *p;
+ char *host;
+
+ host = get_header_value(headers, "Host:");
+
+ if (NULL == host)
+ {
+ log_error(LOG_LEVEL_ERROR, "No \"Host:\" header found.");
+ return JB_ERR_PARSE;
+ }
+
+ p = string_tolower(host);
+ if (p == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
+ chomp(p);
+ q = strdup_or_die(p);
+
+ freez(http->hostport);
+ http->hostport = p;
+ freez(http->host);
+ http->host = q;
+ q = strchr(http->host, ':');
+ if (q != NULL)
+ {
+ /* Terminate hostname and evaluate port string */
+ *q++ = '\0';
+ http->port = atoi(q);
+ }
+ else
+ {
+ http->port = 443;
+ }
+
+ /* Rebuild request URL */
+ freez(http->url);
+ http->url = strdup_or_die(http->path);
+
+ log_error(LOG_LEVEL_HEADER,
+ "Destination extracted from \"Host\" header. New request URL: %s",
+ http->url);
+
+ /*
+ * Regenerate request line in "proxy format"
+ * to make rewrites more convenient.
+ */
+ assert(http->cmd != NULL);
+ freez(http->cmd);
+ http->cmd = strdup_or_die(http->gpc);
+ string_append(&http->cmd, " ");
+ string_append(&http->cmd, http->url);
+ string_append(&http->cmd, " ");
+ string_append(&http->cmd, http->version);
if (http->cmd == NULL)
{
return JB_ERR_MEMORY;
return JB_ERR_OK;
}
+#endif /* def FEATURE_HTTPS_INSPECTION */
/*********************************************************************
}
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
/*********************************************************************
*
* Function : get_expected_content_length
return content_length;
}
-#endif
+
/*
Local Variables: