--- embedaddon/php/sapi/cli/php_cli_server.c 2012/05/29 12:34:35 1.1 +++ embedaddon/php/sapi/cli/php_cli_server.c 2013/07/22 01:32:13 1.1.1.2 @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2012 The PHP Group | + | Copyright (c) 1997-2013 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -17,18 +17,19 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_cli_server.c,v 1.1 2012/05/29 12:34:35 misho Exp $ */ +/* $Id: php_cli_server.c,v 1.1.1.2 2013/07/22 01:32:13 misho Exp $ */ #include #include #include #ifdef PHP_WIN32 -#include -#include -#include "win32/time.h" -#include "win32/signal.h" -#include "win32/php_registry.h" +# include +# include +# include "win32/time.h" +# include "win32/signal.h" +# include "win32/php_registry.h" +# include #else # include "php_config.h" #endif @@ -98,7 +99,6 @@ #include "ext/standard/html.h" #include "ext/standard/url.h" /* for php_url_decode() */ #include "ext/standard/php_string.h" /* for php_dirname() */ -#include "ext/standard/info.h" /* for php_info_print_style() */ #include "php_network.h" #include "php_http_parser.h" @@ -117,7 +117,7 @@ typedef struct php_cli_server_poller { } php_cli_server_poller; typedef struct php_cli_server_request { - enum php_http_method request_method; + enum php_http_method request_method; int protocol_version; char *request_uri; size_t request_uri_len; @@ -174,8 +174,6 @@ typedef struct php_cli_server_client { php_cli_server_request request; unsigned int content_sender_initialized:1; php_cli_server_content_sender content_sender; - php_cli_server_buffer capture_buffer; - unsigned int capturing:1; int file_fd; } php_cli_server_client; @@ -239,30 +237,40 @@ static php_cli_server_http_reponse_status_code_pair st { 415, "Unsupported Media Type" }, { 416, "Requested Range Not Satisfiable" }, { 417, "Expectation Failed" }, + { 428, "Precondition Required" }, + { 429, "Too Many Requests" }, + { 431, "Request Header Fields Too Large" }, { 500, "Internal Server Error" }, { 501, "Not Implemented" }, { 502, "Bad Gateway" }, { 503, "Service Unavailable" }, { 504, "Gateway Timeout" }, { 505, "HTTP Version Not Supported" }, + { 511, "Network Authentication Required" }, }; static php_cli_server_http_reponse_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.

" }, - { 500, "

%s

The server is temporality unavaiable.

" } + { 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.

" }, + { 500, "

%s

The server is temporarily unavailable.

" }, + { 501, "

%s

Request method not supported.

" } }; static php_cli_server_ext_mime_type_pair mime_type_map[] = { + { "html", "text/html" }, + { "htm", "text/html" }, + { "js", "text/javascript" }, + { "css", "text/css" }, { "gif", "image/gif" }, - { "png", "image/png" }, - { "jpe", "image/jpeg" }, { "jpg", "image/jpeg" }, { "jpeg", "image/jpeg" }, - { "css", "text/css" }, - { "html", "text/html" }, + { "jpe", "image/jpeg" }, + { "png", "image/png" }, + { "svg", "image/svg+xml" }, { "txt", "text/plain" }, - { "js", "text/javascript" }, + { "webm", "video/webm" }, + { "ogv", "video/ogg" }, + { "ogg", "audio/ogg" }, { NULL, NULL } }; @@ -276,6 +284,45 @@ static void php_cli_server_log_response(php_cli_server ZEND_DECLARE_MODULE_GLOBALS(cli_server); +/* {{{ static char php_cli_server_css[] + * copied from ext/standard/info.c + */ +static const char php_cli_server_css[] = "\n"; +/* }}} */ + +#ifdef PHP_WIN32 +int php_cli_server_get_system_time(char *buf) { + struct _timeb system_time; + errno_t err; + + if (buf == NULL) { + return -1; + } + + _ftime(&system_time); + err = ctime_s(buf, 52, &(system_time.time) ); + if (err) { + return -1; + } + return 0; +} +#else +int php_cli_server_get_system_time(char *buf) { + struct timeval tv; + struct tm tm; + + gettimeofday(&tv, NULL); + + /* TODO: should be checked for NULL tm/return vaue */ + php_localtime_r(&tv.tv_sec, &tm); + php_asctime_r(&tm, buf); + return 0; +} +#endif + static void char_ptr_dtor_p(char **p) /* {{{ */ { pefree(*p, 1); @@ -425,17 +472,7 @@ static int sapi_cli_server_ub_write(const char *str, u if (!client) { return 0; } - if (client->capturing) { - php_cli_server_chunk *chunk = php_cli_server_chunk_heap_new_self_contained(str_length); - if (!chunk) { - zend_bailout(); - } - memmove(chunk->data.heap.p, str, str_length); - php_cli_server_buffer_append(&client->capture_buffer, chunk); - return str_length; - } else { - return php_cli_server_client_send_through(client, str, str_length); - } + return php_cli_server_client_send_through(client, str, str_length); } /* }}} */ static void sapi_cli_server_flush(void *server_context) /* {{{ */ @@ -470,7 +507,7 @@ static int sapi_cli_server_send_headers(sapi_headers_s sapi_header_struct *h; zend_llist_position pos; - if (client == NULL || client->capturing || SG(request_info).no_headers) { + if (client == NULL || SG(request_info).no_headers) { return SAPI_HEADER_SENT_SUCCESSFULLY; } @@ -533,7 +570,7 @@ static void sapi_cli_server_register_variable(zval *tr } } /* }}} */ -static int sapi_cli_server_register_entry_cb(char **entry TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ { +static int sapi_cli_server_register_entry_cb(char **entry TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ { zval *track_vars_array = va_arg(args, zval *); if (hash_key->nKeyLength) { char *real_key, *key; @@ -573,7 +610,7 @@ static void sapi_cli_server_register_variables(zval *t } else { sapi_cli_server_register_variable(track_vars_array, "REMOTE_ADDR", client->addr_str TSRMLS_CC); } - } + } { char *tmp; spprintf(&tmp, 0, "PHP %s Development Server", PHP_VERSION); @@ -624,13 +661,11 @@ static void sapi_cli_server_register_variables(zval *t static void sapi_cli_server_log_message(char *msg TSRMLS_DC) /* {{{ */ { - struct timeval tv; - struct tm tm; char buf[52]; - gettimeofday(&tv, NULL); - php_localtime_r(&tv.tv_sec, &tm); - php_asctime_r(&tm, buf); - { + + 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 { size_t l = strlen(buf); if (l > 0) { buf[l - 1] = '\0'; @@ -671,7 +706,7 @@ sapi_module_struct cli_server_sapi_module = { sapi_cli_server_log_message, /* Log message */ NULL, /* Get request time */ NULL, /* Child terminate */ - + STANDARD_SAPI_MODULE_PROPERTIES }; /* }}} */ @@ -708,10 +743,9 @@ static void php_cli_server_poller_remove(php_cli_serve if (fd == poller->max_fd) { while (fd > 0) { fd--; - if (((unsigned int *)&poller->rfds)[fd / (8 * sizeof(unsigned int))] || ((unsigned int *)&poller->wfds)[fd / (8 * sizeof(unsigned int))]) { + if (PHP_SAFE_FD_ISSET(fd, &poller->rfds) || PHP_SAFE_FD_ISSET(fd, &poller->wfds)) { break; } - fd -= fd % (8 * sizeof(unsigned int)); } poller->max_fd = fd; } @@ -768,25 +802,22 @@ static int php_cli_server_poller_iter_on_active(php_cl } } } - + #else - php_socket_t fd = 0; + php_socket_t fd; const php_socket_t max_fd = poller->max_fd; - const unsigned int *pr = (unsigned int *)&poller->active.rfds, - *pw = (unsigned int *)&poller->active.wfds, - *e = pr + (max_fd + (8 * sizeof(unsigned int)) - 1) / (8 * sizeof(unsigned int)); - unsigned int mask; - while (pr < e && fd <= max_fd) { - for (mask = 1; mask; mask <<= 1, fd++) { - int events = (*pr & mask ? POLLIN: 0) | (*pw & mask ? POLLOUT: 0); - if (events) { - if (SUCCESS != callback(opaque, fd, events)) { - retval = FAILURE; - } - } + + for (fd=0 ; fd<=max_fd ; fd++) { + if (PHP_SAFE_FD_ISSET(fd, &poller->active.rfds)) { + if (SUCCESS != callback(opaque, fd, POLLIN)) { + retval = FAILURE; + } } - pr++; - pw++; + if (PHP_SAFE_FD_ISSET(fd, &poller->active.wfds)) { + if (SUCCESS != callback(opaque, fd, POLLOUT)) { + retval = FAILURE; + } + } } #endif return retval; @@ -956,7 +987,7 @@ static int php_cli_server_content_sender_send(php_cli_ } else if (nbytes_sent == chunk->data.immortal.len) { php_cli_server_chunk_dtor(chunk); pefree(chunk, 1); - sender->buffer.first = next; + sender->buffer.first = next; if (!next) { sender->buffer.last = NULL; } @@ -1277,8 +1308,8 @@ static void php_cli_server_request_translate_vpath(php struct stat 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_patch = 0, *q, *vpath; - size_t prev_patch_len; + char *p = buf, *prev_path = NULL, *q, *vpath; + size_t prev_path_len; int is_static_file = 0; if (!buf) { @@ -1327,34 +1358,34 @@ static void php_cli_server_request_translate_vpath(php file++; } if (!*file || is_static_file) { - if (prev_patch) { - pefree(prev_patch, 1); + if (prev_path) { + pefree(prev_path, 1); } pefree(buf, 1); return; } } break; /* regular file */ - } - if (prev_patch) { - pefree(prev_patch, 1); + } + if (prev_path) { + pefree(prev_path, 1); *q = DEFAULT_SLASH; } while (q > buf && *(--q) != DEFAULT_SLASH); - prev_patch_len = p - q; - prev_patch = pestrndup(q, prev_patch_len, 1); + prev_path_len = p - q; + prev_path = pestrndup(q, prev_path_len, 1); *q = '\0'; } - if (prev_patch) { - request->path_info_len = prev_patch_len; + if (prev_path) { + request->path_info_len = prev_path_len; #ifdef PHP_WIN32 - while (prev_patch_len--) { - if (prev_patch[prev_patch_len] == '\\') { - prev_patch[prev_patch_len] = '/'; + while (prev_path_len--) { + if (prev_path[prev_path_len] == '\\') { + prev_path[prev_path_len] = '/'; } } #endif - request->path_info = prev_patch; + request->path_info = prev_path; pefree(request->vpath, 1); request->vpath = pestrndup(vpath, q - vpath, 1); request->vpath_len = q - vpath; @@ -1374,7 +1405,7 @@ static void php_cli_server_request_translate_vpath(php if (request->vpath[i] == '\\') { request->vpath[i] = '/'; } - } + } } #endif request->sb = sb; @@ -1442,7 +1473,7 @@ static void normalize_vpath(char **retval, size_t *ret } } } - + *decoded_vpath_end = '\0'; *retval = decoded_vpath; *retval_len = decoded_vpath_end - decoded_vpath; @@ -1608,7 +1639,11 @@ static int php_cli_server_client_read_request(php_cli_ client->parser.data = client; nbytes_consumed = php_http_parser_execute(&client->parser, &settings, buf, nbytes_read); if (nbytes_consumed != nbytes_read) { - *errstr = estrdup("Malformed HTTP request"); + 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) { @@ -1677,18 +1712,6 @@ static void destroy_request_info(sapi_request_info *re { } /* }}} */ -static void php_cli_server_client_begin_capture(php_cli_server_client *client) /* {{{ */ -{ - php_cli_server_buffer_ctor(&client->capture_buffer); - client->capturing = 1; -} /* }}} */ - -static void php_cli_server_client_end_capture(php_cli_server_client *client) /* {{{ */ -{ - client->capturing = 0; - php_cli_server_buffer_dtor(&client->capture_buffer); -} /* }}} */ - static int php_cli_server_client_ctor(php_cli_server_client *client, php_cli_server *server, int client_sock, struct sockaddr *addr, socklen_t addr_len TSRMLS_DC) /* {{{ */ { client->server = server; @@ -1713,7 +1736,6 @@ static int php_cli_server_client_ctor(php_cli_server_c return FAILURE; } client->content_sender_initialized = 0; - client->capturing = 0; client->file_fd = -1; return SUCCESS; } /* }}} */ @@ -1730,9 +1752,6 @@ static void php_cli_server_client_dtor(php_cli_server_ if (client->content_sender_initialized) { php_cli_server_content_sender_dtor(&client->content_sender); } - if (client->capturing) { - php_cli_server_buffer_dtor(&client->capture_buffer); - } } /* }}} */ static void php_cli_server_close_connection(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */ @@ -1758,7 +1777,7 @@ static int php_cli_server_send_error_page(php_cli_serv escaped_request_uri = php_escape_html_entities_ex((unsigned char *)client->request.request_uri, client->request.request_uri_len, &escaped_request_uri_len, 0, ENT_QUOTES, NULL, 0 TSRMLS_CC); { - static const char prologue_template[] = "%d %s"; + 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; @@ -1768,43 +1787,11 @@ static int php_cli_server_send_error_page(php_cli_serv php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } { - int err = 0; - zval *style = NULL; - zend_try { - if (!SG(sapi_started)) { - php_output_activate(TSRMLS_C); - } - php_output_start_user(NULL, 0, PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC); - php_info_print_style(TSRMLS_C); - MAKE_STD_ZVAL(style); - php_output_get_contents(style TSRMLS_CC); - php_output_discard(TSRMLS_C); - if (!SG(sapi_started)) { - static int (*send_header_func)(sapi_headers_struct * TSRMLS_DC); - send_header_func = sapi_module.send_headers; - /* we don't want the header to be sent now */ - sapi_module.send_headers = sapi_cli_server_discard_headers; - php_output_deactivate(TSRMLS_C); - sapi_module.send_headers = send_header_func; - } - if (style && Z_STRVAL_P(style)) { - char *block = pestrndup(Z_STRVAL_P(style), Z_STRLEN_P(style), 1); - php_cli_server_chunk *chunk = php_cli_server_chunk_heap_new(block, block, Z_STRLEN_P(style)); - if (!chunk) { - zval_ptr_dtor(&style); - goto fail; - } - php_cli_server_buffer_append(&client->content_sender.buffer, chunk); - zval_ptr_dtor(&style); - } else { - err = 1; - } - } zend_catch { - err = 1; - } zend_end_try(); - if (err) { + 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); } { static const char template[] = ""; @@ -1846,7 +1833,7 @@ static int php_cli_server_send_error_page(php_cli_serv smart_str_append_generic_ex(&buffer, php_cli_server_buffer_size(&client->content_sender.buffer), 1, size_t, _unsigned); 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.c, buffer.c, buffer.len); if (!chunk) { smart_str_free_ex(&buffer, 1); @@ -1864,6 +1851,9 @@ static int php_cli_server_send_error_page(php_cli_serv return SUCCESS; fail: + if (errstr) { + pefree(errstr, 1); + } efree(escaped_request_uri); return FAILURE; } /* }}} */ @@ -1948,7 +1938,7 @@ static int php_cli_server_begin_send_static(php_cli_se } /* }}} */ -static int php_cli_server_request_startup(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) { /* {{{ */ +static int php_cli_server_request_startup(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) { /* {{{ */ char **auth; php_cli_server_client_populate_request_info(client, &SG(request_info)); if (SUCCESS == zend_hash_find(&client->request.headers, "Authorization", sizeof("Authorization"), (void**)&auth)) { @@ -1973,8 +1963,8 @@ static int php_cli_server_request_shutdown(php_cli_ser SG(server_context) = NULL; SG(rfc1867_uploaded_files) = NULL; return SUCCESS; -} -/* }}} */ +} +/* }}} */ static int php_cli_server_dispatch_router(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */ { @@ -2033,7 +2023,7 @@ static int php_cli_server_dispatch(php_cli_server *ser destroy_request_info(&SG(request_info)); return SUCCESS; } - } + } if (server->router) { if (!php_cli_server_dispatch_router(server, client TSRMLS_CC)) { @@ -2047,17 +2037,20 @@ static int php_cli_server_dispatch(php_cli_server *ser || SUCCESS != php_cli_server_send_error_page(server, client, 500 TSRMLS_CC)) { php_cli_server_request_shutdown(server, client TSRMLS_CC); return SUCCESS; - } + } } else { if (server->router) { static int (*send_header_func)(sapi_headers_struct * TSRMLS_DC); send_header_func = sapi_module.send_headers; - /* we don't want the header to be sent now */ + /* do not generate default content type header */ + 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(rfc1867_uploaded_files) = NULL; - } + } if (SUCCESS != php_cli_server_begin_send_static(server, client TSRMLS_CC)) { php_cli_server_close_connection(server, client TSRMLS_CC); } @@ -2219,6 +2212,8 @@ static int php_cli_server_recv_event_read_request(php_ efree(errstr); php_cli_server_close_connection(server, client TSRMLS_CC); return FAILURE; + } else if (status == 1 && client->request.request_method == PHP_HTTP_NOT_IMPLEMENTED) { + return php_cli_server_send_error_page(server, client, 501 TSRMLS_CC); } else if (status == 1) { php_cli_server_poller_remove(&server->poller, POLLIN, client->sock); php_cli_server_dispatch(server, client TSRMLS_CC); @@ -2339,7 +2334,7 @@ static void php_cli_server_do_event_for_each_fd(php_cl static int php_cli_server_do_event_loop(php_cli_server *server TSRMLS_DC) /* {{{ */ { int retval = SUCCESS; - while (server->is_running) { + while (server->is_running) { static const struct timeval tv = { 1, 0 }; int n = php_cli_server_poller_poll(&server->poller, &tv); if (n > 0) { @@ -2428,14 +2423,14 @@ int do_cli_server(int argc, char **argv TSRMLS_DC) /* sapi_module.phpinfo_as_text = 0; { - struct timeval tv; - struct tm tm; char buf[52]; - gettimeofday(&tv, NULL); - php_localtime_r(&tv.tv_sec, &tm); - php_asctime_r(&tm, buf); + + if (php_cli_server_get_system_time(buf) != 0) { + memmove(buf, "unknown time, can't be fetched", sizeof("unknown time, can't be fetched")); + } + printf("PHP %s Development Server started at %s" - "Listening on %s\n" + "Listening on http://%s\n" "Document root is %s\n" "Press Ctrl-C to quit.\n", PHP_VERSION, buf, server_bind_address, document_root);