PageRenderTime 57ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/sapi/cli/php_cli_server.c

http://github.com/php/php-src
C | 2733 lines | 2361 code | 296 blank | 76 comment | 488 complexity | c3cbe5ceef94d383ec232d7395263716 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Moriyoshi Koizumi <moriyoshi@php.net> |
  14. | Xinchen Hui <laruence@php.net> |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <fcntl.h>
  20. #include <assert.h>
  21. #ifdef PHP_WIN32
  22. # include <process.h>
  23. # include <io.h>
  24. # include "win32/time.h"
  25. # include "win32/signal.h"
  26. # include "win32/php_registry.h"
  27. # include <sys/timeb.h>
  28. #else
  29. # include "php_config.h"
  30. #endif
  31. #ifdef __riscos__
  32. #include <unixlib/local.h>
  33. #endif
  34. #if HAVE_SYS_TIME_H
  35. #include <sys/time.h>
  36. #endif
  37. #if HAVE_UNISTD_H
  38. #include <unistd.h>
  39. #endif
  40. #include <signal.h>
  41. #include <locale.h>
  42. #if HAVE_DLFCN_H
  43. #include <dlfcn.h>
  44. #endif
  45. #include "SAPI.h"
  46. #include "php.h"
  47. #include "php_ini.h"
  48. #include "php_main.h"
  49. #include "php_globals.h"
  50. #include "php_variables.h"
  51. #include "zend_hash.h"
  52. #include "zend_modules.h"
  53. #include "fopen_wrappers.h"
  54. #include "http_status_codes.h"
  55. #include "zend_compile.h"
  56. #include "zend_execute.h"
  57. #include "zend_highlight.h"
  58. #include "zend_exceptions.h"
  59. #include "php_getopt.h"
  60. #ifndef PHP_WIN32
  61. # define php_select(m, r, w, e, t) select(m, r, w, e, t)
  62. # define SOCK_EINVAL EINVAL
  63. # define SOCK_EAGAIN EAGAIN
  64. # define SOCK_EINTR EINTR
  65. # define SOCK_EADDRINUSE EADDRINUSE
  66. #else
  67. # include "win32/select.h"
  68. # define SOCK_EINVAL WSAEINVAL
  69. # define SOCK_EAGAIN WSAEWOULDBLOCK
  70. # define SOCK_EINTR WSAEINTR
  71. # define SOCK_EADDRINUSE WSAEADDRINUSE
  72. #endif
  73. #include "ext/standard/file.h" /* for php_set_sock_blocking() :-( */
  74. #include "zend_smart_str.h"
  75. #include "ext/standard/html.h"
  76. #include "ext/standard/url.h" /* for php_raw_url_decode() */
  77. #include "ext/standard/php_string.h" /* for php_dirname() */
  78. #include "ext/date/php_date.h" /* for php_format_date() */
  79. #include "php_network.h"
  80. #include "php_http_parser.h"
  81. #include "php_cli_server.h"
  82. #include "mime_type_map.h"
  83. #include "php_cli_process_title.h"
  84. #define OUTPUT_NOT_CHECKED -1
  85. #define OUTPUT_IS_TTY 1
  86. #define OUTPUT_NOT_TTY 0
  87. #if HAVE_FORK
  88. # include <sys/wait.h>
  89. static pid_t php_cli_server_master;
  90. static pid_t *php_cli_server_workers;
  91. static zend_long php_cli_server_workers_max;
  92. #endif
  93. typedef struct php_cli_server_poller {
  94. fd_set rfds, wfds;
  95. struct {
  96. fd_set rfds, wfds;
  97. } active;
  98. php_socket_t max_fd;
  99. } php_cli_server_poller;
  100. typedef struct php_cli_server_request {
  101. enum php_http_method request_method;
  102. int protocol_version;
  103. char *request_uri;
  104. size_t request_uri_len;
  105. char *vpath;
  106. size_t vpath_len;
  107. char *path_translated;
  108. size_t path_translated_len;
  109. char *path_info;
  110. size_t path_info_len;
  111. char *query_string;
  112. size_t query_string_len;
  113. HashTable headers;
  114. HashTable headers_original_case;
  115. char *content;
  116. size_t content_len;
  117. const char *ext;
  118. size_t ext_len;
  119. zend_stat_t sb;
  120. } php_cli_server_request;
  121. typedef struct php_cli_server_chunk {
  122. struct php_cli_server_chunk *next;
  123. enum php_cli_server_chunk_type {
  124. PHP_CLI_SERVER_CHUNK_HEAP,
  125. PHP_CLI_SERVER_CHUNK_IMMORTAL
  126. } type;
  127. union {
  128. struct { void *block; char *p; size_t len; } heap;
  129. struct { const char *p; size_t len; } immortal;
  130. } data;
  131. } php_cli_server_chunk;
  132. typedef struct php_cli_server_buffer {
  133. php_cli_server_chunk *first;
  134. php_cli_server_chunk *last;
  135. } php_cli_server_buffer;
  136. typedef struct php_cli_server_content_sender {
  137. php_cli_server_buffer buffer;
  138. } php_cli_server_content_sender;
  139. typedef struct php_cli_server_client {
  140. struct php_cli_server *server;
  141. php_socket_t sock;
  142. struct sockaddr *addr;
  143. socklen_t addr_len;
  144. char *addr_str;
  145. size_t addr_str_len;
  146. php_http_parser parser;
  147. unsigned int request_read:1;
  148. char *current_header_name;
  149. size_t current_header_name_len;
  150. unsigned int current_header_name_allocated:1;
  151. char *current_header_value;
  152. size_t current_header_value_len;
  153. enum { HEADER_NONE=0, HEADER_FIELD, HEADER_VALUE } last_header_element;
  154. size_t post_read_offset;
  155. php_cli_server_request request;
  156. unsigned int content_sender_initialized:1;
  157. php_cli_server_content_sender content_sender;
  158. int file_fd;
  159. } php_cli_server_client;
  160. typedef struct php_cli_server {
  161. php_socket_t server_sock;
  162. php_cli_server_poller poller;
  163. int is_running;
  164. char *host;
  165. int port;
  166. int address_family;
  167. char *document_root;
  168. size_t document_root_len;
  169. char *router;
  170. size_t router_len;
  171. socklen_t socklen;
  172. HashTable clients;
  173. HashTable extension_mime_types;
  174. } php_cli_server;
  175. typedef struct php_cli_server_http_response_status_code_pair {
  176. int code;
  177. const char *str;
  178. } php_cli_server_http_response_status_code_pair;
  179. static php_cli_server_http_response_status_code_pair template_map[] = {
  180. { 400, "<h1>%s</h1><p>Your browser sent a request that this server could not understand.</p>" },
  181. { 404, "<h1>%s</h1><p>The requested resource <code class=\"url\">%s</code> was not found on this server.</p>" },
  182. { 500, "<h1>%s</h1><p>The server is temporarily unavailable.</p>" },
  183. { 501, "<h1>%s</h1><p>Request method not supported.</p>" }
  184. };
  185. #define PHP_CLI_SERVER_LOG_PROCESS 1
  186. #define PHP_CLI_SERVER_LOG_ERROR 2
  187. #define PHP_CLI_SERVER_LOG_MESSAGE 3
  188. static int php_cli_server_log_level = 3;
  189. #if HAVE_UNISTD_H
  190. static int php_cli_output_is_tty = OUTPUT_NOT_CHECKED;
  191. #endif
  192. static const char php_cli_server_request_error_unexpected_eof[] = "Unexpected EOF";
  193. static size_t php_cli_server_client_send_through(php_cli_server_client *client, const char *str, size_t str_len);
  194. static php_cli_server_chunk *php_cli_server_chunk_heap_new_self_contained(size_t len);
  195. static void php_cli_server_buffer_append(php_cli_server_buffer *buffer, php_cli_server_chunk *chunk);
  196. static void php_cli_server_logf(int type, const char *format, ...);
  197. static void php_cli_server_log_response(php_cli_server_client *client, int status, const char *message);
  198. ZEND_DECLARE_MODULE_GLOBALS(cli_server)
  199. /* {{{ static char php_cli_server_css[]
  200. * copied from ext/standard/info.c
  201. */
  202. static const char php_cli_server_css[] = "<style>\n" \
  203. "body { background-color: #fcfcfc; color: #333333; margin: 0; padding:0; }\n" \
  204. "h1 { font-size: 1.5em; font-weight: normal; background-color: #9999cc; min-height:2em; line-height:2em; border-bottom: 1px inset black; margin: 0; }\n" \
  205. "h1, p { padding-left: 10px; }\n" \
  206. "code.url { background-color: #eeeeee; font-family:monospace; padding:0 2px;}\n" \
  207. "</style>\n";
  208. /* }}} */
  209. #ifdef PHP_WIN32
  210. int php_cli_server_get_system_time(char *buf) {
  211. struct _timeb system_time;
  212. errno_t err;
  213. if (buf == NULL) {
  214. return -1;
  215. }
  216. _ftime(&system_time);
  217. err = ctime_s(buf, 52, &(system_time.time) );
  218. if (err) {
  219. return -1;
  220. }
  221. return 0;
  222. }
  223. #else
  224. int php_cli_server_get_system_time(char *buf) {
  225. struct timeval tv;
  226. struct tm tm;
  227. gettimeofday(&tv, NULL);
  228. /* TODO: should be checked for NULL tm/return value */
  229. php_localtime_r(&tv.tv_sec, &tm);
  230. php_asctime_r(&tm, buf);
  231. return 0;
  232. }
  233. #endif
  234. static void char_ptr_dtor_p(zval *zv) /* {{{ */
  235. {
  236. pefree(Z_PTR_P(zv), 1);
  237. } /* }}} */
  238. static char *get_last_error() /* {{{ */
  239. {
  240. return pestrdup(strerror(errno), 1);
  241. } /* }}} */
  242. static int status_comp(const void *a, const void *b) /* {{{ */
  243. {
  244. const http_response_status_code_pair *pa = (const http_response_status_code_pair *) a;
  245. const http_response_status_code_pair *pb = (const http_response_status_code_pair *) b;
  246. if (pa->code < pb->code) {
  247. return -1;
  248. } else if (pa->code > pb->code) {
  249. return 1;
  250. }
  251. return 0;
  252. } /* }}} */
  253. static const char *get_status_string(int code) /* {{{ */
  254. {
  255. http_response_status_code_pair needle = {code, NULL},
  256. *result = NULL;
  257. result = bsearch(&needle, http_status_map, http_status_map_len, sizeof(needle), status_comp);
  258. if (result) {
  259. return result->str;
  260. }
  261. /* Returning NULL would require complicating append_http_status_line() to
  262. * not segfault in that case, so let's just return a placeholder, since RFC
  263. * 2616 requires a reason phrase. This is basically what a lot of other Web
  264. * servers do in this case anyway. */
  265. return "Unknown Status Code";
  266. } /* }}} */
  267. static const char *get_template_string(int code) /* {{{ */
  268. {
  269. size_t e = (sizeof(template_map) / sizeof(php_cli_server_http_response_status_code_pair));
  270. size_t s = 0;
  271. while (e != s) {
  272. size_t c = MIN((e + s + 1) / 2, e - 1);
  273. int d = template_map[c].code;
  274. if (d > code) {
  275. e = c;
  276. } else if (d < code) {
  277. s = c;
  278. } else {
  279. return template_map[c].str;
  280. }
  281. }
  282. return NULL;
  283. } /* }}} */
  284. static void append_http_status_line(smart_str *buffer, int protocol_version, int response_code, int persistent) /* {{{ */
  285. {
  286. if (!response_code) {
  287. response_code = 200;
  288. }
  289. smart_str_appendl_ex(buffer, "HTTP", 4, persistent);
  290. smart_str_appendc_ex(buffer, '/', persistent);
  291. smart_str_append_long_ex(buffer, protocol_version / 100, persistent);
  292. smart_str_appendc_ex(buffer, '.', persistent);
  293. smart_str_append_long_ex(buffer, protocol_version % 100, persistent);
  294. smart_str_appendc_ex(buffer, ' ', persistent);
  295. smart_str_append_long_ex(buffer, response_code, persistent);
  296. smart_str_appendc_ex(buffer, ' ', persistent);
  297. smart_str_appends_ex(buffer, get_status_string(response_code), persistent);
  298. smart_str_appendl_ex(buffer, "\r\n", 2, persistent);
  299. } /* }}} */
  300. static void append_essential_headers(smart_str* buffer, php_cli_server_client *client, int persistent) /* {{{ */
  301. {
  302. char *val;
  303. struct timeval tv = {0};
  304. if (NULL != (val = zend_hash_str_find_ptr(&client->request.headers, "host", sizeof("host")-1))) {
  305. smart_str_appends_ex(buffer, "Host: ", persistent);
  306. smart_str_appends_ex(buffer, val, persistent);
  307. smart_str_appends_ex(buffer, "\r\n", persistent);
  308. }
  309. if (!gettimeofday(&tv, NULL)) {
  310. zend_string *dt = php_format_date("D, d M Y H:i:s", sizeof("D, d M Y H:i:s") - 1, tv.tv_sec, 0);
  311. smart_str_appends_ex(buffer, "Date: ", persistent);
  312. smart_str_appends_ex(buffer, dt->val, persistent);
  313. smart_str_appends_ex(buffer, " GMT\r\n", persistent);
  314. zend_string_release_ex(dt, 0);
  315. }
  316. smart_str_appendl_ex(buffer, "Connection: close\r\n", sizeof("Connection: close\r\n") - 1, persistent);
  317. } /* }}} */
  318. static const char *get_mime_type(const php_cli_server *server, const char *ext, size_t ext_len) /* {{{ */
  319. {
  320. return (const char*)zend_hash_str_find_ptr(&server->extension_mime_types, ext, ext_len);
  321. } /* }}} */
  322. PHP_FUNCTION(apache_request_headers) /* {{{ */
  323. {
  324. php_cli_server_client *client;
  325. HashTable *headers;
  326. zend_string *key;
  327. char *value;
  328. zval tmp;
  329. if (zend_parse_parameters_none() == FAILURE) {
  330. RETURN_THROWS();
  331. }
  332. client = SG(server_context);
  333. headers = &client->request.headers_original_case;
  334. array_init_size(return_value, zend_hash_num_elements(headers));
  335. ZEND_HASH_FOREACH_STR_KEY_PTR(headers, key, value) {
  336. ZVAL_STRING(&tmp, value);
  337. zend_symtable_update(Z_ARRVAL_P(return_value), key, &tmp);
  338. } ZEND_HASH_FOREACH_END();
  339. }
  340. /* }}} */
  341. static void add_response_header(sapi_header_struct *h, zval *return_value) /* {{{ */
  342. {
  343. char *s, *p;
  344. ptrdiff_t len;
  345. ALLOCA_FLAG(use_heap)
  346. if (h->header_len > 0) {
  347. p = strchr(h->header, ':');
  348. len = p - h->header;
  349. if (p && (len > 0)) {
  350. while (len > 0 && (h->header[len-1] == ' ' || h->header[len-1] == '\t')) {
  351. len--;
  352. }
  353. if (len) {
  354. s = do_alloca(len + 1, use_heap);
  355. memcpy(s, h->header, len);
  356. s[len] = 0;
  357. do {
  358. p++;
  359. } while (*p == ' ' || *p == '\t');
  360. add_assoc_stringl_ex(return_value, s, (uint32_t)len, p, h->header_len - (p - h->header));
  361. free_alloca(s, use_heap);
  362. }
  363. }
  364. }
  365. }
  366. /* }}} */
  367. PHP_FUNCTION(apache_response_headers) /* {{{ */
  368. {
  369. if (zend_parse_parameters_none() == FAILURE) {
  370. RETURN_THROWS();
  371. }
  372. array_init(return_value);
  373. zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t)add_response_header, return_value);
  374. }
  375. /* }}} */
  376. /* {{{ cli_server module
  377. */
  378. static void cli_server_init_globals(zend_cli_server_globals *cg)
  379. {
  380. cg->color = 0;
  381. }
  382. PHP_INI_BEGIN()
  383. STD_PHP_INI_BOOLEAN("cli_server.color", "0", PHP_INI_ALL, OnUpdateBool, color, zend_cli_server_globals, cli_server_globals)
  384. PHP_INI_END()
  385. static PHP_MINIT_FUNCTION(cli_server)
  386. {
  387. ZEND_INIT_MODULE_GLOBALS(cli_server, cli_server_init_globals, NULL);
  388. REGISTER_INI_ENTRIES();
  389. return SUCCESS;
  390. }
  391. static PHP_MSHUTDOWN_FUNCTION(cli_server)
  392. {
  393. UNREGISTER_INI_ENTRIES();
  394. return SUCCESS;
  395. }
  396. static PHP_MINFO_FUNCTION(cli_server)
  397. {
  398. DISPLAY_INI_ENTRIES();
  399. }
  400. zend_module_entry cli_server_module_entry = {
  401. STANDARD_MODULE_HEADER,
  402. "cli_server",
  403. NULL,
  404. PHP_MINIT(cli_server),
  405. PHP_MSHUTDOWN(cli_server),
  406. NULL,
  407. NULL,
  408. PHP_MINFO(cli_server),
  409. PHP_VERSION,
  410. STANDARD_MODULE_PROPERTIES
  411. };
  412. /* }}} */
  413. ZEND_BEGIN_ARG_INFO(arginfo_no_args, 0)
  414. ZEND_END_ARG_INFO()
  415. const zend_function_entry server_additional_functions[] = {
  416. PHP_FE(cli_set_process_title, arginfo_cli_set_process_title)
  417. PHP_FE(cli_get_process_title, arginfo_cli_get_process_title)
  418. PHP_FE(apache_request_headers, arginfo_no_args)
  419. PHP_FE(apache_response_headers, arginfo_no_args)
  420. PHP_FALIAS(getallheaders, apache_request_headers, arginfo_no_args)
  421. PHP_FE_END
  422. };
  423. static int sapi_cli_server_startup(sapi_module_struct *sapi_module) /* {{{ */
  424. {
  425. char *workers;
  426. if (php_module_startup(sapi_module, &cli_server_module_entry, 1) == FAILURE) {
  427. return FAILURE;
  428. }
  429. if ((workers = getenv("PHP_CLI_SERVER_WORKERS"))) {
  430. #ifndef SO_REUSEPORT
  431. fprintf(stderr, "platform does not support SO_REUSEPORT, cannot create workers\n");
  432. #elif HAVE_FORK
  433. ZEND_ATOL(php_cli_server_workers_max, workers);
  434. if (php_cli_server_workers_max > 1) {
  435. zend_long php_cli_server_worker;
  436. php_cli_server_workers = calloc(
  437. php_cli_server_workers_max, sizeof(pid_t));
  438. if (!php_cli_server_workers) {
  439. php_cli_server_workers_max = 1;
  440. return SUCCESS;
  441. }
  442. php_cli_server_master = getpid();
  443. for (php_cli_server_worker = 0;
  444. php_cli_server_worker < php_cli_server_workers_max;
  445. php_cli_server_worker++) {
  446. pid_t pid = fork();
  447. if (pid == FAILURE) {
  448. /* no more forks allowed, work with what we have ... */
  449. php_cli_server_workers_max =
  450. php_cli_server_worker + 1;
  451. return SUCCESS;
  452. } else if (pid == SUCCESS) {
  453. return SUCCESS;
  454. } else {
  455. php_cli_server_workers[
  456. php_cli_server_worker
  457. ] = pid;
  458. }
  459. }
  460. } else {
  461. fprintf(stderr, "number of workers must be larger than 1\n");
  462. }
  463. #else
  464. fprintf(stderr, "forking is not supported on this platform\n");
  465. #endif
  466. }
  467. return SUCCESS;
  468. } /* }}} */
  469. static size_t sapi_cli_server_ub_write(const char *str, size_t str_length) /* {{{ */
  470. {
  471. php_cli_server_client *client = SG(server_context);
  472. if (!client) {
  473. return 0;
  474. }
  475. return php_cli_server_client_send_through(client, str, str_length);
  476. } /* }}} */
  477. static void sapi_cli_server_flush(void *server_context) /* {{{ */
  478. {
  479. php_cli_server_client *client = server_context;
  480. if (!client) {
  481. return;
  482. }
  483. if (!ZEND_VALID_SOCKET(client->sock)) {
  484. php_handle_aborted_connection();
  485. return;
  486. }
  487. if (!SG(headers_sent)) {
  488. sapi_send_headers();
  489. SG(headers_sent) = 1;
  490. }
  491. } /* }}} */
  492. static int sapi_cli_server_discard_headers(sapi_headers_struct *sapi_headers) /* {{{ */{
  493. return SAPI_HEADER_SENT_SUCCESSFULLY;
  494. }
  495. /* }}} */
  496. static int sapi_cli_server_send_headers(sapi_headers_struct *sapi_headers) /* {{{ */
  497. {
  498. php_cli_server_client *client = SG(server_context);
  499. smart_str buffer = { 0 };
  500. sapi_header_struct *h;
  501. zend_llist_position pos;
  502. if (client == NULL || SG(request_info).no_headers) {
  503. return SAPI_HEADER_SENT_SUCCESSFULLY;
  504. }
  505. if (SG(sapi_headers).http_status_line) {
  506. smart_str_appends(&buffer, SG(sapi_headers).http_status_line);
  507. smart_str_appendl(&buffer, "\r\n", 2);
  508. } else {
  509. append_http_status_line(&buffer, client->request.protocol_version, SG(sapi_headers).http_response_code, 0);
  510. }
  511. append_essential_headers(&buffer, client, 0);
  512. h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
  513. while (h) {
  514. if (h->header_len) {
  515. smart_str_appendl(&buffer, h->header, h->header_len);
  516. smart_str_appendl(&buffer, "\r\n", 2);
  517. }
  518. h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
  519. }
  520. smart_str_appendl(&buffer, "\r\n", 2);
  521. php_cli_server_client_send_through(client, ZSTR_VAL(buffer.s), ZSTR_LEN(buffer.s));
  522. smart_str_free(&buffer);
  523. return SAPI_HEADER_SENT_SUCCESSFULLY;
  524. }
  525. /* }}} */
  526. static char *sapi_cli_server_read_cookies(void) /* {{{ */
  527. {
  528. php_cli_server_client *client = SG(server_context);
  529. char *val;
  530. if (NULL == (val = zend_hash_str_find_ptr(&client->request.headers, "cookie", sizeof("cookie")-1))) {
  531. return NULL;
  532. }
  533. return val;
  534. } /* }}} */
  535. static size_t sapi_cli_server_read_post(char *buf, size_t count_bytes) /* {{{ */
  536. {
  537. php_cli_server_client *client = SG(server_context);
  538. if (client->request.content) {
  539. size_t content_len = client->request.content_len;
  540. size_t nbytes_copied = MIN(client->post_read_offset + count_bytes, content_len) - client->post_read_offset;
  541. memmove(buf, client->request.content + client->post_read_offset, nbytes_copied);
  542. client->post_read_offset += nbytes_copied;
  543. return nbytes_copied;
  544. }
  545. return 0;
  546. } /* }}} */
  547. static void sapi_cli_server_register_variable(zval *track_vars_array, const char *key, const char *val) /* {{{ */
  548. {
  549. char *new_val = (char *)val;
  550. size_t new_val_len;
  551. if (NULL == val) {
  552. return;
  553. }
  554. if (sapi_module.input_filter(PARSE_SERVER, (char*)key, &new_val, strlen(val), &new_val_len)) {
  555. php_register_variable_safe((char *)key, new_val, new_val_len, track_vars_array);
  556. }
  557. } /* }}} */
  558. static int sapi_cli_server_register_entry_cb(char **entry, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ {
  559. zval *track_vars_array = va_arg(args, zval *);
  560. if (hash_key->key) {
  561. char *real_key, *key;
  562. uint32_t i;
  563. key = estrndup(ZSTR_VAL(hash_key->key), ZSTR_LEN(hash_key->key));
  564. for(i=0; i<ZSTR_LEN(hash_key->key); i++) {
  565. if (key[i] == '-') {
  566. key[i] = '_';
  567. } else {
  568. key[i] = toupper(key[i]);
  569. }
  570. }
  571. spprintf(&real_key, 0, "%s_%s", "HTTP", key);
  572. if (strcmp(key, "CONTENT_TYPE") == 0 || strcmp(key, "CONTENT_LENGTH") == 0) {
  573. sapi_cli_server_register_variable(track_vars_array, key, *entry);
  574. }
  575. sapi_cli_server_register_variable(track_vars_array, real_key, *entry);
  576. efree(key);
  577. efree(real_key);
  578. }
  579. return ZEND_HASH_APPLY_KEEP;
  580. }
  581. /* }}} */
  582. static void sapi_cli_server_register_variables(zval *track_vars_array) /* {{{ */
  583. {
  584. php_cli_server_client *client = SG(server_context);
  585. sapi_cli_server_register_variable(track_vars_array, "DOCUMENT_ROOT", client->server->document_root);
  586. {
  587. char *tmp;
  588. if ((tmp = strrchr(client->addr_str, ':'))) {
  589. char addr[64], port[8];
  590. const char *addr_start = client->addr_str, *addr_end = tmp;
  591. if (addr_start[0] == '[') addr_start++;
  592. if (addr_end[-1] == ']') addr_end--;
  593. strncpy(port, tmp + 1, 8);
  594. port[7] = '\0';
  595. strncpy(addr, addr_start, addr_end - addr_start);
  596. addr[addr_end - addr_start] = '\0';
  597. sapi_cli_server_register_variable(track_vars_array, "REMOTE_ADDR", addr);
  598. sapi_cli_server_register_variable(track_vars_array, "REMOTE_PORT", port);
  599. } else {
  600. sapi_cli_server_register_variable(track_vars_array, "REMOTE_ADDR", client->addr_str);
  601. }
  602. }
  603. {
  604. char *tmp;
  605. spprintf(&tmp, 0, "PHP %s Development Server", PHP_VERSION);
  606. sapi_cli_server_register_variable(track_vars_array, "SERVER_SOFTWARE", tmp);
  607. efree(tmp);
  608. }
  609. {
  610. char *tmp;
  611. spprintf(&tmp, 0, "HTTP/%d.%d", client->request.protocol_version / 100, client->request.protocol_version % 100);
  612. sapi_cli_server_register_variable(track_vars_array, "SERVER_PROTOCOL", tmp);
  613. efree(tmp);
  614. }
  615. sapi_cli_server_register_variable(track_vars_array, "SERVER_NAME", client->server->host);
  616. {
  617. char *tmp;
  618. spprintf(&tmp, 0, "%i", client->server->port);
  619. sapi_cli_server_register_variable(track_vars_array, "SERVER_PORT", tmp);
  620. efree(tmp);
  621. }
  622. sapi_cli_server_register_variable(track_vars_array, "REQUEST_URI", client->request.request_uri);
  623. sapi_cli_server_register_variable(track_vars_array, "REQUEST_METHOD", SG(request_info).request_method);
  624. sapi_cli_server_register_variable(track_vars_array, "SCRIPT_NAME", client->request.vpath);
  625. if (SG(request_info).path_translated) {
  626. sapi_cli_server_register_variable(track_vars_array, "SCRIPT_FILENAME", SG(request_info).path_translated);
  627. } else if (client->server->router) {
  628. sapi_cli_server_register_variable(track_vars_array, "SCRIPT_FILENAME", client->server->router);
  629. }
  630. if (client->request.path_info) {
  631. sapi_cli_server_register_variable(track_vars_array, "PATH_INFO", client->request.path_info);
  632. }
  633. if (client->request.path_info_len) {
  634. char *tmp;
  635. spprintf(&tmp, 0, "%s%s", client->request.vpath, client->request.path_info);
  636. sapi_cli_server_register_variable(track_vars_array, "PHP_SELF", tmp);
  637. efree(tmp);
  638. } else {
  639. sapi_cli_server_register_variable(track_vars_array, "PHP_SELF", client->request.vpath);
  640. }
  641. if (client->request.query_string) {
  642. sapi_cli_server_register_variable(track_vars_array, "QUERY_STRING", client->request.query_string);
  643. }
  644. zend_hash_apply_with_arguments(&client->request.headers, (apply_func_args_t)sapi_cli_server_register_entry_cb, 1, track_vars_array);
  645. } /* }}} */
  646. static void sapi_cli_server_log_write(int type, char *msg) /* {{{ */
  647. {
  648. char buf[52];
  649. if (php_cli_server_log_level < type) {
  650. return;
  651. }
  652. if (php_cli_server_get_system_time(buf) != 0) {
  653. memmove(buf, "unknown time, can't be fetched", sizeof("unknown time, can't be fetched"));
  654. } else {
  655. size_t l = strlen(buf);
  656. if (l > 0) {
  657. buf[l - 1] = '\0';
  658. } else {
  659. memmove(buf, "unknown", sizeof("unknown"));
  660. }
  661. }
  662. #ifdef HAVE_FORK
  663. if (php_cli_server_workers_max > 1) {
  664. fprintf(stderr, "[%ld] [%s] %s\n", (long) getpid(), buf, msg);
  665. } else {
  666. fprintf(stderr, "[%s] %s\n", buf, msg);
  667. }
  668. #else
  669. fprintf(stderr, "[%s] %s\n", buf, msg);
  670. #endif
  671. } /* }}} */
  672. static void sapi_cli_server_log_message(char *msg, int syslog_type_int) /* {{{ */
  673. {
  674. sapi_cli_server_log_write(PHP_CLI_SERVER_LOG_MESSAGE, msg);
  675. } /* }}} */
  676. /* {{{ sapi_module_struct cli_server_sapi_module
  677. */
  678. sapi_module_struct cli_server_sapi_module = {
  679. "cli-server", /* name */
  680. "Built-in HTTP server", /* pretty name */
  681. sapi_cli_server_startup, /* startup */
  682. php_module_shutdown_wrapper, /* shutdown */
  683. NULL, /* activate */
  684. NULL, /* deactivate */
  685. sapi_cli_server_ub_write, /* unbuffered write */
  686. sapi_cli_server_flush, /* flush */
  687. NULL, /* get uid */
  688. NULL, /* getenv */
  689. php_error, /* error handler */
  690. NULL, /* header handler */
  691. sapi_cli_server_send_headers, /* send headers handler */
  692. NULL, /* send header handler */
  693. sapi_cli_server_read_post, /* read POST data */
  694. sapi_cli_server_read_cookies, /* read Cookies */
  695. sapi_cli_server_register_variables, /* register server variables */
  696. sapi_cli_server_log_message, /* Log message */
  697. NULL, /* Get request time */
  698. NULL, /* Child terminate */
  699. STANDARD_SAPI_MODULE_PROPERTIES
  700. }; /* }}} */
  701. static int php_cli_server_poller_ctor(php_cli_server_poller *poller) /* {{{ */
  702. {
  703. FD_ZERO(&poller->rfds);
  704. FD_ZERO(&poller->wfds);
  705. poller->max_fd = -1;
  706. return SUCCESS;
  707. } /* }}} */
  708. static void php_cli_server_poller_add(php_cli_server_poller *poller, int mode, php_socket_t fd) /* {{{ */
  709. {
  710. if (mode & POLLIN) {
  711. PHP_SAFE_FD_SET(fd, &poller->rfds);
  712. }
  713. if (mode & POLLOUT) {
  714. PHP_SAFE_FD_SET(fd, &poller->wfds);
  715. }
  716. if (fd > poller->max_fd) {
  717. poller->max_fd = fd;
  718. }
  719. } /* }}} */
  720. static void php_cli_server_poller_remove(php_cli_server_poller *poller, int mode, php_socket_t fd) /* {{{ */
  721. {
  722. if (mode & POLLIN) {
  723. PHP_SAFE_FD_CLR(fd, &poller->rfds);
  724. }
  725. if (mode & POLLOUT) {
  726. PHP_SAFE_FD_CLR(fd, &poller->wfds);
  727. }
  728. #ifndef PHP_WIN32
  729. if (fd == poller->max_fd) {
  730. while (fd > 0) {
  731. fd--;
  732. if (PHP_SAFE_FD_ISSET(fd, &poller->rfds) || PHP_SAFE_FD_ISSET(fd, &poller->wfds)) {
  733. break;
  734. }
  735. }
  736. poller->max_fd = fd;
  737. }
  738. #endif
  739. } /* }}} */
  740. static int php_cli_server_poller_poll(php_cli_server_poller *poller, struct timeval *tv) /* {{{ */
  741. {
  742. memmove(&poller->active.rfds, &poller->rfds, sizeof(poller->rfds));
  743. memmove(&poller->active.wfds, &poller->wfds, sizeof(poller->wfds));
  744. return php_select(poller->max_fd + 1, &poller->active.rfds, &poller->active.wfds, NULL, tv);
  745. } /* }}} */
  746. static int php_cli_server_poller_iter_on_active(php_cli_server_poller *poller, void *opaque, int(*callback)(void *, php_socket_t fd, int events)) /* {{{ */
  747. {
  748. int retval = SUCCESS;
  749. #ifdef PHP_WIN32
  750. struct socket_entry {
  751. SOCKET fd;
  752. int events;
  753. } entries[FD_SETSIZE * 2];
  754. size_t i;
  755. struct socket_entry *n = entries, *m;
  756. for (i = 0; i < poller->active.rfds.fd_count; i++) {
  757. n->events = POLLIN;
  758. n->fd = poller->active.rfds.fd_array[i];
  759. n++;
  760. }
  761. m = n;
  762. for (i = 0; i < poller->active.wfds.fd_count; i++) {
  763. struct socket_entry *e;
  764. SOCKET fd = poller->active.wfds.fd_array[i];
  765. for (e = entries; e < m; e++) {
  766. if (e->fd == fd) {
  767. e->events |= POLLOUT;
  768. }
  769. }
  770. if (e == m) {
  771. assert(n < entries + FD_SETSIZE * 2);
  772. n->events = POLLOUT;
  773. n->fd = fd;
  774. n++;
  775. }
  776. }
  777. {
  778. struct socket_entry *e = entries;
  779. for (; e < n; e++) {
  780. if (SUCCESS != callback(opaque, e->fd, e->events)) {
  781. retval = FAILURE;
  782. }
  783. }
  784. }
  785. #else
  786. php_socket_t fd;
  787. const php_socket_t max_fd = poller->max_fd;
  788. for (fd=0 ; fd<=max_fd ; fd++) {
  789. if (PHP_SAFE_FD_ISSET(fd, &poller->active.rfds)) {
  790. if (SUCCESS != callback(opaque, fd, POLLIN)) {
  791. retval = FAILURE;
  792. }
  793. }
  794. if (PHP_SAFE_FD_ISSET(fd, &poller->active.wfds)) {
  795. if (SUCCESS != callback(opaque, fd, POLLOUT)) {
  796. retval = FAILURE;
  797. }
  798. }
  799. }
  800. #endif
  801. return retval;
  802. } /* }}} */
  803. static size_t php_cli_server_chunk_size(const php_cli_server_chunk *chunk) /* {{{ */
  804. {
  805. switch (chunk->type) {
  806. case PHP_CLI_SERVER_CHUNK_HEAP:
  807. return chunk->data.heap.len;
  808. case PHP_CLI_SERVER_CHUNK_IMMORTAL:
  809. return chunk->data.immortal.len;
  810. }
  811. return 0;
  812. } /* }}} */
  813. static void php_cli_server_chunk_dtor(php_cli_server_chunk *chunk) /* {{{ */
  814. {
  815. switch (chunk->type) {
  816. case PHP_CLI_SERVER_CHUNK_HEAP:
  817. if (chunk->data.heap.block != chunk) {
  818. pefree(chunk->data.heap.block, 1);
  819. }
  820. break;
  821. case PHP_CLI_SERVER_CHUNK_IMMORTAL:
  822. break;
  823. }
  824. } /* }}} */
  825. static void php_cli_server_buffer_dtor(php_cli_server_buffer *buffer) /* {{{ */
  826. {
  827. php_cli_server_chunk *chunk, *next;
  828. for (chunk = buffer->first; chunk; chunk = next) {
  829. next = chunk->next;
  830. php_cli_server_chunk_dtor(chunk);
  831. pefree(chunk, 1);
  832. }
  833. } /* }}} */
  834. static void php_cli_server_buffer_ctor(php_cli_server_buffer *buffer) /* {{{ */
  835. {
  836. buffer->first = NULL;
  837. buffer->last = NULL;
  838. } /* }}} */
  839. static void php_cli_server_buffer_append(php_cli_server_buffer *buffer, php_cli_server_chunk *chunk) /* {{{ */
  840. {
  841. php_cli_server_chunk *last;
  842. for (last = chunk; last->next; last = last->next);
  843. if (!buffer->last) {
  844. buffer->first = chunk;
  845. } else {
  846. buffer->last->next = chunk;
  847. }
  848. buffer->last = last;
  849. } /* }}} */
  850. static void php_cli_server_buffer_prepend(php_cli_server_buffer *buffer, php_cli_server_chunk *chunk) /* {{{ */
  851. {
  852. php_cli_server_chunk *last;
  853. for (last = chunk; last->next; last = last->next);
  854. last->next = buffer->first;
  855. if (!buffer->last) {
  856. buffer->last = last;
  857. }
  858. buffer->first = chunk;
  859. } /* }}} */
  860. static size_t php_cli_server_buffer_size(const php_cli_server_buffer *buffer) /* {{{ */
  861. {
  862. php_cli_server_chunk *chunk;
  863. size_t retval = 0;
  864. for (chunk = buffer->first; chunk; chunk = chunk->next) {
  865. retval += php_cli_server_chunk_size(chunk);
  866. }
  867. return retval;
  868. } /* }}} */
  869. static php_cli_server_chunk *php_cli_server_chunk_immortal_new(const char *buf, size_t len) /* {{{ */
  870. {
  871. php_cli_server_chunk *chunk = pemalloc(sizeof(php_cli_server_chunk), 1);
  872. chunk->type = PHP_CLI_SERVER_CHUNK_IMMORTAL;
  873. chunk->next = NULL;
  874. chunk->data.immortal.p = buf;
  875. chunk->data.immortal.len = len;
  876. return chunk;
  877. } /* }}} */
  878. static php_cli_server_chunk *php_cli_server_chunk_heap_new(void *block, char *buf, size_t len) /* {{{ */
  879. {
  880. php_cli_server_chunk *chunk = pemalloc(sizeof(php_cli_server_chunk), 1);
  881. chunk->type = PHP_CLI_SERVER_CHUNK_HEAP;
  882. chunk->next = NULL;
  883. chunk->data.heap.block = block;
  884. chunk->data.heap.p = buf;
  885. chunk->data.heap.len = len;
  886. return chunk;
  887. } /* }}} */
  888. static php_cli_server_chunk *php_cli_server_chunk_heap_new_self_contained(size_t len) /* {{{ */
  889. {
  890. php_cli_server_chunk *chunk = pemalloc(sizeof(php_cli_server_chunk) + len, 1);
  891. chunk->type = PHP_CLI_SERVER_CHUNK_HEAP;
  892. chunk->next = NULL;
  893. chunk->data.heap.block = chunk;
  894. chunk->data.heap.p = (char *)(chunk + 1);
  895. chunk->data.heap.len = len;
  896. return chunk;
  897. } /* }}} */
  898. static void php_cli_server_content_sender_dtor(php_cli_server_content_sender *sender) /* {{{ */
  899. {
  900. php_cli_server_buffer_dtor(&sender->buffer);
  901. } /* }}} */
  902. static void php_cli_server_content_sender_ctor(php_cli_server_content_sender *sender) /* {{{ */
  903. {
  904. php_cli_server_buffer_ctor(&sender->buffer);
  905. } /* }}} */
  906. static int php_cli_server_content_sender_send(php_cli_server_content_sender *sender, php_socket_t fd, size_t *nbytes_sent_total) /* {{{ */
  907. {
  908. php_cli_server_chunk *chunk, *next;
  909. size_t _nbytes_sent_total = 0;
  910. for (chunk = sender->buffer.first; chunk; chunk = next) {
  911. #ifdef PHP_WIN32
  912. int nbytes_sent;
  913. #else
  914. ssize_t nbytes_sent;
  915. #endif
  916. next = chunk->next;
  917. switch (chunk->type) {
  918. case PHP_CLI_SERVER_CHUNK_HEAP:
  919. #ifdef PHP_WIN32
  920. nbytes_sent = send(fd, chunk->data.heap.p, (int)chunk->data.heap.len, 0);
  921. #else
  922. nbytes_sent = send(fd, chunk->data.heap.p, chunk->data.heap.len, 0);
  923. #endif
  924. if (nbytes_sent < 0) {
  925. *nbytes_sent_total = _nbytes_sent_total;
  926. return php_socket_errno();
  927. #ifdef PHP_WIN32
  928. } else if (nbytes_sent == chunk->data.heap.len) {
  929. #else
  930. } else if (nbytes_sent == (ssize_t)chunk->data.heap.len) {
  931. #endif
  932. php_cli_server_chunk_dtor(chunk);
  933. pefree(chunk, 1);
  934. sender->buffer.first = next;
  935. if (!next) {
  936. sender->buffer.last = NULL;
  937. }
  938. } else {
  939. chunk->data.heap.p += nbytes_sent;
  940. chunk->data.heap.len -= nbytes_sent;
  941. }
  942. _nbytes_sent_total += nbytes_sent;
  943. break;
  944. case PHP_CLI_SERVER_CHUNK_IMMORTAL:
  945. #ifdef PHP_WIN32
  946. nbytes_sent = send(fd, chunk->data.immortal.p, (int)chunk->data.immortal.len, 0);
  947. #else
  948. nbytes_sent = send(fd, chunk->data.immortal.p, chunk->data.immortal.len, 0);
  949. #endif
  950. if (nbytes_sent < 0) {
  951. *nbytes_sent_total = _nbytes_sent_total;
  952. return php_socket_errno();
  953. #ifdef PHP_WIN32
  954. } else if (nbytes_sent == chunk->data.immortal.len) {
  955. #else
  956. } else if (nbytes_sent == (ssize_t)chunk->data.immortal.len) {
  957. #endif
  958. php_cli_server_chunk_dtor(chunk);
  959. pefree(chunk, 1);
  960. sender->buffer.first = next;
  961. if (!next) {
  962. sender->buffer.last = NULL;
  963. }
  964. } else {
  965. chunk->data.immortal.p += nbytes_sent;
  966. chunk->data.immortal.len -= nbytes_sent;
  967. }
  968. _nbytes_sent_total += nbytes_sent;
  969. break;
  970. }
  971. }
  972. *nbytes_sent_total = _nbytes_sent_total;
  973. return 0;
  974. } /* }}} */
  975. static int php_cli_server_content_sender_pull(php_cli_server_content_sender *sender, int fd, size_t *nbytes_read) /* {{{ */
  976. {
  977. #ifdef PHP_WIN32
  978. int _nbytes_read;
  979. #else
  980. ssize_t _nbytes_read;
  981. #endif
  982. php_cli_server_chunk *chunk = php_cli_server_chunk_heap_new_self_contained(131072);
  983. #ifdef PHP_WIN32
  984. _nbytes_read = read(fd, chunk->data.heap.p, (unsigned int)chunk->data.heap.len);
  985. #else
  986. _nbytes_read = read(fd, chunk->data.heap.p, chunk->data.heap.len);
  987. #endif
  988. if (_nbytes_read < 0) {
  989. if (php_cli_server_log_level >= PHP_CLI_SERVER_LOG_ERROR) {
  990. char *errstr = get_last_error();
  991. php_cli_server_logf(PHP_CLI_SERVER_LOG_ERROR, "%s", errstr);
  992. pefree(errstr, 1);
  993. }
  994. php_cli_server_chunk_dtor(chunk);
  995. pefree(chunk, 1);
  996. return 1;
  997. }
  998. chunk->data.heap.len = _nbytes_read;
  999. php_cli_server_buffer_append(&sender->buffer, chunk);
  1000. *nbytes_read = _nbytes_read;
  1001. return 0;
  1002. } /* }}} */
  1003. #if HAVE_UNISTD_H
  1004. static int php_cli_is_output_tty() /* {{{ */
  1005. {
  1006. if (php_cli_output_is_tty == OUTPUT_NOT_CHECKED) {
  1007. php_cli_output_is_tty = isatty(STDOUT_FILENO);
  1008. }
  1009. return php_cli_output_is_tty;
  1010. } /* }}} */
  1011. #endif
  1012. static void php_cli_server_log_response(php_cli_server_client *client, int status, const char *message) /* {{{ */
  1013. {
  1014. int color = 0, effective_status = status;
  1015. char *basic_buf, *message_buf = "", *error_buf = "";
  1016. zend_bool append_error_message = 0;
  1017. if (PG(last_error_message)) {
  1018. switch (PG(last_error_type)) {
  1019. case E_ERROR:
  1020. case E_CORE_ERROR:
  1021. case E_COMPILE_ERROR:
  1022. case E_USER_ERROR:
  1023. case E_PARSE:
  1024. if (status == 200) {
  1025. /* the status code isn't changed by a fatal error, so fake it */
  1026. effective_status = 500;
  1027. }
  1028. append_error_message = 1;
  1029. break;
  1030. }
  1031. }
  1032. #if HAVE_UNISTD_H
  1033. if (CLI_SERVER_G(color) && php_cli_is_output_tty() == OUTPUT_IS_TTY) {
  1034. if (effective_status >= 500) {
  1035. /* server error: red */
  1036. color = 1;
  1037. } else if (effective_status >= 400) {
  1038. /* client error: yellow */
  1039. color = 3;
  1040. } else if (effective_status >= 200) {
  1041. /* success: green */
  1042. color = 2;
  1043. }
  1044. }
  1045. #endif
  1046. /* basic */
  1047. spprintf(&basic_buf, 0, "%s [%d]: %s %s", client->addr_str, status, SG(request_info).request_method, client->request.request_uri);
  1048. if (!basic_buf) {
  1049. return;
  1050. }
  1051. /* message */
  1052. if (message) {
  1053. spprintf(&message_buf, 0, " - %s", message);
  1054. if (!message_buf) {
  1055. efree(basic_buf);
  1056. return;
  1057. }
  1058. }
  1059. /* error */
  1060. if (append_error_message) {
  1061. spprintf(&error_buf, 0, " - %s in %s on line %d", PG(last_error_message), PG(last_error_file), PG(last_error_lineno));
  1062. if (!error_buf) {
  1063. efree(basic_buf);
  1064. if (message) {
  1065. efree(message_buf);
  1066. }
  1067. return;
  1068. }
  1069. }
  1070. if (color) {
  1071. php_cli_server_logf(PHP_CLI_SERVER_LOG_MESSAGE, "\x1b[3%dm%s%s%s\x1b[0m", color, basic_buf, message_buf, error_buf);
  1072. } else {
  1073. php_cli_server_logf(PHP_CLI_SERVER_LOG_MESSAGE, "%s%s%s", basic_buf, message_buf, error_buf);
  1074. }
  1075. efree(basic_buf);
  1076. if (message) {
  1077. efree(message_buf);
  1078. }
  1079. if (append_error_message) {
  1080. efree(error_buf);
  1081. }
  1082. } /* }}} */
  1083. static void php_cli_server_logf(int type, const char *format, ...) /* {{{ */
  1084. {
  1085. char *buf = NULL;
  1086. va_list ap;
  1087. if (php_cli_server_log_level < type) {
  1088. return;
  1089. }
  1090. va_start(ap, format);
  1091. vspprintf(&buf, 0, format, ap);
  1092. va_end(ap);
  1093. if (!buf) {
  1094. return;
  1095. }
  1096. sapi_cli_server_log_write(type, buf);
  1097. efree(buf);
  1098. } /* }}} */
  1099. static php_socket_t php_network_listen_socket(const char *host, int *port, int socktype, int *af, socklen_t *socklen, zend_string **errstr) /* {{{ */
  1100. {
  1101. php_socket_t retval = SOCK_ERR;
  1102. int err = 0;
  1103. struct sockaddr *sa = NULL, **p, **sal;
  1104. int num_addrs = php_network_getaddresses(host, socktype, &sal, errstr);
  1105. if (num_addrs == 0) {
  1106. return -1;
  1107. }
  1108. for (p = sal; *p; p++) {
  1109. if (sa) {
  1110. pefree(sa, 1);
  1111. sa = NULL;
  1112. }
  1113. retval = socket((*p)->sa_family, socktype, 0);
  1114. if (retval == SOCK_ERR) {
  1115. continue;
  1116. }
  1117. switch ((*p)->sa_family) {
  1118. #if HAVE_GETADDRINFO && HAVE_IPV6
  1119. case AF_INET6:
  1120. sa = pemalloc(sizeof(struct sockaddr_in6), 1);
  1121. *(struct sockaddr_in6 *)sa = *(struct sockaddr_in6 *)*p;
  1122. ((struct sockaddr_in6 *)sa)->sin6_port = htons(*port);
  1123. *socklen = sizeof(struct sockaddr_in6);
  1124. break;
  1125. #endif
  1126. case AF_INET:
  1127. sa = pemalloc(sizeof(struct sockaddr_in), 1);
  1128. *(struct sockaddr_in *)sa = *(struct sockaddr_in *)*p;
  1129. ((struct sockaddr_in *)sa)->sin_port = htons(*port);
  1130. *socklen = sizeof(struct sockaddr_in);
  1131. break;
  1132. default:
  1133. /* Unknown family */
  1134. *socklen = 0;
  1135. closesocket(retval);
  1136. continue;
  1137. }
  1138. #ifdef SO_REUSEADDR
  1139. {
  1140. int val = 1;
  1141. setsockopt(retval, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val));
  1142. }
  1143. #endif
  1144. #if defined(HAVE_FORK) && defined(SO_REUSEPORT)
  1145. if (php_cli_server_workers_max > 1) {
  1146. int val = 1;
  1147. setsockopt(retval, SOL_SOCKET, SO_REUSEPORT, (char*)&val, sizeof(val));
  1148. }
  1149. #endif
  1150. if (bind(retval, sa, *socklen) == SOCK_CONN_ERR) {
  1151. err = php_socket_errno();
  1152. if (err == SOCK_EINVAL || err == SOCK_EADDRINUSE) {
  1153. goto out;
  1154. }
  1155. closesocket(retval);
  1156. retval = SOCK_ERR;
  1157. continue;
  1158. }
  1159. err = 0;
  1160. *af = sa->sa_family;
  1161. if (*port == 0) {
  1162. if (getsockname(retval, sa, socklen)) {
  1163. err = php_socket_errno();
  1164. goto out;
  1165. }
  1166. switch (sa->sa_family) {
  1167. #if HAVE_GETADDRINFO && HAVE_IPV6
  1168. case AF_INET6:
  1169. *port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
  1170. break;
  1171. #endif
  1172. case AF_INET:
  1173. *port = ntohs(((struct sockaddr_in *)sa)->sin_port);
  1174. break;
  1175. }
  1176. }
  1177. break;
  1178. }
  1179. if (retval == SOCK_ERR) {
  1180. goto out;
  1181. }
  1182. if (listen(retval, SOMAXCONN)) {
  1183. err = php_socket_errno();
  1184. goto out;
  1185. }
  1186. out:
  1187. if (sa) {
  1188. pefree(sa, 1);
  1189. }
  1190. if (sal) {
  1191. php_network_freeaddresses(sal);
  1192. }
  1193. if (err) {
  1194. if (ZEND_VALID_SOCKET(retval)) {
  1195. closesocket(retval);
  1196. }
  1197. if (errstr) {
  1198. *errstr = php_socket_error_str(err);
  1199. }
  1200. return SOCK_ERR;
  1201. }
  1202. return retval;
  1203. } /* }}} */
  1204. static int php_cli_server_request_ctor(php_cli_server_request *req) /* {{{ */
  1205. {
  1206. req->protocol_version = 0;
  1207. req->request_uri = NULL;
  1208. req->request_uri_len = 0;
  1209. req->vpath = NULL;
  1210. req->vpath_len = 0;
  1211. req->path_translated = NULL;
  1212. req->path_translated_len = 0;
  1213. req->path_info = NULL;
  1214. req->path_info_len = 0;
  1215. req->query_string = NULL;
  1216. req->query_string_len = 0;
  1217. zend_hash_init(&req->headers, 0, NULL, char_ptr_dtor_p, 1);
  1218. zend_hash_init(&req->headers_original_case, 0, NULL, NULL, 1);
  1219. req->content = NULL;
  1220. req->content_len = 0;
  1221. req->ext = NULL;
  1222. req->ext_len = 0;
  1223. return SUCCESS;
  1224. } /* }}} */
  1225. static void php_cli_server_request_dtor(php_cli_server_request *req) /* {{{ */
  1226. {
  1227. if (req->request_uri) {
  1228. pefree(req->request_uri, 1);
  1229. }
  1230. if (req->vpath) {
  1231. pefree(req->vpath, 1);
  1232. }
  1233. if (req->path_translated) {
  1234. pefree(req->path_translated, 1);
  1235. }
  1236. if (req->path_info) {
  1237. pefree(req->path_info, 1);
  1238. }
  1239. if (req->query_string) {
  1240. pefree(req->query_string, 1);
  1241. }
  1242. zend_hash_destroy(&req->headers);
  1243. zend_hash_destroy(&req->headers_original_case);
  1244. if (req->content) {
  1245. pefree(req->content, 1);
  1246. }
  1247. } /* }}} */
  1248. static void php_cli_server_request_translate_vpath(php_cli_server_request *request, const char *document_root, size_t document_root_len) /* {{{ */
  1249. {
  1250. zend_stat_t sb;
  1251. static const char *index_files[] = { "index.php", "index.html", NULL };
  1252. char *buf = safe_pemalloc(1, request->vpath_len, 1 + document_root_len + 1 + sizeof("index.html"), 1);
  1253. char *p = buf, *prev_path = NULL, *q, *vpath;
  1254. size_t prev_path_len = 0;
  1255. int is_static_file = 0;
  1256. memmove(p, document_root, document_root_len);
  1257. p += document_root_len;
  1258. vpath = p;
  1259. if (request->vpath_len > 0 && request->vpath[0] != '/') {
  1260. *p++ = DEFAULT_SLASH;
  1261. }
  1262. q = request->vpath + request->vpath_len;
  1263. while (q > request->vpath) {
  1264. if (*q-- == '.') {
  1265. is_static_file = 1;
  1266. break;
  1267. }
  1268. }
  1269. memmove(p, request->vpath, request->vpath_len);
  1270. #ifdef PHP_WIN32
  1271. q = p + request->vpath_len;
  1272. do {
  1273. if (*q == '/') {
  1274. *q = '\\';
  1275. }
  1276. } while (q-- > p);
  1277. #endif
  1278. p += request->vpath_len;
  1279. *p = '\0';
  1280. q = p;
  1281. while (q > buf) {
  1282. if (!php_sys_stat(buf, &sb)) {
  1283. if (sb.st_mode & S_IFDIR) {
  1284. const char **file = index_files;
  1285. if (q[-1] != DEFAULT_SLASH) {
  1286. *q++ = DEFAULT_SLASH;
  1287. }
  1288. while (*file) {
  1289. size_t l = strlen(*file);
  1290. memmove(q, *file, l + 1);
  1291. if (!php_sys_stat(buf, &sb) && (sb.st_mode & S_IFREG)) {
  1292. q += l;
  1293. break;
  1294. }
  1295. file++;
  1296. }
  1297. if (!*file || is_static_file) {
  1298. if (prev_path) {
  1299. pefree(prev_path, 1);
  1300. }
  1301. pefree(buf, 1);
  1302. return;
  1303. }
  1304. }
  1305. break; /* regular file */
  1306. }
  1307. if (prev_path) {
  1308. pefree(prev_path, 1);
  1309. *q = DEFAULT_SLASH;
  1310. }
  1311. while (q > buf && *(--q) != DEFAULT_SLASH);
  1312. prev_path_len = p - q;
  1313. prev_path = pestrndup(q, prev_path_len, 1);
  1314. *q = '\0';
  1315. }
  1316. if (prev_path) {
  1317. request->path_info_len = prev_path_len;
  1318. #ifdef PHP_WIN32
  1319. while (prev_path_len--) {
  1320. if (prev_path[prev_path_len] == '\\') {
  1321. prev_path[prev_path_len] = '/';
  1322. }
  1323. }
  1324. #endif
  1325. request->path_info = prev_path;
  1326. pefree(request->vpath, 1);
  1327. request->vpath = pestrndup(vpath, q - vpath, 1);
  1328. request->vpath_len = q - vpath;
  1329. request->path_translated = buf;
  1330. request->path_translated_len = q - buf;
  1331. } else {
  1332. pefree(request->vpath, 1);
  1333. request->vpath = pestrndup(vpath, q - vpath, 1);
  1334. request->vpath_len = q - vpath;
  1335. request->path_translated = buf;
  1336. request->path_translated_len = q - buf;
  1337. }
  1338. #ifdef PHP_WIN32
  1339. {
  1340. uint32_t i = 0;
  1341. for (;i<request->vpath_len;i++) {
  1342. if (request->vpath[i] == '\\') {
  1343. request->vpath[i] = '/';
  1344. }
  1345. }
  1346. }
  1347. #endif
  1348. request->sb = sb;
  1349. } /* }}} */
  1350. static void normalize_vpath(char **retval, size_t *retval_len, const char *vpath, size_t vpath_len, int persistent) /* {{{ */
  1351. {
  1352. char *decoded_vpath = NULL;
  1353. char *decoded_vpath_end;
  1354. char *p;
  1355. *retval = NULL;
  1356. *retval_len = 0;
  1357. decoded_vpath = pestrndup(vpath, vpath_len, persistent);
  1358. if (!decoded_vpath) {
  1359. return;
  1360. }
  1361. decoded_vpath_end = decoded_vpath + php_raw_url_decode(decoded_vpath, (int)vpath_len);
  1362. #ifdef PHP_WIN32
  1363. {
  1364. char *p = decoded_vpath;
  1365. do {
  1366. if (*p == '\\') {
  1367. *p = '/';
  1368. }
  1369. } while (*p++);
  1370. }
  1371. #endif
  1372. p = decoded_vpath;
  1373. if (p < decoded_vpath_end && *p == '/') {
  1374. char *n = p;
  1375. while (n < decoded_vpath_end && *n == '/') n++;
  1376. memmove(++p, n, decoded_vpath_end - n);
  1377. decoded_vpath_end -= n - p;
  1378. }
  1379. while (p < decoded_vpath_end) {
  1380. char *n = p;
  1381. while (n < decoded_vpath_end && *n != '/') n++;
  1382. if (n - p == 2 && p[0] == '.' && p[1] == '.') {
  1383. if (p > decoded_vpath) {
  1384. --p;
  1385. for (;;) {
  1386. if (p == decoded_vpath) {
  1387. if (*p == '/') {
  1388. p++;
  1389. }
  1390. break;
  1391. }
  1392. if (*(--p) == '/') {
  1393. p++;
  1394. break;
  1395. }
  1396. }
  1397. }
  1398. while (n < decoded_vpath_end && *n == '/') n++;
  1399. memmove(p, n, decoded_vpath_end - n);
  1400. decoded_vpath_end -= n - p;
  1401. } else if (n - p == 1 && p[0] == '.') {
  1402. while (n < decoded_vpath_end && *n == '/') n++;
  1403. memmove(p, n, decoded_vpath_end - n);
  1404. decoded_vpath_end -= n - p;
  1405. } else {
  1406. if (n < decoded_vpath_end) {
  1407. char *nn = n;
  1408. while (nn < decoded_vpath_end && *nn == '/') nn++;
  1409. p = n + 1;
  1410. memmove(p, nn, decoded_vpath_end - nn);
  1411. decoded_vpath_end -= nn - p;
  1412. } else {
  1413. p = n;
  1414. }
  1415. }
  1416. }
  1417. *decoded_vpath_end = '\0';
  1418. *retval = decoded_vpath;
  1419. *retval_len = decoded_vpath_end - decoded_vpath;
  1420. } /* }}} */
  1421. /* {{{ php_cli_server_client_read_request */
  1422. static int php_cli_server_client_read_request_on_message_begin(php_http_parser *parser)
  1423. {
  1424. return 0;
  1425. }
  1426. static int php_cli_server_client_read_request_on_path(php_http_parser *parser, const char *at, size_t length)
  1427. {
  1428. php_cli_server_client *client = parser->data;
  1429. {
  1430. char *vpath;
  1431. size_t vpath_len;
  1432. normalize_vpath(&vpath, &vpath_len, at, length, 1);
  1433. client->request.vpath = vpath;
  1434. client->request.vpath_len = vpath_len;
  1435. }
  1436. return 0;
  1437. }
  1438. static int php_cli_server_client_read_request_on_query_string(php_http_parser *parser, const char *at, size_t length)
  1439. {
  1440. php_cli_server_client *client = parser->data;
  1441. client->request.query_string = pestrndup(at, length, 1);
  1442. client->request.query_string_len = length;
  1443. return 0;
  1444. }
  1445. static int php_cli_server_client_read_request_on_url(php_http_parser *parser, const char *at, size_t length)
  1446. {
  1447. php_cli_server_client *client = parser->data;
  1448. client->request.request_method = parser->method;
  1449. client->request.request_uri = pestrndup(at, length, 1);
  1450. client->request.request_uri_len = length;
  1451. return 0;
  1452. }
  1453. static int php_cli_server_client_read_request_on_fragment(php_http_parser *parser, const char *at, size_t length)
  1454. {
  1455. return 0;
  1456. }
  1457. static void php_cli_server_client_save_header(php_cli_server_client *client)
  1458. {
  1459. /* strip off the colon */
  1460. zend_string *orig_header_name = zend_string_init(client->current_header_name, client->current_header_name_len, 1);
  1461. zend_string *lc_header_name = zend_string_alloc(client->current_header_name_len, 1);
  1462. zend_str_tolower_copy(ZSTR_VAL(lc_header_name), client->current_header_name, client->current_header_name_len);
  1463. GC_MAKE_PERSISTENT_LOCAL(orig_header_name);
  1464. GC_MAKE_PERSISTENT_LOCAL(lc_header_name);
  1465. zend_hash_add_ptr(&client->request.headers, lc_header_name, client->current_header_value);
  1466. zend_hash_add_ptr(&client->request.headers_original_case, orig_header_name, client->current_header_value);
  1467. zend_string_release_ex(lc_header_name, 1);
  1468. zend_string_release_ex(orig_header_name, 1);
  1469. if (client->current_header_name_allocated) {
  1470. pefree(client->current_header_name, 1);
  1471. client->current_header_name_allocated = 0;
  1472. }
  1473. client->current_header_name = NULL;
  1474. client->current_header_name_len = 0;
  1475. client->current_header_value = NULL;
  1476. client->current_header_value_len = 0;
  1477. }
  1478. static int php_cli_server_client_read_request_on_header_field(php_http_parser *parser, const char *at, size_t length)
  1479. {
  1480. php_cli_server_client *client = parser->data;
  1481. switch (client->last_header_element) {
  1482. case HEADER_VALUE:
  1483. php_cli_server_client_save_header(client);
  1484. /* break missing intentionally */
  1485. case HEADER_NONE:
  1486. client->current_header_name = (char *)at;
  1487. client->current_header_name_len = length;
  1488. break;
  1489. case HEADER_FIELD:
  1490. if (client->current_header_name_allocated) {
  1491. size_t new_length = client->current_header_name_len + length;
  1492. client->current_header_name = perealloc(client->current_header_name, new_length + 1, 1);
  1493. memcpy(client->current_header_name + client->current_header_name_len, at, length);
  1494. client->current_header_name[new_length] = '\0';
  1495. client->current_header_name_len = new_length;
  1496. } else {
  1497. size_t new_length = client->current_header_name_len + length;
  1498. char* field = pemalloc(new_length + 1, 1);
  1499. memcpy(field, client->current_header_name, client->current_header_name_len);
  1500. memcpy(field + client->current_header_name_len, at, length);
  1501. field[new_length] = '\0';
  1502. client->current_header_name = field;
  1503. client->current_header_name_len = new_length;
  1504. client->current_header_name_allocated = 1;
  1505. }
  1506. break;
  1507. }
  1508. client->last_header_element = HEADER_FIELD;
  1509. return 0;
  1510. }
  1511. static int php_cli_server_client_read_request_on_header_value(php_http_parser *parser, const char *at, size_t length)
  1512. {
  1513. php_cli_server_client *client = parser->data;
  1514. switch (client->last_header_element) {
  1515. case HEADER_FIELD:
  1516. client->current_header_value = pestrndup(at, length, 1);
  1517. client->current_header_value_len = length;
  1518. break;
  1519. case HEADER_VALUE:
  1520. {
  1521. size_t new_length = client->current_header_value_len + length;
  1522. client->current_header_value = perealloc(client->current_header_value, new_length + 1, 1);
  1523. memcpy(client->current_header_value + client->current_header_value_len, at, length);
  1524. client->current_header_value[new_length] = '\0';
  1525. client->current_header_value_len = new_length;
  1526. }
  1527. break;
  1528. case HEADER_NONE:
  1529. // can't happen
  1530. assert(0);
  1531. break;
  1532. }
  1533. client->last_header_element = HEADER_VALUE;
  1534. return 0;
  1535. }
  1536. static int php_cli_server_client_read_request_on_headers_complete(php_http_parser *parser)
  1537. {
  1538. php_cli_server_client *client = parser->data;
  1539. switch (client->last_header_element) {
  1540. case HEADER_NONE:
  1541. break;
  1542. case HEADER_FIELD:
  1543. client->current_header_value = pemalloc(1, 1);
  1544. *client->current_header_value = '\0';
  1545. client->current_header_value_len = 0;
  1546. /* break missing intentionally */
  1547. case HEADER_VALUE:
  1548. php_cli_server_client_save_header(client);
  1549. break;
  1550. }
  1551. client->last_header_element = HEADER_NONE;
  1552. return 0;
  1553. }
  1554. static int php_cli_server_client_read_request_on_body(php_http_parser *parser, const char *at, size_t length)
  1555. {
  1556. php_cli_server_client *client = parser->data;
  1557. if (!client->request.content) {
  1558. client->request.content = pemalloc(parser->content_length, 1);
  1559. client->request.content_len = 0;
  1560. }
  1561. client->request.content = perealloc(client->request.content, client->request.content_len + length, 1);
  1562. memmove(client->request.content + client->request.content_len, at, length);
  1563. client->request.content_len += length;
  1564. return 0;
  1565. }
  1566. static int php_cli_server_client_read_request_on_message_complete(php_http_parser *parser)
  1567. {
  1568. php_cli_server_client *client = parser->data;
  1569. client->request.protocol_version = parser->http_major * 100 + parser->http_minor;
  1570. php_cli_server_request_translate_vpath(&client->request, client->server->document_root, client->server->document_root_len);
  1571. {
  1572. const char *vpath = client->request.vpath, *end = vpath + client->request.vpath_len, *p = end;
  1573. client->request.ext = end;
  1574. client->request.ext_len = 0;
  1575. while (p > vpath) {
  1576. --p;
  1577. if (*p == '.') {
  1578. ++p;
  1579. client->request.ext = p;
  1580. client->request.ext_len = end - p;
  1581. break;
  1582. }
  1583. }
  1584. }
  1585. client->request_read = 1;
  1586. return 0;
  1587. }
  1588. static int php_cli_server_client_read_request(php_cli_server_client *client, char **errstr)
  1589. {
  1590. char buf[16384];
  1591. static const php_http_parser_settings settings = {
  1592. php_cli_server_client_read_request_on_message_begin,
  1593. php_cli_server_client_read_request_on_path,
  1594. php_cli_server_client_read_request_on_query_string,
  1595. php_cli_server_client_read_request_on_url,
  1596. php_cli_server_client_read_request_on_fragment,
  1597. php_cli_server_client_read_request_on_header_field,
  1598. php_cli_server_client_read_request_on_header_value,
  1599. php_cli_server_client_read_request_on_headers_complete,
  1600. php_cli_server_client_read_request_on_body,
  1601. php_cli_server_client_read_request_on_message_complete
  1602. };
  1603. size_t nbytes_consumed;
  1604. int nbytes_read;
  1605. if (client->request_read) {
  1606. return 1;
  1607. }
  1608. nbytes_read = recv(client->sock, buf, sizeof(buf) - 1, 0);
  1609. if (nbytes_read < 0) {
  1610. int err = php_socket_errno

Large files files are truncated, but you can click here to view the full file