]> granicus.if.org Git - php/commitdiff
Fix bug 60471 by correctly identifying unused speculative preconnections
authorSammy Kaye Powers <sammyk@sammykmedia.com>
Wed, 29 Mar 2017 14:27:18 +0000 (09:27 -0500)
committerSara Golemon <pollita@php.net>
Tue, 11 Apr 2017 22:08:05 +0000 (15:08 -0700)
* Correctly identify unused speculative preconnections from browsers
  like Chrome and Firefox
* Add a new message to the debug level that is emitted when a TCP
  connection is closed without sending any request (a preconnection)
* Fix an issue where the existing debug messages were not being
  displayed even when debug mode was enabled

sapi/cli/php_cli_server.c
sapi/cli/php_http_parser.c
sapi/cli/php_http_parser.h

index de4cfb2195fe2db0f5f4ed2db03da2835915256a..1f4eb386046ca33e9c583d1ace0e5a9d89e3812d 100644 (file)
@@ -211,6 +211,8 @@ static php_cli_server_http_response_status_code_pair template_map[] = {
 static int php_cli_output_is_tty = OUTPUT_NOT_CHECKED;
 #endif
 
+static const char php_cli_server_request_error_unexpected_eof[] = "Unexpected EOF";
+
 static size_t php_cli_server_client_send_through(php_cli_server_client *client, const char *str, size_t str_len);
 static php_cli_server_chunk *php_cli_server_chunk_heap_new_self_contained(size_t len);
 static void php_cli_server_buffer_append(php_cli_server_buffer *buffer, php_cli_server_chunk *chunk);
@@ -1462,7 +1464,7 @@ static void normalize_vpath(char **retval, size_t *retval_len, const char *vpath
 #ifdef PHP_WIN32
        {
                char *p = decoded_vpath;
-               
+
                do {
                        if (*p == '\\') {
                                *p = '/';
@@ -1677,7 +1679,7 @@ static int php_cli_server_client_read_request(php_cli_server_client *client, cha
                *errstr = php_socket_strerror(err, NULL, 0);
                return -1;
        } else if (nbytes_read == 0) {
-               *errstr = estrdup("Unexpected EOF");
+               *errstr = estrdup(php_cli_server_request_error_unexpected_eof);
                return -1;
        }
        client->parser.data = client;
@@ -1806,7 +1808,7 @@ static void php_cli_server_client_dtor(php_cli_server_client *client) /* {{{ */
 
 static void php_cli_server_close_connection(php_cli_server *server, php_cli_server_client *client) /* {{{ */
 {
-#ifdef DEBUG
+#if PHP_DEBUG
        php_cli_server_logf("%s Closing", client->addr_str);
 #endif
        zend_hash_index_del(&server->clients, client->sock);
@@ -2297,7 +2299,13 @@ static int php_cli_server_recv_event_read_request(php_cli_server *server, php_cl
        char *errstr = NULL;
        int status = php_cli_server_client_read_request(client, &errstr);
        if (status < 0) {
-               php_cli_server_logf("%s Invalid request (%s)", client->addr_str, errstr);
+               if (strcmp(errstr, php_cli_server_request_error_unexpected_eof) == 0 && client->parser.state == s_start_req) {
+#if PHP_DEBUG
+                       php_cli_server_logf("%s Closed without sending a request; it was probably just an unused speculative preconnection", client->addr_str);
+#endif
+               } else {
+                       php_cli_server_logf("%s Invalid request (%s)", client->addr_str, errstr);
+               }
                efree(errstr);
                php_cli_server_close_connection(server, client);
                return FAILURE;
@@ -2379,7 +2387,7 @@ static int php_cli_server_do_event_for_each_fd_callback(void *_params, php_socke
                        closesocket(client_sock);
                        return SUCCESS;
                }
-#ifdef DEBUG
+#if PHP_DEBUG
                php_cli_server_logf("%s Accepted", client->addr_str);
 #endif
                zend_hash_index_update_ptr(&server->clients, client_sock, client);
index 59361d091184a1b82070fafa051792db8ba3d4e1..63769c15acfa9be419d6363b2d5419f95c9016a1 100644 (file)
@@ -195,75 +195,6 @@ static const uint8_t normal_url_char[256] = {
         1,       1,       1,       1,       1,       1,       1,       0 };
 
 
-enum state
-  { s_dead = 1 /* important that this is > 0 */
-
-  , s_start_req_or_res
-  , s_res_or_resp_H
-  , s_start_res
-  , s_res_H
-  , s_res_HT
-  , s_res_HTT
-  , s_res_HTTP
-  , s_res_first_http_major
-  , s_res_http_major
-  , s_res_first_http_minor
-  , s_res_http_minor
-  , s_res_first_status_code
-  , s_res_status_code
-  , s_res_status
-  , s_res_line_almost_done
-
-  , s_start_req
-
-  , s_req_method
-  , s_req_spaces_before_url
-  , s_req_schema
-  , s_req_schema_slash
-  , s_req_schema_slash_slash
-  , s_req_host
-  , s_req_port
-  , s_req_path
-  , s_req_query_string_start
-  , s_req_query_string
-  , s_req_fragment_start
-  , s_req_fragment
-  , s_req_http_start
-  , s_req_http_H
-  , s_req_http_HT
-  , s_req_http_HTT
-  , s_req_http_HTTP
-  , s_req_first_http_major
-  , s_req_http_major
-  , s_req_first_http_minor
-  , s_req_http_minor
-  , s_req_line_almost_done
-
-  , s_header_field_start
-  , s_header_field
-  , s_header_value_start
-  , s_header_value
-
-  , s_header_almost_done
-
-  , s_headers_almost_done
-  /* Important: 's_headers_almost_done' must be the last 'header' state. All
-   * states beyond this must be 'body' states. It is used for overflow
-   * checking. See the PARSING_HEADER() macro.
-   */
-  , s_chunk_size_start
-  , s_chunk_size
-  , s_chunk_size_almost_done
-  , s_chunk_parameters
-  , s_chunk_data
-  , s_chunk_data_almost_done
-  , s_chunk_data_done
-
-  , s_body_identity
-  , s_body_identity_eof
-  };
-
-
 #define PARSING_HEADER(state) (state <= s_headers_almost_done && 0 == (parser->flags & F_TRAILING))
 
 
index fa4873abeb04d3bd9fbd83710e1162dd490df4f8..d2fa69b757cfda6e57e079a5b78f5b295c5230a4 100644 (file)
@@ -110,6 +110,73 @@ enum php_http_method
 
 enum php_http_parser_type { PHP_HTTP_REQUEST, PHP_HTTP_RESPONSE, PHP_HTTP_BOTH };
 
+enum state
+  { s_dead = 1 /* important that this is > 0 */
+
+  , s_start_req_or_res
+  , s_res_or_resp_H
+  , s_start_res
+  , s_res_H
+  , s_res_HT
+  , s_res_HTT
+  , s_res_HTTP
+  , s_res_first_http_major
+  , s_res_http_major
+  , s_res_first_http_minor
+  , s_res_http_minor
+  , s_res_first_status_code
+  , s_res_status_code
+  , s_res_status
+  , s_res_line_almost_done
+
+  , s_start_req
+
+  , s_req_method
+  , s_req_spaces_before_url
+  , s_req_schema
+  , s_req_schema_slash
+  , s_req_schema_slash_slash
+  , s_req_host
+  , s_req_port
+  , s_req_path
+  , s_req_query_string_start
+  , s_req_query_string
+  , s_req_fragment_start
+  , s_req_fragment
+  , s_req_http_start
+  , s_req_http_H
+  , s_req_http_HT
+  , s_req_http_HTT
+  , s_req_http_HTTP
+  , s_req_first_http_major
+  , s_req_http_major
+  , s_req_first_http_minor
+  , s_req_http_minor
+  , s_req_line_almost_done
+
+  , s_header_field_start
+  , s_header_field
+  , s_header_value_start
+  , s_header_value
+
+  , s_header_almost_done
+
+  , s_headers_almost_done
+  /* Important: 's_headers_almost_done' must be the last 'header' state. All
+   * states beyond this must be 'body' states. It is used for overflow
+   * checking. See the PARSING_HEADER() macro.
+   */
+  , s_chunk_size_start
+  , s_chunk_size
+  , s_chunk_size_almost_done
+  , s_chunk_parameters
+  , s_chunk_data
+  , s_chunk_data_almost_done
+  , s_chunk_data_done
+
+  , s_body_identity
+  , s_body_identity_eof
+  };
 
 struct php_http_parser {
   /** PRIVATE **/