Allow to use extended host patterns and vanilla host patterns at the same time
[privoxy.git] / jcc.c
diff --git a/jcc.c b/jcc.c
index 6963015..d29b511 100644 (file)
--- a/jcc.c
+++ b/jcc.c
 #include "project.h"
 #include "list.h"
 #include "jcc.h"
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
 #include "ssl.h"
 #endif
 #include "filters.h"
@@ -146,7 +146,7 @@ int g_terminate = 0;
 #if !defined(_WIN32) && !defined(__OS2__)
 static void sig_handler(int the_signal);
 #endif
-static int client_protocol_is_unsupported(const struct client_state *csp, char *req);
+static int client_protocol_is_unsupported(struct client_state *csp, char *req);
 static jb_err get_request_destination_elsewhere(struct client_state *csp, struct list *headers);
 static jb_err get_server_headers(struct client_state *csp);
 static const char *crunch_reason(const struct http_response *rsp);
@@ -193,12 +193,10 @@ privoxy_mutex_t log_mutex;
 privoxy_mutex_t log_init_mutex;
 privoxy_mutex_t connection_reuse_mutex;
 
-#ifdef LIMIT_MUTEX_NUMBER
-privoxy_mutex_t certificates_mutexes[32];
-#else
-privoxy_mutex_t certificates_mutexes[65536];
-#endif /* LIMIT_MUTEX_NUMBER */
+#ifdef FEATURE_HTTPS_INSPECTION
+privoxy_mutex_t certificate_mutex;
 privoxy_mutex_t rng_mutex;
+#endif
 
 #ifdef FEATURE_EXTERNAL_FILTERS
 privoxy_mutex_t external_filter_mutex;
@@ -447,7 +445,7 @@ static unsigned int get_write_delay(const struct client_state *csp)
  *                FALSE if the request doesn't look invalid.
  *
  *********************************************************************/
-static int client_protocol_is_unsupported(const struct client_state *csp, char *req)
+static int client_protocol_is_unsupported(struct client_state *csp, char *req)
 {
    /*
     * If it's a FTP or gopher request, we don't support it.
@@ -483,8 +481,20 @@ static int client_protocol_is_unsupported(const struct client_state *csp, char *
       log_error(LOG_LEVEL_CLF,
          "%s - - [%T] \"%s\" 400 0", csp->ip_addr_str, req);
       freez(req);
-      write_socket_delayed(csp->cfd, response, strlen(response),
-         get_write_delay(csp));
+
+#ifdef FEATURE_HTTPS_INSPECTION
+      if (client_use_ssl(csp))
+      {
+         ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+            (const unsigned char *)response, strlen(response),
+            get_write_delay(csp));
+      }
+      else
+#endif
+      {
+         write_socket_delayed(csp->cfd, response, strlen(response),
+            get_write_delay(csp));
+      }
 
       return TRUE;
    }
@@ -577,10 +587,8 @@ static jb_err get_request_destination_elsewhere(struct client_state *csp, struct
    }
    else if (JB_ERR_OK == get_destination_from_headers(headers, csp->http))
    {
-#ifndef FEATURE_EXTENDED_HOST_PATTERNS
       /* Split the domain we just got for pattern matching */
       init_domain_components(csp->http);
-#endif
 
       return JB_ERR_OK;
    }
@@ -839,18 +847,32 @@ static void send_crunch_response(struct client_state *csp, struct http_response
 
       /* Log that the request was crunched and why. */
       log_applied_actions(csp->action);
-      log_error(LOG_LEVEL_CRUNCH, "%s: %s", crunch_reason(rsp), http->url);
-      log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" %s %u",
-         csp->ip_addr_str, http->ocmd, status_code, rsp->content_length);
-
+#ifdef FEATURE_HTTPS_INSPECTION
+      if (client_use_ssl(csp))
+      {
+         log_error(LOG_LEVEL_CRUNCH, "%s: https://%s%s", crunch_reason(rsp),
+            http->hostport, http->path);
+         log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s https://%s%s %s\" %s %llu",
+            csp->ip_addr_str, http->gpc, http->hostport, http->path,
+            http->version, status_code, rsp->content_length);
+      }
+      else
+#endif
+      {
+         log_error(LOG_LEVEL_CRUNCH, "%s: %s", crunch_reason(rsp), http->url);
+         log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" %s %u",
+            csp->ip_addr_str, http->ocmd, status_code, rsp->content_length);
+      }
       /* Write the answer to the client */
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
       if (client_use_ssl(csp))
       {
-         if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-                 (const unsigned char *)rsp->head, rsp->head_length) < 0)
-          || (ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-                 (const unsigned char *)rsp->body, rsp->content_length) < 0))
+         if ((ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+                (const unsigned char *)rsp->head, rsp->head_length,
+                get_write_delay(csp)) < 0)
+          || (ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+                (const unsigned char *)rsp->body, rsp->content_length,
+                get_write_delay(csp)) < 0))
          {
             /* There is nothing we can do about it. */
             log_error(LOG_LEVEL_CONNECT, "Couldn't deliver the error message "
@@ -976,10 +998,10 @@ static void build_request_line(struct client_state *csp, const struct forward_sp
     * if +downgrade action applies.
     */
    if ((csp->action->flags & ACTION_DOWNGRADE)
-     && (!strcmpic(http->ver, "HTTP/1.1")))
+     && (!strcmpic(http->version, "HTTP/1.1")))
    {
-      freez(http->ver);
-      http->ver = strdup_or_die("HTTP/1.0");
+      freez(http->version);
+      http->version = strdup_or_die("HTTP/1.0");
    }
 
    /*
@@ -998,7 +1020,7 @@ static void build_request_line(struct client_state *csp, const struct forward_sp
       string_append(request_line, http->path);
    }
    string_append(request_line, " ");
-   string_append(request_line, http->ver);
+   string_append(request_line, http->version);
 
    if (*request_line == NULL)
    {
@@ -1598,7 +1620,7 @@ extern int fuzz_client_request(struct client_state *csp, char *fuzz_input_file)
    if (strcmp(fuzz_input_file, "-") != 0)
    {
       log_error(LOG_LEVEL_FATAL,
-         "Fuzzed client requests can currenty only be read from stdin (-).");
+         "Fuzzed client requests can currently only be read from stdin (-).");
    }
    err = receive_client_request(csp);
    if (err != JB_ERR_OK)
@@ -1889,7 +1911,7 @@ static jb_err parse_client_request(struct client_state *csp)
 
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
    if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
-    && (!strcmpic(csp->http->ver, "HTTP/1.1"))
+    && (!strcmpic(csp->http->version, "HTTP/1.1"))
     && (csp->http->ssl == 0))
    {
       /* Assume persistence until further notice */
@@ -2014,7 +2036,7 @@ static int send_http_request(struct client_state *csp)
 }
 
 
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
 /*********************************************************************
  *
  * Function    : receive_and_send_encrypted_post_data
@@ -2028,14 +2050,26 @@ static int send_http_request(struct client_state *csp)
  * Returns     :  0 on success, anything else is an error.
  *
  *********************************************************************/
-static jb_err receive_and_send_encrypted_post_data(struct client_state *csp)
+static int receive_and_send_encrypted_post_data(struct client_state *csp)
 {
-   unsigned char buf[BUFFER_SIZE];
-   int len;
+   int content_length_known = csp->expected_client_content_length != 0;
 
-   while (is_ssl_pending(&(csp->mbedtls_client_attr.ssl)))
+   while (is_ssl_pending(&(csp->mbedtls_client_attr.ssl))
+      || (content_length_known && csp->expected_client_content_length != 0))
    {
-      len = ssl_recv_data(&(csp->mbedtls_client_attr.ssl), buf, sizeof(buf));
+      unsigned char buf[BUFFER_SIZE];
+      int len;
+      int max_bytes_to_read = sizeof(buf);
+
+      if (content_length_known && csp->expected_client_content_length < sizeof(buf))
+      {
+         max_bytes_to_read = (int)csp->expected_client_content_length;
+      }
+      log_error(LOG_LEVEL_CONNECT,
+         "Waiting for up to %d bytes of POST data from the client.",
+         max_bytes_to_read);
+      len = ssl_recv_data(&(csp->mbedtls_client_attr.ssl), buf,
+         (unsigned)max_bytes_to_read);
       if (len == -1)
       {
          return 1;
@@ -2045,7 +2079,7 @@ static jb_err receive_and_send_encrypted_post_data(struct client_state *csp)
          /* XXX: Does this actually happen? */
          break;
       }
-      log_error(LOG_LEVEL_HEADER, "Forwarding %d bytes of encrypted POST data",
+      log_error(LOG_LEVEL_CONNECT, "Forwarding %d bytes of encrypted POST data",
          len);
       len = ssl_send_data(&(csp->mbedtls_server_attr.ssl), buf, (size_t)len);
       if (len == -1)
@@ -2058,10 +2092,15 @@ static jb_err receive_and_send_encrypted_post_data(struct client_state *csp)
          {
             csp->expected_client_content_length -= (unsigned)len;
          }
+         if (csp->expected_client_content_length == 0)
+         {
+            log_error(LOG_LEVEL_CONNECT, "Forwarded the last %d bytes", len);
+            break;
+         }
       }
    }
 
-   log_error(LOG_LEVEL_HEADER, "Done forwarding encrypted POST data");
+   log_error(LOG_LEVEL_CONNECT, "Done forwarding encrypted POST data");
 
    return 0;
 
@@ -2109,7 +2148,6 @@ static int send_https_request(struct client_state *csp)
          "Failed sending encrypted request headers to: %s: %E",
          csp->http->hostport);
       mark_server_socket_tainted(csp);
-      close_client_and_server_ssl_connections(csp);
       return 1;
    }
 
@@ -2180,7 +2218,8 @@ static jb_err receive_encrypted_request(struct client_state *csp)
    do
    {
       log_error(LOG_LEVEL_HEADER, "Reading encrypted headers");
-      if (!data_is_available(csp->cfd, (int)csp->config->keep_alive_timeout))
+      if (!is_ssl_pending(&(csp->mbedtls_client_attr.ssl)) &&
+          !data_is_available(csp->cfd, csp->config->socket_timeout))
       {
          log_error(LOG_LEVEL_CONNECT,
             "Socket %d timed out while waiting for client headers", csp->cfd);
@@ -2231,8 +2270,10 @@ static jb_err process_encrypted_request(struct client_state *csp)
    if (err != JB_ERR_OK)
    {
       /* XXX: Also used for JB_ERR_MEMORY */
-      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-         (const unsigned char *)CHEADER, strlen(CHEADER));
+      log_error(LOG_LEVEL_ERROR, "Failed to receive encrypted request: %s",
+         jb_err_to_string(err));
+      ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp));
       return err;
    }
 
@@ -2240,16 +2281,20 @@ static jb_err process_encrypted_request(struct client_state *csp)
    request_line = get_header(csp->client_iob);
    if (request_line == NULL)
    {
-      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-         (const unsigned char *)CHEADER, strlen(CHEADER));
+      log_error(LOG_LEVEL_ERROR, "Failed to get the encrypted request line");
+      ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp));
       return JB_ERR_PARSE;
    }
    assert(*request_line != '\0');
 
    if (client_protocol_is_unsupported(csp, request_line))
    {
-      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-         (const unsigned char *)CHEADER, strlen(CHEADER));
+      /*
+       * If the protocol is unsupported we're done here.
+       * client_protocol_is_unsupported() took care of sending
+       * the error response and logging the error message.
+       */
       return JB_ERR_PARSE;
    }
 
@@ -2270,8 +2315,8 @@ static jb_err process_encrypted_request(struct client_state *csp)
    freez(request_line);
    if (JB_ERR_OK != err)
    {
-      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-         (const unsigned char *)CHEADER, strlen(CHEADER));
+      ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp));
       /* XXX: Use correct size */
       log_error(LOG_LEVEL_CLF, "%s - - [%T] \"Invalid request\" 400 0", csp->ip_addr_str);
       log_error(LOG_LEVEL_ERROR,
@@ -2303,15 +2348,15 @@ static jb_err process_encrypted_request(struct client_state *csp)
        * Our attempts to get the request destination
        * elsewhere failed.
        */
-      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-         (const unsigned char *)CHEADER, strlen(CHEADER));
+      log_error(LOG_LEVEL_ERROR,
+         "Failed to get the encrypted request destination");
+      ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp));
       return JB_ERR_PARSE;
    }
 
-#ifndef FEATURE_EXTENDED_HOST_PATTERNS
    /* Split the domain we just got for pattern matching */
    init_domain_components(csp->http);
-#endif
 
 #ifdef FEATURE_TOGGLE
    if ((csp->flags & CSP_FLAG_TOGGLED_ON) != 0)
@@ -2341,8 +2386,8 @@ static jb_err process_encrypted_request(struct client_state *csp)
    err = sed_https(csp);
    if (JB_ERR_OK != err)
    {
-      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-         (const unsigned char *)CHEADER, strlen(CHEADER));
+      ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp));
       log_error(LOG_LEVEL_ERROR, "Failed to parse client request from %s.",
          csp->ip_addr_str);
       log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0",
@@ -2352,10 +2397,39 @@ static jb_err process_encrypted_request(struct client_state *csp)
 
    log_error(LOG_LEVEL_HEADER, "Encrypted request processed");
    log_applied_actions(csp->action);
+   log_error(LOG_LEVEL_REQUEST, "https://%s%s", csp->http->hostport,
+      csp->http->path);
 
    return err;
 
 }
+
+/*********************************************************************
+ *
+ * Function    :  cgi_page_requested
+ *
+ * Description :  Checks if a request is for an internal CGI page.
+ *
+ * Parameters  :
+ *          1  :  host = The host requested by the client.
+ *
+ * Returns     :  1 if a CGI page has been requested, 0 otherwise
+ *
+ *********************************************************************/
+static int cgi_page_requested(const char *host)
+{
+   if ((0 == strcmpic(host, CGI_SITE_1_HOST))
+    || (0 == strcmpic(host, CGI_SITE_1_HOST "."))
+    || (0 == strcmpic(host, CGI_SITE_2_HOST))
+    || (0 == strcmpic(host, CGI_SITE_2_HOST ".")))
+   {
+      return 1;
+   }
+
+   return 0;
+
+}
+
 #endif
 
 
@@ -2391,19 +2465,12 @@ static void handle_established_connection(struct client_state *csp)
    long len = 0; /* for buffer sizes (and negative error codes) */
    int buffer_and_filter_content = 0;
    unsigned int write_delay;
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
    int ret = 0;
    int use_ssl_tunnel = 0;
    csp->dont_verify_certificate = 0;
 
-   /*
-    * Preset flags informing if SSL connections with server or client
-    * are opened or closed
-    */
-   csp->ssl_with_server_is_opened = 0;
-   csp->ssl_with_client_is_opened = 0;
-
-   if (csp->http->ssl && !(csp->action->flags & ACTION_ENABLE_HTTPS_FILTER))
+   if (csp->http->ssl && !(csp->action->flags & ACTION_HTTPS_INSPECTION))
    {
       /* Pass encrypted content without filtering. */
       use_ssl_tunnel = 1;
@@ -2514,114 +2581,62 @@ static void handle_established_connection(struct client_state *csp)
       }
 #endif  /* FEATURE_CONNECTION_KEEP_ALIVE */
 
-#ifdef FEATURE_HTTPS_FILTERING
-      /*
-       * Test if some data from client or destination server are pending
-       * on TLS/SSL. We must work with them preferably. TLS/SSL data can
-       * be pending because of maximal fragment size.
-       */
-      int read_ssl_server = 0;
-      int read_ssl_client = 0;
-
-      if (client_use_ssl(csp))
-      {
-         read_ssl_client = is_ssl_pending(&(csp->mbedtls_client_attr.ssl)) != 0;
-      }
-
-      if (server_use_ssl(csp))
+#ifdef HAVE_POLL
+      poll_fds[0].fd = csp->cfd;
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+      if (!watch_client_socket)
       {
-         read_ssl_server = is_ssl_pending(&(csp->mbedtls_server_attr.ssl)) != 0;
+         /*
+          * Ignore incoming data, but still watch out
+          * for disconnects etc. These flags are always
+          * implied anyway but explicitly setting them
+          * doesn't hurt.
+          */
+         poll_fds[0].events = POLLERR|POLLHUP;
       }
-
-      if (!read_ssl_server && !read_ssl_client)
+      else
 #endif
       {
-#ifdef HAVE_POLL
-         poll_fds[0].fd = csp->cfd;
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
-         if (!watch_client_socket)
-         {
-            /*
-             * Ignore incoming data, but still watch out
-             * for disconnects etc. These flags are always
-             * implied anyway but explicitly setting them
-             * doesn't hurt.
-             */
-            poll_fds[0].events = POLLERR|POLLHUP;
-         }
-         else
-#endif
-         {
-            poll_fds[0].events = POLLIN;
-         }
-         poll_fds[1].fd = csp->server_connection.sfd;
-         poll_fds[1].events = POLLIN;
-         n = poll(poll_fds, 2, csp->config->socket_timeout * 1000);
+         poll_fds[0].events = POLLIN;
+      }
+      poll_fds[1].fd = csp->server_connection.sfd;
+      poll_fds[1].events = POLLIN;
+      n = poll(poll_fds, 2, csp->config->socket_timeout * 1000);
 #else
-         timeout.tv_sec = csp->config->socket_timeout;
-         timeout.tv_usec = 0;
-         n = select((int)maxfd + 1, &rfds, NULL, NULL, &timeout);
+      timeout.tv_sec = csp->config->socket_timeout;
+      timeout.tv_usec = 0;
+      n = select((int)maxfd + 1, &rfds, NULL, NULL, &timeout);
 #endif /* def HAVE_POLL */
 
-         /*server or client not responding in timeout */
-         if (n == 0)
+      /*server or client not responding in timeout */
+      if (n == 0)
+      {
+         log_error(LOG_LEVEL_CONNECT, "Socket timeout %d reached: %s",
+            csp->config->socket_timeout, http->url);
+         if ((byte_count == 0) && (http->ssl == 0))
          {
-            log_error(LOG_LEVEL_CONNECT, "Socket timeout %d reached: %s",
-               csp->config->socket_timeout, http->url);
-            if ((byte_count == 0) && (http->ssl == 0))
-            {
-               send_crunch_response(csp, error_response(csp, "connection-timeout"));
-            }
-            mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
-            close_client_and_server_ssl_connections(csp);
-#endif
-            return;
+            send_crunch_response(csp, error_response(csp, "connection-timeout"));
          }
-         else if (n < 0)
-         {
-#ifdef HAVE_POLL
-            log_error(LOG_LEVEL_ERROR, "poll() failed!: %E");
-#else
-            log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
-#endif
-            mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
-            close_client_and_server_ssl_connections(csp);
+         mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_INSPECTION
+         close_client_and_server_ssl_connections(csp);
 #endif
-            return;
-         }
+         return;
       }
-#ifdef FEATURE_HTTPS_FILTERING
-      else
+      else if (n < 0)
       {
-         /* set FD if some data are pending on TLS/SSL connections */
-#ifndef HAVE_POLL
-         FD_ZERO(&rfds);
-#endif
-         if (read_ssl_client)
-         {
 #ifdef HAVE_POLL
-            poll_fds[0].fd = csp->cfd;
-            poll_fds[0].events = POLLIN;
+         log_error(LOG_LEVEL_ERROR, "poll() failed!: %E");
 #else
-            FD_SET(csp->cfd, &rfds);
+         log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
 #endif
-            n++;
-         }
-
-         if (read_ssl_server)
-         {
-#ifdef HAVE_POLL
-            poll_fds[1].fd = csp->server_connection.sfd;
-            poll_fds[1].events = POLLIN;
-#else
-            FD_SET(csp->server_connection.sfd, &rfds);
+         mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_INSPECTION
+         close_client_and_server_ssl_connections(csp);
 #endif
-            n++;
-         }
+         return;
       }
-#endif
+
       /*
        * This is the body of the browser's request,
        * just read and write it.
@@ -2692,39 +2707,14 @@ static void handle_established_connection(struct client_state *csp)
          assert(max_bytes_to_read <= csp->receive_buffer_size);
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
-#ifdef FEATURE_HTTPS_FILTERING
-         /*
-          * Reading data from standard or secured connection (HTTP/HTTPS)
-          */
+#ifdef FEATURE_HTTPS_INSPECTION
          if (client_use_ssl(csp))
          {
-            /*
-             * Receiving HTTP request from client over TLS/SSL and sending
-             * it to server over TLS/SSL.
-             */
-            len = ssl_recv_data(&(csp->mbedtls_client_attr.ssl),
-               (unsigned char *)csp->receive_buffer, (size_t)max_bytes_to_read);
-
-            if (len <= 0)
-            {
-               mark_server_socket_tainted(csp);
-               break;
-            }
-
-            ret = ssl_send_data(&(csp->mbedtls_server_attr.ssl),
-               (const unsigned char *)csp->receive_buffer, (size_t)len);
-
-            if (ret < 0)
-            {
-               log_error(LOG_LEVEL_ERROR,
-                  "Send request over TLS/SSL to: %s failed", http->host);
-               mark_server_socket_tainted(csp);
-               close_client_and_server_ssl_connections(csp);
-               return;
-            }
+            log_error(LOG_LEVEL_CONNECT, "Breaking with TLS/SSL.");
+            break;
          }
          else
-#endif /* def FEATURE_HTTPS_FILTERING */
+#endif /* def FEATURE_HTTPS_INSPECTION */
          {
             len = read_socket(csp->cfd, csp->receive_buffer, max_bytes_to_read);
 
@@ -2757,9 +2747,6 @@ static void handle_established_connection(struct client_state *csp)
             {
                log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
                mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
-               close_client_and_server_ssl_connections(csp);
-#endif
                return;
             }
          }
@@ -2794,7 +2781,7 @@ static void handle_established_connection(struct client_state *csp)
             log_error(LOG_LEVEL_CONNECT,
                "The server still wants to talk, but the client hung up on us.");
             mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
             close_client_and_server_ssl_connections(csp);
 #endif
             return;
@@ -2802,7 +2789,7 @@ static void handle_established_connection(struct client_state *csp)
          }
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
          /*
           * Reading data from standard or secured connection (HTTP/HTTPS)
           */
@@ -2823,7 +2810,7 @@ static void handle_established_connection(struct client_state *csp)
             log_error(LOG_LEVEL_ERROR, "read from: %s failed: %E", http->host);
 
             if ((http->ssl && (csp->fwd == NULL))
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                && use_ssl_tunnel
 #endif
                 )
@@ -2849,7 +2836,7 @@ static void handle_established_connection(struct client_state *csp)
                log_error(LOG_LEVEL_ERROR, "Already forwarded the original headers. "
                   "Unable to tell the client about the problem.");
                mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                close_client_and_server_ssl_connections(csp);
 #endif
                return;
@@ -2918,7 +2905,7 @@ static void handle_established_connection(struct client_state *csp)
          {
 
             if (server_body || (http->ssl
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                   && use_ssl_tunnel
 #endif
                ))
@@ -2968,17 +2955,18 @@ static void handle_established_connection(struct client_state *csp)
                      log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header");
                   }
 
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                   /*
                    * Sending data with standard or secured connection (HTTP/HTTPS)
                    */
                   if (client_use_ssl(csp))
                   {
-                     if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-                            (const unsigned char *)hdr, strlen(hdr)) < 0)
-                        || (ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                     if ((ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+                              (const unsigned char *)hdr, strlen(hdr),
+                              get_write_delay(csp)) < 0)
+                        || (ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
                               (const unsigned char *) ((p != NULL) ? p : csp->iob->cur),
-                              csp->content_length) < 0))
+                              csp->content_length, get_write_delay(csp)) < 0))
                      {
                         log_error(LOG_LEVEL_ERROR, "write modified content to "
                            "client over TLS/SSL failed");
@@ -2990,7 +2978,7 @@ static void handle_established_connection(struct client_state *csp)
                      }
                   }
                   else
-#endif /* def FEATURE_HTTPS_FILTERING */
+#endif /* def FEATURE_HTTPS_INSPECTION */
                   {
                      if (write_socket_delayed(csp->cfd, hdr, strlen(hdr), write_delay)
                       || write_socket_delayed(csp->cfd, ((p != NULL) ? p : csp->iob->cur),
@@ -3000,9 +2988,6 @@ static void handle_established_connection(struct client_state *csp)
                         freez(hdr);
                         freez(p);
                         mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
-                        close_client_and_server_ssl_connections(csp);
-#endif
                         return;
                      }
                   }
@@ -3035,7 +3020,7 @@ static void handle_established_connection(struct client_state *csp)
           * content-filtering.
           */
          if (server_body || (http->ssl
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                && use_ssl_tunnel
 #endif
             ))
@@ -3066,25 +3051,26 @@ static void handle_established_connection(struct client_state *csp)
                      rsp = cgi_error_memory();
                      send_crunch_response(csp, rsp);
                      mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                      close_client_and_server_ssl_connections(csp);
 #endif
                      return;
                   }
                   hdrlen = strlen(hdr);
 
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                   /*
                    * Sending data with standard or secured connection (HTTP/HTTPS)
                    */
                   if (client_use_ssl(csp))
                   {
-                     if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-                            (const unsigned char *)hdr, hdrlen) < 0)
+                     if ((ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+                             (const unsigned char *)hdr, hdrlen, get_write_delay(csp)) < 0)
                         || ((flushed = ssl_flush_socket(&(csp->mbedtls_client_attr.ssl),
                                 csp->iob)) < 0)
-                        || (ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-                              (const unsigned char *)csp->receive_buffer, (size_t)len) < 0))
+                        || (ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+                              (const unsigned char *)csp->receive_buffer, (size_t)len,
+                              get_write_delay(csp)) < 0))
                      {
                         log_error(LOG_LEVEL_CONNECT,
                            "Flush header and buffers to client failed");
@@ -3095,7 +3081,7 @@ static void handle_established_connection(struct client_state *csp)
                      }
                   }
                   else
-#endif /* def FEATURE_HTTPS_FILTERING */
+#endif /* def FEATURE_HTTPS_INSPECTION */
                   {
                      if (write_socket_delayed(csp->cfd, hdr, hdrlen, write_delay)
                       || ((flushed = flush_iob(csp->cfd, csp->iob, write_delay)) < 0)
@@ -3106,9 +3092,6 @@ static void handle_established_connection(struct client_state *csp)
                            "Flush header and buffers to client failed: %E");
                         freez(hdr);
                         mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
-                        close_client_and_server_ssl_connections(csp);
-#endif
                         return;
                      }
                   }
@@ -3126,14 +3109,15 @@ static void handle_established_connection(struct client_state *csp)
             }
             else
             {
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                /*
                 * Sending data with standard or secured connection (HTTP/HTTPS)
                 */
                if (client_use_ssl(csp))
                {
-                  ret = ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-                     (const unsigned char *)csp->receive_buffer, (size_t)len);
+                  ret = ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+                     (const unsigned char *)csp->receive_buffer, (size_t)len,
+                     get_write_delay(csp));
                   if (ret < 0)
                   {
                      log_error(LOG_LEVEL_ERROR,
@@ -3144,16 +3128,13 @@ static void handle_established_connection(struct client_state *csp)
                   }
                }
                else
-#endif /* def FEATURE_HTTPS_FILTERING */
+#endif /* def FEATURE_HTTPS_INSPECTION */
                {
                   if (write_socket_delayed(csp->cfd, csp->receive_buffer,
                         (size_t)len, write_delay))
                   {
                      log_error(LOG_LEVEL_ERROR, "write to client failed: %E");
                      mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
-                     close_client_and_server_ssl_connections(csp);
-#endif
                      return;
                   }
                }
@@ -3174,7 +3155,7 @@ static void handle_established_connection(struct client_state *csp)
                rsp = cgi_error_memory();
                send_crunch_response(csp, rsp);
                mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                close_client_and_server_ssl_connections(csp);
 #endif
                return;
@@ -3194,25 +3175,25 @@ static void handle_established_connection(struct client_state *csp)
                      "Applying the MS IIS5 hack didn't help.");
                   log_error(LOG_LEVEL_CLF,
                      "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                   /*
                    * Sending data with standard or secured connection (HTTP/HTTPS)
                    */
                   if (client_use_ssl(csp))
                   {
-                     ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                     ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
                         (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE,
-                        strlen(INVALID_SERVER_HEADERS_RESPONSE));
+                        strlen(INVALID_SERVER_HEADERS_RESPONSE), get_write_delay(csp));
                   }
                   else
-#endif /* def FEATURE_HTTPS_FILTERING */
+#endif /* def FEATURE_HTTPS_INSPECTION */
                   {
                      write_socket_delayed(csp->cfd,
                         INVALID_SERVER_HEADERS_RESPONSE,
                         strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay);
                   }
                   mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                   close_client_and_server_ssl_connections(csp);
 #endif
                   return;
@@ -3260,7 +3241,7 @@ static void handle_established_connection(struct client_state *csp)
                }
                free_http_request(http);
                mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                close_client_and_server_ssl_connections(csp);
 #endif
                return;
@@ -3288,25 +3269,26 @@ static void handle_established_connection(struct client_state *csp)
                   csp->headers->first->str);
                log_error(LOG_LEVEL_CLF,
                   "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                /*
                 * Sending data with standard or secured connection (HTTP/HTTPS)
                 */
                if (client_use_ssl(csp))
                {
-                  ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                  ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
                      (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE,
-                     strlen(INVALID_SERVER_HEADERS_RESPONSE));
+                     strlen(INVALID_SERVER_HEADERS_RESPONSE),
+                     get_write_delay(csp));
                }
                else
-#endif /* def FEATURE_HTTPS_FILTERING */
+#endif /* def FEATURE_HTTPS_INSPECTION */
                {
                   write_socket_delayed(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE,
                      strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay);
                }
                free_http_request(http);
                mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                close_client_and_server_ssl_connections(csp);
 #endif
                return;
@@ -3320,15 +3302,16 @@ static void handle_established_connection(struct client_state *csp)
             {
                log_error(LOG_LEVEL_CLF,
                   "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                /*
                 * Sending data with standard or secured connection (HTTP/HTTPS)
                 */
                if (client_use_ssl(csp))
                {
-                  ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                  ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
                      (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE,
-                     strlen(INVALID_SERVER_HEADERS_RESPONSE));
+                     strlen(INVALID_SERVER_HEADERS_RESPONSE),
+                     get_write_delay(csp));
                }
                else
 #endif
@@ -3338,7 +3321,7 @@ static void handle_established_connection(struct client_state *csp)
                }
                free_http_request(http);
                mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                close_client_and_server_ssl_connections(csp);
 #endif
                return;
@@ -3375,7 +3358,7 @@ static void handle_established_connection(struct client_state *csp)
                 */
                freez(hdr);
                mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                close_client_and_server_ssl_connections(csp);
 #endif
                return;
@@ -3392,11 +3375,12 @@ static void handle_established_connection(struct client_state *csp)
                 * may be in the buffer). Use standard or secured
                 * connection.
                 */
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                if (client_use_ssl(csp))
                {
-                  if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-                          (const unsigned char *)hdr, strlen(hdr)) < 0)
+                  if ((ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
+                          (const unsigned char *)hdr, strlen(hdr),
+                          get_write_delay(csp)) < 0)
                      || (len = ssl_flush_socket(&(csp->mbedtls_client_attr.ssl),
                             csp->iob) < 0))
                   {
@@ -3408,14 +3392,14 @@ static void handle_established_connection(struct client_state *csp)
                       */
                      freez(hdr);
                      mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                      close_client_and_server_ssl_connections(csp);
 #endif
                      return;
                   }
                }
                else
-#endif /* def FEATURE_HTTPS_FILTERING */
+#endif /* def FEATURE_HTTPS_INSPECTION */
                {
                   if (write_socket_delayed(csp->cfd, hdr, strlen(hdr), write_delay)
                      || ((len = flush_iob(csp->cfd, csp->iob, write_delay)) < 0))
@@ -3428,9 +3412,6 @@ static void handle_established_connection(struct client_state *csp)
                       */
                      freez(hdr);
                      mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
-                     close_client_and_server_ssl_connections(csp);
-#endif
                      return;
                   }
                }
@@ -3453,24 +3434,25 @@ static void handle_established_connection(struct client_state *csp)
                   "Applying the MS IIS5 hack didn't help.");
                log_error(LOG_LEVEL_CLF,
                   "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                /*
                 * Sending data with standard or secured connection (HTTP/HTTPS)
                 */
                if (client_use_ssl(csp))
                {
-                  ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                  ssl_send_data_delayed(&(csp->mbedtls_client_attr.ssl),
                      (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE,
-                     strlen(INVALID_SERVER_HEADERS_RESPONSE));
+                     strlen(INVALID_SERVER_HEADERS_RESPONSE),
+                     get_write_delay(csp));
                }
                else
-#endif /* def FEATURE_HTTPS_FILTERING */
+#endif /* def FEATURE_HTTPS_INSPECTION */
                {
                   write_socket_delayed(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE,
                      strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay);
                }
                mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
                close_client_and_server_ssl_connections(csp);
 #endif
                return;
@@ -3479,12 +3461,12 @@ static void handle_established_connection(struct client_state *csp)
          continue;
       }
       mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
       close_client_and_server_ssl_connections(csp);
 #endif
       return; /* huh? we should never get here */
    }
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
    close_client_and_server_ssl_connections(csp);
 #endif
    if (csp->content_length == 0)
@@ -3507,9 +3489,19 @@ static void handle_established_connection(struct client_state *csp)
    }
 #endif
 
-   log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %llu",
-      csp->ip_addr_str, http->ocmd, csp->content_length);
-
+#ifdef FEATURE_HTTPS_INSPECTION
+   if (client_use_ssl(csp))
+   {
+      log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s https://%s%s %s\" 200 %llu",
+         csp->ip_addr_str, http->gpc, http->hostport, http->path,
+         http->version, csp->content_length);
+   }
+   else
+#endif
+   {
+      log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %llu",
+         csp->ip_addr_str, http->ocmd, csp->content_length);
+   }
    csp->server_connection.timestamp = time(NULL);
 }
 
@@ -3544,7 +3536,7 @@ static void chat(struct client_state *csp)
    struct http_request *http;
    /* Skeleton for HTTP response, if we should intercept the request */
    struct http_response *rsp;
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
    int use_ssl_tunnel = 0;
 #endif
 
@@ -3568,12 +3560,13 @@ static void chat(struct client_state *csp)
       return;
    }
 
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
    /*
     * Setting flags to use old solution with SSL tunnel and to disable
-    * certificates verification.
+    * certificate verification.
     */
-   if (csp->http->ssl && !(csp->action->flags & ACTION_ENABLE_HTTPS_FILTER))
+   if (csp->http->ssl && !(csp->action->flags & ACTION_HTTPS_INSPECTION)
+      && !cgi_page_requested(csp->http->host))
    {
       use_ssl_tunnel = 1;
    }
@@ -3625,7 +3618,7 @@ static void chat(struct client_state *csp)
     *
     */
 
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
    /*
     * Presetting SSL client and server flags
     */
@@ -3641,6 +3634,18 @@ static void chat(struct client_state *csp)
    }
 #endif
 
+#ifdef FEATURE_HTTPS_INSPECTION
+   /*
+    * Log the request unless we're https inspecting
+    * in which case we don't have the path yet and
+    * will log the request later.
+    */
+   if (!client_use_ssl(csp))
+#endif
+   {
+      log_error(LOG_LEVEL_REQUEST, "%s%s", http->hostport, http->path);
+   }
+
    if (http->ssl && connect_port_is_forbidden(csp))
    {
       const char *acceptable_connect_ports =
@@ -3651,7 +3656,7 @@ static void chat(struct client_state *csp)
          csp->ip_addr_str, acceptable_connect_ports, csp->http->hostport);
       csp->action->flags |= ACTION_BLOCK;
       http->ssl = 0;
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
       http->client_ssl = 0;
       http->server_ssl = 0;
 #endif
@@ -3668,7 +3673,7 @@ static void chat(struct client_state *csp)
     * response later.
     */
    if (
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
        !client_use_ssl(csp) &&
 #endif
        crunch_response_triggered(csp, crunchers_all))
@@ -3680,8 +3685,6 @@ static void chat(struct client_state *csp)
    }
 
    log_applied_actions(csp->action);
-   log_error(LOG_LEVEL_GPC, "%s%s", http->hostport, http->path);
-
    if (fwd->forward_host)
    {
       log_error(LOG_LEVEL_CONNECT, "via [%s]:%d to: %s",
@@ -3725,37 +3728,30 @@ static void chat(struct client_state *csp)
          mark_connection_closed(&csp->server_connection);
       }
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
       if (http->ssl && !use_ssl_tunnel)
       {
          int ret;
          /*
-          * Creating an SSL proxy. If forwarding is disabled, we must send
-          * CSUCCEED mesage to client. Then TLS/SSL connection with client
-          * is created.
+          * Creating a SSL proxy.
+          *
+          * By sending the CSUCCEED message we're lying to the client as
+          * the connection hasn't actually been established yet. We don't
+          * establish the connection until we have seen and parsed the
+          * encrypted client headers.
           */
-
-         if (fwd->forward_host == NULL)
+         if (write_socket_delayed(csp->cfd, CSUCCEED,
+               strlen(CSUCCEED), get_write_delay(csp)) != 0)
          {
-            /*
-             * We're lying to the client as the connection hasn't actually
-             * been established yet. We don't establish the connection until
-             * we have seen and parsed the encrypted client headers.
-             */
-            if (write_socket_delayed(csp->cfd, CSUCCEED,
-                  strlen(CSUCCEED), get_write_delay(csp)) != 0)
-            {
-               log_error(LOG_LEVEL_ERROR, "Sending SUCCEED to client failed");
-               return;
-            }
+            log_error(LOG_LEVEL_ERROR, "Sending SUCCEED to client failed");
+            return;
          }
 
          ret = create_client_ssl_connection(csp);
          if (ret != 0)
          {
             log_error(LOG_LEVEL_ERROR,
-               "Can't open secure connection with client");
-            close_client_ssl_connection(csp); /* XXX: Is this needed? */
+               "Failed to open a secure connection with the client");
             return;
          }
          if (JB_ERR_OK != process_encrypted_request(csp))
@@ -3818,13 +3814,16 @@ static void chat(struct client_state *csp)
           * client body in the buffer (if there is one) and to
           * continue parsing the bytes that follow.
           */
+#ifdef FEATURE_HTTPS_INSPECTION
+         close_client_ssl_connection(csp);
+#endif
          drain_and_close_socket(csp->cfd);
          csp->cfd = JB_INVALID_SOCKET;
 
          return;
       }
 
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
       /*
        * Creating TLS/SSL connections with destination server or parent
        * proxy. If forwarding is enabled, we must send client request to
@@ -3883,97 +3882,61 @@ static void chat(struct client_state *csp)
             }
 
             /*
-             * Test if connection with destination server was established
-             * successfully by parent proxy. Then we can send response to
-             * the client and continue or stop.
+             * Test if the connection to the destination server was
+             * established successfully by the parent proxy.
              */
             if (!tunnel_established_successfully(server_response, (unsigned int)len))
             {
-               log_error(LOG_LEVEL_ERROR, "Forwarder hasn't established "
-                  "connection with destination server.");
-
-               write_socket(csp->cfd, server_response, (size_t)len);
-               mark_server_socket_tainted(csp);
-               close_client_ssl_connection(csp);
-               return;
-            }
-
-            /*
-             * Parent proxy has established connection with destination server.
-             * Now we must create TLS/SSL connection with parent proxy.
-             */
-            ret = create_server_ssl_connection(csp);
-
-            /*
-            * If TLS/SSL connection wasn't created and invalid certificate
-            * wasn't detected, we can interrupt this function. Otherwise, we
-            * must inform the client about invalid server certificate.
-            */
-            if (ret != 0
-               && (csp->server_cert_verification_result == SSL_CERT_NOT_VERIFIED
-                  || csp->server_cert_verification_result == SSL_CERT_VALID))
-            {
+               log_error(LOG_LEVEL_ERROR,
+                  "The forwarder %s failed to establish a connection with %s",
+                  fwd->forward_host, http->host);
                rsp = error_response(csp, "connect-failed");
                if (rsp)
                {
                   send_crunch_response(csp, rsp);
                }
+               mark_server_socket_tainted(csp);
+               close_client_ssl_connection(csp);
                return;
             }
+         } /* -END- if (fwd->forward_host != NULL) */
 
-            /*
-             * TLS/SSL connection with parent proxy is established, we can
-             * inform client about success.
-             */
-            ret = write_socket(csp->cfd, server_response, (size_t)len);
-            if (ret != 0)
+         /*
+          * We can now create the TLS/SSL connection with the destination server.
+          */
+         int ret = create_server_ssl_connection(csp);
+         if (ret != 0)
+         {
+            if (csp->server_cert_verification_result != SSL_CERT_VALID &&
+                csp->server_cert_verification_result != SSL_CERT_NOT_VERIFIED)
             {
-               log_error(LOG_LEVEL_ERROR,
-                  "Sending parent proxy response to client failed");
-               mark_server_socket_tainted(csp);
-               close_client_ssl_connection(csp);
+               /*
+                * If the server certificate is invalid, we must inform
+                * the client and then close connection to the client.
+                */
+               ssl_send_certificate_error(csp);
+               close_client_and_server_ssl_connections(csp);
                return;
             }
-         }/* -END- if (fwd->forward_host != NULL) */
-         else
-         {
-            /*
-             * Parent proxy is not used, we can just create TLS/SSL connection
-             * with destination server
-             */
-            int ret = create_server_ssl_connection(csp);
-            if (ret != 0)
+            if (csp->server_cert_verification_result == SSL_CERT_NOT_VERIFIED
+             || csp->server_cert_verification_result == SSL_CERT_VALID)
             {
-               if (csp->server_cert_verification_result != SSL_CERT_VALID &&
-                   csp->server_cert_verification_result != SSL_CERT_NOT_VERIFIED)
-               {
-                  /*
-                   * If the server certificate is invalid, we must inform
-                   * the client and then close connection to the client.
-                   */
-                  ssl_send_certificate_error(csp);
-                  close_client_and_server_ssl_connections(csp);
-                  return;
-               }
-               if (csp->server_cert_verification_result == SSL_CERT_NOT_VERIFIED
-                || csp->server_cert_verification_result == SSL_CERT_VALID)
+               /*
+                * The TLS/SSL connection wasn't created but an invalid
+                * certificate wasn't detected. Report it as connection
+                * failure.
+                */
+               rsp = error_response(csp, "connect-failed");
+               if (rsp)
                {
-                  /*
-                   * The TLS/SSL connection wasn't created but an invalid
-                   * certificate wasn't detected. Report it as connection
-                   * failure.
-                   */
-                  rsp = error_response(csp, "connect-failed");
-                  if (rsp)
-                  {
-                     send_crunch_response(csp, rsp);
-                  }
-                  return;
+                  send_crunch_response(csp, rsp);
                }
+               close_client_and_server_ssl_connections(csp);
+               return;
             }
          }
       }/* -END- if (http->ssl) */
-#endif /* def FEATURE_HTTPS_FILTERING */
+#endif /* def FEATURE_HTTPS_INSPECTION */
 
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
       save_connection_destination(csp->server_connection.sfd,
@@ -3991,7 +3954,7 @@ static void chat(struct client_state *csp)
       assert(csp->headers->last == NULL);
    }
    else if (http->ssl == 0 || (fwd->forward_host
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
          && use_ssl_tunnel
 #endif
            ))
@@ -4012,7 +3975,7 @@ static void chat(struct client_state *csp)
        * Using old solution with SSL tunnel or new solution with SSL proxy
        */
       list_remove_all(csp->headers);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
       if (use_ssl_tunnel)
 #endif
       {
@@ -4027,7 +3990,7 @@ static void chat(struct client_state *csp)
             return;
          }
       }
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
       else
       {
          /*
@@ -4051,7 +4014,7 @@ static void chat(struct client_state *csp)
             return;
          }
       }
-#endif /* def FEATURE_HTTPS_FILTERING */
+#endif /* def FEATURE_HTTPS_INSPECTION */
       clear_iob(csp->client_iob);
    }/* -END- else ... if (http->ssl == 1) */
 
@@ -4275,7 +4238,7 @@ static void serve(struct client_state *csp)
          {
             log_error(LOG_LEVEL_CONNECT,
                "Closing server socket %d connected to %s. "
-               "Keep-alive %u. Tainted: %u. Socket alive %u. Timeout: %u.",
+               "Keep-alive: %u. Tainted: %u. Socket alive: %u. Timeout: %u.",
                csp->server_connection.sfd, csp->server_connection.host,
                0 != (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE),
                0 != (csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED),
@@ -4590,17 +4553,10 @@ static void initialize_mutexes(void)
     * Prepare global mutex semaphores
     */
 
-#ifdef LIMIT_MUTEX_NUMBER
-   int i = 0;
-   for (i = 0; i < 32; i++)
-#else
-   int i = 0;
-   for (i = 0; i < 65536; i++)
-#endif /* LIMIT_MUTEX_NUMBER */
-   {
-      privoxy_mutex_init(&(certificates_mutexes[i]));
-   }
+#ifdef FEATURE_HTTPS_INSPECTION
+   privoxy_mutex_init(&certificate_mutex);
    privoxy_mutex_init(&rng_mutex);
+#endif
 
    privoxy_mutex_init(&log_mutex);
    privoxy_mutex_init(&log_init_mutex);
@@ -5637,7 +5593,7 @@ static void listen_loop(void)
 
    /* NOTREACHED unless FEATURE_GRACEFUL_TERMINATION is defined */
 
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
    /* Clean up.  Aim: free all memory (no leaks) */
    if (rng_seeded == 1)
    {