thttpd.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2016 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Sascha Schumann <sascha@schumann.cx> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id$ */
  19. #include "php.h"
  20. #include "SAPI.h"
  21. #include "php_main.h"
  22. #include "php_thttpd.h"
  23. #include "php_variables.h"
  24. #include "version.h"
  25. #include "php_ini.h"
  26. #include "zend_highlight.h"
  27. #include "ext/standard/php_smart_str.h"
  28. #include <sys/time.h>
  29. #include <sys/types.h>
  30. #include <sys/uio.h>
  31. #include <stdlib.h>
  32. #include <unistd.h>
  33. #ifdef HAVE_GETNAMEINFO
  34. #include <sys/socket.h>
  35. #include <netdb.h>
  36. #endif
  37. typedef struct {
  38. httpd_conn *hc;
  39. void (*on_close)(int);
  40. size_t unconsumed_length;
  41. smart_str sbuf;
  42. int seen_cl;
  43. int seen_cn;
  44. } php_thttpd_globals;
  45. #define PHP_SYS_CALL(x) do { x } while (n == -1 && errno == EINTR)
  46. #ifdef PREMIUM_THTTPD
  47. # define do_keep_alive persistent
  48. #endif
  49. #ifdef ZTS
  50. static int thttpd_globals_id;
  51. #define TG(v) TSRMG(thttpd_globals_id, php_thttpd_globals *, v)
  52. #else
  53. static php_thttpd_globals thttpd_globals;
  54. #define TG(v) (thttpd_globals.v)
  55. #endif
  56. static int sapi_thttpd_ub_write(const char *str, uint str_length TSRMLS_DC)
  57. {
  58. int n;
  59. uint sent = 0;
  60. if (TG(sbuf).c != 0) {
  61. smart_str_appendl_ex(&TG(sbuf), str, str_length, 1);
  62. return str_length;
  63. }
  64. while (str_length > 0) {
  65. PHP_SYS_CALL(n = send(TG(hc)->conn_fd, str, str_length, 0););
  66. if (n == -1) {
  67. if (errno == EAGAIN) {
  68. smart_str_appendl_ex(&TG(sbuf), str, str_length, 1);
  69. return sent + str_length;
  70. } else
  71. php_handle_aborted_connection();
  72. }
  73. TG(hc)->bytes_sent += n;
  74. str += n;
  75. sent += n;
  76. str_length -= n;
  77. }
  78. return sent;
  79. }
  80. #define COMBINE_HEADERS 64
  81. #if defined(IOV_MAX)
  82. # if IOV_MAX - 64 <= 0
  83. # define SERIALIZE_HEADERS
  84. # endif
  85. #endif
  86. static int do_writev(struct iovec *vec, int nvec, int len TSRMLS_DC)
  87. {
  88. int n;
  89. assert(nvec <= IOV_MAX);
  90. if (TG(sbuf).c == 0) {
  91. PHP_SYS_CALL(n = writev(TG(hc)->conn_fd, vec, nvec););
  92. if (n == -1) {
  93. if (errno == EAGAIN) {
  94. n = 0;
  95. } else {
  96. php_handle_aborted_connection();
  97. }
  98. }
  99. TG(hc)->bytes_sent += n;
  100. } else {
  101. n = 0;
  102. }
  103. if (n < len) {
  104. int i;
  105. /* merge all unwritten data into sbuf */
  106. for (i = 0; i < nvec; vec++, i++) {
  107. /* has this vector been written completely? */
  108. if (n >= vec->iov_len) {
  109. /* yes, proceed */
  110. n -= vec->iov_len;
  111. continue;
  112. }
  113. if (n > 0) {
  114. /* adjust vector */
  115. vec->iov_base = (char *) vec->iov_base + n;
  116. vec->iov_len -= n;
  117. n = 0;
  118. }
  119. smart_str_appendl_ex(&TG(sbuf), vec->iov_base, vec->iov_len, 1);
  120. }
  121. }
  122. return 0;
  123. }
  124. #ifdef SERIALIZE_HEADERS
  125. # define ADD_VEC(str,l) smart_str_appendl(&vec_str, (str), (l))
  126. # define VEC_BASE() smart_str vec_str = {0}
  127. # define VEC_FREE() smart_str_free(&vec_str)
  128. #else
  129. # define ADD_VEC(str,l) vec[n].iov_base=str;len += (vec[n].iov_len=l); n++
  130. # define VEC_BASE() struct iovec vec[COMBINE_HEADERS]
  131. # define VEC_FREE() do {} while (0)
  132. #endif
  133. #define ADD_VEC_S(str) ADD_VEC((str), sizeof(str)-1)
  134. #define CL_TOKEN "Content-length: "
  135. #define CN_TOKEN "Connection: "
  136. #define KA_DO "Connection: keep-alive\r\n"
  137. #define KA_NO "Connection: close\r\n"
  138. #define DEF_CT "Content-Type: text/html\r\n"
  139. static int sapi_thttpd_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
  140. {
  141. char buf[1024], *p;
  142. VEC_BASE();
  143. int n = 0;
  144. zend_llist_position pos;
  145. sapi_header_struct *h;
  146. size_t len = 0;
  147. if (!SG(sapi_headers).http_status_line) {
  148. ADD_VEC_S("HTTP/1.1 ");
  149. p = smart_str_print_long(buf+sizeof(buf)-1,
  150. SG(sapi_headers).http_response_code);
  151. ADD_VEC(p, strlen(p));
  152. ADD_VEC_S(" HTTP\r\n");
  153. } else {
  154. ADD_VEC(SG(sapi_headers).http_status_line,
  155. strlen(SG(sapi_headers).http_status_line));
  156. ADD_VEC("\r\n", 2);
  157. }
  158. TG(hc)->status = SG(sapi_headers).http_response_code;
  159. if (SG(sapi_headers).send_default_content_type) {
  160. ADD_VEC(DEF_CT, strlen(DEF_CT));
  161. }
  162. h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
  163. while (h) {
  164. switch (h->header[0]) {
  165. case 'c': case 'C':
  166. if (!TG(seen_cl) && strncasecmp(h->header, CL_TOKEN, sizeof(CL_TOKEN)-1) == 0) {
  167. TG(seen_cl) = 1;
  168. } else if (!TG(seen_cn) && strncasecmp(h->header, CN_TOKEN, sizeof(CN_TOKEN)-1) == 0) {
  169. TG(seen_cn) = 1;
  170. }
  171. }
  172. ADD_VEC(h->header, h->header_len);
  173. #ifndef SERIALIZE_HEADERS
  174. if (n >= COMBINE_HEADERS - 1) {
  175. len = do_writev(vec, n, len TSRMLS_CC);
  176. n = 0;
  177. }
  178. #endif
  179. ADD_VEC("\r\n", 2);
  180. h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
  181. }
  182. if (TG(seen_cl) && !TG(seen_cn) && TG(hc)->do_keep_alive) {
  183. ADD_VEC(KA_DO, sizeof(KA_DO)-1);
  184. } else {
  185. TG(hc)->do_keep_alive = 0;
  186. ADD_VEC(KA_NO, sizeof(KA_NO)-1);
  187. }
  188. ADD_VEC("\r\n", 2);
  189. #ifdef SERIALIZE_HEADERS
  190. sapi_thttpd_ub_write(vec_str.c, vec_str.len TSRMLS_CC);
  191. #else
  192. do_writev(vec, n, len TSRMLS_CC);
  193. #endif
  194. VEC_FREE();
  195. return SAPI_HEADER_SENT_SUCCESSFULLY;
  196. }
  197. /* to understand this, read cgi_interpose_input() in libhttpd.c */
  198. #define SIZEOF_UNCONSUMED_BYTES() (TG(hc)->read_idx - TG(hc)->checked_idx)
  199. #define CONSUME_BYTES(n) do { TG(hc)->checked_idx += (n); } while (0)
  200. static int sapi_thttpd_read_post(char *buffer, uint count_bytes TSRMLS_DC)
  201. {
  202. size_t read_bytes = 0;
  203. if (TG(unconsumed_length) > 0) {
  204. read_bytes = MIN(TG(unconsumed_length), count_bytes);
  205. memcpy(buffer, TG(hc)->read_buf + TG(hc)->checked_idx, read_bytes);
  206. TG(unconsumed_length) -= read_bytes;
  207. CONSUME_BYTES(read_bytes);
  208. }
  209. return read_bytes;
  210. }
  211. static char *sapi_thttpd_read_cookies(TSRMLS_D)
  212. {
  213. return TG(hc)->cookie;
  214. }
  215. #define BUF_SIZE 512
  216. #define ADD_STRING_EX(name,buf) \
  217. php_register_variable(name, buf, track_vars_array TSRMLS_CC)
  218. #define ADD_STRING(name) ADD_STRING_EX((name), buf)
  219. static void sapi_thttpd_register_variables(zval *track_vars_array TSRMLS_DC)
  220. {
  221. char buf[BUF_SIZE + 1];
  222. char *p;
  223. php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
  224. php_register_variable("SERVER_SOFTWARE", SERVER_SOFTWARE, track_vars_array TSRMLS_CC);
  225. php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
  226. php_register_variable("REQUEST_METHOD", (char *) SG(request_info).request_method, track_vars_array TSRMLS_CC);
  227. php_register_variable("REQUEST_URI", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
  228. php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
  229. if (TG(hc)->one_one) {
  230. php_register_variable("SERVER_PROTOCOL", "HTTP/1.1", track_vars_array TSRMLS_CC);
  231. } else {
  232. php_register_variable("SERVER_PROTOCOL", "HTTP/1.0", track_vars_array TSRMLS_CC);
  233. }
  234. p = httpd_ntoa(&TG(hc)->client_addr);
  235. ADD_STRING_EX("REMOTE_ADDR", p);
  236. ADD_STRING_EX("REMOTE_HOST", p);
  237. ADD_STRING_EX("SERVER_PORT",
  238. smart_str_print_long(buf + sizeof(buf) - 1,
  239. TG(hc)->hs->port));
  240. buf[0] = '/';
  241. memcpy(buf + 1, TG(hc)->pathinfo, strlen(TG(hc)->pathinfo) + 1);
  242. ADD_STRING("PATH_INFO");
  243. buf[0] = '/';
  244. memcpy(buf + 1, TG(hc)->origfilename, strlen(TG(hc)->origfilename) + 1);
  245. ADD_STRING("SCRIPT_NAME");
  246. #define CONDADD(name, field) \
  247. if (TG(hc)->field[0]) { \
  248. php_register_variable(#name, TG(hc)->field, track_vars_array TSRMLS_CC); \
  249. }
  250. CONDADD(QUERY_STRING, query);
  251. CONDADD(HTTP_HOST, hdrhost);
  252. CONDADD(HTTP_REFERER, referer);
  253. CONDADD(HTTP_USER_AGENT, useragent);
  254. CONDADD(HTTP_ACCEPT, accept);
  255. CONDADD(HTTP_ACCEPT_LANGUAGE, acceptl);
  256. CONDADD(HTTP_ACCEPT_ENCODING, accepte);
  257. CONDADD(HTTP_COOKIE, cookie);
  258. CONDADD(CONTENT_TYPE, contenttype);
  259. CONDADD(REMOTE_USER, remoteuser);
  260. CONDADD(SERVER_PROTOCOL, protocol);
  261. if (TG(hc)->contentlength != -1) {
  262. ADD_STRING_EX("CONTENT_LENGTH",
  263. smart_str_print_long(buf + sizeof(buf) - 1,
  264. TG(hc)->contentlength));
  265. }
  266. if (TG(hc)->authorization[0])
  267. php_register_variable("AUTH_TYPE", "Basic", track_vars_array TSRMLS_CC);
  268. }
  269. static PHP_MINIT_FUNCTION(thttpd)
  270. {
  271. return SUCCESS;
  272. }
  273. static zend_module_entry php_thttpd_module = {
  274. STANDARD_MODULE_HEADER,
  275. "thttpd",
  276. NULL,
  277. PHP_MINIT(thttpd),
  278. NULL,
  279. NULL,
  280. NULL,
  281. NULL, /* info */
  282. NULL,
  283. STANDARD_MODULE_PROPERTIES
  284. };
  285. static int php_thttpd_startup(sapi_module_struct *sapi_module)
  286. {
  287. #if PHP_API_VERSION >= 20020918
  288. if (php_module_startup(sapi_module, &php_thttpd_module, 1) == FAILURE) {
  289. #else
  290. if (php_module_startup(sapi_module) == FAILURE
  291. || zend_startup_module(&php_thttpd_module) == FAILURE) {
  292. #endif
  293. return FAILURE;
  294. }
  295. return SUCCESS;
  296. }
  297. static int sapi_thttpd_get_fd(int *nfd TSRMLS_DC)
  298. {
  299. if (nfd) *nfd = TG(hc)->conn_fd;
  300. return SUCCESS;
  301. }
  302. static sapi_module_struct thttpd_sapi_module = {
  303. "thttpd",
  304. "thttpd",
  305. php_thttpd_startup,
  306. php_module_shutdown_wrapper,
  307. NULL, /* activate */
  308. NULL, /* deactivate */
  309. sapi_thttpd_ub_write,
  310. NULL,
  311. NULL, /* get uid */
  312. NULL, /* getenv */
  313. php_error,
  314. NULL,
  315. sapi_thttpd_send_headers,
  316. NULL,
  317. sapi_thttpd_read_post,
  318. sapi_thttpd_read_cookies,
  319. sapi_thttpd_register_variables,
  320. NULL, /* Log message */
  321. NULL, /* Get request time */
  322. NULL, /* Child terminate */
  323. NULL, /* php.ini path override */
  324. NULL, /* Block interruptions */
  325. NULL, /* Unblock interruptions */
  326. NULL,
  327. NULL,
  328. NULL,
  329. 0,
  330. sapi_thttpd_get_fd
  331. };
  332. static void thttpd_module_main(int show_source TSRMLS_DC)
  333. {
  334. zend_file_handle file_handle;
  335. if (php_request_startup(TSRMLS_C) == FAILURE) {
  336. return;
  337. }
  338. if (show_source) {
  339. zend_syntax_highlighter_ini syntax_highlighter_ini;
  340. php_get_highlight_struct(&syntax_highlighter_ini);
  341. highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC);
  342. } else {
  343. file_handle.type = ZEND_HANDLE_FILENAME;
  344. file_handle.filename = SG(request_info).path_translated;
  345. file_handle.free_filename = 0;
  346. file_handle.opened_path = NULL;
  347. php_execute_script(&file_handle TSRMLS_CC);
  348. }
  349. php_request_shutdown(NULL);
  350. }
  351. static void thttpd_request_ctor(TSRMLS_D)
  352. {
  353. smart_str s = {0};
  354. TG(seen_cl) = 0;
  355. TG(seen_cn) = 0;
  356. TG(sbuf).c = 0;
  357. SG(request_info).query_string = TG(hc)->query?strdup(TG(hc)->query):NULL;
  358. smart_str_appends_ex(&s, TG(hc)->hs->cwd, 1);
  359. smart_str_appends_ex(&s, TG(hc)->expnfilename, 1);
  360. smart_str_0(&s);
  361. SG(request_info).path_translated = s.c;
  362. s.c = NULL;
  363. smart_str_appendc_ex(&s, '/', 1);
  364. smart_str_appends_ex(&s, TG(hc)->origfilename, 1);
  365. smart_str_0(&s);
  366. SG(request_info).request_uri = s.c;
  367. SG(request_info).request_method = httpd_method_str(TG(hc)->method);
  368. if (TG(hc)->one_one) SG(request_info).proto_num = 1001;
  369. else SG(request_info).proto_num = 1000;
  370. SG(sapi_headers).http_response_code = 200;
  371. if (TG(hc)->contenttype)
  372. SG(request_info).content_type = strdup(TG(hc)->contenttype);
  373. SG(request_info).content_length = TG(hc)->contentlength == -1 ? 0
  374. : TG(hc)->contentlength;
  375. TG(unconsumed_length) = SG(request_info).content_length;
  376. php_handle_auth_data(TG(hc)->authorization TSRMLS_CC);
  377. }
  378. static void thttpd_request_dtor(TSRMLS_D)
  379. {
  380. smart_str_free_ex(&TG(sbuf), 1);
  381. if (SG(request_info).query_string)
  382. free(SG(request_info).query_string);
  383. free(SG(request_info).request_uri);
  384. free(SG(request_info).path_translated);
  385. if (SG(request_info).content_type)
  386. free(SG(request_info).content_type);
  387. }
  388. #ifdef ZTS
  389. #ifdef TSRM_ST
  390. #define thread_create_simple_detached(n) st_thread_create(n, NULL, 0, 0)
  391. #define thread_usleep(n) st_usleep(n)
  392. #define thread_exit() st_thread_exit(NULL)
  393. /* No preemption, simple operations are safe */
  394. #define thread_atomic_inc(n) (++n)
  395. #define thread_atomic_dec(n) (--n)
  396. #else
  397. #error No thread primitives available
  398. #endif
  399. /* We might want to replace this with a STAILQ */
  400. typedef struct qreq {
  401. httpd_conn *hc;
  402. struct qreq *next;
  403. } qreq_t;
  404. static MUTEX_T qr_lock;
  405. static qreq_t *queued_requests;
  406. static qreq_t *last_qr;
  407. static int nr_free_threads;
  408. static int nr_threads;
  409. static int max_threads = 50;
  410. #define HANDLE_STRINGS() { \
  411. HANDLE_STR(encodedurl); \
  412. HANDLE_STR(decodedurl); \
  413. HANDLE_STR(origfilename); \
  414. HANDLE_STR(expnfilename); \
  415. HANDLE_STR(pathinfo); \
  416. HANDLE_STR(query); \
  417. HANDLE_STR(referer); \
  418. HANDLE_STR(useragent); \
  419. HANDLE_STR(accept); \
  420. HANDLE_STR(accepte); \
  421. HANDLE_STR(acceptl); \
  422. HANDLE_STR(cookie); \
  423. HANDLE_STR(contenttype); \
  424. HANDLE_STR(authorization); \
  425. HANDLE_STR(remoteuser); \
  426. }
  427. static httpd_conn *duplicate_conn(httpd_conn *hc, httpd_conn *nhc)
  428. {
  429. memcpy(nhc, hc, sizeof(*nhc));
  430. #define HANDLE_STR(m) nhc->m = nhc->m ? strdup(nhc->m) : NULL
  431. HANDLE_STRINGS();
  432. #undef HANDLE_STR
  433. return nhc;
  434. }
  435. static void destroy_conn(httpd_conn *hc)
  436. {
  437. #define HANDLE_STR(m) if (hc->m) free(hc->m)
  438. HANDLE_STRINGS();
  439. #undef HANDLE_STR
  440. }
  441. static httpd_conn *dequeue_request(void)
  442. {
  443. httpd_conn *ret = NULL;
  444. qreq_t *m;
  445. tsrm_mutex_lock(qr_lock);
  446. if (queued_requests) {
  447. m = queued_requests;
  448. ret = m->hc;
  449. if (!(queued_requests = m->next))
  450. last_qr = NULL;
  451. free(m);
  452. }
  453. tsrm_mutex_unlock(qr_lock);
  454. return ret;
  455. }
  456. static void *worker_thread(void *);
  457. static void queue_request(httpd_conn *hc)
  458. {
  459. qreq_t *m;
  460. httpd_conn *nhc;
  461. /* Mark as long-running request */
  462. hc->file_address = (char *) 1;
  463. /*
  464. * We cannot synchronously revoke accesses to hc in the worker
  465. * thread, so we need to pass a copy of hc to the worker thread.
  466. */
  467. nhc = malloc(sizeof *nhc);
  468. duplicate_conn(hc, nhc);
  469. /* Allocate request queue container */
  470. m = malloc(sizeof *m);
  471. m->hc = nhc;
  472. m->next = NULL;
  473. tsrm_mutex_lock(qr_lock);
  474. /* Create new threads when reaching a certain threshold */
  475. if (nr_threads < max_threads && nr_free_threads < 2) {
  476. nr_threads++; /* protected by qr_lock */
  477. thread_atomic_inc(nr_free_threads);
  478. thread_create_simple_detached(worker_thread);
  479. }
  480. /* Insert container into request queue */
  481. if (queued_requests)
  482. last_qr->next = m;
  483. else
  484. queued_requests = m;
  485. last_qr = m;
  486. tsrm_mutex_unlock(qr_lock);
  487. }
  488. static off_t thttpd_real_php_request(httpd_conn *hc, int TSRMLS_DC);
  489. static void *worker_thread(void *dummy)
  490. {
  491. int do_work = 50;
  492. httpd_conn *hc;
  493. while (do_work) {
  494. hc = dequeue_request();
  495. if (!hc) {
  496. /* do_work--; */
  497. thread_usleep(500000);
  498. continue;
  499. }
  500. /* do_work = 50; */
  501. thread_atomic_dec(nr_free_threads);
  502. thttpd_real_php_request(hc, 0 TSRMLS_CC);
  503. shutdown(hc->conn_fd, 0);
  504. destroy_conn(hc);
  505. free(hc);
  506. thread_atomic_inc(nr_free_threads);
  507. }
  508. thread_atomic_dec(nr_free_threads);
  509. thread_atomic_dec(nr_threads);
  510. thread_exit();
  511. }
  512. static void remove_dead_conn(int fd)
  513. {
  514. qreq_t *m, *prev = NULL;
  515. tsrm_mutex_lock(qr_lock);
  516. m = queued_requests;
  517. while (m) {
  518. if (m->hc->conn_fd == fd) {
  519. if (prev)
  520. if (!(prev->next = m->next))
  521. last_qr = prev;
  522. else
  523. if (!(queued_requests = m->next))
  524. last_qr = NULL;
  525. destroy_conn(m->hc);
  526. free(m->hc);
  527. free(m);
  528. break;
  529. }
  530. prev = m;
  531. m = m->next;
  532. }
  533. tsrm_mutex_unlock(qr_lock);
  534. }
  535. #endif
  536. static off_t thttpd_real_php_request(httpd_conn *hc, int show_source TSRMLS_DC)
  537. {
  538. TG(hc) = hc;
  539. hc->bytes_sent = 0;
  540. if (hc->contentlength != -1) {
  541. hc->should_linger = 1;
  542. hc->do_keep_alive = 0;
  543. }
  544. if (hc->contentlength != -1
  545. && SIZEOF_UNCONSUMED_BYTES() < hc->contentlength) {
  546. hc->read_body_into_mem = 1;
  547. return 0;
  548. }
  549. thttpd_request_ctor(TSRMLS_C);
  550. thttpd_module_main(show_source TSRMLS_CC);
  551. /* disable kl, if no content-length was seen or Connection: was set */
  552. if (TG(seen_cl) == 0 || TG(seen_cn) == 1) {
  553. TG(hc)->do_keep_alive = 0;
  554. }
  555. if (TG(sbuf).c != 0) {
  556. if (TG(hc)->response)
  557. free(TG(hc)->response);
  558. TG(hc)->response = TG(sbuf).c;
  559. TG(hc)->responselen = TG(sbuf).len;
  560. TG(hc)->maxresponse = TG(sbuf).a;
  561. TG(sbuf).c = 0;
  562. TG(sbuf).len = 0;
  563. TG(sbuf).a = 0;
  564. }
  565. thttpd_request_dtor(TSRMLS_C);
  566. return 0;
  567. }
  568. off_t thttpd_php_request(httpd_conn *hc, int show_source)
  569. {
  570. #ifdef ZTS
  571. queue_request(hc);
  572. #else
  573. TSRMLS_FETCH();
  574. return thttpd_real_php_request(hc, show_source TSRMLS_CC);
  575. #endif
  576. }
  577. void thttpd_register_on_close(void (*arg)(int))
  578. {
  579. TSRMLS_FETCH();
  580. TG(on_close) = arg;
  581. }
  582. void thttpd_closed_conn(int fd)
  583. {
  584. TSRMLS_FETCH();
  585. if (TG(on_close)) TG(on_close)(fd);
  586. }
  587. int thttpd_get_fd(void)
  588. {
  589. TSRMLS_FETCH();
  590. return TG(hc)->conn_fd;
  591. }
  592. void thttpd_set_dont_close(void)
  593. {
  594. TSRMLS_FETCH();
  595. #ifndef PREMIUM_THTTPD
  596. TG(hc)->file_address = (char *) 1;
  597. #endif
  598. }
  599. void thttpd_php_init(void)
  600. {
  601. char *ini;
  602. #ifdef ZTS
  603. tsrm_startup(1, 1, 0, NULL);
  604. ts_allocate_id(&thttpd_globals_id, sizeof(php_thttpd_globals), NULL, NULL);
  605. qr_lock = tsrm_mutex_alloc();
  606. thttpd_register_on_close(remove_dead_conn);
  607. #endif
  608. if ((ini = getenv("PHP_INI_PATH"))) {
  609. thttpd_sapi_module.php_ini_path_override = ini;
  610. }
  611. sapi_startup(&thttpd_sapi_module);
  612. thttpd_sapi_module.startup(&thttpd_sapi_module);
  613. {
  614. TSRMLS_FETCH();
  615. SG(server_context) = (void *) 1;
  616. }
  617. }
  618. void thttpd_php_shutdown(void)
  619. {
  620. TSRMLS_FETCH();
  621. if (SG(server_context) != NULL) {
  622. thttpd_sapi_module.shutdown(&thttpd_sapi_module);
  623. sapi_shutdown();
  624. #ifdef ZTS
  625. tsrm_shutdown();
  626. #endif
  627. }
  628. }