*
* Purpose : Declares functions to parse/crunch headers and pages.
*
- * Copyright : Written by and Copyright (C) 2001-2017 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
/*********************************************************************
*
- * 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 (bufsize >= csp->config->buffer_limit)
{
log_error(LOG_LEVEL_ERROR, "Buffer limit reached while decompressing iob");
+ freez(buf);
return JB_ERR_MEMORY;
}
}
+#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
if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)
&& !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED))
{
- 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);
*
* 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...)
#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
if ((NULL == timeptr) || !strftime(newheader,
sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr))
{
+#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_unlock(&gmtime_mutex);
+#endif
log_error(LOG_LEVEL_ERROR,
"Randomizing '%s' failed. Crunching the header without replacement.",
*header);
freez(*header);
return JB_ERR_OK;
}
-
+#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_unlock(&gmtime_mutex);
+#endif
freez(*header);
*header = strdup("Last-Modified: ");
string_append(header, newheader);
#elif defined(MUTEX_LOCKS_AVAILABLE)
privoxy_mutex_lock(&gmtime_mutex);
timeptr = gmtime(&tm);
- privoxy_mutex_unlock(&gmtime_mutex);
#else
timeptr = gmtime(&tm);
#endif
if ((NULL == timeptr) || !strftime(newheader,
sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr))
{
+#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_unlock(&gmtime_mutex);
+#endif
log_error(LOG_LEVEL_ERROR,
"Randomizing '%s' failed. Crunching the header without replacement.",
*header);
freez(*header);
return JB_ERR_OK;
}
-
+#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_unlock(&gmtime_mutex);
+#endif
freez(*header);
*header = strdup("If-Modified-Since: ");
string_append(header, newheader);
#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;
#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
if (NULL == timeptr)
{
+#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_unlock(&gmtime_mutex);
+#endif
log_error(LOG_LEVEL_FATAL,
"Failed to get the time in add_cooky_expiry_date()");
}
strftime(tmp, sizeof(tmp), "; expires=%a, %d-%b-%Y %H:%M:%S GMT", timeptr);
+#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_unlock(&gmtime_mutex);
+#endif
if (JB_ERR_OK != string_append(cookie, tmp))
{
log_error(LOG_LEVEL_FATAL, "Out of memory in add_cooky_expiry()");
char *p;
char *host;
- assert(!http->ssl);
-
host = get_header_value(headers, "Host:");
if (NULL == host)
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 = strdup_or_die(host);
+ 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 */
/*********************************************************************