listen_loop(): Use a dedicated variable for the pthread_create() return code
[privoxy.git] / jcc.c
diff --git a/jcc.c b/jcc.c
index d40265d..8d92f65 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -156,6 +156,7 @@ static jb_err receive_client_request(struct client_state *csp);
 static jb_err parse_client_request(struct client_state *csp);
 static void build_request_line(struct client_state *csp, const struct forward_spec *fwd, char **request_line);
 static jb_err change_request_destination(struct client_state *csp);
+static void handle_established_connection(struct client_state *csp);
 static void chat(struct client_state *csp);
 static void serve(struct client_state *csp);
 #if !defined(_WIN32) || defined(_WIN_CONSOLE)
@@ -195,7 +196,7 @@ privoxy_mutex_t connection_reuse_mutex;
 
 #ifdef FEATURE_HTTPS_INSPECTION
 privoxy_mutex_t certificate_mutex;
-privoxy_mutex_t rng_mutex;
+privoxy_mutex_t ssl_init_mutex;
 #endif
 
 #ifdef FEATURE_EXTERNAL_FILTERS
@@ -204,6 +205,10 @@ privoxy_mutex_t external_filter_mutex;
 #ifdef FEATURE_CLIENT_TAGS
 privoxy_mutex_t client_tags_mutex;
 #endif
+#ifdef FEATURE_EXTENDED_STATISTICS
+privoxy_mutex_t filter_statistics_mutex;
+privoxy_mutex_t block_statistics_mutex;
+#endif
 
 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_GETHOSTBYNAME_R)
 privoxy_mutex_t resolver_mutex;
@@ -485,8 +490,9 @@ static int client_protocol_is_unsupported(struct client_state *csp, char *req)
 #ifdef FEATURE_HTTPS_INSPECTION
       if (client_use_ssl(csp))
       {
-         ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-            (const unsigned char *)response, strlen(response));
+         ssl_send_data_delayed(&(csp->ssl_client_attr),
+            (const unsigned char *)response, strlen(response),
+            get_write_delay(csp));
       }
       else
 #endif
@@ -586,10 +592,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;
    }
@@ -868,15 +872,17 @@ static void send_crunch_response(struct client_state *csp, struct http_response
 #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->ssl_client_attr),
+                (const unsigned char *)rsp->head, rsp->head_length,
+                get_write_delay(csp)) < 0)
+          || (ssl_send_data_delayed(&(csp->ssl_client_attr),
+                (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 "
-               "for %s through client socket %d using TLS/SSL",
-               http->url, csp->cfd);
+               "for https://%s%s through client socket %d using TLS/SSL",
+               http->hostport, http->url, csp->cfd);
          }
       }
       else
@@ -1195,6 +1201,7 @@ void save_connection_destination(jb_socket sfd,
    }
    server_connection->forward_port = fwd->forward_port;
 }
+#endif /* FEATURE_CONNECTION_KEEP_ALIVE */
 
 
 /*********************************************************************
@@ -1295,7 +1302,6 @@ static void verify_request_length(struct client_state *csp)
       log_error(LOG_LEVEL_CONNECT, "Complete client request received.");
    }
 }
-#endif /* FEATURE_CONNECTION_KEEP_ALIVE */
 
 
 /*********************************************************************
@@ -1619,7 +1625,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)
@@ -1916,6 +1922,7 @@ static jb_err parse_client_request(struct client_state *csp)
       /* Assume persistence until further notice */
       csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
    }
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
    if (csp->http->ssl == 0)
    {
@@ -1936,11 +1943,12 @@ static jb_err parse_client_request(struct client_state *csp)
       }
       verify_request_length(csp);
    }
+#ifndef FEATURE_HTTPS_INSPECTION
    else
    {
       csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED;
    }
-#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+#endif
 
    err = sed(csp, FILTER_CLIENT_HEADERS);
    if (JB_ERR_OK != err)
@@ -2053,7 +2061,7 @@ static int receive_and_send_encrypted_post_data(struct client_state *csp)
 {
    int content_length_known = csp->expected_client_content_length != 0;
 
-   while (is_ssl_pending(&(csp->mbedtls_client_attr.ssl))
+   while (is_ssl_pending(&(csp->ssl_client_attr))
       || (content_length_known && csp->expected_client_content_length != 0))
    {
       unsigned char buf[BUFFER_SIZE];
@@ -2067,7 +2075,7 @@ static int receive_and_send_encrypted_post_data(struct client_state *csp)
       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,
+      len = ssl_recv_data(&(csp->ssl_client_attr), buf,
          (unsigned)max_bytes_to_read);
       if (len == -1)
       {
@@ -2080,7 +2088,7 @@ static int receive_and_send_encrypted_post_data(struct client_state *csp)
       }
       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);
+      len = ssl_send_data(&(csp->ssl_server_attr), buf, (size_t)len);
       if (len == -1)
       {
          return 1;
@@ -2093,13 +2101,13 @@ static int receive_and_send_encrypted_post_data(struct client_state *csp)
          }
          if (csp->expected_client_content_length == 0)
          {
-            log_error(LOG_LEVEL_HEADER, "Forwarded the last %d bytes", len);
+            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;
 
@@ -2137,7 +2145,7 @@ static int send_https_request(struct client_state *csp)
     * Write the client's (modified) header to the server
     * (along with anything else that may be in the buffer)
     */
-   ret = ssl_send_data(&(csp->mbedtls_server_attr.ssl),
+   ret = ssl_send_data(&(csp->ssl_server_attr),
       (const unsigned char *)hdr, strlen(hdr));
    freez(hdr);
 
@@ -2151,7 +2159,7 @@ static int send_https_request(struct client_state *csp)
    }
 
    if (((csp->flags & CSP_FLAG_PIPELINED_REQUEST_WAITING) == 0)
-      && ((flushed = ssl_flush_socket(&(csp->mbedtls_server_attr.ssl),
+      && ((flushed = ssl_flush_socket(&(csp->ssl_server_attr),
             csp->client_iob)) < 0))
    {
       log_error(LOG_LEVEL_CONNECT, "Failed sending request body to: %s: %E",
@@ -2217,14 +2225,21 @@ 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->ssl_client_attr)) &&
+          !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);
          return JB_ERR_PARSE;
       }
-      len = ssl_recv_data(&(csp->mbedtls_client_attr.ssl),
+      len = ssl_recv_data(&(csp->ssl_client_attr),
          (unsigned char *)buf, sizeof(buf));
+      if (len == 0)
+      {
+         log_error(LOG_LEVEL_CONNECT,
+            "Socket %d closed while waiting for client headers", csp->cfd);
+         return JB_ERR_PARSE;
+      }
       if (len == -1)
       {
          return JB_ERR_PARSE;
@@ -2264,14 +2279,30 @@ static jb_err process_encrypted_request(struct client_state *csp)
    struct list header_list;
    struct list *headers = &header_list;
 
+   assert(csp->ssl_with_client_is_opened);
+
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+   if (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
+   {
+      csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
+   }
+#endif
    err = receive_encrypted_request(csp);
    if (err != JB_ERR_OK)
    {
+      if (csp->client_iob->cur == NULL)
+      {
+         /*
+          * We did not receive any data, most likely because the
+          * client is done. Don't log this as a parse failure.
+          */
+         return JB_ERR_PARSE;
+      }
       /* XXX: Also used for JB_ERR_MEMORY */
       log_error(LOG_LEVEL_ERROR, "Failed to receive encrypted request: %s",
          jb_err_to_string(err));
-      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-         (const unsigned char *)CHEADER, strlen(CHEADER));
+      ssl_send_data_delayed(&(csp->ssl_client_attr),
+         (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp));
       return err;
    }
 
@@ -2280,8 +2311,8 @@ static jb_err process_encrypted_request(struct client_state *csp)
    if (request_line == NULL)
    {
       log_error(LOG_LEVEL_ERROR, "Failed to get the encrypted request line");
-      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-         (const unsigned char *)CHEADER, strlen(CHEADER));
+      ssl_send_data_delayed(&(csp->ssl_client_attr),
+         (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp));
       return JB_ERR_PARSE;
    }
    assert(*request_line != '\0');
@@ -2313,8 +2344,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->ssl_client_attr),
+         (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,
@@ -2348,21 +2379,32 @@ static jb_err process_encrypted_request(struct client_state *csp)
        */
       log_error(LOG_LEVEL_ERROR,
          "Failed to get the encrypted request destination");
-      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-         (const unsigned char *)CHEADER, strlen(CHEADER));
+      ssl_send_data_delayed(&(csp->ssl_client_attr),
+         (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);
+
+#ifdef FEATURE_CLIENT_TAGS
+   /* XXX: If the headers were enlisted sooner, passing csp would do. */
+   if (csp->client_address == NULL)
+   {
+      set_client_address(csp, headers);
+      get_tag_list_for_client(csp->client_tags, csp->client_address);
+   }
 #endif
 
 #ifdef FEATURE_TOGGLE
    if ((csp->flags & CSP_FLAG_TOGGLED_ON) != 0)
 #endif
    {
-      /* Determine the actions for this URL */
+      /*
+       * Determine the actions for this request after
+       * clearing the ones from the previous one.
+       */
+      free_current_action(csp->action);
       get_url_actions(csp, csp->http);
    }
 
@@ -2386,8 +2428,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->ssl_client_attr),
+         (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",
@@ -2397,12 +2439,113 @@ 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_GPC, "https://%s%s", csp->http->hostport,
+   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;
+
+}
+
+
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+/*********************************************************************
+ *
+ * Function    :  continue_https_chat
+ *
+ * Description :  Behaves similar to chat() but only deals with
+ *                https-inspected requests that arrive on an already
+ *                established connection. The first request is always
+ *                served by chat() which is a lot more complex as it
+ *                has to deal with forwarding settings and connection
+ *                failures etc.
+ *
+ *                If a connection to the server has already been
+ *                opened it is reused unless the request is blocked.
+ *
+ *                If a connection to the server has not yet been
+ *                opened (because the previous request was crunched)
+ *                the connection is dropped so that the client retries
+ *                on a fresh one.
+ *
+ *                XXX: Forwarding settings are currently ignored.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  Nothing.
+ *
+ *********************************************************************/
+static void continue_https_chat(struct client_state *csp)
+{
+   if (JB_ERR_OK != process_encrypted_request(csp))
+   {
+      return;
+   }
+
+   csp->requests_received_total++;
+
+   /*
+    * We have an encrypted request. Check if one of the crunchers wants it.
+    */
+   if (crunch_response_triggered(csp, crunchers_all))
+   {
+      /*
+       * Yes. The client got the crunch response and we're done here.
+       */
+      return;
+   }
+   if (csp->ssl_with_server_is_opened == 0)
+   {
+      log_error(LOG_LEVEL_CONNECT,
+         "Dropping the client connection on socket %d. "
+         "The server connection has not been established yet.",
+         csp->cfd);
+      csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
+      return;
+   }
+   if (send_https_request(csp))
+   {
+      /*
+       * Most likely the server connection timed out. We can't easily
+       * create a new one so simply drop the client connection without a
+       * error response to let the client retry.
+       */
+      log_error(LOG_LEVEL_CONNECT,
+         "Dropping client connection on socket %d. "
+         "Forwarding the encrypted client request failed.",
+         csp->cfd);
+      return;
+   }
+   handle_established_connection(csp);
+   freez(csp->receive_buffer);
+}
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 #endif
 
 
@@ -2768,7 +2911,7 @@ static void handle_established_connection(struct client_state *csp)
           */
          if (server_use_ssl(csp))
          {
-            len = ssl_recv_data(&(csp->mbedtls_server_attr.ssl),
+            len = ssl_recv_data(&(csp->ssl_server_attr),
                (unsigned char *)csp->receive_buffer, csp->receive_buffer_size);
          }
          else
@@ -2934,11 +3077,12 @@ static void handle_established_connection(struct client_state *csp)
                    */
                   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->ssl_client_attr),
+                              (const unsigned char *)hdr, strlen(hdr),
+                              get_write_delay(csp)) < 0)
+                        || (ssl_send_data_delayed(&(csp->ssl_client_attr),
                               (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");
@@ -3036,12 +3180,13 @@ static void handle_established_connection(struct client_state *csp)
                    */
                   if (client_use_ssl(csp))
                   {
-                     if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl),
-                            (const unsigned char *)hdr, hdrlen) < 0)
-                        || ((flushed = ssl_flush_socket(&(csp->mbedtls_client_attr.ssl),
+                     if ((ssl_send_data_delayed(&(csp->ssl_client_attr),
+                             (const unsigned char *)hdr, hdrlen, get_write_delay(csp)) < 0)
+                        || ((flushed = ssl_flush_socket(&(csp->ssl_client_attr),
                                 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->ssl_client_attr),
+                              (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");
@@ -3086,8 +3231,9 @@ static void handle_established_connection(struct client_state *csp)
                 */
                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->ssl_client_attr),
+                     (const unsigned char *)csp->receive_buffer, (size_t)len,
+                     get_write_delay(csp));
                   if (ret < 0)
                   {
                      log_error(LOG_LEVEL_ERROR,
@@ -3151,9 +3297,9 @@ static void handle_established_connection(struct client_state *csp)
                    */
                   if (client_use_ssl(csp))
                   {
-                     ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                     ssl_send_data_delayed(&(csp->ssl_client_attr),
                         (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_INSPECTION */
@@ -3245,9 +3391,10 @@ static void handle_established_connection(struct client_state *csp)
                 */
                if (client_use_ssl(csp))
                {
-                  ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                  ssl_send_data_delayed(&(csp->ssl_client_attr),
                      (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_INSPECTION */
@@ -3277,9 +3424,10 @@ static void handle_established_connection(struct client_state *csp)
                 */
                if (client_use_ssl(csp))
                {
-                  ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                  ssl_send_data_delayed(&(csp->ssl_client_attr),
                      (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE,
-                     strlen(INVALID_SERVER_HEADERS_RESPONSE));
+                     strlen(INVALID_SERVER_HEADERS_RESPONSE),
+                     get_write_delay(csp));
                }
                else
 #endif
@@ -3346,9 +3494,10 @@ static void handle_established_connection(struct client_state *csp)
 #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)
-                     || (len = ssl_flush_socket(&(csp->mbedtls_client_attr.ssl),
+                  if ((ssl_send_data_delayed(&(csp->ssl_client_attr),
+                          (const unsigned char *)hdr, strlen(hdr),
+                          get_write_delay(csp)) < 0)
+                     || (len = ssl_flush_socket(&(csp->ssl_client_attr),
                             csp->iob) < 0))
                   {
                      log_error(LOG_LEVEL_CONNECT, "Write header to client failed");
@@ -3407,9 +3556,10 @@ static void handle_established_connection(struct client_state *csp)
                 */
                if (client_use_ssl(csp))
                {
-                  ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                  ssl_send_data_delayed(&(csp->ssl_client_attr),
                      (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_INSPECTION */
@@ -3432,9 +3582,7 @@ static void handle_established_connection(struct client_state *csp)
 #endif
       return; /* huh? we should never get here */
    }
-#ifdef FEATURE_HTTPS_INSPECTION
-   close_client_and_server_ssl_connections(csp);
-#endif
+
    if (csp->content_length == 0)
    {
       /*
@@ -3529,9 +3677,10 @@ static void chat(struct client_state *csp)
 #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_HTTPS_INSPECTION))
+   if (csp->http->ssl && !(csp->action->flags & ACTION_HTTPS_INSPECTION)
+      && !cgi_page_requested(csp->http->host))
    {
       use_ssl_tunnel = 1;
    }
@@ -3599,6 +3748,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 =
@@ -3638,17 +3799,6 @@ static void chat(struct client_state *csp)
    }
 
    log_applied_actions(csp->action);
-#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_GPC, "%s%s", http->hostport, http->path);
-   }
    if (fwd->forward_host)
    {
       log_error(LOG_LEVEL_CONNECT, "via [%s]:%d to: %s",
@@ -3676,7 +3826,11 @@ static void chat(struct client_state *csp)
       if (csp->server_connection.sfd != JB_INVALID_SOCKET)
       {
 #ifdef FEATURE_CONNECTION_SHARING
-         if (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)
+         if (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING
+#ifdef FEATURE_HTTPS_INSPECTION
+            && !server_use_ssl(csp)
+#endif
+            )
          {
             remember_connection(&csp->server_connection);
          }
@@ -3697,32 +3851,25 @@ static void chat(struct client_state *csp)
       {
          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))
@@ -3741,7 +3888,6 @@ static void chat(struct client_state *csp)
             /*
              * Yes. The client got the crunch response and we're done here.
              */
-            close_client_ssl_connection(csp);
             return;
          }
       }
@@ -3853,94 +3999,57 @@ 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);
-                  }
-                  close_client_and_server_ssl_connections(csp);
-                  return;
+                  send_crunch_response(csp, rsp);
                }
+               close_client_and_server_ssl_connections(csp);
+               return;
             }
          }
       }/* -END- if (http->ssl) */
@@ -4057,7 +4166,7 @@ extern int fuzz_server_response(struct client_state *csp, char *fuzz_input_file)
 
    if (strcmp(fuzz_input_file, "-") == 0)
    {
-      /* XXX: Doesn'T work yet. */
+      /* XXX: Doesn't work yet. */
       csp->server_connection.sfd = 0;
    }
    else
@@ -4122,6 +4231,9 @@ static void prepare_csp_for_next_request(struct client_state *csp)
    freez(csp->error_message);
    free_http_request(csp->http);
    destroy_list(csp->headers);
+#ifdef FEATURE_HTTPS_INSPECTION
+   destroy_list(csp->https_headers);
+#endif
    destroy_list(csp->tags);
 #ifdef FEATURE_CLIENT_TAGS
    destroy_list(csp->client_tags);
@@ -4206,7 +4318,16 @@ static void serve(struct client_state *csp)
    {
       unsigned int latency;
 
-      chat(csp);
+#ifdef FEATURE_HTTPS_INSPECTION
+      if (continue_chatting && client_use_ssl(csp))
+      {
+         continue_https_chat(csp);
+      }
+      else
+#endif
+      {
+         chat(csp);
+      }
 
       /*
        * If the request has been crunched,
@@ -4246,7 +4367,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),
@@ -4258,6 +4379,9 @@ static void serve(struct client_state *csp)
                forget_connection(csp->server_connection.sfd);
             }
 #endif /* def FEATURE_CONNECTION_SHARING */
+#ifdef FEATURE_HTTPS_INSPECTION
+            close_server_ssl_connection(csp);
+#endif
             close_socket(csp->server_connection.sfd);
             mark_connection_closed(&csp->server_connection);
          }
@@ -4268,6 +4392,15 @@ static void serve(struct client_state *csp)
          continue_chatting = 0;
          config_file_change_detected = 1;
       }
+#ifdef FEATURE_HTTPS_INSPECTION
+      if (continue_chatting && client_use_ssl(csp) &&
+         csp->ssl_with_client_is_opened == 0)
+      {
+         continue_chatting = 0;
+         log_error(LOG_LEVEL_CONNECT, "Client socket %d is no longer usable. "
+            "The TLS session has been terminated.", csp->cfd);
+      }
+#endif
 
       if (continue_chatting)
       {
@@ -4303,8 +4436,8 @@ static void serve(struct client_state *csp)
             && socket_is_still_alive(csp->cfd))
          {
             log_error(LOG_LEVEL_CONNECT,
-               "Client request %u arrived in time on socket %d.",
-               csp->requests_received_total+1, csp->cfd);
+               "Data arrived in time on client socket %d. Requests so far: %u",
+               csp->cfd, csp->requests_received_total);
             prepare_csp_for_next_request(csp);
          }
          else
@@ -4312,7 +4445,11 @@ static void serve(struct client_state *csp)
 #ifdef FEATURE_CONNECTION_SHARING
             if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)
                && (csp->server_connection.sfd != JB_INVALID_SOCKET)
-               && (socket_is_still_alive(csp->server_connection.sfd)))
+               && (socket_is_still_alive(csp->server_connection.sfd))
+#ifdef FEATURE_HTTPS_INSPECTION
+               && !server_use_ssl(csp)
+#endif
+                )
             {
                time_t time_open = time(NULL) - csp->server_connection.timestamp;
 
@@ -4367,6 +4504,11 @@ static void serve(struct client_state *csp)
          forget_connection(csp->server_connection.sfd);
       }
 #endif /* def FEATURE_CONNECTION_SHARING */
+
+#ifdef FEATURE_HTTPS_INSPECTION
+      close_server_ssl_connection(csp);
+#endif /* def FEATURE_HTTPS_INSPECTION */
+
       close_socket(csp->server_connection.sfd);
    }
 
@@ -4382,6 +4524,9 @@ static void serve(struct client_state *csp)
          csp->cfd, 0 != (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE),
          socket_is_still_alive(csp->cfd), data_is_available(csp->cfd, 0),
          config_file_change_detected, csp->requests_received_total);
+#ifdef FEATURE_HTTPS_INSPECTION
+      close_client_ssl_connection(csp);
+#endif
       drain_and_close_socket(csp->cfd);
    }
 
@@ -4563,7 +4708,7 @@ static void initialize_mutexes(void)
 
 #ifdef FEATURE_HTTPS_INSPECTION
    privoxy_mutex_init(&certificate_mutex);
-   privoxy_mutex_init(&rng_mutex);
+   privoxy_mutex_init(&ssl_init_mutex);
 #endif
 
    privoxy_mutex_init(&log_mutex);
@@ -4575,6 +4720,10 @@ static void initialize_mutexes(void)
 #ifdef FEATURE_CLIENT_TAGS
    privoxy_mutex_init(&client_tags_mutex);
 #endif
+#ifdef FEATURE_EXTENDED_STATISTICS
+   privoxy_mutex_init(&filter_statistics_mutex);
+   privoxy_mutex_init(&block_statistics_mutex);
+#endif
 
    /*
     * XXX: The assumptions below are a bit naive
@@ -5455,10 +5604,11 @@ static void listen_loop(void)
 #define SELECTED_ONE_OPTION
          {
             pthread_t the_thread;
+            int ret;
 
-            errno = pthread_create(&the_thread, &attrs,
+            ret = pthread_create(&the_thread, &attrs,
                (void * (*)(void *))serve, csp);
-            child_id = errno ? -1 : 0;
+            child_id = ret ? -1 : 0;
          }
 #endif
 
@@ -5603,16 +5753,12 @@ static void listen_loop(void)
 
 #ifdef FEATURE_HTTPS_INSPECTION
    /* Clean up.  Aim: free all memory (no leaks) */
-   if (rng_seeded == 1)
-   {
-      mbedtls_ctr_drbg_free(&ctr_drbg);
-      mbedtls_entropy_free(&entropy);
-   }
+   ssl_release();
 #endif
 
 #ifdef FEATURE_GRACEFUL_TERMINATION
 
-   log_error(LOG_LEVEL_ERROR, "Graceful termination requested");
+   log_error(LOG_LEVEL_INFO, "Graceful termination requested");
 
    unload_current_config_file();
    unload_current_actions_file();