diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 7c69fdef1749e..486c929407b1d 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -202,6 +202,7 @@ typedef struct php_cli_server_http_response_status_code_pair { static php_cli_server_http_response_status_code_pair template_map[] = { { 400, "

%s

Your browser sent a request that this server could not understand.

" }, { 404, "

%s

The requested resource %s was not found on this server.

" }, + { 405, "

%s

Requested method not allowed.

" }, { 500, "

%s

The server is temporarily unavailable.

" }, { 501, "

%s

Request method not supported.

" } }; @@ -1980,49 +1981,51 @@ static zend_result php_cli_server_send_error_page(php_cli_server *server, php_cl php_cli_server_content_sender_ctor(&client->content_sender); client->content_sender_initialized = true; - escaped_request_uri = php_escape_html_entities_ex((const unsigned char *) ZSTR_VAL(client->request.request_uri), ZSTR_LEN(client->request.request_uri), 0, ENT_QUOTES, NULL, /* double_encode */ 0, /* quiet */ 0); + if (client->request.request_method != PHP_HTTP_HEAD) { + escaped_request_uri = php_escape_html_entities_ex((const unsigned char *) ZSTR_VAL(client->request.request_uri), ZSTR_LEN(client->request.request_uri), 0, ENT_QUOTES, NULL, /* double_encode */ 0, /* quiet */ 0); - { - static const char prologue_template[] = "%d %s"; - php_cli_server_chunk *chunk = php_cli_server_chunk_heap_new_self_contained(strlen(prologue_template) + 3 + strlen(status_string) + 1); - if (!chunk) { - goto fail; + { + static const char prologue_template[] = "%d %s"; + php_cli_server_chunk *chunk = php_cli_server_chunk_heap_new_self_contained(strlen(prologue_template) + 3 + strlen(status_string) + 1); + if (!chunk) { + goto fail; + } + snprintf(chunk->data.heap.p, chunk->data.heap.len, prologue_template, status, status_string); + chunk->data.heap.len = strlen(chunk->data.heap.p); + php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } - snprintf(chunk->data.heap.p, chunk->data.heap.len, prologue_template, status, status_string); - chunk->data.heap.len = strlen(chunk->data.heap.p); - php_cli_server_buffer_append(&client->content_sender.buffer, chunk); - } - { - php_cli_server_chunk *chunk = php_cli_server_chunk_immortal_new(php_cli_server_css, sizeof(php_cli_server_css) - 1); - if (!chunk) { - goto fail; + { + php_cli_server_chunk *chunk = php_cli_server_chunk_immortal_new(php_cli_server_css, sizeof(php_cli_server_css) - 1); + if (!chunk) { + goto fail; + } + php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } - php_cli_server_buffer_append(&client->content_sender.buffer, chunk); - } - { - static const char template[] = ""; - php_cli_server_chunk *chunk = php_cli_server_chunk_immortal_new(template, sizeof(template) - 1); - if (!chunk) { - goto fail; + { + static const char template[] = ""; + php_cli_server_chunk *chunk = php_cli_server_chunk_immortal_new(template, sizeof(template) - 1); + if (!chunk) { + goto fail; + } + php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } - php_cli_server_buffer_append(&client->content_sender.buffer, chunk); - } - { - php_cli_server_chunk *chunk = php_cli_server_chunk_heap_new_self_contained(strlen(content_template) + ZSTR_LEN(escaped_request_uri) + 3 + strlen(status_string) + 1); - if (!chunk) { - goto fail; + { + php_cli_server_chunk *chunk = php_cli_server_chunk_heap_new_self_contained(strlen(content_template) + ZSTR_LEN(escaped_request_uri) + 3 + strlen(status_string) + 1); + if (!chunk) { + goto fail; + } + snprintf(chunk->data.heap.p, chunk->data.heap.len, content_template, status_string, ZSTR_VAL(escaped_request_uri)); + chunk->data.heap.len = strlen(chunk->data.heap.p); + php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } - snprintf(chunk->data.heap.p, chunk->data.heap.len, content_template, status_string, ZSTR_VAL(escaped_request_uri)); - chunk->data.heap.len = strlen(chunk->data.heap.p); - php_cli_server_buffer_append(&client->content_sender.buffer, chunk); - } - { - static const char epilogue_template[] = ""; - php_cli_server_chunk *chunk = php_cli_server_chunk_immortal_new(epilogue_template, sizeof(epilogue_template) - 1); - if (!chunk) { - goto fail; + { + static const char epilogue_template[] = ""; + php_cli_server_chunk *chunk = php_cli_server_chunk_immortal_new(epilogue_template, sizeof(epilogue_template) - 1); + if (!chunk) { + goto fail; + } + php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } - php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } { @@ -2038,6 +2041,15 @@ static zend_result php_cli_server_send_error_page(php_cli_server *server, php_cl smart_str_appends_ex(&buffer, "Content-Length: ", 1); smart_str_append_unsigned_ex(&buffer, php_cli_server_buffer_size(&client->content_sender.buffer), 1); smart_str_appendl_ex(&buffer, "\r\n", 2, 1); + if (status == 405) { + smart_str_appends_ex(&buffer, "Allow: ", 1); + smart_str_appends_ex(&buffer, php_http_method_str(PHP_HTTP_GET), 1); + smart_str_appends_ex(&buffer, ", ", 1); + smart_str_appends_ex(&buffer, php_http_method_str(PHP_HTTP_HEAD), 1); + smart_str_appends_ex(&buffer, ", ", 1); + smart_str_appends_ex(&buffer, php_http_method_str(PHP_HTTP_POST), 1); + smart_str_appendl_ex(&buffer, "\r\n", 2, 1); + } smart_str_appendl_ex(&buffer, "\r\n", 2, 1); chunk = php_cli_server_chunk_heap_new(buffer.s, ZSTR_VAL(buffer.s), ZSTR_LEN(buffer.s)); @@ -2053,14 +2065,18 @@ static zend_result php_cli_server_send_error_page(php_cli_server *server, php_cl if (errstr) { pefree(errstr, 1); } - zend_string_free(escaped_request_uri); + if (escaped_request_uri) { + zend_string_free(escaped_request_uri); + } return SUCCESS; fail: if (errstr) { pefree(errstr, 1); } - zend_string_free(escaped_request_uri); + if (escaped_request_uri) { + zend_string_free(escaped_request_uri); + } return FAILURE; } /* }}} */ @@ -2088,6 +2104,12 @@ static zend_result php_cli_server_begin_send_static(php_cli_server *server, php_ int fd; int status = 200; + if (client->request.request_method == PHP_HTTP_DELETE + || client->request.request_method == PHP_HTTP_PUT + || client->request.request_method == PHP_HTTP_PATCH) { + return php_cli_server_send_error_page(server, client, 405); + } + if (client->request.path_translated && strlen(client->request.path_translated) != client->request.path_translated_len) { /* can't handle paths that contain nul bytes */ return php_cli_server_send_error_page(server, client, 400); @@ -2115,7 +2137,9 @@ static zend_result php_cli_server_begin_send_static(php_cli_server *server, php_ php_cli_server_content_sender_ctor(&client->content_sender); client->content_sender_initialized = true; - client->file_fd = fd; + if (client->request.request_method != PHP_HTTP_HEAD) { + client->file_fd = fd; + } { php_cli_server_chunk *chunk; diff --git a/sapi/cli/tests/php_cli_server_013.phpt b/sapi/cli/tests/php_cli_server_013.phpt index 8042219afe316..11e3fdf065b1f 100644 --- a/sapi/cli/tests/php_cli_server_013.phpt +++ b/sapi/cli/tests/php_cli_server_013.phpt @@ -58,6 +58,60 @@ HEAD /main/foo/bar HTTP/1.1 Host: {$host} +HEADER +)) { + while (!feof($fp)) { + $output .= fgets($fp); + } +} + +echo preg_replace("/", $output), "\n"; +fclose($fp); + +$output = ''; +$fp = php_cli_server_connect(); + +if(fwrite($fp, <<
(.*?)<\/style>/s", "", $output), "\n"; +fclose($fp); + +$output = ''; +$fp = php_cli_server_connect(); + +if(fwrite($fp, <<
(.*?)<\/style>/s", "", $output), "\n"; +fclose($fp); + +$output = ''; +$fp = php_cli_server_connect(); + +if(fwrite($fp, <<
404 Not Found -

Not Found

The requested resource /main/foo/bar was not found on this server.

+ +HTTP/1.1 405 Method Not Allowed +Host: %s +Date: %s +Connection: close +Content-Type: text/html; charset=UTF-8 +Content-Length: %d +Allow: GET, HEAD, POST + +405 Method Not Allowed +

Method Not Allowed

Requested method not allowed.

+HTTP/1.1 405 Method Not Allowed +Host: %s +Date: %s +Connection: close +Content-Type: text/html; charset=UTF-8 +Content-Length: %d +Allow: GET, HEAD, POST + +405 Method Not Allowed +

Method Not Allowed

Requested method not allowed.

+HTTP/1.1 405 Method Not Allowed +Host: %s +Date: %s +Connection: close +Content-Type: text/html; charset=UTF-8 +Content-Length: %d +Allow: GET, HEAD, POST + +405 Method Not Allowed +

Method Not Allowed

Requested method not allowed.