php_tux.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  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. #include "php.h"
  19. #include "SAPI.h"
  20. #include "php_main.h"
  21. #include "php_variables.h"
  22. #include "ext/standard/php_smart_str.h"
  23. #include "tuxmodule.h"
  24. #include <sys/uio.h>
  25. #if 0
  26. #include <pthread.h>
  27. #endif
  28. void tux_closed_conn(int fd);
  29. enum {
  30. PHP_TUX_BACKGROUND_CONN = 1
  31. };
  32. typedef struct {
  33. user_req_t *req;
  34. void (*on_close)(int);
  35. int tux_action;
  36. struct iovec *header_vec;
  37. int number_vec;
  38. } php_tux_globals;
  39. static php_tux_globals tux_globals;
  40. #define TG(v) (tux_globals.v)
  41. static int sapi_tux_ub_write(const char *str, uint str_length TSRMLS_DC)
  42. {
  43. int n;
  44. int m;
  45. const char *estr;
  46. /* combine headers and body */
  47. if (TG(number_vec)) {
  48. struct iovec *vec = TG(header_vec);
  49. n = TG(number_vec);
  50. vec[n].iov_base = (void *) str;
  51. vec[n++].iov_len = str_length;
  52. /* XXX: this might need more complete error handling */
  53. if ((m = writev(TG(req)->sock, vec, n)) == -1 && errno == EPIPE)
  54. php_handle_aborted_connection();
  55. if (m > 0)
  56. TG(req)->bytes_sent += str_length;
  57. TG(number_vec) = 0;
  58. return str_length;
  59. }
  60. estr = str + str_length;
  61. while (str < estr) {
  62. n = send(TG(req)->sock, str, estr - str, 0);
  63. if (n == -1 && errno == EPIPE)
  64. php_handle_aborted_connection();
  65. if (n == -1 && errno == EAGAIN)
  66. continue;
  67. if (n <= 0)
  68. return n;
  69. str += n;
  70. }
  71. n = str_length - (estr - str);
  72. TG(req)->bytes_sent += n;
  73. return n;
  74. }
  75. static int sapi_tux_send_headers(sapi_headers_struct *sapi_headers)
  76. {
  77. char buf[1024];
  78. struct iovec *vec;
  79. int n;
  80. int max_headers;
  81. zend_llist_position pos;
  82. sapi_header_struct *h;
  83. size_t len;
  84. char *status_line;
  85. int locate_cl;
  86. TSRMLS_FETCH();
  87. max_headers = 30;
  88. n = 1;
  89. vec = malloc(sizeof(struct iovec) * max_headers);
  90. status_line = malloc(30);
  91. /* safe sprintf use */
  92. len = slprintf(status_line, 30, "HTTP/1.1 %d NA\r\n", SG(sapi_headers).http_response_code);
  93. vec[0].iov_base = status_line;
  94. vec[0].iov_len = len;
  95. TG(req)->http_status = SG(sapi_headers).http_response_code;
  96. if (TG(tux_action) == TUX_ACTION_FINISH_CLOSE_REQ && TG(req)->http_version == HTTP_1_1)
  97. locate_cl = 1;
  98. else
  99. locate_cl = 0;
  100. h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
  101. while (h) {
  102. if (locate_cl
  103. && strncasecmp(h->header, "Content-length:", sizeof("Content-length:")-1) == 0) {
  104. TG(tux_action) = TUX_ACTION_FINISH_REQ;
  105. locate_cl = 0;
  106. }
  107. vec[n].iov_base = h->header;
  108. vec[n++].iov_len = h->header_len;
  109. if (n >= max_headers - 3) {
  110. max_headers *= 2;
  111. vec = realloc(vec, sizeof(struct iovec) * max_headers);
  112. }
  113. vec[n].iov_base = "\r\n";
  114. vec[n++].iov_len = 2;
  115. h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
  116. }
  117. vec[n].iov_base = "\r\n";
  118. vec[n++].iov_len = 2;
  119. TG(number_vec) = n;
  120. TG(header_vec) = vec;
  121. return SAPI_HEADER_SENT_SUCCESSFULLY;
  122. }
  123. static int sapi_tux_read_post(char *buffer, uint count_bytes)
  124. {
  125. #if 0
  126. int amount = 0;
  127. TSRMLS_FETCH();
  128. TG(req)->objectlen = count_bytes;
  129. TG(req)->object_addr = buffer;
  130. if (tux(TUX_ACTION_READ_POST_DATA, TG(req)))
  131. return 0;
  132. TG(read_post_data) = 1;
  133. return TG(req)->objectlen;
  134. #else
  135. return 0;
  136. #endif
  137. }
  138. static char *sapi_tux_read_cookies(void)
  139. {
  140. TSRMLS_FETCH();
  141. return TG(req)->cookies;
  142. }
  143. #define BUF_SIZE 512
  144. #define ADD_STRING(name) \
  145. php_register_variable(name, buf, track_vars_array TSRMLS_CC)
  146. static void sapi_tux_register_variables(zval *track_vars_array TSRMLS_DC)
  147. {
  148. char buf[BUF_SIZE + 1];
  149. char *p;
  150. sapi_header_line ctr = {0};
  151. ctr.line = buf;
  152. ctr.line_len = slprintf(buf, sizeof(buf), "Server: %s", TUXAPI_version);
  153. sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
  154. php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
  155. php_register_variable("SERVER_SOFTWARE", TUXAPI_version, track_vars_array TSRMLS_CC);
  156. php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
  157. php_register_variable("REQUEST_METHOD", (char *) SG(request_info).request_method, track_vars_array TSRMLS_CC);
  158. php_register_variable("DOCUMENT_ROOT", TUXAPI_docroot, track_vars_array TSRMLS_CC);
  159. php_register_variable("SERVER_NAME", TUXAPI_servername, track_vars_array TSRMLS_CC);
  160. php_register_variable("REQUEST_URI", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
  161. php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
  162. p = inet_ntoa(TG(req)->client_host);
  163. /* string representation of IPs are never larger than 512 bytes */
  164. if (p) {
  165. memcpy(buf, p, strlen(p) + 1);
  166. ADD_STRING("REMOTE_ADDR");
  167. ADD_STRING("REMOTE_HOST");
  168. }
  169. snprintf(buf, sizeof(buf), "%d", CGI_SERVER_PORT(TG(req)));
  170. ADD_STRING("SERVER_PORT");
  171. #if 0
  172. snprintf(buf, BUF_SIZE, "/%s", TG(hc)->pathinfo);
  173. ADD_STRING("PATH_INFO");
  174. snprintf(buf, BUF_SIZE, "/%s", TG(hc)->origfilename);
  175. ADD_STRING("SCRIPT_NAME");
  176. #endif
  177. #define CONDADD(name, field) \
  178. if (TG(req)->field[0]) { \
  179. php_register_variable(#name, TG(req)->field, track_vars_array TSRMLS_CC); \
  180. }
  181. CONDADD(HTTP_REFERER, referer);
  182. CONDADD(HTTP_USER_AGENT, user_agent);
  183. CONDADD(HTTP_ACCEPT, accept);
  184. CONDADD(HTTP_ACCEPT_ENCODING, accept_encoding);
  185. CONDADD(HTTP_ACCEPT_LANGUAGE, accept_language);
  186. CONDADD(HTTP_COOKIE, cookies);
  187. CONDADD(CONTENT_TYPE, content_type);
  188. #if 0
  189. if (TG(hc)->contentlength != -1) {
  190. snprintf(buf, sizeof(buf), "%ld", (long) TG(hc)->contentlength);
  191. ADD_STRING("CONTENT_LENGTH");
  192. }
  193. #endif
  194. #if 0
  195. if (TG(hc)->authorization[0])
  196. php_register_variable("AUTH_TYPE", "Basic", track_vars_array TSRMLS_CC);
  197. #endif
  198. }
  199. static int php_tux_startup(sapi_module_struct *sapi_module)
  200. {
  201. if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {
  202. return FAILURE;
  203. } else {
  204. return SUCCESS;
  205. }
  206. }
  207. static sapi_module_struct tux_sapi_module = {
  208. "tux",
  209. "tux",
  210. php_tux_startup,
  211. php_module_shutdown_wrapper,
  212. NULL, /* activate */
  213. NULL, /* deactivate */
  214. sapi_tux_ub_write,
  215. NULL,
  216. NULL, /* get uid */
  217. NULL, /* getenv */
  218. php_error,
  219. NULL,
  220. sapi_tux_send_headers,
  221. NULL,
  222. sapi_tux_read_post,
  223. sapi_tux_read_cookies,
  224. sapi_tux_register_variables,
  225. NULL, /* Log message */
  226. NULL, /* Get request time */
  227. NULL, /* Child terminate */
  228. STANDARD_SAPI_MODULE_PROPERTIES
  229. };
  230. static void tux_module_main(TSRMLS_D)
  231. {
  232. zend_file_handle file_handle;
  233. file_handle.type = ZEND_HANDLE_FILENAME;
  234. file_handle.filename = SG(request_info).path_translated;
  235. file_handle.free_filename = 0;
  236. file_handle.opened_path = NULL;
  237. if (php_request_startup(TSRMLS_C) == FAILURE) {
  238. return;
  239. }
  240. php_execute_script(&file_handle TSRMLS_CC);
  241. php_request_shutdown(NULL);
  242. }
  243. static void tux_request_ctor(TSRMLS_D)
  244. {
  245. char buf[1024];
  246. int offset;
  247. size_t filename_len;
  248. size_t cwd_len;
  249. smart_str s = {0};
  250. char *p;
  251. TG(number_vec) = 0;
  252. TG(header_vec) = NULL;
  253. SG(request_info).query_string = strdup(TG(req)->query);
  254. smart_str_appends_ex(&s, "/", 1);
  255. smart_str_appends_ex(&s, TG(req)->query, 1);
  256. smart_str_0(&s);
  257. p = strchr(s.c, '&');
  258. if (p)
  259. *p = '\0';
  260. SG(request_info).path_translated = s.c;
  261. s.c = NULL;
  262. smart_str_appendc_ex(&s, '/', 1);
  263. smart_str_appends_ex(&s, TG(req)->objectname, 1);
  264. smart_str_0(&s);
  265. SG(request_info).request_uri = s.c;
  266. SG(request_info).request_method = CGI_REQUEST_METHOD(TG(req));
  267. if(TG(req)->http_version == HTTP_1_1) SG(request_info).proto_num = 1001;
  268. else SG(request_info).proto_num = 1000;
  269. SG(sapi_headers).http_response_code = 200;
  270. SG(request_info).content_type = TG(req)->content_type;
  271. SG(request_info).content_length = 0; /* TG(req)->contentlength; */
  272. #if 0
  273. php_handle_auth_data(TG(hc)->authorization TSRMLS_CC);
  274. #endif
  275. }
  276. static void tux_request_dtor(TSRMLS_D)
  277. {
  278. if (TG(header_vec)) {
  279. /* free status_line */
  280. free(TG(header_vec)[0].iov_base);
  281. free(TG(header_vec));
  282. }
  283. if (SG(request_info).query_string)
  284. free(SG(request_info).query_string);
  285. free(SG(request_info).request_uri);
  286. free(SG(request_info).path_translated);
  287. }
  288. #if 0
  289. static void *separate_thread(void *bla)
  290. {
  291. int fd;
  292. int i = 0;
  293. fd = (int) bla;
  294. while (i++ < 5) {
  295. send(fd, "test<br />\n", 9, 0);
  296. sleep(1);
  297. }
  298. tux(TUX_ACTION_CONTINUE_REQ, (user_req_t *) fd);
  299. /* We HAVE to trigger some event on the fd. Otherwise
  300. fast_thread won't wake up, so that the eventloop
  301. won't be entered -> TUX hangs */
  302. shutdown(fd, 2);
  303. pthread_exit(NULL);
  304. }
  305. #endif
  306. int TUXAPI_handle_events(user_req_t *req)
  307. {
  308. TSRMLS_FETCH();
  309. if (req->event == PHP_TUX_BACKGROUND_CONN) {
  310. tux_closed_conn(req->sock);
  311. return tux(TUX_ACTION_FINISH_CLOSE_REQ, req);
  312. }
  313. TG(req) = req;
  314. TG(tux_action) = TUX_ACTION_FINISH_CLOSE_REQ;
  315. tux_request_ctor(TSRMLS_C);
  316. tux_module_main(TSRMLS_C);
  317. tux_request_dtor(TSRMLS_C);
  318. return tux(TG(tux_action), req);
  319. }
  320. void tux_register_on_close(void (*arg)(int))
  321. {
  322. TG(on_close) = arg;
  323. }
  324. void tux_closed_conn(int fd)
  325. {
  326. TSRMLS_FETCH();
  327. if (TG(on_close)) TG(on_close)(fd);
  328. }
  329. int tux_get_fd(void)
  330. {
  331. TSRMLS_FETCH();
  332. return TG(req)->sock;
  333. }
  334. void tux_set_dont_close(void)
  335. {
  336. TSRMLS_FETCH();
  337. TG(req)->event = PHP_TUX_BACKGROUND_CONN;
  338. tux(TUX_ACTION_POSTPONE_REQ, TG(req));
  339. TG(tux_action) = TUX_ACTION_EVENTLOOP;
  340. }
  341. void TUXAPI_init(void)
  342. {
  343. sapi_startup(&tux_sapi_module);
  344. tux_sapi_module.startup(&tux_sapi_module);
  345. SG(server_context) = (void *) 1;
  346. }
  347. void doesnotmatter_fini(void)
  348. {
  349. if (SG(server_context) != NULL) {
  350. tux_sapi_module.shutdown(&tux_sapi_module);
  351. sapi_shutdown();
  352. }
  353. }
  354. /*
  355. * Local variables:
  356. * tab-width: 4
  357. * c-basic-offset: 4
  358. * End:
  359. * vim600: sw=4 ts=4 fdm=marker
  360. * vim<600: sw=4 ts=4
  361. */