]> granicus.if.org Git - php/commitdiff
improvements to cli server
authorJoe Watkins <krakjoe@php.net>
Wed, 3 Jul 2019 14:30:51 +0000 (16:30 +0200)
committerJoe Watkins <krakjoe@php.net>
Wed, 3 Jul 2019 14:30:51 +0000 (16:30 +0200)
sapi/cli/php_cli_server.c

index bfdf27f8d6bb11c4ca984a599b758148d2e52694..40fad8c10bdad1fcb3e0a05fbcbb99c3d87ea172 100644 (file)
 
 #if HAVE_FORK
 # include <sys/wait.h>
-static pid_t     php_cli_server_master;
-static pid_t    *php_cli_server_workers;
+static pid_t    php_cli_server_master;
+static pid_t   *php_cli_server_workers;
 static zend_long php_cli_server_workers_max;
 #endif
 
@@ -209,6 +209,12 @@ static php_cli_server_http_response_status_code_pair template_map[] = {
        { 501, "<h1>%s</h1><p>Request method not supported.</p>" }
 };
 
+#define PHP_CLI_SERVER_LOG_PROCESS 1
+#define PHP_CLI_SERVER_LOG_ERROR   2
+#define PHP_CLI_SERVER_LOG_MESSAGE 3
+
+static int php_cli_server_log_level = 3;
+
 #if HAVE_UNISTD_H
 static int php_cli_output_is_tty = OUTPUT_NOT_CHECKED;
 #endif
@@ -218,7 +224,7 @@ static const char php_cli_server_request_error_unexpected_eof[] = "Unexpected EO
 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);
-static void php_cli_server_logf(const char *format, ...);
+static void php_cli_server_logf(int type, const char *format, ...);
 static void php_cli_server_log_response(php_cli_server_client *client, int status, const char *message);
 
 ZEND_DECLARE_MODULE_GLOBALS(cli_server);
@@ -490,56 +496,56 @@ const zend_function_entry server_additional_functions[] = {
 
 static int sapi_cli_server_startup(sapi_module_struct *sapi_module) /* {{{ */
 {
-    char *workers;
+       char *workers;
 
        if (php_module_startup(sapi_module, &cli_server_module_entry, 1) == FAILURE) {
                return FAILURE;
        }
 
-    if ((workers = getenv("PHP_CLI_SERVER_WORKERS"))) {
+       if ((workers = getenv("PHP_CLI_SERVER_WORKERS"))) {
 #ifndef SO_REUSEPORT
-        fprintf(stderr, "platform does not support SO_REUSEPORT, cannot create workers\n");
+               fprintf(stderr, "platform does not support SO_REUSEPORT, cannot create workers\n");
 #elif HAVE_FORK
-        ZEND_ATOL(php_cli_server_workers_max, workers);
-
-        if (php_cli_server_workers_max > 1) {
-            zend_long php_cli_server_worker;
-            
-            php_cli_server_workers = calloc(
-                php_cli_server_workers_max, sizeof(pid_t));
-            if (!php_cli_server_workers) {
-                php_cli_server_workers_max = 1;
-
-                return SUCCESS;
-            }
-
-            php_cli_server_master = getpid();
-
-            for (php_cli_server_worker = 0;
-                 php_cli_server_worker < php_cli_server_workers_max;
-                 php_cli_server_worker++) {
-                pid_t pid = fork();
-
-                if (pid == FAILURE) {
-                    /* no more forks allowed, work with what we have ... */
-                    php_cli_server_workers_max = 
-                        php_cli_server_worker + 1;
-                    return SUCCESS;
-                } else if (pid == SUCCESS) {
-                    return SUCCESS;
-                } else {
-                    php_cli_server_workers[
-                        php_cli_server_worker
-                    ] = pid;
-                }
-            }
-        } else {
-            fprintf(stderr, "number of workers must be larger than 1\n");
-        }
+               ZEND_ATOL(php_cli_server_workers_max, workers);
+
+               if (php_cli_server_workers_max > 1) {
+                       zend_long php_cli_server_worker;
+                       
+                       php_cli_server_workers = calloc(
+                               php_cli_server_workers_max, sizeof(pid_t));
+                       if (!php_cli_server_workers) {
+                               php_cli_server_workers_max = 1;
+
+                               return SUCCESS;
+                       }
+
+                       php_cli_server_master = getpid();
+
+                       for (php_cli_server_worker = 0;
+                                php_cli_server_worker < php_cli_server_workers_max;
+                                php_cli_server_worker++) {
+                               pid_t pid = fork();
+
+                               if (pid == FAILURE) {
+                                       /* no more forks allowed, work with what we have ... */
+                                       php_cli_server_workers_max = 
+                                               php_cli_server_worker + 1;
+                                       return SUCCESS;
+                               } else if (pid == SUCCESS) {
+                                       return SUCCESS;
+                               } else {
+                                       php_cli_server_workers[
+                                               php_cli_server_worker
+                                       ] = pid;
+                               }
+                       }
+               } else {
+                       fprintf(stderr, "number of workers must be larger than 1\n");
+               }
 #else
-        fprintf(stderr, "forking is not supported on this platform\n");
+               fprintf(stderr, "forking is not supported on this platform\n");
 #endif
-    }
+       }
 
        return SUCCESS;
 } /* }}} */
@@ -744,10 +750,14 @@ static void sapi_cli_server_register_variables(zval *track_vars_array) /* {{{ */
        zend_hash_apply_with_arguments(&client->request.headers, (apply_func_args_t)sapi_cli_server_register_entry_cb, 1, track_vars_array);
 } /* }}} */
 
-static void sapi_cli_server_log_message(char *msg, int syslog_type_int) /* {{{ */
+static void sapi_cli_server_log_write(int type, char *msg) /* {{{ */
 {
        char buf[52];
 
+       if (php_cli_server_log_level < type) {
+               return;
+       }
+
        if (php_cli_server_get_system_time(buf) != 0) {
                memmove(buf, "unknown time, can't be fetched", sizeof("unknown time, can't be fetched"));
        } else {
@@ -765,10 +775,15 @@ static void sapi_cli_server_log_message(char *msg, int syslog_type_int) /* {{{ *
                fprintf(stderr, "[%s] %s\n", buf, msg);
        }
 #else
-    fprintf(stderr, "[%s] %s\n", buf, msg);
+       fprintf(stderr, "[%s] %s\n", buf, msg);
 #endif
 } /* }}} */
 
+static void sapi_cli_server_log_message(char *msg, int syslog_type_int) /* {{{ */
+{
+       sapi_cli_server_log_write(PHP_CLI_SERVER_LOG_MESSAGE, msg);
+} /* }}} */
+
 /* {{{ sapi_module_struct cli_server_sapi_module
  */
 sapi_module_struct cli_server_sapi_module = {
@@ -901,14 +916,14 @@ static int php_cli_server_poller_iter_on_active(php_cli_server_poller *poller, v
 
        for (fd=0 ; fd<=max_fd ; fd++)  {
                if (PHP_SAFE_FD_ISSET(fd, &poller->active.rfds)) {
-                if (SUCCESS != callback(opaque, fd, POLLIN)) {
-                    retval = FAILURE;
-                }
+                               if (SUCCESS != callback(opaque, fd, POLLIN)) {
+                                       retval = FAILURE;
+                               }
                }
                if (PHP_SAFE_FD_ISSET(fd, &poller->active.wfds)) {
-                if (SUCCESS != callback(opaque, fd, POLLOUT)) {
-                    retval = FAILURE;
-                }
+                               if (SUCCESS != callback(opaque, fd, POLLOUT)) {
+                                       retval = FAILURE;
+                               }
                }
        }
 #endif
@@ -1121,9 +1136,11 @@ static int php_cli_server_content_sender_pull(php_cli_server_content_sender *sen
        _nbytes_read = read(fd, chunk->data.heap.p, chunk->data.heap.len);
 #endif
        if (_nbytes_read < 0) {
-               char *errstr = get_last_error();
-               php_cli_server_logf("%s", errstr);
-               pefree(errstr, 1);
+               if (php_cli_server_log_level >= PHP_CLI_SERVER_LOG_ERROR) {
+                       char *errstr = get_last_error();
+                       php_cli_server_logf(PHP_CLI_SERVER_LOG_ERROR, "%s", errstr);
+                       pefree(errstr, 1);
+               }
                php_cli_server_chunk_dtor(chunk);
                pefree(chunk, 1);
                return 1;
@@ -1210,9 +1227,9 @@ static void php_cli_server_log_response(php_cli_server_client *client, int statu
        }
 
        if (color) {
-               php_cli_server_logf("\x1b[3%dm%s%s%s\x1b[0m", color, basic_buf, message_buf, error_buf);
+               php_cli_server_logf(PHP_CLI_SERVER_LOG_MESSAGE, "\x1b[3%dm%s%s%s\x1b[0m", color, basic_buf, message_buf, error_buf);
        } else {
-               php_cli_server_logf("%s%s%s", basic_buf, message_buf, error_buf);
+               php_cli_server_logf(PHP_CLI_SERVER_LOG_MESSAGE, "%s%s%s", basic_buf, message_buf, error_buf);
        }
 
        efree(basic_buf);
@@ -1224,11 +1241,15 @@ static void php_cli_server_log_response(php_cli_server_client *client, int statu
        }
 } /* }}} */
 
-static void php_cli_server_logf(const char *format, ...) /* {{{ */
+static void php_cli_server_logf(int type, const char *format, ...) /* {{{ */
 {
        char *buf = NULL;
        va_list ap;
 
+       if (php_cli_server_log_level < type) {
+               return;
+       }
+
        va_start(ap, format);
        vspprintf(&buf, 0, format, ap);
        va_end(ap);
@@ -1237,9 +1258,7 @@ static void php_cli_server_logf(const char *format, ...) /* {{{ */
                return;
        }
 
-       if (sapi_module.log_message) {
-               sapi_module.log_message(buf, -1);
-       }
+       sapi_cli_server_log_write(type, buf);
 
        efree(buf);
 } /* }}} */
@@ -1295,10 +1314,10 @@ static php_socket_t php_network_listen_socket(const char *host, int *port, int s
 #endif
 
 #if defined(HAVE_FORK) && defined(SO_REUSEPORT)
-        if (php_cli_server_workers_max > 1) {
-            int val = 1;
+               if (php_cli_server_workers_max > 1) {
+                       int val = 1;
                        setsockopt(retval, SOL_SOCKET, SO_REUSEPORT, (char*)&val, sizeof(val));
-        }
+               }
 #endif
 
                if (bind(retval, sa, *socklen) == SOCK_CONN_ERR) {
@@ -1798,20 +1817,30 @@ static int php_cli_server_client_read_request(php_cli_server_client *client, cha
                if (err == SOCK_EAGAIN) {
                        return 0;
                }
-               *errstr = php_socket_strerror(err, NULL, 0);
+
+               if (php_cli_server_log_level >= PHP_CLI_SERVER_LOG_ERROR) {
+                       *errstr = php_socket_strerror(err, NULL, 0);
+               }
+
                return -1;
        } else if (nbytes_read == 0) {
-               *errstr = estrdup(php_cli_server_request_error_unexpected_eof);
+               if (php_cli_server_log_level >= PHP_CLI_SERVER_LOG_ERROR) {
+                       *errstr = estrdup(php_cli_server_request_error_unexpected_eof);
+               }
+
                return -1;
        }
        client->parser.data = client;
        nbytes_consumed = php_http_parser_execute(&client->parser, &settings, buf, nbytes_read);
        if (nbytes_consumed != (size_t)nbytes_read) {
-               if (buf[0] & 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) {
-                       *errstr = estrdup("Unsupported SSL request");
-               } else {
-                       *errstr = estrdup("Malformed HTTP request");
+               if (php_cli_server_log_level >= PHP_CLI_SERVER_LOG_ERROR) {
+                       if (buf[0] & 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) {
+                               *errstr = estrdup("Unsupported SSL request");
+                       } else {
+                               *errstr = estrdup("Malformed HTTP request");
+                       }
                }
+
                return -1;
        }
        if (client->current_header_name) {
@@ -1935,9 +1964,8 @@ 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) /* {{{ */
 {
-#if PHP_DEBUG
-       php_cli_server_logf("%s Closing", client->addr_str);
-#endif
+       php_cli_server_logf(PHP_CLI_SERVER_LOG_MESSAGE, "%s Closing", client->addr_str);
+
        zend_hash_index_del(&server->clients, client->sock);
 } /* }}} */
 
@@ -2238,12 +2266,12 @@ static int php_cli_server_dispatch(php_cli_server *server, php_cli_server_client
                        static int (*send_header_func)(sapi_headers_struct *);
                        send_header_func = sapi_module.send_headers;
                        /* do not generate default content type header */
-                   SG(sapi_headers).send_default_content_type = 0;
+                       SG(sapi_headers).send_default_content_type = 0;
                        /* we don't want headers to be sent */
                        sapi_module.send_headers = sapi_cli_server_discard_headers;
                        php_request_shutdown(0);
                        sapi_module.send_headers = send_header_func;
-                   SG(sapi_headers).send_default_content_type = 1;
+                       SG(sapi_headers).send_default_content_type = 1;
                        SG(rfc1867_uploaded_files) = NULL;
                }
                if (SUCCESS != php_cli_server_begin_send_static(server, client)) {
@@ -2290,30 +2318,30 @@ static void php_cli_server_dtor(php_cli_server *server) /* {{{ */
                pefree(server->router, 1);
        }
 #if HAVE_FORK
-    if (php_cli_server_workers_max > 1 &&
-        php_cli_server_workers &&
-        getpid() == php_cli_server_master) {
-        zend_long php_cli_server_worker;
-
-        for (php_cli_server_worker = 0;
-             php_cli_server_worker < php_cli_server_workers_max;
-             php_cli_server_worker++) {
-             int php_cli_server_worker_status;
-
-             do {
-                if (waitpid(php_cli_server_workers[php_cli_server_worker], 
-                           &php_cli_server_worker_status, 
-                           0) == FAILURE) {
-                    /* an extremely bad thing happened */
-                    break;
-                }
-
-             } while (!WIFEXITED(php_cli_server_worker_status) && 
-                      !WIFSIGNALED(php_cli_server_worker_status));
-        }
-
-        free(php_cli_server_workers);
-    }
+       if (php_cli_server_workers_max > 1 &&
+               php_cli_server_workers &&
+               getpid() == php_cli_server_master) {
+               zend_long php_cli_server_worker;
+
+               for (php_cli_server_worker = 0;
+                        php_cli_server_worker < php_cli_server_workers_max;
+                        php_cli_server_worker++) {
+                        int php_cli_server_worker_status;
+
+                        do {
+                               if (waitpid(php_cli_server_workers[php_cli_server_worker], 
+                                                  &php_cli_server_worker_status, 
+                                                  0) == FAILURE) {
+                                       /* an extremely bad thing happened */
+                                       break;
+                               }
+
+                        } while (!WIFEXITED(php_cli_server_worker_status) && 
+                                         !WIFSIGNALED(php_cli_server_worker_status));
+               }
+
+               free(php_cli_server_workers);
+       }
 #endif
 } /* }}} */
 
@@ -2321,6 +2349,7 @@ static void php_cli_server_client_dtor_wrapper(zval *zv) /* {{{ */
 {
        php_cli_server_client *p = Z_PTR_P(zv);
 
+       shutdown(p->sock, SHUT_RDWR);
        closesocket(p->sock);
        php_cli_server_poller_remove(&p->server->poller, POLLIN | POLLOUT, p->sock);
        php_cli_server_client_dtor(p);
@@ -2378,7 +2407,7 @@ static int php_cli_server_ctor(php_cli_server *server, const char *addr, const c
 
        server_sock = php_network_listen_socket(host, &port, SOCK_STREAM, &server->address_family, &server->socklen, &errstr);
        if (server_sock == SOCK_ERR) {
-               php_cli_server_logf("Failed to listen on %s:%d (reason: %s)", host, port, errstr ? ZSTR_VAL(errstr) : "?");
+               php_cli_server_logf(PHP_CLI_SERVER_LOG_ERROR, "Failed to listen on %s:%d (reason: %s)", host, port, errstr ? ZSTR_VAL(errstr) : "?");
                if (errstr) {
                        zend_string_release_ex(errstr, 0);
                }
@@ -2453,14 +2482,15 @@ 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) {
-               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);
+               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", client->addr_str);
+                       } else {
+                               php_cli_server_logf(PHP_CLI_SERVER_LOG_ERROR, "%s Invalid request (%s)", client->addr_str, errstr);
+                       }
+                       efree(errstr);
                }
-               efree(errstr);
                php_cli_server_close_connection(server, client);
                return FAILURE;
        } else if (status == 1 && client->request.request_method == PHP_HTTP_NOT_IMPLEMENTED) {
@@ -2522,10 +2552,12 @@ static int php_cli_server_do_event_for_each_fd_callback(void *_params, php_socke
                struct sockaddr *sa = pemalloc(server->socklen, 1);
                client_sock = accept(server->server_sock, sa, &socklen);
                if (!ZEND_VALID_SOCKET(client_sock)) {
-                       char *errstr;
-                       errstr = php_socket_strerror(php_socket_errno(), NULL, 0);
-                       php_cli_server_logf("Failed to accept a client (reason: %s)", errstr);
-                       efree(errstr);
+                       if (php_cli_server_log_level >= PHP_CLI_SERVER_LOG_ERROR) {
+                               char *errstr = php_socket_strerror(php_socket_errno(), NULL, 0);
+                               php_cli_server_logf(PHP_CLI_SERVER_LOG_ERROR,
+                                       "Failed to accept a client (reason: %s)", errstr);
+                               efree(errstr);
+                       }
                        pefree(sa, 1);
                        return SUCCESS;
                }
@@ -2536,16 +2568,17 @@ static int php_cli_server_do_event_for_each_fd_callback(void *_params, php_socke
                }
                client = pemalloc(sizeof(php_cli_server_client), 1);
                if (FAILURE == php_cli_server_client_ctor(client, server, client_sock, sa, socklen)) {
-                       php_cli_server_logf("Failed to create a new request object");
+                       php_cli_server_logf(PHP_CLI_SERVER_LOG_ERROR, "Failed to create a new request object");
                        pefree(sa, 1);
                        closesocket(client_sock);
                        return SUCCESS;
                }
-#if PHP_DEBUG
-               php_cli_server_logf("%s Accepted", client->addr_str);
-#endif
+
+               php_cli_server_logf(PHP_CLI_SERVER_LOG_MESSAGE, "%s Accepted", client->addr_str);
+
                zend_hash_index_update_ptr(&server->clients, client_sock, client);
-               php_cli_server_recv_event_read_request(server, client);
+
+               php_cli_server_poller_add(&server->poller, POLLIN, client->sock);
        } else {
                php_cli_server_client *client;
                if (NULL != (client = zend_hash_index_find_ptr(&server->clients, fd))) {
@@ -2586,9 +2619,11 @@ static int php_cli_server_do_event_loop(php_cli_server *server) /* {{{ */
                } else {
                        int err = php_socket_errno();
                        if (err != SOCK_EINTR) {
-                               char *errstr = php_socket_strerror(err, NULL, 0);
-                               php_cli_server_logf("%s", errstr);
-                               efree(errstr);
+                               if (php_cli_server_log_level >= PHP_CLI_SERVER_LOG_ERROR) {
+                                       char *errstr = php_socket_strerror(err, NULL, 0);
+                                       php_cli_server_logf(PHP_CLI_SERVER_LOG_ERROR, "%s", errstr);
+                                       efree(errstr);
+                               }
                                retval = FAILURE;
                                goto out;
                        }
@@ -2645,6 +2680,11 @@ int do_cli_server(int argc, char **argv) /* {{{ */
                                document_root = document_root_tmp;
 #endif
                                break;
+                       case 'q':
+                               if (php_cli_server_log_level > 1) {
+                                       php_cli_server_log_level--;
+                               }
+                               break;
                }
        }
 
@@ -2683,25 +2723,22 @@ int do_cli_server(int argc, char **argv) /* {{{ */
        sapi_module.phpinfo_as_text = 0;
 
        {
-               char buf[52];
-
-               if (php_cli_server_get_system_time(buf) != 0) {
-                       memmove(buf, "unknown time, can't be fetched", sizeof("unknown time, can't be fetched"));
-               }
-
-#if HAVE_FORK
-        printf("[%ld] PHP %s Development Server (http://%s) started at %s",
-               (long) getpid(), PHP_VERSION, server_bind_address, buf);
-#else
-        printf("PHP %s Development Server (http://%s) started at %s",
-               PHP_VERSION, server_bind_address, buf); 
-#endif
+               php_cli_server_logf(
+                       PHP_CLI_SERVER_LOG_PROCESS,
+                       "PHP %s Development Server (http://%s) started",
+                       PHP_VERSION, server_bind_address);
        }
 
 #if defined(SIGINT)
        signal(SIGINT, php_cli_server_sigint_handler);
-       zend_signal_init();
 #endif
+
+#if defined(SIGPIPE)
+       signal(SIGPIPE, SIG_IGN);
+#endif
+
+       zend_signal_init();
+
        php_cli_server_do_event_loop(&server);
        php_cli_server_dtor(&server);
        return 0;