Skip to content

Instantly share code, notes, and snippets.

@moriyoshi
Created February 20, 2011 04:35
Show Gist options
  • Save moriyoshi/835698 to your computer and use it in GitHub Desktop.
Save moriyoshi/835698 to your computer and use it in GitHub Desktop.

Revisions

  1. moriyoshi revised this gist Mar 6, 2011. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion php-embedded-server-20110220.patch.diff
    Original file line number Diff line number Diff line change
    @@ -1636,7 +1636,7 @@ Index: sapi/cli/php_cli_server.c
    ===================================================================
    --- sapi/cli/php_cli_server.c (revision 0)
    +++ sapi/cli/php_cli_server.c (revision 0)
    @@ -0,0 +1,2081 @@
    @@ -0,0 +1,2083 @@
    +/*
    + +----------------------------------------------------------------------+
    + | PHP Version 5 |
    @@ -2218,6 +2218,7 @@ Index: sapi/cli/php_cli_server.c
    + if (mode & POLLOUT) {
    + PHP_SAFE_FD_CLR(fd, &poller->wfds);
    + }
    +#ifndef PHP_WIN32
    + if (fd == poller->max_fd) {
    + while (fd > 0) {
    + fd--;
    @@ -2228,6 +2229,7 @@ Index: sapi/cli/php_cli_server.c
    + }
    + poller->max_fd = fd;
    + }
    +#endif
    +} /* }}} */
    +
    +static int php_cli_server_poller_poll(php_cli_server_poller *poller, const struct timeval *tv) /* {{{ */
  2. moriyoshi revised this gist Mar 6, 2011. 1 changed file with 19 additions and 17 deletions.
    36 changes: 19 additions & 17 deletions php-embedded-server-20110220.patch.diff
    Original file line number Diff line number Diff line change
    @@ -1636,7 +1636,7 @@ Index: sapi/cli/php_cli_server.c
    ===================================================================
    --- sapi/cli/php_cli_server.c (revision 0)
    +++ sapi/cli/php_cli_server.c (revision 0)
    @@ -0,0 +1,2079 @@
    @@ -0,0 +1,2081 @@
    +/*
    + +----------------------------------------------------------------------+
    + | PHP Version 5 |
    @@ -1734,9 +1734,9 @@ Index: sapi/cli/php_cli_server.c
    +
    +typedef struct php_cli_server_poller {
    + fd_set rfds, wfds;
    + struct {
    + fd_set rfds, wfds;
    + } active;
    + struct {
    + fd_set rfds, wfds;
    + } active;
    + php_socket_t max_fd;
    +} php_cli_server_poller;
    +
    @@ -2155,11 +2155,6 @@ Index: sapi/cli/php_cli_server.c
    + fprintf(stderr, "[%s] %s\n", buf, msg);
    +} /* }}} */
    +
    +static double sapi_cli_server_get_request_time(TSRMLS_D) /* {{{ */
    +{
    + return 0.;
    +} /* }}} */
    +
    +/* {{{ sapi_module_struct cli_server_sapi_module
    + */
    +sapi_module_struct cli_server_sapi_module = {
    @@ -2188,7 +2183,7 @@ Index: sapi/cli/php_cli_server.c
    +
    + sapi_cli_server_register_variables, /* register server variables */
    + sapi_cli_server_log_message, /* Log message */
    + sapi_cli_server_get_request_time, /* Get request time */
    + NULL, /* Get request time */
    + NULL, /* Child terminate */
    +
    + STANDARD_SAPI_MODULE_PROPERTIES
    @@ -2248,21 +2243,21 @@ Index: sapi/cli/php_cli_server.c
    +#ifdef PHP_WIN32
    + struct socket_entry {
    + SOCKET fd;
    + int events;
    + int events;
    + } entries[FD_SETSIZE * 2];
    + php_socket_t fd = 0;
    + size_t i;
    + struct socket_entry *n = entries, *m;
    + struct socket_entry *n = entries, *m;
    +
    + for (i = 0; i < poller->active.rfds.fd_count; i++) {
    + n->events = POLLIN;
    + n->fd = poller->active.rfds.fd_array[i];
    + n++;
    + n++;
    + }
    +
    + m = n;
    + m = n;
    + for (i = 0; i < poller->active.wfds.fd_count; i++) {
    + struct socket_entry *e;
    + struct socket_entry *e;
    + SOCKET fd = poller->active.wfds.fd_array[i];
    + for (e = entries; e < m; e++) {
    + if (e->fd == fd) {
    @@ -2273,7 +2268,7 @@ Index: sapi/cli/php_cli_server.c
    + assert(n < entries + FD_SETSIZE * 2);
    + n->events = POLLOUT;
    + n->fd = fd;
    + n++;
    + n++;
    + }
    + }
    +
    @@ -2291,7 +2286,7 @@ Index: sapi/cli/php_cli_server.c
    + 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));
    + *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++) {
    @@ -2580,6 +2575,13 @@ Index: sapi/cli/php_cli_server.c
    + continue;
    + }
    +
    +#ifdef SO_REUSEADDR
    + {
    + int val = 1;
    + setsockopt(retval, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val));
    + }
    +#endif
    +
    + if (bind(retval, sa, *socklen) == SOCK_CONN_ERR) {
    + err = php_socket_errno();
    + if (err == SOCK_EINVAL || err == SOCK_EADDRINUSE) {
  3. moriyoshi revised this gist Mar 3, 2011. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions php-embedded-server-20110220.patch.diff
    Original file line number Diff line number Diff line change
    @@ -3182,7 +3182,7 @@ Index: sapi/cli/php_cli_server.c
    + goto fail;
    + }
    + append_essential_headers(&buffer, client, 1);
    + smart_str_appends_ex(&buffer, "Content-Type: text/html; charset=UTF=8\r\n", 1);
    + smart_str_appends_ex(&buffer, "Content-Type: text/html; charset=UTF-8\r\n", 1);
    + smart_str_appends_ex(&buffer, "Content-Length: ", 1);
    + 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);
    @@ -3277,7 +3277,7 @@ Index: sapi/cli/php_cli_server.c
    + smart_str_appendl_ex(&buffer, "Content-Type: ", sizeof("Content-Type: ") - 1, 1);
    + smart_str_appends_ex(&buffer, mime_type, 1);
    + if (strncmp(mime_type, "text/", 5) == 0) {
    + smart_str_appends_ex(&buffer, "; charset=UTF=8", 1);
    + smart_str_appends_ex(&buffer, "; charset=UTF-8", 1);
    + }
    + smart_str_appendl_ex(&buffer, "\r\n", 2, 1);
    + smart_str_appends_ex(&buffer, "Content-Length: ", 1);
  4. moriyoshi revised this gist Mar 2, 2011. 1 changed file with 209 additions and 132 deletions.
    341 changes: 209 additions & 132 deletions php-embedded-server-20110220.patch.diff
    Original file line number Diff line number Diff line change
    @@ -2,29 +2,21 @@ Index: sapi/cli/config.w32
    ===================================================================
    --- sapi/cli/config.w32 (revision 308839)
    +++ sapi/cli/config.w32 (working copy)
    @@ -6,7 +6,7 @@
    @@ -6,7 +6,8 @@
    ARG_ENABLE('cli-win32', 'Build console-less CLI version of PHP', 'no');

    if (PHP_CLI == "yes") {
    - SAPI('cli', 'php_cli.c', 'php.exe');
    + SAPI('cli', 'php_cli.c php_http_parser.c php_cli_server.c', 'php.exe');
    + ADD_FLAG("LIBS_CLI", "ws2_32.lib");
    if (PHP_CRT_DEBUG == "yes") {
    ADD_FLAG("CFLAGS_CLI", "/D PHP_WIN32_DEBUG_HEAP");
    }
    @@ -14,7 +14,7 @@
    }

    if (PHP_CLI_WIN32 == "yes") {
    - SAPI('cli_win32', 'cli_win32.c', 'php-win.exe');
    + SAPI('cli_win32', 'cli_win32.c php_http_parser.c php_cli_server.c', 'php-win.exe');
    ADD_FLAG("LDFLAGS_CLI_WIN32", "/stack:8388608");
    }

    Index: sapi/cli/php_http_parser.c
    ===================================================================
    --- sapi/cli/php_http_parser.c (revision 0)
    +++ sapi/cli/php_http_parser.c (revision 0)
    @@ -0,0 +1,1601 @@
    @@ -0,0 +1,1602 @@
    +/* Copyright 2009,2010 Ryan Dahl <[email protected]>
    + *
    + * Permission is hereby granted, free of charge, to any person obtaining a copy
    @@ -357,13 +349,6 @@ Index: sapi/cli/php_http_parser.c
    + uint64_t index = parser->index;
    + uint64_t nread = parser->nread;
    +
    + if (len == 0) {
    + if (state == s_body_identity_eof) {
    + CALLBACK2(message_complete);
    + }
    + return 0;
    + }
    +
    + /* technically we could combine all of these (except for url_mark) into one
    + variable, saving stack space, but it seems more clear to have them
    + separated. */
    @@ -374,6 +359,13 @@ Index: sapi/cli/php_http_parser.c
    + const char *path_mark = 0;
    + const char *url_mark = 0;
    +
    + if (len == 0) {
    + if (state == s_body_identity_eof) {
    + CALLBACK2(message_complete);
    + }
    + return 0;
    + }
    +
    + if (state == s_header_field)
    + header_field_mark = data;
    + if (state == s_header_value)
    @@ -622,10 +614,11 @@ Index: sapi/cli/php_http_parser.c
    +
    + case s_req_method:
    + {
    + const char *matcher;
    + if (ch == '\0')
    + goto error;
    +
    + const char *matcher = method_strings[parser->method];
    + matcher = method_strings[parser->method];
    + if (ch == ' ' && matcher[index] == '\0') {
    + state = s_req_spaces_before_url;
    + } else if (ch == matcher[index]) {
    @@ -1643,7 +1636,7 @@ Index: sapi/cli/php_cli_server.c
    ===================================================================
    --- sapi/cli/php_cli_server.c (revision 0)
    +++ sapi/cli/php_cli_server.c (revision 0)
    @@ -0,0 +1,2003 @@
    @@ -0,0 +1,2079 @@
    +/*
    + +----------------------------------------------------------------------+
    + | PHP Version 5 |
    @@ -1666,7 +1659,6 @@ Index: sapi/cli/php_cli_server.c
    +
    +#include <stdio.h>
    +#include <fcntl.h>
    +#include <unistd.h>
    +#include <assert.h>
    +
    +#ifdef PHP_WIN32
    @@ -1742,6 +1734,9 @@ Index: sapi/cli/php_cli_server.c
    +
    +typedef struct php_cli_server_poller {
    + fd_set rfds, wfds;
    + struct {
    + fd_set rfds, wfds;
    + } active;
    + php_socket_t max_fd;
    +} php_cli_server_poller;
    +
    @@ -1820,7 +1815,7 @@ Index: sapi/cli/php_cli_server.c
    + char *router;
    + size_t router_len;
    + socklen_t socklen;
    + php_cli_server_client *clients[FD_SETSIZE];
    + HashTable clients;
    +} php_cli_server;
    +
    +typedef struct php_cli_server_http_reponse_status_code_pair {
    @@ -1877,8 +1872,8 @@ Index: sapi/cli/php_cli_server.c
    +};
    +
    +static php_cli_server_http_reponse_status_code_pair template_map[] = {
    + { 404, "<h1 class=\"h\">%2$s</h1><p>The requested resource %3$s was not found on this server.</p>" },
    + { 500, "<h1 class=\"h\">%2$s</h1><p>The server is temporality unavaiable.</p>" }
    + { 404, "<h1 class=\"h\">%s</h1><p>The requested resource %s was not found on this server.</p>" },
    + { 500, "<h1 class=\"h\">%s</h1><p>The server is temporality unavaiable.</p>" }
    +};
    +
    +static php_cli_server_ext_mime_type_pair mime_type_map[] = {
    @@ -1906,16 +1901,7 @@ Index: sapi/cli/php_cli_server.c
    +
    +static char *get_last_error() /* {{{ */
    +{
    +#ifdef PHP_WIN32
    + char *buf = pemalloc(1024, 1);
    + if (!buf) {
    + return NULL;
    + }
    + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, buf, sizeof(buf) - 1, NULL);
    + return buf;
    +#else
    + return pestrdup(strerror(errno), 1);
    +#endif
    +} /* }}} */
    +
    +static const char *get_status_string(int code) /* {{{ */
    @@ -2249,11 +2235,78 @@ Index: sapi/cli/php_cli_server.c
    + }
    +} /* }}} */
    +
    +static int php_cli_server_poller_poll(php_cli_server_poller *poller, fd_set *rfds, fd_set *wfds, const struct timeval *tv) /* {{{ */
    +static int php_cli_server_poller_poll(php_cli_server_poller *poller, const struct timeval *tv) /* {{{ */
    +{
    + memcpy(rfds, &poller->rfds, sizeof(poller->rfds));
    + memcpy(wfds, &poller->wfds, sizeof(poller->wfds));
    + return php_select(poller->max_fd + 1, rfds, wfds, NULL, (struct timeval *)tv);
    + memcpy(&poller->active.rfds, &poller->rfds, sizeof(poller->rfds));
    + memcpy(&poller->active.wfds, &poller->wfds, sizeof(poller->wfds));
    + return php_select(poller->max_fd + 1, &poller->active.rfds, &poller->active.wfds, NULL, (struct timeval *)tv);
    +} /* }}} */
    +
    +static int php_cli_server_poller_iter_on_active(php_cli_server_poller *poller, void *opaque, int(*callback)(void *, int fd, int events)) /* {{{ */
    +{
    + int retval = SUCCESS;
    +#ifdef PHP_WIN32
    + struct socket_entry {
    + SOCKET fd;
    + int events;
    + } entries[FD_SETSIZE * 2];
    + php_socket_t fd = 0;
    + size_t i;
    + struct socket_entry *n = entries, *m;
    +
    + for (i = 0; i < poller->active.rfds.fd_count; i++) {
    + n->events = POLLIN;
    + n->fd = poller->active.rfds.fd_array[i];
    + n++;
    + }
    +
    + m = n;
    + for (i = 0; i < poller->active.wfds.fd_count; i++) {
    + struct socket_entry *e;
    + SOCKET fd = poller->active.wfds.fd_array[i];
    + for (e = entries; e < m; e++) {
    + if (e->fd == fd) {
    + e->events |= POLLOUT;
    + }
    + }
    + if (e == m) {
    + assert(n < entries + FD_SETSIZE * 2);
    + n->events = POLLOUT;
    + n->fd = fd;
    + n++;
    + }
    + }
    +
    + {
    + struct socket_entry *e = entries;
    + for (; e < n; e++) {
    + if (SUCCESS != callback(opaque, e->fd, e->events)) {
    + retval = FAILURE;
    + }
    + }
    + }
    +
    +#else
    + php_socket_t fd = 0;
    + 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;
    + }
    + }
    + }
    + pr++;
    + pw++;
    + }
    +#endif
    + return retval;
    +} /* }}} */
    +
    +static size_t php_cli_server_chunk_size(const php_cli_server_chunk *chunk) /* {{{ */
    @@ -2389,8 +2442,8 @@ Index: sapi/cli/php_cli_server.c
    + size_t _nbytes_sent_total = 0;
    +
    + for (chunk = sender->buffer.first; chunk; chunk = next) {
    + next = chunk->next;
    + ssize_t nbytes_sent;
    + next = chunk->next;
    +
    + switch (chunk->type) {
    + case PHP_CLI_SERVER_CHUNK_HEAP:
    @@ -2475,7 +2528,7 @@ Index: sapi/cli/php_cli_server.c
    +
    +static int php_network_listen_socket(const char *host, int *port, int socktype, int *af, socklen_t *socklen, char **errstr TSRMLS_DC) /* {{{ */
    +{
    + int retval = -1;
    + int retval = SOCK_ERR;
    + int err = 0;
    + struct sockaddr *sa = NULL, **p, **sal;
    +
    @@ -2499,11 +2552,11 @@ Index: sapi/cli/php_cli_server.c
    + sa = pemalloc(sizeof(struct sockaddr_in6), 1);
    + if (!sa) {
    + closesocket(retval);
    + retval = -1;
    + retval = SOCK_ERR;
    + *errstr = NULL;
    + goto out;
    + }
    + ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
    + *(struct sockaddr_in6 *)sa = *(struct sockaddr_in6 *)*p;
    + ((struct sockaddr_in6 *)sa)->sin6_port = htons(*port);
    + *socklen = sizeof(struct sockaddr_in6);
    + break;
    @@ -2512,11 +2565,11 @@ Index: sapi/cli/php_cli_server.c
    + sa = pemalloc(sizeof(struct sockaddr_in), 1);
    + if (!sa) {
    + closesocket(retval);
    + retval = -1;
    + retval = SOCK_ERR;
    + *errstr = NULL;
    + goto out;
    + }
    + ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
    + *(struct sockaddr_in *)sa = *(struct sockaddr_in *)*p;
    + ((struct sockaddr_in *)sa)->sin_port = htons(*port);
    + *socklen = sizeof(struct sockaddr_in);
    + break;
    @@ -2533,6 +2586,7 @@ Index: sapi/cli/php_cli_server.c
    + goto out;
    + }
    + closesocket(retval);
    + retval = SOCK_ERR;
    + continue;
    + }
    + err = 0;
    @@ -2558,6 +2612,10 @@ Index: sapi/cli/php_cli_server.c
    + break;
    + }
    +
    + if (retval == SOCK_ERR) {
    + goto out;
    + }
    +
    + if (listen(retval, SOMAXCONN)) {
    + err = php_socket_errno();
    + goto out;
    @@ -2577,7 +2635,7 @@ Index: sapi/cli/php_cli_server.c
    + if (errstr) {
    + *errstr = php_socket_strerror(err, NULL, 0);
    + }
    + return -1;
    + return SOCK_ERR;
    + }
    + return retval;
    +} /* }}} */
    @@ -3046,11 +3104,7 @@ Index: sapi/cli/php_cli_server.c
    +#ifdef DEBUG
    + php_cli_server_logf("%s: Closing" TSRMLS_CC, client->addr_str);
    +#endif
    + closesocket(client->sock);
    + php_cli_server_poller_remove(&server->poller, POLLIN | POLLOUT, client->sock);
    + php_cli_server_client_dtor(client);
    + server->clients[client->sock] = NULL;
    + pefree(client, 1);
    + zend_hash_index_del(&server->clients, client->sock);
    +} /* }}} */
    +
    +static int php_cli_server_send_error_page(php_cli_server *server, php_cli_server_client *client, int status TSRMLS_DC) /* {{{ */
    @@ -3067,12 +3121,12 @@ Index: sapi/cli/php_cli_server.c
    + 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[] = "<html><head><title>%1$d %2$s</title>";
    + static const char prologue_template[] = "<html><head><title>%d %s</title>";
    + 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;
    + }
    + sprintf(chunk->data.heap.p, prologue_template, status, status_string, escaped_request_uri);
    + snprintf(chunk->data.heap.p, chunk->data.heap.len, prologue_template, status, status_string, escaped_request_uri);
    + chunk->data.heap.len = strlen(chunk->data.heap.p);
    + php_cli_server_buffer_append(&client->content_sender.buffer, chunk);
    + }
    @@ -3106,7 +3160,7 @@ Index: sapi/cli/php_cli_server.c
    + if (!chunk) {
    + goto fail;
    + }
    + sprintf(chunk->data.heap.p, content_template, status, status_string, escaped_request_uri);
    + snprintf(chunk->data.heap.p, chunk->data.heap.len, content_template, status_string, escaped_request_uri);
    + chunk->data.heap.len = strlen(chunk->data.heap.p);
    + php_cli_server_buffer_append(&client->content_sender.buffer, chunk);
    + }
    @@ -3326,17 +3380,7 @@ Index: sapi/cli/php_cli_server.c
    +
    +static void php_cli_server_dtor(php_cli_server *server TSRMLS_DC) /* {{{ */
    +{
    + {
    + php_cli_server_client **p = server->clients,
    + **e = server->clients + sizeof(server->clients) / sizeof(*server->clients);
    + while (p < e) {
    + if (*p) {
    + php_cli_server_close_connection(server, *p TSRMLS_CC);
    + *p = NULL;
    + }
    + p++;
    + }
    + }
    + zend_hash_destroy(&server->clients);
    + if (server->server_sock >= 0) {
    + closesocket(server->server_sock);
    + }
    @@ -3351,6 +3395,14 @@ Index: sapi/cli/php_cli_server.c
    + }
    +} /* }}} */
    +
    +static void php_cli_server_client_dtor_wrapper(php_cli_server_client **p) /* {{{ */
    +{
    + closesocket((*p)->sock);
    + php_cli_server_poller_remove(&(*p)->server->poller, POLLIN | POLLOUT, (*p)->sock);
    + php_cli_server_client_dtor(*p);
    + pefree(*p, 1);
    +} /* }}} */
    +
    +static int php_cli_server_ctor(php_cli_server *server, const char *addr, const char *document_root, const char *router TSRMLS_DC) /* {{{ */
    +{
    + int retval = SUCCESS;
    @@ -3360,7 +3412,7 @@ Index: sapi/cli/php_cli_server.c
    + char *_router = NULL;
    + int err = 0;
    + int port = 3000;
    + php_socket_t server_sock = -1;
    + php_socket_t server_sock = SOCK_ERR;
    +
    + host = pestrdup(addr, 1);
    + if (!host) {
    @@ -3376,7 +3428,7 @@ Index: sapi/cli/php_cli_server.c
    + }
    +
    + server_sock = php_network_listen_socket(host, &port, SOCK_STREAM, &server->address_family, &server->socklen, &errstr TSRMLS_CC);
    + if (server_sock < 0) {
    + if (server_sock == SOCK_ERR) {
    + php_cli_server_logf("Failed to listen on %s:%d (reason: %s)" TSRMLS_CC, host, port, errstr ? errstr: "?");
    + efree(errstr);
    + retval = FAILURE;
    @@ -3394,12 +3446,7 @@ Index: sapi/cli/php_cli_server.c
    + server->host = host;
    + server->port = port;
    +
    + {
    + size_t i = 0;
    + for (i = 0; i < sizeof(server->clients) / sizeof(*server->clients); i++) {
    + server->clients[i] = 0;
    + }
    + }
    + zend_hash_init(&server->clients, 0, NULL, (void(*)(void*))php_cli_server_client_dtor_wrapper, 1);
    +
    + {
    + size_t document_root_len = strlen(document_root);
    @@ -3495,71 +3542,93 @@ Index: sapi/cli/php_cli_server.c
    +}
    +/* }}} */
    +
    +static void php_cli_server_do_event_for_each_fd(php_cli_server *server, const fd_set *fds, int(*handler)(php_cli_server*, php_cli_server_client* TSRMLS_DC) TSRMLS_DC) /* {{{ */
    +typedef struct php_cli_server_do_event_for_each_fd_callback_params {
    +#ifdef ZTS
    + void ***tsrm_ls;
    +#endif
    + php_cli_server *server;
    + int(*rhandler)(php_cli_server*, php_cli_server_client* TSRMLS_DC);
    + int(*whandler)(php_cli_server*, php_cli_server_client* TSRMLS_DC);
    +} php_cli_server_do_event_for_each_fd_callback_params;
    +
    +static int php_cli_server_do_event_for_each_fd_callback(void *_params, int fd, int event)
    +{
    + php_socket_t fd = 0;
    + php_socket_t max_fd = server->poller.max_fd;
    + const unsigned int *p = (unsigned int *)fds, *e = p + (max_fd + (8 * sizeof(unsigned int)) - 1) / (8 * sizeof(unsigned int));
    + unsigned int mask;
    + while (p < e && fd <= max_fd) {
    + for (mask = 1; mask; mask <<= 1, fd++) {
    + if (*p & mask) {
    + if (fd == server->server_sock) {
    + continue;
    + }
    + if (server->clients[fd]) {
    + handler(server, server->clients[fd] TSRMLS_CC);
    + }
    + php_cli_server_do_event_for_each_fd_callback_params *params = _params;
    +#ifdef ZTS
    + void ***tsrm_ls = params->tsrm_ls;
    +#endif
    + php_cli_server *server = params->server;
    + if (server->server_sock == fd) {
    + php_cli_server_client *client = NULL;
    + php_socket_t client_sock;
    + socklen_t socklen = server->socklen;
    + struct sockaddr *sa = pemalloc(server->socklen, 1);
    + if (!sa) {
    + return FAILURE;
    + }
    + client_sock = accept(server->server_sock, sa, &socklen);
    + if (client_sock < 0) {
    + char *errstr;
    + errstr = php_socket_strerror(php_socket_errno(), NULL, 0);
    + php_cli_server_logf("Failed to accept a client (reason: %s)" TSRMLS_CC, errstr);
    + efree(errstr);
    + pefree(sa, 1);
    + return SUCCESS;
    + }
    + if (SUCCESS != php_set_sock_blocking(client_sock, 0 TSRMLS_CC)) {
    + pefree(sa, 1);
    + closesocket(client_sock);
    + return SUCCESS;
    + }
    + if (!(client = pemalloc(sizeof(php_cli_server_client), 1)) || FAILURE == php_cli_server_client_ctor(client, server, client_sock, sa, socklen TSRMLS_CC)) {
    + php_cli_server_logf("Failed to create a new request object" TSRMLS_CC);
    + pefree(sa, 1);
    + closesocket(client_sock);
    + return SUCCESS;
    + }
    +#ifdef DEBUG
    + php_cli_server_logf("%s: Accepted" TSRMLS_CC, client->addr_str);
    +#endif
    + zend_hash_index_update(&server->clients, client_sock, &client, sizeof(client), NULL);
    + php_cli_server_recv_event_read_request(server, client TSRMLS_CC);
    + } else {
    + php_cli_server_client **client;
    + if (SUCCESS == zend_hash_index_find(&server->clients, fd, (void **)&client)) {
    + if (event & POLLIN) {
    + params->rhandler(server, *client TSRMLS_CC);
    + }
    + if (event & POLLOUT) {
    + params->whandler(server, *client TSRMLS_CC);
    + }
    + }
    + p++;
    + }
    + return SUCCESS;
    +}
    +
    +static void php_cli_server_do_event_for_each_fd(php_cli_server *server, int(*rhandler)(php_cli_server*, php_cli_server_client* TSRMLS_DC), int(*whandler)(php_cli_server*, php_cli_server_client* TSRMLS_DC) TSRMLS_DC) /* {{{ */
    +{
    + php_cli_server_do_event_for_each_fd_callback_params params = {
    +#ifdef ZTS
    + tsrm_ls,
    +#endif
    + server,
    + rhandler,
    + whandler
    + };
    +
    + php_cli_server_poller_iter_on_active(&server->poller, &params, php_cli_server_do_event_for_each_fd_callback);
    +} /* }}} */
    +
    +static int php_cli_server_do_event_loop(php_cli_server *server TSRMLS_DC) /* {{{ */
    +{
    + int retval = SUCCESS;
    + while (server->is_running) {
    + static const struct timeval tv = { 1, 0 };
    + fd_set rfds, wfds;
    + int n = php_cli_server_poller_poll(&server->poller, &rfds, &wfds, &tv);
    + int n = php_cli_server_poller_poll(&server->poller, &tv);
    + if (n > 0) {
    + if (FD_ISSET(server->server_sock, &rfds)) {
    + php_cli_server_client *client = NULL;
    + php_socket_t client_sock;
    + socklen_t socklen = server->socklen;
    + struct sockaddr *sa = pemalloc(server->socklen, 1);
    + if (!sa) {
    + return FAILURE;
    + }
    + client_sock = accept(server->server_sock, sa, &socklen);
    + if (client_sock < 0) {
    + char *errstr;
    + errstr = php_socket_strerror(php_socket_errno(), NULL, 0);
    + php_cli_server_logf("Failed to accept a client (reason: %s)" TSRMLS_CC, errstr);
    + efree(errstr);
    + pefree(sa, 1);
    + continue;
    + }
    + if (SUCCESS != php_set_sock_blocking(client_sock, 0 TSRMLS_CC)) {
    + pefree(sa, 1);
    + closesocket(client_sock);
    + continue;
    + }
    + if (!(client = pemalloc(sizeof(php_cli_server_client), 1)) || FAILURE == php_cli_server_client_ctor(client, server, client_sock, sa, socklen TSRMLS_CC)) {
    + php_cli_server_logf("Failed to create a new request object" TSRMLS_CC);
    + pefree(sa, 1);
    + closesocket(client_sock);
    + continue;
    + }
    +#ifdef DEBUG
    + php_cli_server_logf("%s: Accepted" TSRMLS_CC, client->addr_str);
    +#endif
    + server->clients[client_sock] = client;
    + php_cli_server_recv_event_read_request(server, client TSRMLS_CC);
    + }
    + php_cli_server_do_event_for_each_fd(server, &rfds, php_cli_server_recv_event_read_request TSRMLS_CC);
    + php_cli_server_do_event_for_each_fd(server, &wfds, php_cli_server_send_event TSRMLS_CC);
    + php_cli_server_do_event_for_each_fd(server,
    + php_cli_server_recv_event_read_request,
    + php_cli_server_send_event TSRMLS_CC);
    + } else if (n == 0) {
    + /* do nothing */
    + } else {
    @@ -3881,16 +3950,18 @@ Index: sapi/cli/php_cli.c
    ===================================================================
    --- sapi/cli/php_cli.c (revision 308839)
    +++ sapi/cli/php_cli.c (working copy)
    @@ -84,6 +84,8 @@
    @@ -84,6 +84,10 @@

    #include "php_getopt.h"

    +#ifndef PHP_CLI_WIN32_NO_CONSOLE
    +#include "php_cli_server.h"
    +#endif
    +
    #ifndef PHP_WIN32
    # define php_select(m, r, w, e, t) select(m, r, w, e, t)
    #else
    @@ -126,10 +128,8 @@
    @@ -126,10 +130,8 @@
    "max_execution_time=0\n"
    "max_input_time=-1\n\0";

    @@ -3902,15 +3973,15 @@ Index: sapi/cli/php_cli.c
    {'a', 0, "interactive"},
    {'B', 1, "process-begin"},
    {'C', 0, "no-chdir"}, /* for compatibility with CGI (do not chdir to script directory) */
    @@ -150,6 +150,7 @@
    @@ -150,6 +152,7 @@
    {'r', 1, "run"},
    {'s', 0, "syntax-highlight"},
    {'s', 0, "syntax-highlighting"},
    + {'S', 1, "server"},
    {'w', 0, "strip"},
    {'?', 0, "usage"},/* help alias (both '?' and 'usage') */
    {'v', 0, "version"},
    @@ -172,7 +173,7 @@
    @@ -172,7 +175,7 @@

    static int print_module_info(zend_module_entry *module TSRMLS_DC) /* {{{ */
    {
    @@ -3919,7 +3990,7 @@ Index: sapi/cli/php_cli.c
    return ZEND_HASH_APPLY_KEEP;
    }
    /* }}} */
    @@ -202,7 +203,7 @@
    @@ -202,7 +205,7 @@

    static int print_extension_info(zend_extension *ext, void *arg TSRMLS_DC) /* {{{ */
    {
    @@ -3928,7 +3999,7 @@ Index: sapi/cli/php_cli.c
    return ZEND_HASH_APPLY_KEEP;
    }
    /* }}} */
    @@ -494,7 +495,7 @@
    @@ -494,7 +497,7 @@
    prog = "php";
    }

    @@ -3937,7 +4008,7 @@ Index: sapi/cli/php_cli.c
    " %s [options] -r <code> [--] [args...]\n"
    " %s [options] [-B <begin_code>] -R <code> [-E <end_code>] [--] [args...]\n"
    " %s [options] [-B <begin_code>] -F <file> [-E <end_code>] [--] [args...]\n"
    @@ -650,689 +651,702 @@
    @@ -650,689 +653,708 @@
    }
    /* }}} */

    @@ -5134,9 +5205,11 @@ Index: sapi/cli/php_cli.c
    - }
    + break;
    + }
    +#ifndef PHP_CLI_WIN32_NO_CONSOLE
    + case 'S':
    + sapi_module = &cli_server_sapi_module;
    + break;
    +#endif
    + case 'h': /* help & quit */
    + case '?':
    + php_cli_usage(argv[0]);
    @@ -5175,14 +5248,18 @@ Index: sapi/cli/php_cli.c
    + module_started = 1;
    +
    + zend_first_try {
    +#ifndef PHP_CLI_WIN32_NO_CONSOLE
    + if (sapi_module == &cli_sapi_module) {
    +#endif
    + ini_entries_len += sizeof(HARDCODED_INI) - 2;
    + ini_entries = realloc(ini_entries, ini_entries_len + sizeof(HARDCODED_INI));
    + memcpy(ini_entries, HARDCODED_INI, sizeof(HARDCODED_INI));
    + exit_status = do_cli(argc, argv TSRMLS_CC);
    +#ifndef PHP_CLI_WIN32_NO_CONSOLE
    + } else {
    + exit_status = do_cli_server(argc, argv TSRMLS_CC);
    + }
    +#endif
    } zend_end_try();
    -
    out:
    @@ -5207,7 +5284,7 @@ Index: sapi/cli/php_cli.c
    if (module_started) {
    php_module_shutdown(TSRMLS_C);
    }
    @@ -1342,12 +1356,6 @@
    @@ -1342,12 +1364,6 @@
    #endif

    exit(exit_status);
  5. moriyoshi revised this gist Mar 2, 2011. 1 changed file with 41 additions and 231 deletions.
    272 changes: 41 additions & 231 deletions php-embedded-server-20110220.patch.diff
    Original file line number Diff line number Diff line change
    @@ -1,22 +1,22 @@
    Index: sapi/cli/config.w32
    ===================================================================
    --- sapi/cli/config.w32 (revision 307676)
    --- sapi/cli/config.w32 (revision 308839)
    +++ sapi/cli/config.w32 (working copy)
    @@ -6,7 +6,7 @@
    ARG_ENABLE('cli-win32', 'Build console-less CLI version of PHP', 'no');

    if (PHP_CLI == "yes") {
    - SAPI('cli', 'php_cli.c php_cli_readline.c', 'php.exe');
    + SAPI('cli', 'php_cli.c php_cli_readline.c php_http_parser.c php_cli_server.c', 'php.exe');
    - SAPI('cli', 'php_cli.c', 'php.exe');
    + SAPI('cli', 'php_cli.c php_http_parser.c php_cli_server.c', 'php.exe');
    if (PHP_CRT_DEBUG == "yes") {
    ADD_FLAG("CFLAGS_CLI", "/D PHP_WIN32_DEBUG_HEAP");
    }
    @@ -14,7 +14,7 @@
    }

    if (PHP_CLI_WIN32 == "yes") {
    - SAPI('cli_win32', 'cli_win32.c php_cli_readline.c', 'php-win.exe');
    + SAPI('cli_win32', 'cli_win32.c php_http_parser.c php_cli_readline.c', 'php-win.exe');
    - SAPI('cli_win32', 'cli_win32.c', 'php-win.exe');
    + SAPI('cli_win32', 'cli_win32.c php_http_parser.c php_cli_server.c', 'php-win.exe');
    ADD_FLAG("LDFLAGS_CLI_WIN32", "/stack:8388608");
    }

    @@ -1628,14 +1628,14 @@ Index: sapi/cli/php_http_parser.c
    +}
    Index: sapi/cli/config.m4
    ===================================================================
    --- sapi/cli/config.m4 (revision 307676)
    --- sapi/cli/config.m4 (revision 308839)
    +++ sapi/cli/config.m4 (working copy)
    @@ -14,7 +14,7 @@
    SAPI_CLI_PATH=sapi/cli/php

    dnl Select SAPI
    - PHP_SELECT_SAPI(cli, program, php_cli.c php_cli_readline.c,, '$(SAPI_CLI_PATH)')
    + PHP_SELECT_SAPI(cli, program, php_cli.c php_cli_readline.c php_http_parser.c php_cli_server.c,, '$(SAPI_CLI_PATH)')
    - PHP_SELECT_SAPI(cli, program, php_cli.c,, '$(SAPI_CLI_PATH)')
    + PHP_SELECT_SAPI(cli, program, php_cli.c php_http_parser.c php_cli_server.c,, '$(SAPI_CLI_PATH)')

    case $host_alias in
    *aix*)
    @@ -3879,9 +3879,9 @@ Index: sapi/cli/php_cli_server.h
    + */
    Index: sapi/cli/php_cli.c
    ===================================================================
    --- sapi/cli/php_cli.c (revision 307676)
    --- sapi/cli/php_cli.c (revision 308839)
    +++ sapi/cli/php_cli.c (working copy)
    @@ -93,6 +93,8 @@
    @@ -84,6 +84,8 @@

    #include "php_getopt.h"

    @@ -3890,31 +3890,27 @@ Index: sapi/cli/php_cli.c
    #ifndef PHP_WIN32
    # define php_select(m, r, w, e, t) select(m, r, w, e, t)
    #else
    @@ -129,14 +131,12 @@
    @@ -126,10 +128,8 @@
    "max_execution_time=0\n"
    "max_input_time=-1\n\0";

    -static char *php_optarg = NULL;
    -static int php_optind = 1;
    #if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE)
    static char php_last_char = '\0';
    static FILE *pager_pipe = NULL;
    #endif

    -static const opt_struct OPTIONS[] = {
    +const opt_struct OPTIONS[] = {
    {'a', 0, "interactive"},
    {'B', 1, "process-begin"},
    {'C', 0, "no-chdir"}, /* for compatibility with CGI (do not chdir to script directory) */
    @@ -157,6 +157,7 @@
    @@ -150,6 +150,7 @@
    {'r', 1, "run"},
    {'s', 0, "syntax-highlight"},
    {'s', 0, "syntax-highlighting"},
    + {'S', 1, "server"},
    {'w', 0, "strip"},
    {'?', 0, "usage"},/* help alias (both '?' and 'usage') */
    {'v', 0, "version"},
    @@ -179,7 +180,7 @@
    @@ -172,7 +173,7 @@

    static int print_module_info(zend_module_entry *module TSRMLS_DC) /* {{{ */
    {
    @@ -3923,7 +3919,7 @@ Index: sapi/cli/php_cli.c
    return ZEND_HASH_APPLY_KEEP;
    }
    /* }}} */
    @@ -209,7 +210,7 @@
    @@ -202,7 +203,7 @@

    static int print_extension_info(zend_extension *ext, void *arg TSRMLS_DC) /* {{{ */
    {
    @@ -3932,7 +3928,7 @@ Index: sapi/cli/php_cli.c
    return ZEND_HASH_APPLY_KEEP;
    }
    /* }}} */
    @@ -506,7 +507,7 @@
    @@ -494,7 +495,7 @@
    prog = "php";
    }

    @@ -3941,7 +3937,7 @@ Index: sapi/cli/php_cli.c
    " %s [options] -r <code> [--] [args...]\n"
    " %s [options] [-B <begin_code>] -R <code> [-E <end_code>] [--] [args...]\n"
    " %s [options] [-B <begin_code>] -F <file> [-E <end_code>] [--] [args...]\n"
    @@ -662,793 +663,807 @@
    @@ -650,689 +651,702 @@
    }
    /* }}} */

    @@ -4670,214 +4666,18 @@ Index: sapi/cli/php_cli.c
    + cli_register_file_handles(TSRMLS_C);
    + }

    #if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE)
    - if (interactive) {
    - char *line;
    - size_t size = 4096, pos = 0, len;
    - char *code = emalloc(size);
    - char *prompt = cli_get_prompt("php", '>' TSRMLS_CC);
    - char *history_file;
    + if (interactive) {
    + char *line;
    + size_t size = 4096, pos = 0, len;
    + char *code = emalloc(size);
    + char *prompt = cli_get_prompt("php", '>' TSRMLS_CC);
    + char *history_file;

    - if (PG(auto_prepend_file) && PG(auto_prepend_file)[0]) {
    - zend_file_handle *prepend_file_p;
    - zend_file_handle prepend_file = {0};
    + if (PG(auto_prepend_file) && PG(auto_prepend_file)[0]) {
    + zend_file_handle *prepend_file_p;
    + zend_file_handle prepend_file = {0};

    - prepend_file.filename = PG(auto_prepend_file);
    - prepend_file.opened_path = NULL;
    - prepend_file.free_filename = 0;
    - prepend_file.type = ZEND_HANDLE_FILENAME;
    - prepend_file_p = &prepend_file;
    + prepend_file.filename = PG(auto_prepend_file);
    + prepend_file.opened_path = NULL;
    + prepend_file.free_filename = 0;
    + prepend_file.type = ZEND_HANDLE_FILENAME;
    + prepend_file_p = &prepend_file;

    - zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 1, prepend_file_p);
    - }
    + zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 1, prepend_file_p);
    + }

    - history_file = tilde_expand("~/.php_history");
    - rl_attempted_completion_function = cli_code_completion;
    - rl_special_prefixes = "$";
    - read_history(history_file);
    + history_file = tilde_expand("~/.php_history");
    + rl_attempted_completion_function = cli_code_completion;
    + rl_special_prefixes = "$";
    + read_history(history_file);

    - EG(exit_status) = 0;
    - while ((line = readline(prompt)) != NULL) {
    - if (strcmp(line, "exit") == 0 || strcmp(line, "quit") == 0) {
    - free(line);
    - break;
    - }
    + EG(exit_status) = 0;
    + while ((line = readline(prompt)) != NULL) {
    + if (strcmp(line, "exit") == 0 || strcmp(line, "quit") == 0) {
    + free(line);
    + break;
    + }

    - if (!pos && !*line) {
    - free(line);
    - continue;
    - }
    + if (!pos && !*line) {
    + free(line);
    + continue;
    + }

    - len = strlen(line);
    + len = strlen(line);

    - if (line[0] == '#') {
    - char *param = strstr(&line[1], "=");
    - if (param) {
    - char *cmd;
    - uint cmd_len;
    - param++;
    - cmd_len = param - &line[1] - 1;
    - cmd = estrndup(&line[1], cmd_len);
    + if (line[0] == '#') {
    + char *param = strstr(&line[1], "=");
    + if (param) {
    + char *cmd;
    + uint cmd_len;
    + param++;
    + cmd_len = param - &line[1] - 1;
    + cmd = estrndup(&line[1], cmd_len);

    - zend_alter_ini_entry_ex(cmd, cmd_len + 1, param, strlen(param), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC);
    - efree(cmd);
    - add_history(line);
    + zend_alter_ini_entry_ex(cmd, cmd_len + 1, param, strlen(param), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC);
    + efree(cmd);
    + add_history(line);

    - efree(prompt);
    - /* TODO: This might be wrong! */
    - prompt = cli_get_prompt("php", '>' TSRMLS_CC);
    - continue;
    - }
    + efree(prompt);
    + /* TODO: This might be wrong! */
    + prompt = cli_get_prompt("php", '>' TSRMLS_CC);
    + continue;
    }
    + }

    - if (pos + len + 2 > size) {
    - size = pos + len + 2;
    - code = erealloc(code, size);
    - }
    - memcpy(&code[pos], line, len);
    - pos += len;
    - code[pos] = '\n';
    - code[++pos] = '\0';
    + if (pos + len + 2 > size) {
    + size = pos + len + 2;
    + code = erealloc(code, size);
    + }
    + memcpy(&code[pos], line, len);
    + pos += len;
    + code[pos] = '\n';
    + code[++pos] = '\0';

    - if (*line) {
    - add_history(line);
    - }
    + if (*line) {
    + add_history(line);
    + }

    - free(line);
    - efree(prompt);
    + free(line);
    + efree(prompt);

    - if (!cli_is_valid_code(code, pos, &prompt TSRMLS_CC)) {
    - continue;
    - }
    + if (!cli_is_valid_code(code, pos, &prompt TSRMLS_CC)) {
    + continue;
    + }

    - zend_try {
    - zend_eval_stringl(code, pos, NULL, "php shell code" TSRMLS_CC);
    - } zend_end_try();
    + zend_try {
    + zend_eval_stringl(code, pos, NULL, "php shell code" TSRMLS_CC);
    + } zend_end_try();

    - pos = 0;
    -
    - if (!pager_pipe && php_last_char != '\0' && php_last_char != '\n') {
    - sapi_cli_single_write("\n", 1 TSRMLS_CC);
    - }
    + pos = 0;
    +
    + if (!pager_pipe && php_last_char != '\0' && php_last_char != '\n') {
    + sapi_cli_single_write("\n", 1 TSRMLS_CC);
    + }

    - if (EG(exception)) {
    - zend_exception_error(EG(exception), E_WARNING TSRMLS_CC);
    - }
    + if (EG(exception)) {
    + zend_exception_error(EG(exception), E_WARNING TSRMLS_CC);
    + }

    - if (pager_pipe) {
    - fclose(pager_pipe);
    - pager_pipe = NULL;
    - }
    + if (pager_pipe) {
    + fclose(pager_pipe);
    + pager_pipe = NULL;
    + }

    - php_last_char = '\0';
    - }
    - write_history(history_file);
    - free(history_file);
    - efree(code);
    - efree(prompt);
    - exit_status = EG(exit_status);
    - break;
    + php_last_char = '\0';
    }
    -#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */
    - php_execute_script(&file_handle TSRMLS_CC);
    + write_history(history_file);
    + free(history_file);
    + efree(code);
    + efree(prompt);
    exit_status = EG(exit_status);
    break;
    - case PHP_MODE_LINT:
    - exit_status = php_lint_script(&file_handle TSRMLS_CC);
    - if (exit_status==SUCCESS) {
    - zend_printf("No syntax errors detected in %s\n", file_handle.filename);
    - if (interactive && cli_shell_callbacks.cli_shell_run) {
    - exit_status = cli_shell_callbacks.cli_shell_run(TSRMLS_C);
    - } else {
    - zend_printf("Errors parsing %s\n", file_handle.filename);
    - php_execute_script(&file_handle TSRMLS_CC);
    - exit_status = EG(exit_status);
    - }
    - break;
    - case PHP_MODE_STRIP:
    + if (interactive && cli_shell_callbacks.cli_shell_run) {
    + exit_status = cli_shell_callbacks.cli_shell_run(TSRMLS_C);
    + } else {
    + php_execute_script(&file_handle TSRMLS_CC);
    + exit_status = EG(exit_status);
    + }
    +#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */
    + php_execute_script(&file_handle TSRMLS_CC);
    + exit_status = EG(exit_status);
    + break;
    + case PHP_MODE_LINT:
    + exit_status = php_lint_script(&file_handle TSRMLS_CC);
    @@ -4896,7 +4696,17 @@ Index: sapi/cli/php_cli.c
    + case PHP_MODE_HIGHLIGHT:
    + {
    + zend_syntax_highlighter_ini syntax_highlighter_ini;
    +

    - break;
    - case PHP_MODE_LINT:
    - exit_status = php_lint_script(&file_handle TSRMLS_CC);
    - if (exit_status==SUCCESS) {
    - zend_printf("No syntax errors detected in %s\n", file_handle.filename);
    - } else {
    - zend_printf("Errors parsing %s\n", file_handle.filename);
    - }
    - break;
    - case PHP_MODE_STRIP:
    if (open_file_for_scanning(&file_handle TSRMLS_CC)==SUCCESS) {
    - zend_strip(TSRMLS_C);
    + php_get_highlight_struct(&syntax_highlighter_ini);
    @@ -5397,7 +5207,7 @@ Index: sapi/cli/php_cli.c
    if (module_started) {
    php_module_shutdown(TSRMLS_C);
    }
    @@ -1458,12 +1473,6 @@
    @@ -1342,12 +1356,6 @@
    #endif

    exit(exit_status);
    @@ -5412,7 +5222,7 @@ Index: sapi/cli/php_cli.c

    Index: main/network.c
    ===================================================================
    --- main/network.c (revision 307676)
    --- main/network.c (revision 308839)
    +++ main/network.c (working copy)
    @@ -148,7 +148,7 @@

    @@ -5434,19 +5244,19 @@ Index: main/network.c
    int n;
    Index: main/php_main.h
    ===================================================================
    --- main/php_main.h (revision 307676)
    --- main/php_main.h (revision 308839)
    +++ main/php_main.h (working copy)
    @@ -35,6 +35,7 @@
    PHPAPI void php_module_shutdown_for_exec(void);
    PHPAPI int php_module_shutdown_wrapper(sapi_module_struct *sapi_globals);
    PHPAPI int php_request_startup_for_hook(TSRMLS_D);
    +PHPAPI int php_request_shutdown_for_hook(TSRMLS_D);
    +PHPAPI void php_request_shutdown_for_hook(void *dummy);

    PHPAPI int php_register_extensions(zend_module_entry **ptr, int count TSRMLS_DC);

    Index: main/php_network.h
    ===================================================================
    --- main/php_network.h (revision 307676)
    --- main/php_network.h (revision 308839)
    +++ main/php_network.h (working copy)
    @@ -194,10 +194,12 @@
    /* it is safe to FD_SET too many fd's under win32; the macro will simply ignore
  6. moriyoshi revised this gist Mar 1, 2011. 1 changed file with 13 additions and 1 deletion.
    14 changes: 13 additions & 1 deletion php-embedded-server-20110220.patch.diff
    Original file line number Diff line number Diff line change
    @@ -1643,7 +1643,7 @@ Index: sapi/cli/php_cli_server.c
    ===================================================================
    --- sapi/cli/php_cli_server.c (revision 0)
    +++ sapi/cli/php_cli_server.c (revision 0)
    @@ -0,0 +1,1991 @@
    @@ -0,0 +1,2003 @@
    +/*
    + +----------------------------------------------------------------------+
    + | PHP Version 5 |
    @@ -2124,6 +2124,18 @@ Index: sapi/cli/php_cli_server.c
    + sapi_cli_server_register_variable(track_vars_array, "HTTP_HOST", buf.c TSRMLS_CC);
    + smart_str_free(&buf);
    + }
    + {
    + char **val;
    + if (SUCCESS == zend_hash_find(&client->request.headers, "Cookie", sizeof("Cookie"), (void**)&val)) {
    + sapi_cli_server_register_variable(track_vars_array, "HTTP_COOKIE", *val TSRMLS_CC);
    + }
    + }
    + {
    + char **val;
    + if (SUCCESS == zend_hash_find(&client->request.headers, "Referer", sizeof("Referer"), (void**)&val)) {
    + sapi_cli_server_register_variable(track_vars_array, "HTTP_REFERER", *val TSRMLS_CC);
    + }
    + }
    + sapi_cli_server_register_variable(track_vars_array, "REQUEST_URI", client->request.request_uri TSRMLS_CC);
    + sapi_cli_server_register_variable(track_vars_array, "REQUEST_METHOD", SG(request_info).request_method TSRMLS_CC);
    + sapi_cli_server_register_variable(track_vars_array, "PHP_SELF", client->request.vpath TSRMLS_CC);
  7. moriyoshi revised this gist Mar 1, 2011. 1 changed file with 38 additions and 17 deletions.
    55 changes: 38 additions & 17 deletions php-embedded-server-20110220.patch.diff
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,4 @@
    Index: sapi/cli/config.w32
    ===================================================================
    --- sapi/cli/config.w32 (revision 307676)
    +++ sapi/cli/config.w32 (working copy)
    @@ -1642,7 +1643,7 @@ Index: sapi/cli/php_cli_server.c
    ===================================================================
    --- sapi/cli/php_cli_server.c (revision 0)
    +++ sapi/cli/php_cli_server.c (revision 0)
    @@ -0,0 +1,1983 @@
    @@ -0,0 +1,1991 @@
    +/*
    + +----------------------------------------------------------------------+
    + | PHP Version 5 |
    @@ -1749,8 +1750,6 @@ Index: sapi/cli/php_cli_server.c
    + int protocol_version;
    + char *request_uri;
    + size_t request_uri_len;
    + const char *document_root;
    + size_t document_root_len;
    + char *vpath;
    + size_t vpath_len;
    + char *path_translated;
    @@ -1789,6 +1788,7 @@ Index: sapi/cli/php_cli_server.c
    +} php_cli_server_content_sender;
    +
    +typedef struct php_cli_server_client {
    + struct php_cli_server *server;
    + php_socket_t sock;
    + struct sockaddr *addr;
    + socklen_t addr_len;
    @@ -2114,8 +2114,18 @@ Index: sapi/cli/php_cli_server.c
    +static void sapi_cli_server_register_variables(zval *track_vars_array TSRMLS_DC) /* {{{ */
    +{
    + php_cli_server_client *client = SG(server_context);
    + sapi_cli_server_register_variable(track_vars_array, "DOCUMENT_ROOT", client->request.document_root TSRMLS_CC);
    + sapi_cli_server_register_variable(track_vars_array, "DOCUMENT_ROOT", client->server->document_root TSRMLS_CC);
    + {
    + smart_str buf = { 0 };
    + smart_str_appends(&buf, client->server->host);
    + smart_str_appendc(&buf, ':');
    + smart_str_append_generic_ex(&buf, client->server->port, 0, int, _unsigned);
    + smart_str_0(&buf);
    + sapi_cli_server_register_variable(track_vars_array, "HTTP_HOST", buf.c TSRMLS_CC);
    + smart_str_free(&buf);
    + }
    + sapi_cli_server_register_variable(track_vars_array, "REQUEST_URI", client->request.request_uri TSRMLS_CC);
    + sapi_cli_server_register_variable(track_vars_array, "REQUEST_METHOD", SG(request_info).request_method TSRMLS_CC);
    + sapi_cli_server_register_variable(track_vars_array, "PHP_SELF", client->request.vpath TSRMLS_CC);
    + if (SG(request_info).path_translated) {
    + sapi_cli_server_register_variable(track_vars_array, "SCRIPT_FILENAME", SG(request_info).path_translated TSRMLS_CC);
    @@ -2171,7 +2181,7 @@ Index: sapi/cli/php_cli_server.c
    +
    + php_error, /* error handler */
    +
    + NULL, /* header handler */
    + NULL, /* header handler */
    + sapi_cli_server_send_headers, /* send headers handler */
    + NULL, /* send header handler */
    +
    @@ -2560,13 +2570,11 @@ Index: sapi/cli/php_cli_server.c
    + return retval;
    +} /* }}} */
    +
    +static int php_cli_server_request_ctor(php_cli_server_request *req, const char *document_root, size_t document_root_len) /* {{{ */
    +static int php_cli_server_request_ctor(php_cli_server_request *req) /* {{{ */
    +{
    + req->protocol_version = 0;
    + req->request_uri = NULL;
    + req->request_uri_len = 0;
    + req->document_root = document_root;
    + req->document_root_len = document_root_len;
    + req->vpath = NULL;
    + req->vpath_len = 0;
    + req->path_translated = NULL;
    @@ -2606,14 +2614,14 @@ Index: sapi/cli/php_cli_server.c
    + }
    +} /* }}} */
    +
    +static void php_cli_server_request_translate_vpath(php_cli_server_request *request) /* {{{ */
    +static void php_cli_server_request_translate_vpath(php_cli_server_request *request, const char *document_root, size_t document_root_len) /* {{{ */
    +{
    + struct stat sb;
    + static const char *index_files[] = { "index.html", "index.php", NULL };
    + char *buf = safe_pemalloc(1, request->vpath_len, 1 + request->document_root_len + 1 + sizeof("index.html"), 1);
    + 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;
    + memmove(p, request->document_root, request->document_root_len);
    + p += request->document_root_len;
    + memmove(p, document_root, document_root_len);
    + p += document_root_len;
    + vpath = p;
    + if (request->vpath_len > 0 && request->vpath[0] != '/') {
    + *p++ = '/';
    @@ -2843,7 +2851,7 @@ Index: sapi/cli/php_cli_server.c
    +{
    + php_cli_server_client *client = parser->data;
    + client->request.protocol_version = parser->http_major * 100 + parser->http_minor;
    + php_cli_server_request_translate_vpath(&client->request);
    + php_cli_server_request_translate_vpath(&client->request, client->server->document_root, client->server->document_root_len);
    + {
    + const char *vpath = client->request.vpath, *end = vpath + client->request.vpath_len, *p = end;
    + client->request.ext = end;
    @@ -2975,8 +2983,9 @@ Index: sapi/cli/php_cli_server.c
    + php_cli_server_buffer_dtor(&client->capture_buffer);
    +} /* }}} */
    +
    +static int php_cli_server_client_ctor(php_cli_server_client *client, int client_sock, struct sockaddr *addr, socklen_t addr_len, const char *document_root, size_t document_root_len TSRMLS_DC) /* {{{ */
    +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;
    + client->sock = client_sock;
    + client->addr = addr;
    + client->addr_len = addr_len;
    @@ -2994,7 +3003,7 @@ Index: sapi/cli/php_cli_server.c
    + client->current_header_name_len = 0;
    + client->current_header_name_allocated = 0;
    + client->post_read_offset = 0;
    + if (FAILURE == php_cli_server_request_ctor(&client->request, document_root, document_root_len)) {
    + if (FAILURE == php_cli_server_request_ctor(&client->request)) {
    + return FAILURE;
    + }
    + client->content_sender_initialized = 0;
    @@ -3470,7 +3479,7 @@ Index: sapi/cli/php_cli_server.c
    + php_cli_server_close_connection(server, client TSRMLS_CC);
    + }
    + }
    + return SUCCESS;
    + return SUCCESS;
    +}
    +/* }}} */
    +
    @@ -3525,7 +3534,7 @@ Index: sapi/cli/php_cli_server.c
    + closesocket(client_sock);
    + continue;
    + }
    + if (!(client = pemalloc(sizeof(php_cli_server_client), 1)) || FAILURE == php_cli_server_client_ctor(client, client_sock, sa, socklen, server->document_root, server->document_root_len TSRMLS_CC)) {
    + if (!(client = pemalloc(sizeof(php_cli_server_client), 1)) || FAILURE == php_cli_server_client_ctor(client, server, client_sock, sa, socklen TSRMLS_CC)) {
    + php_cli_server_logf("Failed to create a new request object" TSRMLS_CC);
    + pefree(sa, 1);
    + closesocket(client_sock);
    @@ -5411,6 +5420,18 @@ Index: main/network.c
    {
    struct sockaddr **sap;
    int n;
    Index: main/php_main.h
    ===================================================================
    --- main/php_main.h (revision 307676)
    +++ main/php_main.h (working copy)
    @@ -35,6 +35,7 @@
    PHPAPI void php_module_shutdown_for_exec(void);
    PHPAPI int php_module_shutdown_wrapper(sapi_module_struct *sapi_globals);
    PHPAPI int php_request_startup_for_hook(TSRMLS_D);
    +PHPAPI int php_request_shutdown_for_hook(TSRMLS_D);

    PHPAPI int php_register_extensions(zend_module_entry **ptr, int count TSRMLS_DC);

    Index: main/php_network.h
    ===================================================================
    --- main/php_network.h (revision 307676)
  8. moriyoshi revised this gist Mar 1, 2011. 1 changed file with 3 additions and 4 deletions.
    7 changes: 3 additions & 4 deletions php-embedded-server-20110220.patch.diff
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,3 @@
    Index: sapi/cli/config.w32
    ===================================================================
    --- sapi/cli/config.w32 (revision 307676)
    +++ sapi/cli/config.w32 (working copy)
    @@ -2627,11 +2626,11 @@ Index: sapi/cli/php_cli_server.c
    + if (!stat(buf, &sb)) {
    + if (sb.st_mode & S_IFDIR) {
    + const char **file = index_files;
    + if (p > buf && p[-1] != '/') {
    + *p++ = '/';
    + }
    + while (*file) {
    + size_t l = strlen(*file);
    + if (p > buf && p[-1] != '/') {
    + *p++ = '/';
    + }
    + memmove(p, *file, l + 1);
    + if (!stat(buf, &sb) && (sb.st_mode & S_IFREG)) {
    + p += l;
  9. moriyoshi revised this gist Mar 1, 2011. 1 changed file with 11 additions and 6 deletions.
    17 changes: 11 additions & 6 deletions php-embedded-server-20110220.patch.diff
    Original file line number Diff line number Diff line change
    @@ -1643,7 +1643,7 @@ Index: sapi/cli/php_cli_server.c
    ===================================================================
    --- sapi/cli/php_cli_server.c (revision 0)
    +++ sapi/cli/php_cli_server.c (revision 0)
    @@ -0,0 +1,1978 @@
    @@ -0,0 +1,1983 @@
    +/*
    + +----------------------------------------------------------------------+
    + | PHP Version 5 |
    @@ -2629,10 +2629,12 @@ Index: sapi/cli/php_cli_server.c
    + const char **file = index_files;
    + while (*file) {
    + size_t l = strlen(*file);
    + *p = '/';
    + memmove(p + 1, *file, l + 1);
    + if (p > buf && p[-1] != '/') {
    + *p++ = '/';
    + }
    + memmove(p, *file, l + 1);
    + if (!stat(buf, &sb) && (sb.st_mode & S_IFREG)) {
    + p += l + 1;
    + p += l;
    + break;
    + }
    + file++;
    @@ -3200,7 +3202,10 @@ Index: sapi/cli/php_cli_server.c
    + append_essential_headers(&buffer, client, 1);
    + smart_str_appendl_ex(&buffer, "Content-Type: ", sizeof("Content-Type: ") - 1, 1);
    + smart_str_appends_ex(&buffer, mime_type, 1);
    + smart_str_appends_ex(&buffer, "; charset=UTF=8\r\n", 1);
    + if (strncmp(mime_type, "text/", 5) == 0) {
    + smart_str_appends_ex(&buffer, "; charset=UTF=8", 1);
    + }
    + smart_str_appendl_ex(&buffer, "\r\n", 2, 1);
    + smart_str_appends_ex(&buffer, "Content-Length: ", 1);
    + smart_str_append_generic_ex(&buffer, client->request.sb.st_size, 1, size_t, _unsigned);
    + smart_str_appendl_ex(&buffer, "\r\n", 2, 1);
    @@ -3462,7 +3467,7 @@ Index: sapi/cli/php_cli_server.c
    + return FAILURE;
    + }
    + }
    + if (!client->content_sender.buffer.first) {
    + if (!client->content_sender.buffer.first && client->file_fd < 0) {
    + php_cli_server_close_connection(server, client TSRMLS_CC);
    + }
    + }
  10. moriyoshi revised this gist Mar 1, 2011. 1 changed file with 121 additions and 19 deletions.
    140 changes: 121 additions & 19 deletions php-embedded-server-20110220.patch.diff
    Original file line number Diff line number Diff line change
    @@ -1643,7 +1643,7 @@ Index: sapi/cli/php_cli_server.c
    ===================================================================
    --- sapi/cli/php_cli_server.c (revision 0)
    +++ sapi/cli/php_cli_server.c (revision 0)
    @@ -0,0 +1,1876 @@
    @@ -0,0 +1,1978 @@
    +/*
    + +----------------------------------------------------------------------+
    + | PHP Version 5 |
    @@ -1734,6 +1734,7 @@ Index: sapi/cli/php_cli_server.c
    +#include "ext/standard/php_smart_str.h"
    +#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"
    +
    @@ -1817,6 +1818,8 @@ Index: sapi/cli/php_cli_server.c
    + int address_family;
    + char *document_root;
    + size_t document_root_len;
    + char *router;
    + size_t router_len;
    + socklen_t socklen;
    + php_cli_server_client *clients[FD_SETSIZE];
    +} php_cli_server;
    @@ -2115,7 +2118,9 @@ Index: sapi/cli/php_cli_server.c
    + sapi_cli_server_register_variable(track_vars_array, "DOCUMENT_ROOT", client->request.document_root TSRMLS_CC);
    + sapi_cli_server_register_variable(track_vars_array, "REQUEST_URI", client->request.request_uri TSRMLS_CC);
    + sapi_cli_server_register_variable(track_vars_array, "PHP_SELF", client->request.vpath TSRMLS_CC);
    + sapi_cli_server_register_variable(track_vars_array, "SCRIPT_FILENAME", SG(request_info).path_translated TSRMLS_CC);
    + if (SG(request_info).path_translated) {
    + sapi_cli_server_register_variable(track_vars_array, "SCRIPT_FILENAME", SG(request_info).path_translated TSRMLS_CC);
    + }
    + if (client->request.path_info) {
    + sapi_cli_server_register_variable(track_vars_array, "PATH_INFO", client->request.path_info TSRMLS_CC);
    + }
    @@ -3153,8 +3158,8 @@ Index: sapi/cli/php_cli_server.c
    + }
    +
    + php_request_shutdown(0);
    + destroy_request_info(&SG(request_info));
    + php_cli_server_close_connection(server, client TSRMLS_CC);
    + destroy_request_info(&SG(request_info));
    + return SUCCESS;
    +} /* }}} */
    +
    @@ -3212,17 +3217,78 @@ Index: sapi/cli/php_cli_server.c
    +}
    +/* }}} */
    +
    +static int php_cli_server_dispatch(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */
    +static int php_cli_server_dispatch_router(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */
    +{
    + SG(server_context) = client;
    + if (client->request.ext_len == 3 && memcmp(client->request.ext, "php", 3) == 0 && client->request.path_translated) {
    + if (SUCCESS != php_cli_server_dispatch_script(server, client TSRMLS_CC) &&
    + SUCCESS != php_cli_server_send_error_page(server, client, 500 TSRMLS_CC)) {
    + goto fail;
    + int decline = 0;
    +
    + if (!server->router) {
    + return 1;
    + }
    +
    + php_cli_server_client_populate_request_info(client, &SG(request_info));
    + {
    + zval **val;
    + if (SUCCESS == zend_hash_find(&client->request.headers, "Authorization", sizeof("Authorization"), (void**)&val)) {
    + php_handle_auth_data(Z_STRVAL_PP(val) TSRMLS_CC);
    + }
    + }
    + SG(sapi_headers).http_response_code = 200;
    + if (FAILURE == php_request_startup(TSRMLS_C)) {
    + /* should never be happen */
    + destroy_request_info(&SG(request_info));
    + return -1;
    + }
    + {
    + zend_file_handle zfd;
    + zfd.type = ZEND_HANDLE_FILENAME;
    + zfd.filename = server->router;
    + zfd.handle.fp = NULL;
    + zfd.free_filename = 0;
    + zfd.opened_path = NULL;
    + zend_try {
    + zval *retval = NULL;
    + if (SUCCESS == zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, &retval, 1, &zfd)) {
    + if (retval) {
    + decline = Z_TYPE_P(retval) == IS_BOOL && !Z_LVAL_P(retval);
    + zval_ptr_dtor(&retval);
    + }
    + } else {
    + decline = 1;
    + }
    + } zend_end_try();
    + }
    +
    + if (decline) {
    + php_request_shutdown_for_hook(0);
    + } else {
    + if (SUCCESS != php_cli_server_begin_send_static(server, client TSRMLS_CC)) {
    + goto fail;
    + php_request_shutdown(0);
    + php_cli_server_close_connection(server, client TSRMLS_CC);
    + }
    + destroy_request_info(&SG(request_info));
    +
    + return decline ? 1: 0;
    +}
    +/* }}} */
    +
    +static int php_cli_server_dispatch(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */
    +{
    + int status;
    +
    + SG(server_context) = client;
    + status = php_cli_server_dispatch_router(server, client TSRMLS_CC);
    +
    + if (status < 0) {
    + goto fail;
    + } else if (status > 0) {
    + if (client->request.ext_len == 3 && memcmp(client->request.ext, "php", 3) == 0 && client->request.path_translated) {
    + if (SUCCESS != php_cli_server_dispatch_script(server, client TSRMLS_CC) &&
    + SUCCESS != php_cli_server_send_error_page(server, client, 500 TSRMLS_CC)) {
    + goto fail;
    + }
    + } else {
    + if (SUCCESS != php_cli_server_begin_send_static(server, client TSRMLS_CC)) {
    + goto fail;
    + }
    + }
    + }
    + SG(server_context) = 0;
    @@ -3255,13 +3321,18 @@ Index: sapi/cli/php_cli_server.c
    + if (server->document_root) {
    + pefree(server->document_root, 1);
    + }
    + if (server->router) {
    + pefree(server->router, 1);
    + }
    +} /* }}} */
    +
    +static int php_cli_server_ctor(php_cli_server *server, const char *addr, const char *document_root TSRMLS_DC) /* {{{ */
    +static int php_cli_server_ctor(php_cli_server *server, const char *addr, const char *document_root, const char *router TSRMLS_DC) /* {{{ */
    +{
    + int retval = SUCCESS;
    + char *host = NULL;
    + char *errstr = NULL;
    + char *_document_root = NULL;
    + char *_router = NULL;
    + int err = 0;
    + int port = 3000;
    + php_socket_t server_sock = -1;
    @@ -3307,15 +3378,40 @@ Index: sapi/cli/php_cli_server.c
    +
    + {
    + size_t document_root_len = strlen(document_root);
    + server->document_root = pestrndup(document_root, document_root_len, 1);
    + _document_root = pestrndup(document_root, document_root_len, 1);
    + if (!_document_root) {
    + retval = FAILURE;
    + goto out;
    + }
    + server->document_root = _document_root;
    + server->document_root_len = document_root_len;
    + }
    +
    + if (router) {
    + size_t router_len = strlen(router);
    + _router = pestrndup(router, router_len, 1);
    + if (!_router) {
    + retval = FAILURE;
    + goto out;
    + }
    + server->router = _router;
    + server->router_len = router_len;
    + } else {
    + server->router = NULL;
    + server->router_len = 0;
    + }
    +
    + server->is_running = 1;
    +out:
    + if (retval != SUCCESS) {
    + if (host) {
    + free(host);
    + pefree(host, 1);
    + }
    + if (_document_root) {
    + pefree(_document_root, 1);
    + }
    + if (_router) {
    + pefree(_router, 1);
    + }
    + if (server_sock >= -1) {
    + closesocket(server_sock);
    @@ -3471,8 +3567,9 @@ Index: sapi/cli/php_cli_server.c
    + int c;
    + const char *server_bind_address = NULL;
    + extern const opt_struct OPTIONS[];
    + char buf[PATH_MAX];
    + char buf[MAXPATHLEN];
    + const char *document_root;
    + const char *router = NULL;
    +
    + while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2))!=-1) {
    + switch (c) {
    @@ -3486,18 +3583,23 @@ Index: sapi/cli/php_cli_server.c
    + struct stat sb;
    + document_root = argv[php_optind];
    + if (stat(document_root, &sb)) {
    + fprintf(stderr, "Directory %s does not exist.\n", document_root);
    + fprintf(stderr, "Directory or script %s does not exist.\n", document_root);
    + return 1;
    + }
    + if (!(sb.st_mode & S_IFDIR)) {
    + fprintf(stderr, "%s is not a directory.\n", document_root);
    + if ((sb.st_mode & S_IFREG)) {
    + strncpy(buf, document_root, sizeof(buf) - 1);
    + php_dirname(buf, strlen(buf));
    + router = document_root;
    + document_root = buf;
    + } else if (!(sb.st_mode & S_IFDIR)) {
    + fprintf(stderr, "%s is neither a directory nor a script.\n", document_root);
    + return 1;
    + }
    + } else {
    + document_root = getcwd(buf, sizeof(buf));
    + }
    +
    + if (FAILURE == php_cli_server_ctor(&server, server_bind_address, document_root TSRMLS_CC)) {
    + if (FAILURE == php_cli_server_ctor(&server, server_bind_address, document_root, router TSRMLS_CC)) {
    + return 1;
    + }
    + sapi_module.phpinfo_as_text = 0;
  11. moriyoshi revised this gist Mar 1, 2011. 1 changed file with 415 additions and 195 deletions.
    610 changes: 415 additions & 195 deletions php-embedded-server-20110220.patch.diff
    Original file line number Diff line number Diff line change
    @@ -1643,7 +1643,7 @@ Index: sapi/cli/php_cli_server.c
    ===================================================================
    --- sapi/cli/php_cli_server.c (revision 0)
    +++ sapi/cli/php_cli_server.c (revision 0)
    @@ -0,0 +1,1656 @@
    @@ -0,0 +1,1876 @@
    +/*
    + +----------------------------------------------------------------------+
    + | PHP Version 5 |
    @@ -1720,15 +1720,21 @@ Index: sapi/cli/php_cli_server.c
    +# define php_select(m, r, w, e, t) select(m, r, w, e, t)
    +# define SOCK_EINVAL EINVAL
    +# define SOCK_EAGAIN EAGAIN
    +# define SOCK_EINTR EINTR
    +# define SOCK_EADDRINUSE EADDRINUSE
    +#else
    +# include "win32/select.h"
    +# define SOCK_EINVAL WSAEINVAL
    +# define SOCK_EAGAIN WSAEWOULDBLOCK
    +# define SOCK_EINTR WSAEINTR
    +# define SOCK_EADDRINUSE WSAEADDRINUSE
    +#endif
    +
    +#include "ext/standard/file.h" /* for php_set_sock_blocking() :-( */
    +#include "ext/standard/php_smart_str.h"
    +#include "ext/standard/html.h"
    +#include "ext/standard/url.h" /* for php_url_decode() */
    +#include "ext/standard/info.h" /* for php_info_print_style() */
    +#include "php_network.h"
    +
    +#include "php_http_parser.h"
    @@ -1797,6 +1803,8 @@ Index: sapi/cli/php_cli_server.c
    + php_cli_server_request request;
    + int content_sender_initialized:1;
    + php_cli_server_content_sender content_sender;
    + php_cli_server_buffer capture_buffer;
    + int capturing:1;
    + int file_fd;
    +} php_cli_server_client;
    +
    @@ -1867,8 +1875,8 @@ Index: sapi/cli/php_cli_server.c
    +};
    +
    +static php_cli_server_http_reponse_status_code_pair template_map[] = {
    + { 404, "<html><head><title>%1$d %2$s</title></head><body><h1>%2$s</h1><p>The requested resource %3$s was not found on this server.</p></body></html>" },
    + { 500, "<html><head><title>%1$d %2$s</title></head><body><h1>%2$s</h1><p>The server is temporality unavaiable.</p></body></html>" }
    + { 404, "<h1 class=\"h\">%2$s</h1><p>The requested resource %3$s was not found on this server.</p>" },
    + { 500, "<h1 class=\"h\">%2$s</h1><p>The server is temporality unavaiable.</p>" }
    +};
    +
    +static php_cli_server_ext_mime_type_pair mime_type_map[] = {
    @@ -1885,6 +1893,8 @@ Index: sapi/cli/php_cli_server.c
    +};
    +
    +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 TSRMLS_DC, ...);
    +
    +static void char_ptr_dtor_p(char **p) /* {{{ */
    @@ -1996,7 +2006,17 @@ Index: sapi/cli/php_cli_server.c
    +static int sapi_cli_server_ub_write(const char *str, uint str_length TSRMLS_DC) /* {{{ */
    +{
    + php_cli_server_client *client = SG(server_context);
    + return php_cli_server_client_send_through(client, str, str_length);
    + 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);
    + }
    +} /* }}} */
    +
    +static void sapi_cli_server_flush(void *server_context) /* {{{ */
    @@ -2026,13 +2046,12 @@ Index: sapi/cli/php_cli_server.c
    + sapi_header_struct *h;
    + zend_llist_position pos;
    +
    +
    + if (SG(request_info).no_headers) {
    + if (client->capturing || SG(request_info).no_headers) {
    + return SAPI_HEADER_SENT_SUCCESSFULLY;
    + }
    +
    + if (SG(sapi_headers).http_status_line) {
    + smart_str_append(&buffer, SG(sapi_headers).http_status_line);
    + smart_str_appends(&buffer, SG(sapi_headers).http_status_line);
    + smart_str_appendl(&buffer, "\r\n", 2);
    + } else {
    + append_http_status_line(&buffer, client->request.protocol_version, SG(sapi_headers).http_response_code, 0);
    @@ -2195,10 +2214,10 @@ Index: sapi/cli/php_cli_server.c
    + if (fd == poller->max_fd) {
    + while (fd > 0) {
    + fd--;
    + if (((unsigned long *)&poller->rfds)[fd / (8 * sizeof(unsigned long))] || ((unsigned long *)&poller->wfds)[fd / (8 * sizeof(unsigned long))]) {
    + if (((unsigned int *)&poller->rfds)[fd / (8 * sizeof(unsigned int))] || ((unsigned int *)&poller->wfds)[fd / (8 * sizeof(unsigned int))]) {
    + break;
    + }
    + fd -= fd % (8 * sizeof(unsigned long));
    + fd -= fd % (8 * sizeof(unsigned int));
    + }
    + poller->max_fd = fd;
    + }
    @@ -2211,6 +2230,17 @@ Index: sapi/cli/php_cli_server.c
    + return php_select(poller->max_fd + 1, rfds, wfds, NULL, (struct timeval *)tv);
    +} /* }}} */
    +
    +static size_t php_cli_server_chunk_size(const php_cli_server_chunk *chunk) /* {{{ */
    +{
    + switch (chunk->type) {
    + case PHP_CLI_SERVER_CHUNK_HEAP:
    + return chunk->data.heap.len;
    + case PHP_CLI_SERVER_CHUNK_IMMORTAL:
    + return chunk->data.immortal.len;
    + }
    + return 0;
    +} /* }}} */
    +
    +static void php_cli_server_chunk_dtor(php_cli_server_chunk *chunk) /* {{{ */
    +{
    + switch (chunk->type) {
    @@ -2242,12 +2272,35 @@ Index: sapi/cli/php_cli_server.c
    +
    +static void php_cli_server_buffer_append(php_cli_server_buffer *buffer, php_cli_server_chunk *chunk) /* {{{ */
    +{
    + php_cli_server_chunk *last;
    + for (last = chunk; last->next; last = last->next);
    + if (!buffer->last) {
    + buffer->first = chunk;
    + } else {
    + buffer->last->next = chunk;
    + }
    + buffer->last = chunk;
    + buffer->last = last;
    +} /* }}} */
    +
    +static void php_cli_server_buffer_prepend(php_cli_server_buffer *buffer, php_cli_server_chunk *chunk) /* {{{ */
    +{
    + php_cli_server_chunk *last;
    + for (last = chunk; last->next; last = last->next);
    + last->next = buffer->first;
    + if (!buffer->last) {
    + buffer->last = last;
    + }
    + buffer->first = chunk;
    +} /* }}} */
    +
    +static size_t php_cli_server_buffer_size(const php_cli_server_buffer *buffer) /* {{{ */
    +{
    + php_cli_server_chunk *chunk;
    + size_t retval = 0;
    + for (chunk = buffer->first; chunk; chunk = chunk->next) {
    + retval += php_cli_server_chunk_size(chunk);
    + }
    + return retval;
    +} /* }}} */
    +
    +static php_cli_server_chunk *php_cli_server_chunk_immortal_new(const char *buf, size_t len) /* {{{ */
    @@ -2258,6 +2311,7 @@ Index: sapi/cli/php_cli_server.c
    + }
    +
    + chunk->type = PHP_CLI_SERVER_CHUNK_IMMORTAL;
    + chunk->next = NULL;
    + chunk->data.immortal.p = buf;
    + chunk->data.immortal.len = len;
    + return chunk;
    @@ -2393,30 +2447,21 @@ Index: sapi/cli/php_cli_server.c
    + }
    +} /* }}} */
    +
    +static void php_cli_server_dtor(php_cli_server *server TSRMLS_DC) /* {{{ */
    +{
    + if (server->server_sock >= 0) {
    + closesocket(server->server_sock);
    + }
    + if (server->host) {
    + pefree(server->host, 1);
    + }
    + if (server->document_root) {
    + pefree(server->document_root, 1);
    + }
    +} /* }}} */
    +
    +static int php_network_listen_socket(const char *host, int *port, int socktype, int *af, socklen_t *socklen, char **errstr TSRMLS_DC) /* {{{ */
    +{
    + int retval = -1;
    + int err = 0;
    + struct sockaddr *sa, **p, **sal;
    + struct sockaddr *sa = NULL, **p, **sal;
    +
    + int num_addrs = php_network_getaddresses(host, socktype, &sal, errstr TSRMLS_CC);
    + if (num_addrs == 0) {
    + return -1;
    + }
    + for (p = sal; *p; p++) {
    + if (sa) {
    + pefree(sa, 1);
    + }
    +
    + retval = socket((*p)->sa_family, socktype, 0);
    + if (retval == SOCK_ERR) {
    + continue;
    @@ -2458,7 +2503,7 @@ Index: sapi/cli/php_cli_server.c
    +
    + if (bind(retval, sa, *socklen) == SOCK_CONN_ERR) {
    + err = php_socket_errno();
    + if (err == SOCK_EINVAL) {
    + if (err == SOCK_EINVAL || err == SOCK_EADDRINUSE) {
    + goto out;
    + }
    + closesocket(retval);
    @@ -2542,6 +2587,15 @@ Index: sapi/cli/php_cli_server.c
    + if (req->vpath) {
    + pefree(req->vpath, 1);
    + }
    + if (req->path_translated) {
    + pefree(req->path_translated, 1);
    + }
    + if (req->path_info) {
    + pefree(req->path_info, 1);
    + }
    + if (req->query_string) {
    + pefree(req->query_string, 1);
    + }
    + zend_hash_destroy(&req->headers);
    + if (req->content) {
    + pefree(req->content, 1);
    @@ -2565,14 +2619,14 @@ Index: sapi/cli/php_cli_server.c
    + *p = '\0';
    + q = p;
    + while (q > buf) {
    + if (!lstat(buf, &sb)) {
    + if (!stat(buf, &sb)) {
    + if (sb.st_mode & S_IFDIR) {
    + const char **file = index_files;
    + while (*file) {
    + size_t l = strlen(*file);
    + *p = '/';
    + memmove(p + 1, *file, l + 1);
    + if (!lstat(buf, &sb) && (sb.st_mode & S_IFREG)) {
    + if (!stat(buf, &sb) && (sb.st_mode & S_IFREG)) {
    + p += l + 1;
    + break;
    + }
    @@ -2603,6 +2657,9 @@ Index: sapi/cli/php_cli_server.c
    + request->path_translated = buf;
    + request->path_translated_len = prev_patch - buf;
    + } else {
    + pefree(request->vpath, 1);
    + request->vpath = pestrndup(vpath, p - vpath, 1);
    + request->vpath_len = p - vpath;
    + request->path_translated = buf;
    + request->path_translated_len = p - buf;
    + }
    @@ -2611,41 +2668,70 @@ Index: sapi/cli/php_cli_server.c
    +
    +static void normalize_vpath(char **retval, size_t *retval_len, const char *vpath, size_t vpath_len, int persistent) /* {{{ */
    +{
    + smart_str result = { 0 };
    + const char *vpath_end = vpath + vpath_len;
    + const char *p = vpath;
    + char *decoded_vpath = NULL;
    + char *decoded_vpath_end;
    + char *p;
    +
    + if (p < vpath_end && p[0] == '/') {
    + smart_str_appendc_ex(&result, '/', persistent);
    + p++;
    + *retval = NULL;
    +
    + decoded_vpath = pestrndup(vpath, vpath_len, persistent);
    + if (!decoded_vpath) {
    + return;
    + }
    +
    + while (p < vpath_end) {
    + const char *n = p;
    + while (n < vpath_end && *n != '/')
    + n++;
    + decoded_vpath_end = decoded_vpath + php_url_decode(decoded_vpath, vpath_len);
    +
    + p = decoded_vpath;
    +
    + if (p < decoded_vpath_end && *p == '/') {
    + char *n = p;
    + while (n < decoded_vpath_end && *n == '/') n++;
    + memmove(++p, n, decoded_vpath_end - n);
    + decoded_vpath_end -= n - p;
    + }
    +
    + while (p < decoded_vpath_end) {
    + char *n = p;
    + while (n < decoded_vpath_end && *n != '/') n++;
    + if (n - p == 2 && p[0] == '.' && p[1] == '.') {
    + const char *q = result.c + result.len;
    + while (q > result.c && *(--q) != '/')
    + q--;
    + result.len = q - result.c;
    + p = n == vpath_end ? n: n + 1;
    + } else if (n - p == 0 || (n - p == 1 && p[0] == '.')) {
    + p = n == vpath_end ? n: n + 1;
    + if (p > decoded_vpath) {
    + --p;
    + for (;;) {
    + if (p == decoded_vpath) {
    + if (*p == '/') {
    + p++;
    + }
    + break;
    + }
    + if (*(--p) == '/') {
    + p++;
    + break;
    + }
    + }
    + }
    + while (n < decoded_vpath_end && *n == '/') n++;
    + memmove(p, n, decoded_vpath_end - n);
    + decoded_vpath_end -= n - p;
    + } else if (n - p == 1 && p[0] == '.') {
    + while (n < decoded_vpath_end && *n == '/') n++;
    + memmove(p, n, decoded_vpath_end - n);
    + decoded_vpath_end -= n - p;
    + } else {
    + smart_str_appendl_ex(&result, p, n - p, persistent);
    + if (n == vpath_end) {
    + p = n;
    + } else {
    + smart_str_appendc_ex(&result, '/', persistent);
    + if (n < decoded_vpath_end) {
    + char *nn = n;
    + while (nn < decoded_vpath_end && *nn == '/') nn++;
    + p = n + 1;
    + memmove(p, nn, decoded_vpath_end - nn);
    + decoded_vpath_end -= nn - p;
    + } else {
    + p = n;
    + }
    + }
    + }
    +
    + smart_str_0(&result);
    + *retval = result.c;
    + *retval_len = result.len;
    +
    + *decoded_vpath_end = '\0';
    + *retval = decoded_vpath;
    + *retval_len = decoded_vpath_end - decoded_vpath;
    +} /* }}} */
    +
    +/* {{{ php_cli_server_client_read_request */
    @@ -2869,9 +2955,18 @@ Index: sapi/cli/php_cli_server.c
    +
    +static void destroy_request_info(sapi_request_info *request_info) /* {{{ */
    +{
    + if (request_info->path_translated) {
    + pefree(request_info->path_translated, 1);
    + }
    +} /* }}} */
    +
    +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, int client_sock, struct sockaddr *addr, socklen_t addr_len, const char *document_root, size_t document_root_len TSRMLS_DC) /* {{{ */
    @@ -2897,29 +2992,139 @@ Index: sapi/cli/php_cli_server.c
    + return FAILURE;
    + }
    + client->content_sender_initialized = 0;
    + client->capturing = 0;
    + client->file_fd = -1;
    + return SUCCESS;
    +} /* }}} */
    +
    +static void php_cli_server_client_dtor(php_cli_server_client *client) /* {{{ */
    +{
    + php_cli_server_request_dtor(&client->request);
    + if (client->file_fd >= 0) {
    + close(client->file_fd);
    + client->file_fd = -1;
    + }
    + pefree(client->addr, 1);
    + pefree(client->addr_str, 1);
    + php_cli_server_request_dtor(&client->request);
    + 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) /* {{{ */
    +{
    +#ifdef DEBUG
    + php_cli_server_logf("%s: Closing" TSRMLS_CC, client->addr_str);
    +#endif
    + closesocket(client->sock);
    + php_cli_server_poller_remove(&server->poller, POLLIN | POLLOUT, client->sock);
    + php_cli_server_client_dtor(client);
    + server->clients[client->sock] = NULL;
    + pefree(client, 1);
    +} /* }}} */
    +
    +static int php_cli_server_send_error_page(php_cli_server *server, php_cli_server_client *client, int status TSRMLS_DC) /* {{{ */
    +{
    + char *escaped_request_uri = NULL;
    + size_t escaped_request_uri_len;
    + const char *status_string = get_status_string(status);
    + const char *content_template = get_template_string(status);
    + assert(status_string && content_template);
    +
    + php_cli_server_content_sender_ctor(&client->content_sender);
    + client->content_sender_initialized = 1;
    +
    + 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[] = "<html><head><title>%1$d %2$s</title>";
    + 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;
    + }
    + sprintf(chunk->data.heap.p, prologue_template, status, status_string, escaped_request_uri);
    + chunk->data.heap.len = strlen(chunk->data.heap.p);
    + php_cli_server_buffer_append(&client->content_sender.buffer, chunk);
    + }
    + {
    + int err = 0;
    + sapi_activate_headers_only(TSRMLS_C);
    + php_cli_server_client_begin_capture(client);
    + zend_try {
    + php_info_print_style(TSRMLS_C);
    + php_cli_server_buffer_append(&client->content_sender.buffer, client->capture_buffer.first);
    + client->capture_buffer.first = client->capture_buffer.last = NULL;
    + } zend_catch {
    + err = 1;
    + } zend_end_try();
    + php_cli_server_client_end_capture(client);
    + sapi_deactivate(TSRMLS_C);
    + if (err) {
    + goto fail;
    + }
    + }
    + {
    + static const char template[] = "</head><body>";
    + 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_chunk *chunk = php_cli_server_chunk_heap_new_self_contained(strlen(content_template) + escaped_request_uri_len + 3 + strlen(status_string) + 1);
    + if (!chunk) {
    + goto fail;
    + }
    + sprintf(chunk->data.heap.p, content_template, status, status_string, 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[] = "</body></html>";
    + 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_chunk *chunk;
    + smart_str buffer = { 0 };
    + append_http_status_line(&buffer, client->request.protocol_version, status, 1);
    + if (!buffer.c) {
    + /* out of memory */
    + goto fail;
    + }
    + append_essential_headers(&buffer, client, 1);
    + smart_str_appends_ex(&buffer, "Content-Type: text/html; charset=UTF=8\r\n", 1);
    + smart_str_appends_ex(&buffer, "Content-Length: ", 1);
    + 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);
    + goto fail;
    + }
    + php_cli_server_buffer_prepend(&client->content_sender.buffer, chunk);
    + }
    +
    + php_cli_server_logf("%s: %s - Sending error page (%d)" TSRMLS_CC, client->addr_str, client->request.request_uri, status);
    + php_cli_server_poller_add(&server->poller, POLLOUT, client->sock);
    + efree(escaped_request_uri);
    + return SUCCESS;
    +
    +fail:
    + efree(escaped_request_uri);
    + return FAILURE;
    +} /* }}} */
    +
    +static int php_cli_server_dispatch_script(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */
    +{
    + php_cli_server_client_populate_request_info(client, &SG(request_info));
    @@ -2929,7 +3134,6 @@ Index: sapi/cli/php_cli_server.c
    + php_handle_auth_data(Z_STRVAL_PP(val) TSRMLS_CC);
    + }
    + }
    + SG(server_context) = client;
    + SG(sapi_headers).http_response_code = 200;
    + if (FAILURE == php_request_startup(TSRMLS_C)) {
    + /* should never be happen */
    @@ -2943,7 +3147,7 @@ Index: sapi/cli/php_cli_server.c
    + zfd.handle.fp = NULL;
    + zfd.free_filename = 0;
    + zfd.opened_path = NULL;
    + zend_first_try {
    + zend_try {
    + php_execute_script(&zfd TSRMLS_CC);
    + } zend_end_try();
    + }
    @@ -2954,6 +3158,105 @@ Index: sapi/cli/php_cli_server.c
    + return SUCCESS;
    +} /* }}} */
    +
    +static int php_cli_server_begin_send_static(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */
    +{
    + int fd;
    + int status = 200;
    +
    + fd = client->request.path_translated ? open(client->request.path_translated, O_RDONLY): -1;
    + if (fd < 0) {
    + char *errstr = get_last_error();
    + if (errstr) {
    + php_cli_server_logf("%s: %s - %s" TSRMLS_CC, client->addr_str, client->request.request_uri, errstr);
    + pefree(errstr, 1);
    + } else {
    + php_cli_server_logf("%s: %s - ?" TSRMLS_CC, client->addr_str, client->request.request_uri);
    + }
    + return php_cli_server_send_error_page(server, client, 404 TSRMLS_CC);
    + }
    +
    + php_cli_server_content_sender_ctor(&client->content_sender);
    + client->content_sender_initialized = 1;
    + client->file_fd = fd;
    +
    + {
    + php_cli_server_chunk *chunk;
    + smart_str buffer = { 0 };
    + const char *mime_type = get_mime_type(client->request.ext, client->request.ext_len);
    + if (!mime_type) {
    + mime_type = "application/octet-stream";
    + }
    +
    + append_http_status_line(&buffer, client->request.protocol_version, status, 1);
    + if (!buffer.c) {
    + /* out of memory */
    + return FAILURE;
    + }
    + append_essential_headers(&buffer, client, 1);
    + smart_str_appendl_ex(&buffer, "Content-Type: ", sizeof("Content-Type: ") - 1, 1);
    + smart_str_appends_ex(&buffer, mime_type, 1);
    + smart_str_appends_ex(&buffer, "; charset=UTF=8\r\n", 1);
    + smart_str_appends_ex(&buffer, "Content-Length: ", 1);
    + smart_str_append_generic_ex(&buffer, client->request.sb.st_size, 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);
    + return FAILURE;
    + }
    + php_cli_server_buffer_append(&client->content_sender.buffer, chunk);
    + }
    + php_cli_server_poller_add(&server->poller, POLLOUT, client->sock);
    + return SUCCESS;
    +}
    +/* }}} */
    +
    +static int php_cli_server_dispatch(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */
    +{
    + SG(server_context) = client;
    + if (client->request.ext_len == 3 && memcmp(client->request.ext, "php", 3) == 0 && client->request.path_translated) {
    + if (SUCCESS != php_cli_server_dispatch_script(server, client TSRMLS_CC) &&
    + SUCCESS != php_cli_server_send_error_page(server, client, 500 TSRMLS_CC)) {
    + goto fail;
    + }
    + } else {
    + if (SUCCESS != php_cli_server_begin_send_static(server, client TSRMLS_CC)) {
    + goto fail;
    + }
    + }
    + SG(server_context) = 0;
    + return SUCCESS;
    +fail:
    + SG(server_context) = 0;
    + php_cli_server_close_connection(server, client TSRMLS_CC);
    + return SUCCESS;
    +}
    +
    +static void php_cli_server_dtor(php_cli_server *server TSRMLS_DC) /* {{{ */
    +{
    + {
    + php_cli_server_client **p = server->clients,
    + **e = server->clients + sizeof(server->clients) / sizeof(*server->clients);
    + while (p < e) {
    + if (*p) {
    + php_cli_server_close_connection(server, *p TSRMLS_CC);
    + *p = NULL;
    + }
    + p++;
    + }
    + }
    + if (server->server_sock >= 0) {
    + closesocket(server->server_sock);
    + }
    + if (server->host) {
    + pefree(server->host, 1);
    + }
    + if (server->document_root) {
    + pefree(server->document_root, 1);
    + }
    +} /* }}} */
    +
    +static int php_cli_server_ctor(php_cli_server *server, const char *addr, const char *document_root TSRMLS_DC) /* {{{ */
    +{
    + int retval = SUCCESS;
    @@ -2996,6 +3299,13 @@ Index: sapi/cli/php_cli_server.c
    + server->port = port;
    +
    + {
    + size_t i = 0;
    + for (i = 0; i < sizeof(server->clients) / sizeof(*server->clients); i++) {
    + server->clients[i] = 0;
    + }
    + }
    +
    + {
    + size_t document_root_len = strlen(document_root);
    + server->document_root = pestrndup(document_root, document_root_len, 1);
    + server->document_root_len = document_root_len;
    @@ -3014,139 +3324,19 @@ Index: sapi/cli/php_cli_server.c
    + return retval;
    +} /* }}} */
    +
    +static int php_cli_server_send_error_page(php_cli_server *server, php_cli_server_client *client, int status TSRMLS_DC) /* {{{ */
    +{
    + php_cli_server_chunk *content_chunk;
    + const char *template = get_template_string(status);
    + assert(template);
    +
    + php_cli_server_content_sender_ctor(&client->content_sender);
    + client->content_sender_initialized = 1;
    +
    + {
    + const char *status_string = get_status_string(status);
    + char *escaped_request_uri;
    + size_t escaped_request_uri_len;
    + 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);
    + content_chunk = php_cli_server_chunk_heap_new_self_contained(strlen(template) + escaped_request_uri_len + 3 + strlen(status_string) * 2 + 1);
    + if (!content_chunk) {
    + efree(escaped_request_uri);
    + return FAILURE;
    + }
    + sprintf(content_chunk->data.heap.p, /*content_chunk->data.heap.len,*/ template, status, status_string, escaped_request_uri);
    + content_chunk->data.heap.len = strlen(content_chunk->data.heap.p);
    + efree(escaped_request_uri);
    + }
    +
    + {
    + php_cli_server_chunk *chunk;
    + smart_str buffer = { 0 };
    + append_http_status_line(&buffer, client->request.protocol_version, status, 1);
    + if (!buffer.c) {
    + /* out of memory */
    + return FAILURE;
    + }
    + append_essential_headers(&buffer, client, 1);
    + smart_str_appends_ex(&buffer, "Content-Type: text/html; charset=UTF=8\r\n", 1);
    + smart_str_appends_ex(&buffer, "Content-Length: ", 1);
    + smart_str_append_generic_ex(&buffer, content_chunk->data.heap.len, 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);
    + return FAILURE;
    + }
    + php_cli_server_buffer_append(&client->content_sender.buffer, chunk);
    + }
    + php_cli_server_buffer_append(&client->content_sender.buffer, content_chunk);
    + php_cli_server_poller_add(&server->poller, POLLOUT, client->sock);
    +
    + return SUCCESS;
    +} /* }}} */
    +
    +static int php_cli_server_begin_send_static(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */
    +{
    + int fd;
    + int status = 200;
    +
    + fd = open(client->request.path_translated, O_RDONLY);
    + if (fd < 0) {
    + char *errstr = get_last_error();
    + if (errstr) {
    + php_cli_server_logf("%s" TSRMLS_CC, errstr);
    + pefree(errstr, 1);
    + } else {
    + php_cli_server_logf("?" TSRMLS_CC);
    + }
    + return php_cli_server_send_error_page(server, client, 404 TSRMLS_CC);
    + }
    +
    + php_cli_server_content_sender_ctor(&client->content_sender);
    + client->content_sender_initialized = 1;
    + client->file_fd = fd;
    +
    + {
    + php_cli_server_chunk *chunk;
    + smart_str buffer = { 0 };
    + const char *mime_type = get_mime_type(client->request.ext, client->request.ext_len);
    + if (!mime_type) {
    + mime_type = "application/octet-stream";
    + }
    +
    + append_http_status_line(&buffer, client->request.protocol_version, status, 1);
    + if (!buffer.c) {
    + /* out of memory */
    + return FAILURE;
    + }
    + append_essential_headers(&buffer, client, 1);
    + smart_str_appendl_ex(&buffer, "Content-Type: ", sizeof("Content-Type: ") - 1, 1);
    + smart_str_appends_ex(&buffer, mime_type, 1);
    + smart_str_appends_ex(&buffer, "; charset=UTF=8\r\n", 1);
    + smart_str_appends_ex(&buffer, "Content-Length: ", 1);
    + smart_str_append_generic_ex(&buffer, client->request.sb.st_size, 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);
    + return FAILURE;
    + }
    + php_cli_server_buffer_append(&client->content_sender.buffer, chunk);
    + }
    + php_cli_server_poller_add(&server->poller, POLLOUT, client->sock);
    + return SUCCESS;
    +}
    +/* }}} */
    +
    +static int php_cli_server_recv_event_read_request(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */
    +{
    + char *errstr = NULL;
    + int status = php_cli_server_client_read_request(client, &errstr TSRMLS_CC);
    + if (status < 0) {
    + php_cli_server_logf("%s: Invalid request (%s)" TSRMLS_CC, client->addr_str, errstr);
    + efree(errstr);
    + php_cli_server_logf("%s: Closing connection" TSRMLS_CC, client->addr_str);
    + php_cli_server_close_connection(server, client TSRMLS_CC);
    + return FAILURE;
    + } else if (status == 1) {
    + php_cli_server_logf("%s: Done reading request" TSRMLS_CC, client->addr_str);
    + php_cli_server_logf("%s: %s" TSRMLS_CC, client->addr_str, client->request.request_uri);
    + php_cli_server_poller_remove(&server->poller, POLLIN, client->sock);
    + {
    + if (client->request.ext_len == 4 && memcmp(client->request.ext, ".php", 4) == 0) {
    + if (SUCCESS != php_cli_server_dispatch_script(server, client TSRMLS_CC) &&
    + SUCCESS != php_cli_server_send_error_page(server, client, 500 TSRMLS_CC)) {
    + php_cli_server_close_connection(server, client TSRMLS_CC);
    + return FAILURE;
    + }
    + } else {
    + if (SUCCESS != php_cli_server_begin_send_static(server, client TSRMLS_CC)) {
    + php_cli_server_close_connection(server, client TSRMLS_CC);
    + return FAILURE;
    + }
    + }
    + }
    + php_cli_server_dispatch(server, client TSRMLS_CC);
    + } else {
    + php_cli_server_poller_add(&server->poller, POLLIN, client->sock);
    + }
    @@ -3176,7 +3366,7 @@ Index: sapi/cli/php_cli_server.c
    + return FAILURE;
    + }
    + }
    + if (!client->content_sender.buffer.first && client->file_fd < 0) {
    + if (!client->content_sender.buffer.first) {
    + php_cli_server_close_connection(server, client TSRMLS_CC);
    + }
    + }
    @@ -3188,10 +3378,10 @@ Index: sapi/cli/php_cli_server.c
    +{
    + php_socket_t fd = 0;
    + php_socket_t max_fd = server->poller.max_fd;
    + const unsigned long *p = (unsigned long *)fds, *e = p + (max_fd + (8 * sizeof(unsigned long)) - 1) / (8 * sizeof(unsigned long));
    + unsigned long mask;
    + const unsigned int *p = (unsigned int *)fds, *e = p + (max_fd + (8 * sizeof(unsigned int)) - 1) / (8 * sizeof(unsigned int));
    + unsigned int mask;
    + while (p < e && fd <= max_fd) {
    + for (mask = 1; mask; mask <<= 1) {
    + for (mask = 1; mask; mask <<= 1, fd++) {
    + if (*p & mask) {
    + if (fd == server->server_sock) {
    + continue;
    @@ -3200,7 +3390,6 @@ Index: sapi/cli/php_cli_server.c
    + handler(server, server->clients[fd] TSRMLS_CC);
    + }
    + }
    + fd++;
    + }
    + p++;
    + }
    @@ -3242,7 +3431,9 @@ Index: sapi/cli/php_cli_server.c
    + closesocket(client_sock);
    + continue;
    + }
    +#ifdef DEBUG
    + php_cli_server_logf("%s: Accepted" TSRMLS_CC, client->addr_str);
    +#endif
    + server->clients[client_sock] = client;
    + php_cli_server_recv_event_read_request(server, client TSRMLS_CC);
    + }
    @@ -3251,24 +3442,37 @@ Index: sapi/cli/php_cli_server.c
    + } else if (n == 0) {
    + /* do nothing */
    + } else {
    + char *err = php_socket_strerror(php_socket_errno(), NULL, 0);
    + php_cli_server_logf("%s" TSRMLS_CC, err);
    + efree(err);
    + goto out;
    + int err = php_socket_errno();
    + if (err != SOCK_EINTR) {
    + char *errstr = php_socket_strerror(err, NULL, 0);
    + php_cli_server_logf("%s" TSRMLS_CC, errstr);
    + efree(errstr);
    + retval = FAILURE;
    + goto out;
    + }
    + }
    + }
    +out:
    + return retval;
    +} /* }}} */
    +
    +
    +static php_cli_server server;
    +
    +static void php_cli_server_sigint_handler(int sig)
    +{
    + server.is_running = 0;
    +};
    +
    +int do_cli_server(int argc, char **argv TSRMLS_DC) /* {{{ */
    +{
    + char *php_optarg = NULL;
    + int php_optind = 1;
    + int c;
    + const char *server_bind_address = NULL;
    + extern const opt_struct OPTIONS[];
    + php_cli_server server;
    + char buf[PATH_MAX];
    + const char *document_root;
    +
    + while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2))!=-1) {
    + switch (c) {
    @@ -3278,16 +3482,32 @@ Index: sapi/cli/php_cli_server.c
    + }
    + }
    +
    + {
    + char buf[PATH_MAX];
    + if (FAILURE == php_cli_server_ctor(&server, server_bind_address, getcwd(buf, sizeof(buf)) TSRMLS_CC)) {
    + if (argc > php_optind) {
    + struct stat sb;
    + document_root = argv[php_optind];
    + if (stat(document_root, &sb)) {
    + fprintf(stderr, "Directory %s does not exist.\n", document_root);
    + return 1;
    + }
    + if (!(sb.st_mode & S_IFDIR)) {
    + fprintf(stderr, "%s is not a directory.\n", document_root);
    + return 1;
    + }
    + } else {
    + document_root = getcwd(buf, sizeof(buf));
    + }
    +
    + if (FAILURE == php_cli_server_ctor(&server, server_bind_address, document_root TSRMLS_CC)) {
    + return 1;
    + }
    + sapi_module.phpinfo_as_text = 0;
    +
    + printf("Server is listening on %s:%d... Press CTRL-C to quit.\n", server.host, server.port);
    +
    +#if defined(HAVE_SIGNAL_H) && defined(SIGINT)
    + signal(SIGINT, php_cli_server_sigint_handler);
    +#endif
    + php_cli_server_do_event_loop(&server TSRMLS_CC);
    +out:
    + php_cli_server_dtor(&server TSRMLS_CC);
    + return 0;
    +} /* }}} */
  12. moriyoshi revised this gist Feb 20, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion php-embedded-server-20110220.patch.diff
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@ Index: sapi/cli/config.w32

    if (PHP_CLI == "yes") {
    - SAPI('cli', 'php_cli.c php_cli_readline.c', 'php.exe');
    + SAPI('cli', 'php_cli.c php_cli_readline.c php_cli_server.c', 'php.exe');
    + SAPI('cli', 'php_cli.c php_cli_readline.c php_http_parser.c php_cli_server.c', 'php.exe');
    if (PHP_CRT_DEBUG == "yes") {
    ADD_FLAG("CFLAGS_CLI", "/D PHP_WIN32_DEBUG_HEAP");
    }
  13. moriyoshi created this gist Feb 20, 2011.
    5,114 changes: 5,114 additions & 0 deletions php-embedded-server-20110220.patch.diff
    5,114 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.