From: Sara Golemon Date: Mon, 14 Sep 2020 20:08:39 +0000 (+0000) Subject: Support ephemeral ports in debug server X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a61a9fe9a0d63734136f995451a1fd35b0176292;p=php Support ephemeral ports in debug server --- diff --git a/NEWS b/NEWS index 8cb4a580f5..c4926322db 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,8 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.0.0RC1 +- CLI: + . Allow debug server binding to an ephemeral port via `-S localhost:0`. (Sara) - Core: . Fixed bug #80109 (Cannot skip arguments when extended debug is enabled). (Nikita) diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 337886bcd3..a32b51e3d3 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -2353,6 +2353,65 @@ static void php_cli_server_client_dtor_wrapper(zval *zv) /* {{{ */ pefree(p, 1); } /* }}} */ +/** + * Parse the host and port portions of an address specifier in + * one of the following forms: + * - hostOrIP:port + * - [hostOrIP]:port + */ +static char *php_cli_server_parse_addr(const char *addr, int *pport) { + const char *p, *end; + long port; + + if (addr[0] == '[') { + /* Encapsulated [hostOrIP]:port */ + const char *start = addr + 1; + end = strchr(start, ']'); + if (!end) { + /* No ending ] delimiter to match [ */ + return NULL; + } + + p = end + 1; + if (*p != ':') { + /* Invalid char following address/missing port */ + return NULL; + } + + port = strtol(p + 1, (char**)&p, 10); + if (p && *p) { + /* Non-numeric in port */ + return NULL; + } + if (port < 0 || port > 65535) { + /* Invalid port */ + return NULL; + } + + /* Full [hostOrIP]:port provided */ + *pport = (int)port; + return pestrndup(start, end - start, 1); + } + + end = strchr(addr, ':'); + if (!end) { + /* Missing port */ + return NULL; + } + + port = strtol(end + 1, (char**)&p, 10); + if (p && *p) { + /* Non-numeric port */ + return NULL; + } + if (port < 0 || port > 65535) { + /* Invalid port */ + return NULL; + } + *pport = (int)port; + return pestrndup(addr, end - addr, 1); +} + static int php_cli_server_ctor(php_cli_server *server, const char *addr, const char *document_root, const char *router) /* {{{ */ { int retval = SUCCESS; @@ -2363,40 +2422,9 @@ static int php_cli_server_ctor(php_cli_server *server, const char *addr, const c int err = 0; int port = 3000; php_socket_t server_sock = SOCK_ERR; - char *p = NULL; - if (addr[0] == '[') { - host = pestrdup(addr + 1, 1); - if (!host) { - return FAILURE; - } - p = strchr(host, ']'); - if (p) { - *p++ = '\0'; - if (*p == ':') { - port = strtol(p + 1, &p, 10); - if (port <= 0 || port > 65535) { - p = NULL; - } - } else if (*p != '\0') { - p = NULL; - } - } - } else { - host = pestrdup(addr, 1); - if (!host) { - return FAILURE; - } - p = strchr(host, ':'); - if (p) { - *p++ = '\0'; - port = strtol(p, &p, 10); - if (port <= 0 || port > 65535) { - p = NULL; - } - } - } - if (!p) { + host = php_cli_server_parse_addr(addr, &port); + if (!host) { fprintf(stderr, "Invalid address: %s\n", addr); retval = FAILURE; goto out; @@ -2720,10 +2748,12 @@ int do_cli_server(int argc, char **argv) /* {{{ */ sapi_module.phpinfo_as_text = 0; { + zend_bool ipv6 = strchr(server.host, ':'); php_cli_server_logf( PHP_CLI_SERVER_LOG_PROCESS, - "PHP %s Development Server (http://%s) started", - PHP_VERSION, server_bind_address); + "PHP %s Development Server (http://%s%s%s:%d) started", + PHP_VERSION, ipv6 ? "[" : "", server.host, + ipv6 ? "]" : "", server.port); } #if defined(SIGINT)