Skip to content

Commit fd0e71d

Browse files
SammyKsgolemon
authored andcommitted
Fix bug 60471 by correctly identifying unused speculative preconnections
* 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
1 parent 8121cb5 commit fd0e71d

3 files changed

Lines changed: 80 additions & 74 deletions

File tree

sapi/cli/php_cli_server.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ static php_cli_server_http_response_status_code_pair template_map[] = {
211211
static int php_cli_output_is_tty = OUTPUT_NOT_CHECKED;
212212
#endif
213213

214+
static const char php_cli_server_request_error_unexpected_eof[] = "Unexpected EOF";
215+
214216
static size_t php_cli_server_client_send_through(php_cli_server_client *client, const char *str, size_t str_len);
215217
static php_cli_server_chunk *php_cli_server_chunk_heap_new_self_contained(size_t len);
216218
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
14621464
#ifdef PHP_WIN32
14631465
{
14641466
char *p = decoded_vpath;
1465-
1467+
14661468
do {
14671469
if (*p == '\\') {
14681470
*p = '/';
@@ -1677,7 +1679,7 @@ static int php_cli_server_client_read_request(php_cli_server_client *client, cha
16771679
*errstr = php_socket_strerror(err, NULL, 0);
16781680
return -1;
16791681
} else if (nbytes_read == 0) {
1680-
*errstr = estrdup("Unexpected EOF");
1682+
*errstr = estrdup(php_cli_server_request_error_unexpected_eof);
16811683
return -1;
16821684
}
16831685
client->parser.data = client;
@@ -1806,7 +1808,7 @@ static void php_cli_server_client_dtor(php_cli_server_client *client) /* {{{ */
18061808

18071809
static void php_cli_server_close_connection(php_cli_server *server, php_cli_server_client *client) /* {{{ */
18081810
{
1809-
#ifdef DEBUG
1811+
#if PHP_DEBUG
18101812
php_cli_server_logf("%s Closing", client->addr_str);
18111813
#endif
18121814
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
22972299
char *errstr = NULL;
22982300
int status = php_cli_server_client_read_request(client, &errstr);
22992301
if (status < 0) {
2300-
php_cli_server_logf("%s Invalid request (%s)", client->addr_str, errstr);
2302+
if (strcmp(errstr, php_cli_server_request_error_unexpected_eof) == 0 && client->parser.state == s_start_req) {
2303+
#if PHP_DEBUG
2304+
php_cli_server_logf("%s Closed without sending a request; it was probably just an unused speculative preconnection", client->addr_str);
2305+
#endif
2306+
} else {
2307+
php_cli_server_logf("%s Invalid request (%s)", client->addr_str, errstr);
2308+
}
23012309
efree(errstr);
23022310
php_cli_server_close_connection(server, client);
23032311
return FAILURE;
@@ -2379,7 +2387,7 @@ static int php_cli_server_do_event_for_each_fd_callback(void *_params, php_socke
23792387
closesocket(client_sock);
23802388
return SUCCESS;
23812389
}
2382-
#ifdef DEBUG
2390+
#if PHP_DEBUG
23832391
php_cli_server_logf("%s Accepted", client->addr_str);
23842392
#endif
23852393
zend_hash_index_update_ptr(&server->clients, client_sock, client);

sapi/cli/php_http_parser.c

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -195,75 +195,6 @@ static const uint8_t normal_url_char[256] = {
195195
1, 1, 1, 1, 1, 1, 1, 0 };
196196

197197

198-
enum state
199-
{ s_dead = 1 /* important that this is > 0 */
200-
201-
, s_start_req_or_res
202-
, s_res_or_resp_H
203-
, s_start_res
204-
, s_res_H
205-
, s_res_HT
206-
, s_res_HTT
207-
, s_res_HTTP
208-
, s_res_first_http_major
209-
, s_res_http_major
210-
, s_res_first_http_minor
211-
, s_res_http_minor
212-
, s_res_first_status_code
213-
, s_res_status_code
214-
, s_res_status
215-
, s_res_line_almost_done
216-
217-
, s_start_req
218-
219-
, s_req_method
220-
, s_req_spaces_before_url
221-
, s_req_schema
222-
, s_req_schema_slash
223-
, s_req_schema_slash_slash
224-
, s_req_host
225-
, s_req_port
226-
, s_req_path
227-
, s_req_query_string_start
228-
, s_req_query_string
229-
, s_req_fragment_start
230-
, s_req_fragment
231-
, s_req_http_start
232-
, s_req_http_H
233-
, s_req_http_HT
234-
, s_req_http_HTT
235-
, s_req_http_HTTP
236-
, s_req_first_http_major
237-
, s_req_http_major
238-
, s_req_first_http_minor
239-
, s_req_http_minor
240-
, s_req_line_almost_done
241-
242-
, s_header_field_start
243-
, s_header_field
244-
, s_header_value_start
245-
, s_header_value
246-
247-
, s_header_almost_done
248-
249-
, s_headers_almost_done
250-
/* Important: 's_headers_almost_done' must be the last 'header' state. All
251-
* states beyond this must be 'body' states. It is used for overflow
252-
* checking. See the PARSING_HEADER() macro.
253-
*/
254-
, s_chunk_size_start
255-
, s_chunk_size
256-
, s_chunk_size_almost_done
257-
, s_chunk_parameters
258-
, s_chunk_data
259-
, s_chunk_data_almost_done
260-
, s_chunk_data_done
261-
262-
, s_body_identity
263-
, s_body_identity_eof
264-
};
265-
266-
267198
#define PARSING_HEADER(state) (state <= s_headers_almost_done && 0 == (parser->flags & F_TRAILING))
268199

269200

sapi/cli/php_http_parser.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,73 @@ enum php_http_method
110110

111111
enum php_http_parser_type { PHP_HTTP_REQUEST, PHP_HTTP_RESPONSE, PHP_HTTP_BOTH };
112112

113+
enum state
114+
{ s_dead = 1 /* important that this is > 0 */
115+
116+
, s_start_req_or_res
117+
, s_res_or_resp_H
118+
, s_start_res
119+
, s_res_H
120+
, s_res_HT
121+
, s_res_HTT
122+
, s_res_HTTP
123+
, s_res_first_http_major
124+
, s_res_http_major
125+
, s_res_first_http_minor
126+
, s_res_http_minor
127+
, s_res_first_status_code
128+
, s_res_status_code
129+
, s_res_status
130+
, s_res_line_almost_done
131+
132+
, s_start_req
133+
134+
, s_req_method
135+
, s_req_spaces_before_url
136+
, s_req_schema
137+
, s_req_schema_slash
138+
, s_req_schema_slash_slash
139+
, s_req_host
140+
, s_req_port
141+
, s_req_path
142+
, s_req_query_string_start
143+
, s_req_query_string
144+
, s_req_fragment_start
145+
, s_req_fragment
146+
, s_req_http_start
147+
, s_req_http_H
148+
, s_req_http_HT
149+
, s_req_http_HTT
150+
, s_req_http_HTTP
151+
, s_req_first_http_major
152+
, s_req_http_major
153+
, s_req_first_http_minor
154+
, s_req_http_minor
155+
, s_req_line_almost_done
156+
157+
, s_header_field_start
158+
, s_header_field
159+
, s_header_value_start
160+
, s_header_value
161+
162+
, s_header_almost_done
163+
164+
, s_headers_almost_done
165+
/* Important: 's_headers_almost_done' must be the last 'header' state. All
166+
* states beyond this must be 'body' states. It is used for overflow
167+
* checking. See the PARSING_HEADER() macro.
168+
*/
169+
, s_chunk_size_start
170+
, s_chunk_size
171+
, s_chunk_size_almost_done
172+
, s_chunk_parameters
173+
, s_chunk_data
174+
, s_chunk_data_almost_done
175+
, s_chunk_data_done
176+
177+
, s_body_identity
178+
, s_body_identity_eof
179+
};
113180

114181
struct php_http_parser {
115182
/** PRIVATE **/

0 commit comments

Comments
 (0)