+ /*
+ * 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)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Sending parent proxy response to client failed");
+ mark_server_socket_tainted(csp);
+ close_client_ssl_connection(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 TLS/SSL connection wasn't created and invalid certificate
+ * wasn't detected, we can interrupt this function. Otherwise, we
+ * must inform 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))
+ {
+ rsp = error_response(csp, "connect-failed");
+ if (rsp)
+ {
+ send_crunch_response(csp, rsp);
+ }
+ return;
+ }
+ }
+ }/* -END- if (http->ssl) */
+#endif /* def FEATURE_HTTPS_FILTERING */
+
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ save_connection_destination(csp->server_connection.sfd,
+ http, fwd, &csp->server_connection);
+ csp->server_connection.keep_alive_timeout =
+ (unsigned)csp->config->keep_alive_timeout;
+ }
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
+ csp->server_connection.requests_sent_total++;
+
+ if ((fwd->type == SOCKS_5T) && (NULL == csp->headers->first))
+ {
+ /* Client headers have been sent optimistically */
+ assert(csp->headers->last == NULL);
+ }
+ else if (http->ssl == 0 || (fwd->forward_host
+#ifdef FEATURE_HTTPS_FILTERING
+ && use_ssl_tunnel
+#endif
+ ))
+ {
+ if (send_http_request(csp))
+ {
+ rsp = error_response(csp, "connect-failed");
+ if (rsp)
+ {
+ send_crunch_response(csp, rsp);
+ }
+ return;
+ }
+ }
+ else
+ {
+ /*
+ * Using old solution with SSL tunnel or new solution with SSL proxy
+ */
+ list_remove_all(csp->headers);
+#ifdef FEATURE_HTTPS_FILTERING
+ if (use_ssl_tunnel)
+#endif
+ {
+ /*
+ * We're running an SSL tunnel and we're not forwarding,
+ * so just ditch the client headers, send the "connect succeeded"
+ * message to the client, flush the rest, and get out of the way.
+ */
+ if (write_socket_delayed(csp->cfd, CSUCCEED,
+ strlen(CSUCCEED), get_write_delay(csp)))
+ {
+ return;
+ }
+ }
+#ifdef FEATURE_HTTPS_FILTERING
+ else
+ {
+ /*
+ * If server certificate is invalid, we must inform client and then
+ * close connection with client.
+ */
+ if (csp->server_cert_verification_result != SSL_CERT_VALID)
+ {
+ ssl_send_certificate_error(csp);
+ close_client_and_server_ssl_connections(csp);
+ return;
+ }
+ if (send_https_request(csp))
+ {
+ rsp = error_response(csp, "connect-failed");
+ if (rsp)
+ {
+ send_crunch_response(csp, rsp); /* XXX: use ssl*/
+ }
+ close_client_and_server_ssl_connections(csp);
+ return;
+ }
+ }
+#endif /* def FEATURE_HTTPS_FILTERING */
+ clear_iob(csp->client_iob);
+ }/* -END- else ... if (http->ssl == 1) */
+
+ log_error(LOG_LEVEL_CONNECT, "to %s successful", http->hostport);
+
+ /* XXX: should the time start earlier for optimistically sent data? */
+ csp->server_connection.request_sent = time(NULL);
+
+ handle_established_connection(csp);
+ freez(csp->receive_buffer);
+}
+
+
+#ifdef FUZZ
+/*********************************************************************
+ *
+ * Function : fuzz_server_response
+ *
+ * Description : Treat the input as a whole server response.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : fuzz_input_file = File to read the input from.
+ *
+ * Returns : 0
+ *
+ *********************************************************************/
+extern int fuzz_server_response(struct client_state *csp, char *fuzz_input_file)
+{
+ static struct forward_spec fwd; /* Zero'd due to being static */
+ csp->cfd = 0;
+
+ if (strcmp(fuzz_input_file, "-") == 0)
+ {
+ /* XXX: Doesn'T work yet. */
+ csp->server_connection.sfd = 0;
+ }
+ else
+ {
+ csp->server_connection.sfd = open(fuzz_input_file, O_RDONLY);
+ if (csp->server_connection.sfd == -1)
+ {
+ log_error(LOG_LEVEL_FATAL, "Failed to open %s: %E",
+ fuzz_input_file);
+ }
+ }
+ csp->fwd = &fwd;
+ csp->content_type |= CT_GIF;
+ csp->action->flags |= ACTION_DEANIMATE;
+ csp->action->string[ACTION_STRING_DEANIMATE] = "last";
+
+ csp->http->path = strdup_or_die("/");
+ csp->http->host = strdup_or_die("fuzz.example.org");
+ csp->http->hostport = strdup_or_die("fuzz.example.org:80");
+ /* Prevent client socket monitoring */
+ csp->flags |= CSP_FLAG_PIPELINED_REQUEST_WAITING;
+ csp->flags |= CSP_FLAG_CHUNKED;
+
+ csp->config->feature_flags |= RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
+ csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
+
+ csp->content_type |= CT_DECLARED|CT_GIF;
+
+ csp->config->socket_timeout = 0;
+
+ cgi_init_error_messages();
+
+ handle_established_connection(csp);
+ freez(csp->receive_buffer);
+
+ return 0;
+}
+#endif
+
+
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+/*********************************************************************
+ *
+ * Function : prepare_csp_for_next_request
+ *
+ * Description : Put the csp in a mostly vergin state.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : N/A
+ *
+ *********************************************************************/
+static void prepare_csp_for_next_request(struct client_state *csp)
+{
+ csp->content_type = 0;
+ csp->content_length = 0;
+ csp->expected_content_length = 0;
+ csp->expected_client_content_length = 0;
+ list_remove_all(csp->headers);
+ clear_iob(csp->iob);
+ freez(csp->error_message);
+ free_http_request(csp->http);
+ destroy_list(csp->headers);
+ destroy_list(csp->tags);
+#ifdef FEATURE_CLIENT_TAGS
+ destroy_list(csp->client_tags);
+ freez(csp->client_address);
+#endif
+ free_current_action(csp->action);
+ if (NULL != csp->fwd)
+ {
+ unload_forward_spec(csp->fwd);
+ csp->fwd = NULL;
+ }
+ /* XXX: Store per-connection flags someplace else. */
+ csp->flags = (CSP_FLAG_ACTIVE | CSP_FLAG_REUSED_CLIENT_CONNECTION);
+#ifdef FEATURE_TOGGLE
+ if (global_toggle_state)
+#endif /* def FEATURE_TOGGLE */
+ {
+ csp->flags |= CSP_FLAG_TOGGLED_ON;
+ }
+
+ if (csp->client_iob->eod > csp->client_iob->cur)
+ {
+ long bytes_to_shift = csp->client_iob->cur - csp->client_iob->buf;
+ size_t data_length = (size_t)(csp->client_iob->eod - csp->client_iob->cur);