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 614c7f1..d29b511 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -485,8 +485,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->mbedtls_client_attr.ssl),
+            (const unsigned char *)response, strlen(response),
+            get_write_delay(csp));
       }
       else
 #endif
@@ -586,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;
    }
@@ -848,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_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 "
@@ -985,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");
    }
 
    /*
@@ -1007,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)
    {
@@ -1607,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)
@@ -1898,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 */
@@ -2037,11 +2050,12 @@ 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)
 {
    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))
    {
       unsigned char buf[BUFFER_SIZE];
       int len;
@@ -2065,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)
@@ -2080,13 +2094,13 @@ static jb_err 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;
 
@@ -2204,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);
@@ -2257,8 +2272,8 @@ static jb_err process_encrypted_request(struct client_state *csp)
       /* 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->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp));
       return err;
    }
 
@@ -2267,8 +2282,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->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp));
       return JB_ERR_PARSE;
    }
    assert(*request_line != '\0');
@@ -2300,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,
@@ -2335,15 +2350,13 @@ 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->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)
@@ -2373,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",
@@ -2384,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
 
 
@@ -2666,35 +2708,10 @@ static void handle_established_connection(struct client_state *csp)
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
 #ifdef FEATURE_HTTPS_INSPECTION
-         /*
-          * Reading data from standard or secured connection (HTTP/HTTPS)
-          */
          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_INSPECTION */
@@ -2944,11 +2961,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->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");
@@ -3046,12 +3064,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)
+                     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");
@@ -3096,8 +3115,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->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,
@@ -3161,9 +3181,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->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_INSPECTION */
@@ -3255,9 +3275,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->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_INSPECTION */
@@ -3287,9 +3308,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->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
@@ -3356,8 +3378,9 @@ 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)
+                  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))
                   {
@@ -3417,9 +3440,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->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_INSPECTION */
@@ -3465,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);
 }
 
@@ -3529,9 +3563,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 +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 =
@@ -3638,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",
@@ -3688,32 +3733,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))
@@ -3844,94 +3882,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) */
@@ -4237,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),