From 82d407b7e046b0a2d561b5a613ca5324ab93b907 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 21 May 2022 16:52:21 +0200 Subject: [PATCH] Revert "Refactor CLI SAPI php_cli_server_client struct to use zend_string (#8522)" This reverts commit 9b19d9043256427b54c65ac5a3b886d03cf06f2d. This has broken the ZEND_RC_DEBUG build. --- sapi/cli/php_cli_server.c | 242 +++++++++--------- .../cli_server_persistent_string001.phpt | 19 -- .../cli_server_persistent_string002.phpt | 42 --- sapi/cli/tests/php_cli_server.inc | 37 +-- sapi/cli/tests/php_cli_server_022.phpt | 45 ---- 5 files changed, 142 insertions(+), 243 deletions(-) delete mode 100644 sapi/cli/tests/cli_server_persistent_string001.phpt delete mode 100644 sapi/cli/tests/cli_server_persistent_string002.phpt delete mode 100644 sapi/cli/tests/php_cli_server_022.phpt diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 983d5f88bac..65a8a65fe2f 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -164,15 +164,19 @@ typedef struct php_cli_server_client { php_socket_t sock; struct sockaddr *addr; socklen_t addr_len; - zend_string *addr_str; + char *addr_str; + size_t addr_str_len; php_http_parser parser; - bool request_read; - zend_string *current_header_name; - zend_string *current_header_value; + unsigned int request_read:1; + char *current_header_name; + size_t current_header_name_len; + unsigned int current_header_name_allocated:1; + char *current_header_value; + size_t current_header_value_len; enum { HEADER_NONE=0, HEADER_FIELD, HEADER_VALUE } last_header_element; size_t post_read_offset; php_cli_server_request request; - bool content_sender_initialized; + unsigned int content_sender_initialized:1; php_cli_server_content_sender content_sender; int file_fd; } php_cli_server_client; @@ -266,10 +270,9 @@ static bool php_cli_server_get_system_time(char *buf) { } #endif -/* Destructor for php_cli_server_request->headers, this frees header value */ -static void cli_header_value_dtor(zval *zv) /* {{{ */ +static void char_ptr_dtor_p(zval *zv) /* {{{ */ { - zend_string_release_ex(Z_STR_P(zv), /* persistent */ true); + pefree(Z_PTR_P(zv), 1); } /* }}} */ static char *get_last_error(void) /* {{{ */ @@ -347,19 +350,19 @@ static void append_http_status_line(smart_str *buffer, int protocol_version, int static void append_essential_headers(smart_str* buffer, php_cli_server_client *client, bool persistent) /* {{{ */ { - zval *val; + char *val; struct timeval tv = {0}; - if (NULL != (val = zend_hash_str_find(&client->request.headers, "host", sizeof("host")-1))) { + if (NULL != (val = zend_hash_str_find_ptr(&client->request.headers, "host", sizeof("host")-1))) { smart_str_appends_ex(buffer, "Host: ", persistent); - smart_str_append_ex(buffer, Z_STR_P(val), persistent); + smart_str_appends_ex(buffer, val, persistent); smart_str_appends_ex(buffer, "\r\n", persistent); } if (!gettimeofday(&tv, NULL)) { zend_string *dt = php_format_date("D, d M Y H:i:s", sizeof("D, d M Y H:i:s") - 1, tv.tv_sec, 0); smart_str_appends_ex(buffer, "Date: ", persistent); - smart_str_append_ex(buffer, dt, persistent); + smart_str_appends_ex(buffer, dt->val, persistent); smart_str_appends_ex(buffer, " GMT\r\n", persistent); zend_string_release_ex(dt, 0); } @@ -381,6 +384,9 @@ static const char *get_mime_type(const php_cli_server *server, const char *ext, PHP_FUNCTION(apache_request_headers) /* {{{ */ { php_cli_server_client *client; + HashTable *headers; + zend_string *key; + char *value; zval tmp; if (zend_parse_parameters_none() == FAILURE) { @@ -388,10 +394,14 @@ PHP_FUNCTION(apache_request_headers) /* {{{ */ } client = SG(server_context); + headers = &client->request.headers_original_case; - /* Need to copy the HashTable */ - ZVAL_ARR(&tmp,&client->request.headers_original_case); - RETURN_COPY(&tmp); + array_init_size(return_value, zend_hash_num_elements(headers)); + + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(headers, key, value) { + ZVAL_STRING(&tmp, value); + zend_symtable_update(Z_ARRVAL_P(return_value), key, &tmp); + } ZEND_HASH_FOREACH_END(); } /* }}} */ @@ -564,11 +574,11 @@ static int sapi_cli_server_send_headers(sapi_headers_struct *sapi_headers) /* {{ static char *sapi_cli_server_read_cookies(void) /* {{{ */ { php_cli_server_client *client = SG(server_context); - zval *val; - if (NULL == (val = zend_hash_str_find(&client->request.headers, "cookie", sizeof("cookie")-1))) { + char *val; + if (NULL == (val = zend_hash_str_find_ptr(&client->request.headers, "cookie", sizeof("cookie")-1))) { return NULL; } - return Z_STRVAL_P(val); + return val; } /* }}} */ static size_t sapi_cli_server_read_post(char *buf, size_t count_bytes) /* {{{ */ @@ -598,12 +608,8 @@ static void sapi_cli_server_register_variable(zval *track_vars_array, const char } } /* }}} */ -/* The entry zval will always contain a zend_string* */ -static int sapi_cli_server_register_entry_cb(zval *entry, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ { +static int sapi_cli_server_register_entry_cb(char **entry, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ { zval *track_vars_array = va_arg(args, zval *); - - ZEND_ASSERT(Z_TYPE_P(entry) == IS_STRING); - if (hash_key->key) { char *real_key, *key; uint32_t i; @@ -617,10 +623,9 @@ static int sapi_cli_server_register_entry_cb(zval *entry, int num_args, va_list } spprintf(&real_key, 0, "%s_%s", "HTTP", key); if (strcmp(key, "CONTENT_TYPE") == 0 || strcmp(key, "CONTENT_LENGTH") == 0) { - // TODO make a version specialized for zend_string? - sapi_cli_server_register_variable(track_vars_array, key, Z_STRVAL_P(entry)); + sapi_cli_server_register_variable(track_vars_array, key, *entry); } - sapi_cli_server_register_variable(track_vars_array, real_key, Z_STRVAL_P(entry)); + sapi_cli_server_register_variable(track_vars_array, real_key, *entry); efree(key); efree(real_key); } @@ -635,9 +640,9 @@ static void sapi_cli_server_register_variables(zval *track_vars_array) /* {{{ */ sapi_cli_server_register_variable(track_vars_array, "DOCUMENT_ROOT", client->server->document_root); { char *tmp; - if ((tmp = strrchr(ZSTR_VAL(client->addr_str), ':'))) { + if ((tmp = strrchr(client->addr_str, ':'))) { char addr[64], port[8]; - const char *addr_start = ZSTR_VAL(client->addr_str), *addr_end = tmp; + const char *addr_start = client->addr_str, *addr_end = tmp; if (addr_start[0] == '[') addr_start++; if (addr_end[-1] == ']') addr_end--; @@ -648,7 +653,7 @@ static void sapi_cli_server_register_variables(zval *track_vars_array) /* {{{ */ sapi_cli_server_register_variable(track_vars_array, "REMOTE_ADDR", addr); sapi_cli_server_register_variable(track_vars_array, "REMOTE_PORT", port); } else { - sapi_cli_server_register_variable(track_vars_array, "REMOTE_ADDR", ZSTR_VAL(client->addr_str)); + sapi_cli_server_register_variable(track_vars_array, "REMOTE_ADDR", client->addr_str); } } { @@ -1147,8 +1152,7 @@ static void php_cli_server_log_response(php_cli_server_client *client, int statu #endif /* basic */ - spprintf(&basic_buf, 0, "%s [%d]: %s %s", ZSTR_VAL(client->addr_str), status, - php_http_method_str(client->request.request_method), client->request.request_uri); + spprintf(&basic_buf, 0, "%s [%d]: %s %s", client->addr_str, status, php_http_method_str(client->request.request_method), client->request.request_uri); if (!basic_buf) { return; } @@ -1335,8 +1339,7 @@ static void php_cli_server_request_ctor(php_cli_server_request *req) /* {{{ */ req->path_info_len = 0; req->query_string = NULL; req->query_string_len = 0; - zend_hash_init(&req->headers, 0, NULL, cli_header_value_dtor, 1); - /* No destructor is registered as the value pointed by is the same as for &req->headers */ + zend_hash_init(&req->headers, 0, NULL, char_ptr_dtor_p, 1); zend_hash_init(&req->headers_original_case, 0, NULL, NULL, 1); req->content = NULL; req->content_len = 0; @@ -1370,7 +1373,7 @@ static void php_cli_server_request_dtor(php_cli_server_request *req) /* {{{ */ static void php_cli_server_request_translate_vpath(php_cli_server_request *request, const char *document_root, size_t document_root_len) /* {{{ */ { - zend_stat_t sb = {0}; + zend_stat_t sb; static const char *index_files[] = { "index.php", "index.html", NULL }; char *buf = safe_pemalloc(1, request->vpath_len, 1 + document_root_len + 1 + sizeof("index.html"), 1); char *p = buf, *prev_path = NULL, *q, *vpath; @@ -1619,53 +1622,56 @@ static int php_cli_server_client_read_request_on_fragment(php_http_parser *parse static void php_cli_server_client_save_header(php_cli_server_client *client) { - /* Wrap header value in a zval to add is to the HashTable which acts as an array */ - zval tmp; - ZVAL_STR(&tmp, client->current_header_value); /* strip off the colon */ - zend_string *lc_header_name = zend_string_tolower_ex(client->current_header_name, /* persistent */ true); - - /* Add the wrapped zend_string to the HashTable */ - zend_hash_add(&client->request.headers, lc_header_name, &tmp); - zend_hash_add(&client->request.headers_original_case, client->current_header_name, &tmp); - - zend_string_release_ex(lc_header_name, /* persistent */ true); + zend_string *orig_header_name = zend_string_init(client->current_header_name, client->current_header_name_len, 1); + zend_string *lc_header_name = zend_string_alloc(client->current_header_name_len, 1); + zend_str_tolower_copy(ZSTR_VAL(lc_header_name), client->current_header_name, client->current_header_name_len); + GC_MAKE_PERSISTENT_LOCAL(orig_header_name); + GC_MAKE_PERSISTENT_LOCAL(lc_header_name); + zend_hash_add_ptr(&client->request.headers, lc_header_name, client->current_header_value); + zend_hash_add_ptr(&client->request.headers_original_case, orig_header_name, client->current_header_value); + zend_string_release_ex(lc_header_name, 1); + zend_string_release_ex(orig_header_name, 1); + if (client->current_header_name_allocated) { + pefree(client->current_header_name, 1); + client->current_header_name_allocated = 0; + } client->current_header_name = NULL; + client->current_header_name_len = 0; client->current_header_value = NULL; -} - -static zend_string* cli_concat_persistent_zstr_with_char(zend_string *old_str, const char *at, size_t length) -{ - /* Assert that there is only one reference to the string, as then zend_string_extends() - * will reallocate it such that we do not need to release the old value. */ - ZEND_ASSERT(GC_REFCOUNT(old_str) == 1); - /* Previous element was part of header value, append content to it */ - size_t old_length = ZSTR_LEN(old_str); - zend_string *str = zend_string_extend(old_str, old_length + length, /* persistent */ true); - memcpy(ZSTR_VAL(str) + old_length, at, length); - // Null terminate - ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0'; - return str; + client->current_header_value_len = 0; } static int php_cli_server_client_read_request_on_header_field(php_http_parser *parser, const char *at, size_t length) { php_cli_server_client *client = parser->data; switch (client->last_header_element) { - case HEADER_VALUE: - /* Save previous header before creating new one */ - php_cli_server_client_save_header(client); - ZEND_FALLTHROUGH; - case HEADER_NONE: - /* Create new header field */ - client->current_header_name = zend_string_init(at, length, /* persistent */ true); - break; - case HEADER_FIELD: { - /* Append header name to the previous value of it */ - client->current_header_name = cli_concat_persistent_zstr_with_char(client->current_header_name, at, length); - break; + case HEADER_VALUE: + php_cli_server_client_save_header(client); + ZEND_FALLTHROUGH; + case HEADER_NONE: + client->current_header_name = (char *)at; + client->current_header_name_len = length; + break; + case HEADER_FIELD: + if (client->current_header_name_allocated) { + size_t new_length = client->current_header_name_len + length; + client->current_header_name = perealloc(client->current_header_name, new_length + 1, 1); + memcpy(client->current_header_name + client->current_header_name_len, at, length); + client->current_header_name[new_length] = '\0'; + client->current_header_name_len = new_length; + } else { + size_t new_length = client->current_header_name_len + length; + char* field = pemalloc(new_length + 1, 1); + memcpy(field, client->current_header_name, client->current_header_name_len); + memcpy(field + client->current_header_name_len, at, length); + field[new_length] = '\0'; + client->current_header_name = field; + client->current_header_name_len = new_length; + client->current_header_name_allocated = 1; } + break; } client->last_header_element = HEADER_FIELD; @@ -1676,19 +1682,23 @@ static int php_cli_server_client_read_request_on_header_value(php_http_parser *p { php_cli_server_client *client = parser->data; switch (client->last_header_element) { - case HEADER_FIELD: - /* Previous element was the header field, create the header value */ - client->current_header_value = zend_string_init(at, length, /* persistent */ true); - break; - case HEADER_VALUE: { - /* Append header value to the previous value of it */ - client->current_header_value = cli_concat_persistent_zstr_with_char(client->current_header_value, at, length); - break; + case HEADER_FIELD: + client->current_header_value = pestrndup(at, length, 1); + client->current_header_value_len = length; + break; + case HEADER_VALUE: + { + size_t new_length = client->current_header_value_len + length; + client->current_header_value = perealloc(client->current_header_value, new_length + 1, 1); + memcpy(client->current_header_value + client->current_header_value_len, at, length); + client->current_header_value[new_length] = '\0'; + client->current_header_value_len = new_length; } - case HEADER_NONE: - /* Cannot happen as a header field must have been found before */ - assert(0); - break; + break; + case HEADER_NONE: + // can't happen + assert(0); + break; } client->last_header_element = HEADER_VALUE; return 0; @@ -1701,11 +1711,11 @@ static int php_cli_server_client_read_request_on_headers_complete(php_http_parse case HEADER_NONE: break; case HEADER_FIELD: - /* Previous element was the header field, set it's value to an empty string */ - client->current_header_value = ZSTR_EMPTY_ALLOC(); + client->current_header_value = pemalloc(1, 1); + *client->current_header_value = '\0'; + client->current_header_value_len = 0; ZEND_FALLTHROUGH; case HEADER_VALUE: - /* Save last header value */ php_cli_server_client_save_header(client); break; } @@ -1745,7 +1755,7 @@ static int php_cli_server_client_read_request_on_message_complete(php_http_parse } } } - client->request_read = true; + client->request_read = 1; return 0; } @@ -1806,7 +1816,12 @@ static int php_cli_server_client_read_request(php_cli_server_client *client, cha return -1; } - + if (client->current_header_name) { + char *header_name = safe_pemalloc(client->current_header_name_len, 1, 1, 1); + memmove(header_name, client->current_header_name, client->current_header_name_len); + client->current_header_name = header_name; + client->current_header_name_allocated = 1; + } return client->request_read ? 1: 0; } /* }}} */ @@ -1851,7 +1866,7 @@ static size_t php_cli_server_client_send_through(php_cli_server_client *client, static void php_cli_server_client_populate_request_info(const php_cli_server_client *client, sapi_request_info *request_info) /* {{{ */ { - zval *val; + char *val; request_info->request_method = php_http_method_str(client->request.request_method); request_info->proto_num = client->request.protocol_version; @@ -1860,8 +1875,8 @@ static void php_cli_server_client_populate_request_info(const php_cli_server_cli request_info->query_string = client->request.query_string; request_info->content_length = client->request.content_len; request_info->auth_user = request_info->auth_password = request_info->auth_digest = NULL; - if (NULL != (val = zend_hash_str_find(&client->request.headers, "content-type", sizeof("content-type")-1))) { - request_info->content_type = Z_STRVAL_P(val); + if (NULL != (val = zend_hash_str_find_ptr(&client->request.headers, "content-type", sizeof("content-type")-1))) { + request_info->content_type = val; } } /* }}} */ @@ -1876,26 +1891,29 @@ static void php_cli_server_client_ctor(php_cli_server_client *client, php_cli_se client->sock = client_sock; client->addr = addr; client->addr_len = addr_len; + { + zend_string *addr_str = 0; - // TODO To prevent the reallocation need to retrieve a persistent string - // Create a new php_network_populate_name_from_sockaddr_ex() API with a persistent flag? - zend_string *tmp_addr = NULL; - php_network_populate_name_from_sockaddr(addr, addr_len, &tmp_addr, NULL, 0); - client->addr_str = zend_string_dup(tmp_addr, /* persistent */ true); - zend_string_release_ex(tmp_addr, /* persistent */ false); - + php_network_populate_name_from_sockaddr(addr, addr_len, &addr_str, NULL, 0); + client->addr_str = pestrndup(ZSTR_VAL(addr_str), ZSTR_LEN(addr_str), 1); + client->addr_str_len = ZSTR_LEN(addr_str); + zend_string_release_ex(addr_str, 0); + } php_http_parser_init(&client->parser, PHP_HTTP_REQUEST); - client->request_read = false; + client->request_read = 0; client->last_header_element = HEADER_NONE; client->current_header_name = NULL; + client->current_header_name_len = 0; + client->current_header_name_allocated = 0; client->current_header_value = NULL; + client->current_header_value_len = 0; client->post_read_offset = 0; php_cli_server_request_ctor(&client->request); - client->content_sender_initialized = false; + client->content_sender_initialized = 0; client->file_fd = -1; } /* }}} */ @@ -1907,19 +1925,15 @@ static void php_cli_server_client_dtor(php_cli_server_client *client) /* {{{ */ client->file_fd = -1; } pefree(client->addr, 1); - zend_string_release_ex(client->addr_str, /* persistent */ true); - + pefree(client->addr_str, 1); if (client->content_sender_initialized) { - /* Headers must be set if we reached the content initialisation */ - assert(client->current_header_name == NULL); - assert(client->current_header_value == NULL); php_cli_server_content_sender_dtor(&client->content_sender); } } /* }}} */ static void php_cli_server_close_connection(php_cli_server *server, php_cli_server_client *client) /* {{{ */ { - php_cli_server_logf(PHP_CLI_SERVER_LOG_MESSAGE, "%s Closing", ZSTR_VAL(client->addr_str)); + php_cli_server_logf(PHP_CLI_SERVER_LOG_MESSAGE, "%s Closing", client->addr_str); zend_hash_index_del(&server->clients, client->sock); } /* }}} */ @@ -1933,7 +1947,7 @@ static zend_result php_cli_server_send_error_page(php_cli_server *server, php_cl assert(status_string && content_template); php_cli_server_content_sender_ctor(&client->content_sender); - client->content_sender_initialized = true; + client->content_sender_initialized = 1; escaped_request_uri = php_escape_html_entities_ex((const unsigned char *) client->request.request_uri, client->request.request_uri_len, 0, ENT_QUOTES, NULL, /* double_encode */ 0, /* quiet */ 0); @@ -2069,7 +2083,7 @@ 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->content_sender_initialized = 1; client->file_fd = fd; { @@ -2111,10 +2125,10 @@ static zend_result php_cli_server_begin_send_static(php_cli_server *server, php_ /* }}} */ static zend_result php_cli_server_request_startup(php_cli_server *server, php_cli_server_client *client) { /* {{{ */ - zval *auth; + char *auth; php_cli_server_client_populate_request_info(client, &SG(request_info)); - if (NULL != (auth = zend_hash_str_find(&client->request.headers, "authorization", sizeof("authorization")-1))) { - php_handle_auth_data(Z_STRVAL_P(auth)); + if (NULL != (auth = zend_hash_str_find_ptr(&client->request.headers, "authorization", sizeof("authorization")-1))) { + php_handle_auth_data(auth); } SG(sapi_headers).http_response_code = 200; if (FAILURE == php_request_startup()) { @@ -2501,9 +2515,9 @@ static zend_result php_cli_server_recv_event_read_request(php_cli_server *server if (errstr) { if (strcmp(errstr, php_cli_server_request_error_unexpected_eof) == 0 && client->parser.state == s_start_req) { php_cli_server_logf(PHP_CLI_SERVER_LOG_MESSAGE, - "%s Closed without sending a request; it was probably just an unused speculative preconnection", ZSTR_VAL(client->addr_str)); + "%s Closed without sending a request; it was probably just an unused speculative preconnection", client->addr_str); } else { - php_cli_server_logf(PHP_CLI_SERVER_LOG_ERROR, "%s Invalid request (%s)", ZSTR_VAL(client->addr_str), errstr); + php_cli_server_logf(PHP_CLI_SERVER_LOG_ERROR, "%s Invalid request (%s)", client->addr_str, errstr); } efree(errstr); } @@ -2591,7 +2605,7 @@ static zend_result php_cli_server_do_event_for_each_fd_callback(void *_params, p php_cli_server_client_ctor(client, server, client_sock, sa, socklen); - php_cli_server_logf(PHP_CLI_SERVER_LOG_MESSAGE, "%s Accepted", ZSTR_VAL(client->addr_str)); + php_cli_server_logf(PHP_CLI_SERVER_LOG_MESSAGE, "%s Accepted", client->addr_str); zend_hash_index_update_ptr(&server->clients, client_sock, client); @@ -2710,7 +2724,7 @@ int do_cli_server(int argc, char **argv) /* {{{ */ } if (document_root) { - zend_stat_t sb = {0}; + zend_stat_t sb; if (php_sys_stat(document_root, &sb)) { fprintf(stderr, "Directory %s does not exist.\n", document_root); diff --git a/sapi/cli/tests/cli_server_persistent_string001.phpt b/sapi/cli/tests/cli_server_persistent_string001.phpt deleted file mode 100644 index 6c7e2ef2bf5..00000000000 --- a/sapi/cli/tests/cli_server_persistent_string001.phpt +++ /dev/null @@ -1,19 +0,0 @@ ---TEST-- -Close request before server sends a response ---SKIPIF-- - ---FILE-- - -===DONE=== ---EXPECT-- -===DONE=== diff --git a/sapi/cli/tests/cli_server_persistent_string002.phpt b/sapi/cli/tests/cli_server_persistent_string002.phpt deleted file mode 100644 index 9c0ae28514b..00000000000 --- a/sapi/cli/tests/cli_server_persistent_string002.phpt +++ /dev/null @@ -1,42 +0,0 @@ ---TEST-- -Server processing multiple request at the same time ---SKIPIF-- - ---FILE-- - -===DONE=== ---EXPECTF-- -HTTP/1.0 200 OK -Date: %s -Connection: close -X-Powered-By: %s -Content-type: text/html; charset=UTF-8 - -Hello worldHTTP/1.0 200 OK -Host: hello -Date: %s -Connection: close -X-Powered-By: %s -Content-type: text/html; charset=UTF-8 - -Hello world -===DONE=== diff --git a/sapi/cli/tests/php_cli_server.inc b/sapi/cli/tests/php_cli_server.inc index 65f2cc9a85d..a7d68b16cf2 100644 --- a/sapi/cli/tests/php_cli_server.inc +++ b/sapi/cli/tests/php_cli_server.inc @@ -28,40 +28,37 @@ function php_cli_server_start( $cmd[] = $router; } - $output_file = tempnam(sys_get_temp_dir(), 'cli_server_output'); - $output_file_fd = fopen($output_file, 'ab'); - if ($output_file_fd === false) { - die(sprintf("Failed opening output file %s\n", $output_file)); - } - $descriptorspec = array( 0 => STDIN, - 1 => $output_file_fd, - 2 => $output_file_fd, + 1 => STDOUT, + 2 => ['pipe', 'w'], ); $handle = proc_open($cmd, $descriptorspec, $pipes, $doc_root, null, array("suppress_errors" => true)); // First, wait for the dev server to declare itself ready. $bound = null; + stream_set_blocking($pipes[2], false); for ($i = 0; $i < 60; $i++) { usleep(50000); // 50ms per try $status = proc_get_status($handle); if (empty($status['running'])) { - echo "Server failed to start\n"; - printf("Server output:\n%s\n", file_get_contents($output_file)); + echo "Server is not running\n"; proc_terminate($handle); exit(1); } - $output = file_get_contents($output_file); - if (preg_match('@PHP \S* Development Server \(https?://(.*?:\d+)\) started@', $output, $matches)) { - $bound = $matches[1]; - break; + while (($line = fgets($pipes[2])) !== false) { + if (preg_match('@PHP \S* Development Server \(https?://(.*?:\d+)\) started@', $line, $matches)) { + $bound = $matches[1]; + // Now that we've identified the listen address, close STDERR. + // Otherwise the pipe may clog up with unread log messages. + fclose($pipes[2]); + break 2; + } } } if ($bound === null) { echo "Server did not output startup message"; - printf("Server output:\n%s\n", file_get_contents($output_file)); proc_terminate($handle); exit(1); } @@ -76,7 +73,7 @@ function php_cli_server_start( $fp = @fsockopen("tcp://$bound"); // Failure, the server is no longer running if (!($status && $status['running'])) { - $error = sprintf("Server stopped\nServer output:\n%s\n", file_get_contents($output_file)); + $error = "Server is not running\n"; break; } // Success, Connected to servers @@ -93,14 +90,8 @@ function php_cli_server_start( } register_shutdown_function( - function($handle) use($router, $doc_root, $output_file) { + function($handle) use($router, $doc_root) { proc_terminate($handle); - $status = proc_get_status($handle); - if ($status['exitcode'] !== -1 && $status['exitcode'] !== 0 - && !($status['exitcode'] === 255 && PHP_OS_FAMILY == 'Windows')) { - printf("Server exited with non-zero status: %d\n", $status['exitcode']); - printf("Server output:\n%s\n", file_get_contents($output_file)); - } @unlink(__DIR__ . "/{$router}"); @rmdir($doc_root); }, diff --git a/sapi/cli/tests/php_cli_server_022.phpt b/sapi/cli/tests/php_cli_server_022.phpt deleted file mode 100644 index 763a2036fcd..00000000000 --- a/sapi/cli/tests/php_cli_server_022.phpt +++ /dev/null @@ -1,45 +0,0 @@ ---TEST-- -Check PHP file body is executed ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -HTTP/1.1 200 OK -Host: %s -Date: %s -Connection: close -X-Powered-By: %s -Bar-Foo: Foo -Content-type: text/html; charset=UTF-8 - -Hello world -bool(true)