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

/main/SAPI.c

http://github.com/infusion/PHP
C | 954 lines | 743 code | 126 blank | 85 comment | 181 complexity | 1b6b0b2d29771bd956f96d93ca28cc09 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2011 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. | Original design: Shane Caraveo <shane@caraveo.com> |
  16. | Authors: Andi Gutmans <andi@zend.com> |
  17. | Zeev Suraski <zeev@zend.com> |
  18. +----------------------------------------------------------------------+
  19. */
  20. /* $Id: SAPI.c 309319 2011-03-16 23:54:14Z pajoye $ */
  21. #include <ctype.h>
  22. #include <sys/stat.h>
  23. #include "php.h"
  24. #include "SAPI.h"
  25. #include "php_variables.h"
  26. #include "php_ini.h"
  27. #include "ext/standard/php_string.h"
  28. #include "ext/standard/pageinfo.h"
  29. #if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE)
  30. #include "ext/pcre/php_pcre.h"
  31. #endif
  32. #ifdef ZTS
  33. #include "TSRM.h"
  34. #endif
  35. #ifdef HAVE_SYS_TIME_H
  36. #include <sys/time.h>
  37. #endif
  38. #include "rfc1867.h"
  39. #ifdef PHP_WIN32
  40. #define STRCASECMP stricmp
  41. #else
  42. #define STRCASECMP strcasecmp
  43. #endif
  44. #include "php_content_types.h"
  45. #ifdef ZTS
  46. SAPI_API int sapi_globals_id;
  47. #else
  48. sapi_globals_struct sapi_globals;
  49. #endif
  50. static void sapi_globals_ctor(sapi_globals_struct *sapi_globals TSRMLS_DC)
  51. {
  52. memset(sapi_globals, 0, sizeof(*sapi_globals));
  53. zend_hash_init_ex(&sapi_globals->known_post_content_types, 5, NULL, NULL, 1, 0);
  54. php_setup_sapi_content_types(TSRMLS_C);
  55. }
  56. static void sapi_globals_dtor(sapi_globals_struct *sapi_globals TSRMLS_DC)
  57. {
  58. zend_hash_destroy(&sapi_globals->known_post_content_types);
  59. }
  60. /* True globals (no need for thread safety) */
  61. SAPI_API sapi_module_struct sapi_module;
  62. SAPI_API void sapi_startup(sapi_module_struct *sf)
  63. {
  64. sf->ini_entries = NULL;
  65. sapi_module = *sf;
  66. #ifdef ZTS
  67. ts_allocate_id(&sapi_globals_id, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor);
  68. # ifdef PHP_WIN32
  69. _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
  70. # endif
  71. #else
  72. sapi_globals_ctor(&sapi_globals);
  73. #endif
  74. virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */
  75. #ifdef PHP_WIN32
  76. tsrm_win32_startup();
  77. #endif
  78. reentrancy_startup();
  79. }
  80. SAPI_API void sapi_shutdown(void)
  81. {
  82. #ifdef ZTS
  83. ts_free_id(sapi_globals_id);
  84. #else
  85. sapi_globals_dtor(&sapi_globals);
  86. #endif
  87. reentrancy_shutdown();
  88. virtual_cwd_shutdown();
  89. #ifdef PHP_WIN32
  90. tsrm_win32_shutdown();
  91. #endif
  92. }
  93. SAPI_API void sapi_free_header(sapi_header_struct *sapi_header)
  94. {
  95. efree(sapi_header->header);
  96. }
  97. SAPI_API void sapi_handle_post(void *arg TSRMLS_DC)
  98. {
  99. if (SG(request_info).post_entry && SG(request_info).content_type_dup) {
  100. SG(request_info).post_entry->post_handler(SG(request_info).content_type_dup, arg TSRMLS_CC);
  101. if (SG(request_info).post_data) {
  102. efree(SG(request_info).post_data);
  103. SG(request_info).post_data = NULL;
  104. }
  105. efree(SG(request_info).content_type_dup);
  106. SG(request_info).content_type_dup = NULL;
  107. }
  108. }
  109. static void sapi_read_post_data(TSRMLS_D)
  110. {
  111. sapi_post_entry *post_entry;
  112. uint content_type_length = strlen(SG(request_info).content_type);
  113. char *content_type = estrndup(SG(request_info).content_type, content_type_length);
  114. char *p;
  115. char oldchar=0;
  116. void (*post_reader_func)(TSRMLS_D) = NULL;
  117. /* dedicated implementation for increased performance:
  118. * - Make the content type lowercase
  119. * - Trim descriptive data, stay with the content-type only
  120. */
  121. for (p=content_type; p<content_type+content_type_length; p++) {
  122. switch (*p) {
  123. case ';':
  124. case ',':
  125. case ' ':
  126. content_type_length = p-content_type;
  127. oldchar = *p;
  128. *p = 0;
  129. break;
  130. default:
  131. *p = tolower(*p);
  132. break;
  133. }
  134. }
  135. /* now try to find an appropriate POST content handler */
  136. if (zend_hash_find(&SG(known_post_content_types), content_type,
  137. content_type_length+1, (void **) &post_entry) == SUCCESS) {
  138. /* found one, register it for use */
  139. SG(request_info).post_entry = post_entry;
  140. post_reader_func = post_entry->post_reader;
  141. } else {
  142. /* fallback */
  143. SG(request_info).post_entry = NULL;
  144. if (!sapi_module.default_post_reader) {
  145. /* no default reader ? */
  146. SG(request_info).content_type_dup = NULL;
  147. sapi_module.sapi_error(E_WARNING, "Unsupported content type: '%s'", content_type);
  148. return;
  149. }
  150. }
  151. if (oldchar) {
  152. *(p-1) = oldchar;
  153. }
  154. SG(request_info).content_type_dup = content_type;
  155. if(post_reader_func) {
  156. post_reader_func(TSRMLS_C);
  157. }
  158. if(sapi_module.default_post_reader) {
  159. sapi_module.default_post_reader(TSRMLS_C);
  160. }
  161. }
  162. SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data)
  163. {
  164. int read_bytes;
  165. int allocated_bytes=SAPI_POST_BLOCK_SIZE+1;
  166. if ((SG(post_max_size) > 0) && (SG(request_info).content_length > SG(post_max_size))) {
  167. php_error_docref(NULL TSRMLS_CC, E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes",
  168. SG(request_info).content_length, SG(post_max_size));
  169. return;
  170. }
  171. SG(request_info).post_data = emalloc(allocated_bytes);
  172. for (;;) {
  173. read_bytes = sapi_module.read_post(SG(request_info).post_data+SG(read_post_bytes), SAPI_POST_BLOCK_SIZE TSRMLS_CC);
  174. if (read_bytes<=0) {
  175. break;
  176. }
  177. SG(read_post_bytes) += read_bytes;
  178. if ((SG(post_max_size) > 0) && (SG(read_post_bytes) > SG(post_max_size))) {
  179. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Actual POST length does not match Content-Length, and exceeds %ld bytes", SG(post_max_size));
  180. break;
  181. }
  182. if (read_bytes < SAPI_POST_BLOCK_SIZE) {
  183. break;
  184. }
  185. if (SG(read_post_bytes)+SAPI_POST_BLOCK_SIZE >= allocated_bytes) {
  186. allocated_bytes = SG(read_post_bytes)+SAPI_POST_BLOCK_SIZE+1;
  187. SG(request_info).post_data = erealloc(SG(request_info).post_data, allocated_bytes);
  188. }
  189. }
  190. SG(request_info).post_data[SG(read_post_bytes)] = 0; /* terminating NULL */
  191. SG(request_info).post_data_length = SG(read_post_bytes);
  192. }
  193. SAPI_API char *sapi_get_default_content_type(TSRMLS_D)
  194. {
  195. char *mimetype, *charset, *content_type;
  196. mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE;
  197. charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
  198. if (strncasecmp(mimetype, "text/", 5) == 0 && *charset) {
  199. int len = strlen(mimetype) + sizeof("; charset=") + strlen(charset); /* sizeof() includes \0 */
  200. content_type = emalloc(len);
  201. snprintf(content_type, len, "%s; charset=%s", mimetype, charset);
  202. } else {
  203. content_type = estrdup(mimetype);
  204. }
  205. return content_type;
  206. }
  207. SAPI_API void sapi_get_default_content_type_header(sapi_header_struct *default_header TSRMLS_DC)
  208. {
  209. char *default_content_type = sapi_get_default_content_type(TSRMLS_C);
  210. int default_content_type_len = strlen(default_content_type);
  211. default_header->header_len = (sizeof("Content-type: ")-1) + default_content_type_len;
  212. default_header->header = emalloc(default_header->header_len+1);
  213. memcpy(default_header->header, "Content-type: ", sizeof("Content-type: "));
  214. memcpy(default_header->header+sizeof("Content-type: ")-1, default_content_type, default_content_type_len);
  215. default_header->header[default_header->header_len] = 0;
  216. efree(default_content_type);
  217. }
  218. /*
  219. * Add charset on content-type header if the MIME type starts with
  220. * "text/", the default_charset directive is not empty and
  221. * there is not already a charset option in there.
  222. *
  223. * If "mimetype" is non-NULL, it should point to a pointer allocated
  224. * with emalloc(). If a charset is added, the string will be
  225. * re-allocated and the new length is returned. If mimetype is
  226. * unchanged, 0 is returned.
  227. *
  228. */
  229. SAPI_API size_t sapi_apply_default_charset(char **mimetype, size_t len TSRMLS_DC)
  230. {
  231. char *charset, *newtype;
  232. size_t newlen;
  233. charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
  234. if (*mimetype != NULL) {
  235. if (*charset && strncmp(*mimetype, "text/", 5) == 0 && strstr(*mimetype, "charset=") == NULL) {
  236. newlen = len + (sizeof(";charset=")-1) + strlen(charset);
  237. newtype = emalloc(newlen + 1);
  238. PHP_STRLCPY(newtype, *mimetype, newlen + 1, len);
  239. strlcat(newtype, ";charset=", newlen + 1);
  240. strlcat(newtype, charset, newlen + 1);
  241. efree(*mimetype);
  242. *mimetype = newtype;
  243. return newlen;
  244. }
  245. }
  246. return 0;
  247. }
  248. SAPI_API void sapi_activate_headers_only(TSRMLS_D)
  249. {
  250. if (SG(request_info).headers_read == 1)
  251. return;
  252. SG(request_info).headers_read = 1;
  253. zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct),
  254. (void (*)(void *)) sapi_free_header, 0);
  255. SG(sapi_headers).send_default_content_type = 1;
  256. /* SG(sapi_headers).http_response_code = 200; */
  257. SG(sapi_headers).http_status_line = NULL;
  258. SG(sapi_headers).mimetype = NULL;
  259. SG(read_post_bytes) = 0;
  260. SG(request_info).post_data = NULL;
  261. SG(request_info).raw_post_data = NULL;
  262. SG(request_info).current_user = NULL;
  263. SG(request_info).current_user_length = 0;
  264. SG(request_info).no_headers = 0;
  265. SG(request_info).post_entry = NULL;
  266. SG(global_request_time) = 0;
  267. /*
  268. * It's possible to override this general case in the activate() callback,
  269. * if necessary.
  270. */
  271. if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
  272. SG(request_info).headers_only = 1;
  273. } else {
  274. SG(request_info).headers_only = 0;
  275. }
  276. if (SG(server_context)) {
  277. SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
  278. if (sapi_module.activate) {
  279. sapi_module.activate(TSRMLS_C);
  280. }
  281. }
  282. if (sapi_module.input_filter_init ) {
  283. sapi_module.input_filter_init(TSRMLS_C);
  284. }
  285. }
  286. /*
  287. * Called from php_request_startup() for every request.
  288. */
  289. SAPI_API void sapi_activate(TSRMLS_D)
  290. {
  291. zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), (void (*)(void *)) sapi_free_header, 0);
  292. SG(sapi_headers).send_default_content_type = 1;
  293. /*
  294. SG(sapi_headers).http_response_code = 200;
  295. */
  296. SG(sapi_headers).http_status_line = NULL;
  297. SG(sapi_headers).mimetype = NULL;
  298. SG(headers_sent) = 0;
  299. SG(read_post_bytes) = 0;
  300. SG(request_info).post_data = NULL;
  301. SG(request_info).raw_post_data = NULL;
  302. SG(request_info).current_user = NULL;
  303. SG(request_info).current_user_length = 0;
  304. SG(request_info).no_headers = 0;
  305. SG(request_info).post_entry = NULL;
  306. SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
  307. SG(global_request_time) = 0;
  308. /* It's possible to override this general case in the activate() callback, if
  309. * necessary.
  310. */
  311. if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
  312. SG(request_info).headers_only = 1;
  313. } else {
  314. SG(request_info).headers_only = 0;
  315. }
  316. SG(rfc1867_uploaded_files) = NULL;
  317. /* handle request mehtod */
  318. if (SG(server_context)) {
  319. if ( SG(request_info).request_method) {
  320. if(!strcmp(SG(request_info).request_method, "POST")
  321. && (SG(request_info).content_type)) {
  322. /* HTTP POST -> may contain form data to be read into variables
  323. depending on content type given
  324. */
  325. sapi_read_post_data(TSRMLS_C);
  326. } else {
  327. /* any other method with content payload will fill
  328. $HTTP_RAW_POST_DATA if enabled by always_populate_raw_post_data
  329. it is up to the webserver to decide whether to allow a method or not
  330. */
  331. SG(request_info).content_type_dup = NULL;
  332. if(sapi_module.default_post_reader) {
  333. sapi_module.default_post_reader(TSRMLS_C);
  334. }
  335. }
  336. } else {
  337. SG(request_info).content_type_dup = NULL;
  338. }
  339. /* Cookies */
  340. SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
  341. if (sapi_module.activate) {
  342. sapi_module.activate(TSRMLS_C);
  343. }
  344. }
  345. if (sapi_module.input_filter_init ) {
  346. sapi_module.input_filter_init(TSRMLS_C);
  347. }
  348. }
  349. static void sapi_send_headers_free(TSRMLS_D)
  350. {
  351. if (SG(sapi_headers).http_status_line) {
  352. efree(SG(sapi_headers).http_status_line);
  353. SG(sapi_headers).http_status_line = NULL;
  354. }
  355. }
  356. SAPI_API void sapi_deactivate(TSRMLS_D)
  357. {
  358. zend_llist_destroy(&SG(sapi_headers).headers);
  359. if (SG(request_info).post_data) {
  360. efree(SG(request_info).post_data);
  361. } else if (SG(server_context)) {
  362. if(sapi_module.read_post) {
  363. /* make sure we've consumed all request input data */
  364. char dummy[SAPI_POST_BLOCK_SIZE];
  365. int read_bytes;
  366. while((read_bytes = sapi_module.read_post(dummy, sizeof(dummy)-1 TSRMLS_CC)) > 0) {
  367. SG(read_post_bytes) += read_bytes;
  368. }
  369. }
  370. }
  371. if (SG(request_info).raw_post_data) {
  372. efree(SG(request_info).raw_post_data);
  373. }
  374. if (SG(request_info).auth_user) {
  375. efree(SG(request_info).auth_user);
  376. }
  377. if (SG(request_info).auth_password) {
  378. efree(SG(request_info).auth_password);
  379. }
  380. if (SG(request_info).auth_digest) {
  381. efree(SG(request_info).auth_digest);
  382. }
  383. if (SG(request_info).content_type_dup) {
  384. efree(SG(request_info).content_type_dup);
  385. }
  386. if (SG(request_info).current_user) {
  387. efree(SG(request_info).current_user);
  388. }
  389. if (sapi_module.deactivate) {
  390. sapi_module.deactivate(TSRMLS_C);
  391. }
  392. if (SG(rfc1867_uploaded_files)) {
  393. destroy_uploaded_files_hash(TSRMLS_C);
  394. }
  395. if (SG(sapi_headers).mimetype) {
  396. efree(SG(sapi_headers).mimetype);
  397. SG(sapi_headers).mimetype = NULL;
  398. }
  399. sapi_send_headers_free(TSRMLS_C);
  400. SG(sapi_started) = 0;
  401. SG(headers_sent) = 0;
  402. SG(request_info).headers_read = 0;
  403. SG(global_request_time) = 0;
  404. }
  405. SAPI_API void sapi_initialize_empty_request(TSRMLS_D)
  406. {
  407. SG(server_context) = NULL;
  408. SG(request_info).request_method = NULL;
  409. SG(request_info).auth_digest = SG(request_info).auth_user = SG(request_info).auth_password = NULL;
  410. SG(request_info).content_type_dup = NULL;
  411. }
  412. static int sapi_extract_response_code(const char *header_line)
  413. {
  414. int code = 200;
  415. const char *ptr;
  416. for (ptr = header_line; *ptr; ptr++) {
  417. if (*ptr == ' ' && *(ptr + 1) != ' ') {
  418. code = atoi(ptr + 1);
  419. break;
  420. }
  421. }
  422. return code;
  423. }
  424. static void sapi_update_response_code(int ncode TSRMLS_DC)
  425. {
  426. /* if the status code did not change, we do not want
  427. to change the status line, and no need to change the code */
  428. if (SG(sapi_headers).http_response_code == ncode) {
  429. return;
  430. }
  431. if (SG(sapi_headers).http_status_line) {
  432. efree(SG(sapi_headers).http_status_line);
  433. SG(sapi_headers).http_status_line = NULL;
  434. }
  435. SG(sapi_headers).http_response_code = ncode;
  436. }
  437. static int sapi_find_matching_header(void *element1, void *element2)
  438. {
  439. int len = strlen((char*)element2);
  440. return strncasecmp(((sapi_header_struct*)element1)->header, (char*)element2, len) == 0 && ((sapi_header_struct*)element1)->header[len] == ':';
  441. }
  442. SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace TSRMLS_DC)
  443. {
  444. sapi_header_line ctr = {0};
  445. int r;
  446. ctr.line = header_line;
  447. ctr.line_len = header_line_len;
  448. r = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD,
  449. &ctr TSRMLS_CC);
  450. if (!duplicate)
  451. efree(header_line);
  452. return r;
  453. }
  454. SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
  455. {
  456. int retval;
  457. sapi_header_struct sapi_header;
  458. char *colon_offset;
  459. long myuid = 0L;
  460. char *header_line;
  461. uint header_line_len;
  462. int http_response_code;
  463. if (SG(headers_sent) && !SG(request_info).no_headers) {
  464. char *output_start_filename = php_get_output_start_filename(TSRMLS_C);
  465. int output_start_lineno = php_get_output_start_lineno(TSRMLS_C);
  466. if (output_start_filename) {
  467. sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)",
  468. output_start_filename, output_start_lineno);
  469. } else {
  470. sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent");
  471. }
  472. return FAILURE;
  473. }
  474. switch (op) {
  475. case SAPI_HEADER_SET_STATUS:
  476. sapi_update_response_code((int)(zend_intptr_t) arg TSRMLS_CC);
  477. return SUCCESS;
  478. case SAPI_HEADER_ADD:
  479. case SAPI_HEADER_REPLACE:
  480. case SAPI_HEADER_DELETE: {
  481. sapi_header_line *p = arg;
  482. if (!p->line || !p->line_len) {
  483. return FAILURE;
  484. }
  485. header_line = p->line;
  486. header_line_len = p->line_len;
  487. http_response_code = p->response_code;
  488. break;
  489. }
  490. case SAPI_HEADER_DELETE_ALL:
  491. if (sapi_module.header_handler) {
  492. sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
  493. }
  494. zend_llist_clean(&SG(sapi_headers).headers);
  495. return SUCCESS;
  496. default:
  497. return FAILURE;
  498. }
  499. header_line = estrndup(header_line, header_line_len);
  500. /* cut of trailing spaces, linefeeds and carriage-returns */
  501. while(header_line_len && isspace(header_line[header_line_len-1]))
  502. header_line[--header_line_len]='\0';
  503. if (op == SAPI_HEADER_DELETE) {
  504. if (strchr(header_line, ':')) {
  505. efree(header_line);
  506. sapi_module.sapi_error(E_WARNING, "Header to delete may not contain colon.");
  507. return FAILURE;
  508. }
  509. } else {
  510. /* new line safety check */
  511. char *s = header_line, *e = header_line + header_line_len, *p;
  512. while (s < e && (p = memchr(s, '\n', (e - s)))) {
  513. if (*(p + 1) == ' ' || *(p + 1) == '\t') {
  514. s = p + 1;
  515. continue;
  516. }
  517. efree(header_line);
  518. sapi_module.sapi_error(E_WARNING, "Header may not contain more than a single header, new line detected.");
  519. return FAILURE;
  520. }
  521. }
  522. sapi_header.header = header_line;
  523. sapi_header.header_len = header_line_len;
  524. if (op == SAPI_HEADER_DELETE) {
  525. if (sapi_module.header_handler) {
  526. sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
  527. }
  528. zend_llist_del_element(&SG(sapi_headers).headers, sapi_header.header, (int(*)(void*, void*))sapi_find_matching_header);
  529. sapi_free_header(&sapi_header);
  530. return SUCCESS;
  531. }
  532. /* Check the header for a few cases that we have special support for in SAPI */
  533. if (header_line_len>=5
  534. && !strncasecmp(header_line, "HTTP/", 5)) {
  535. /* filter out the response code */
  536. sapi_update_response_code(sapi_extract_response_code(header_line) TSRMLS_CC);
  537. /* sapi_update_response_code doesn't free the status line if the code didn't change */
  538. if (SG(sapi_headers).http_status_line) {
  539. efree(SG(sapi_headers).http_status_line);
  540. }
  541. SG(sapi_headers).http_status_line = header_line;
  542. return SUCCESS;
  543. } else {
  544. colon_offset = strchr(header_line, ':');
  545. if (colon_offset) {
  546. *colon_offset = 0;
  547. if (!STRCASECMP(header_line, "Content-Type")) {
  548. char *ptr = colon_offset+1, *mimetype = NULL, *newheader;
  549. size_t len = header_line_len - (ptr - header_line), newlen;
  550. while (*ptr == ' ') {
  551. ptr++;
  552. len--;
  553. }
  554. /* Disable possible output compression for images */
  555. if (!strncmp(ptr, "image/", sizeof("image/")-1)) {
  556. zend_alter_ini_entry("zlib.output_compression", sizeof("zlib.output_compression"), "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
  557. }
  558. mimetype = estrdup(ptr);
  559. newlen = sapi_apply_default_charset(&mimetype, len TSRMLS_CC);
  560. if (!SG(sapi_headers).mimetype){
  561. SG(sapi_headers).mimetype = estrdup(mimetype);
  562. }
  563. if (newlen != 0) {
  564. newlen += sizeof("Content-type: ");
  565. newheader = emalloc(newlen);
  566. PHP_STRLCPY(newheader, "Content-type: ", newlen, sizeof("Content-type: ")-1);
  567. strlcat(newheader, mimetype, newlen);
  568. sapi_header.header = newheader;
  569. sapi_header.header_len = newlen - 1;
  570. efree(header_line);
  571. }
  572. efree(mimetype);
  573. SG(sapi_headers).send_default_content_type = 0;
  574. } else if (!STRCASECMP(header_line, "Location")) {
  575. if ((SG(sapi_headers).http_response_code < 300 ||
  576. SG(sapi_headers).http_response_code > 307) &&
  577. SG(sapi_headers).http_response_code != 201) {
  578. /* Return a Found Redirect if one is not already specified */
  579. if (http_response_code) { /* user specified redirect code */
  580. sapi_update_response_code(http_response_code TSRMLS_CC);
  581. } else if (SG(request_info).proto_num > 1000 &&
  582. SG(request_info).request_method &&
  583. strcmp(SG(request_info).request_method, "HEAD") &&
  584. strcmp(SG(request_info).request_method, "GET")) {
  585. sapi_update_response_code(303 TSRMLS_CC);
  586. } else {
  587. sapi_update_response_code(302 TSRMLS_CC);
  588. }
  589. }
  590. } else if (!STRCASECMP(header_line, "WWW-Authenticate")) { /* HTTP Authentication */
  591. sapi_update_response_code(401 TSRMLS_CC); /* authentication-required */
  592. {
  593. myuid = php_getuid();
  594. efree(header_line);
  595. sapi_header.header_len = spprintf(&sapi_header.header, 0, "WWW-Authenticate: Basic realm=\"%ld\"", myuid);
  596. }
  597. }
  598. if (sapi_header.header==header_line) {
  599. *colon_offset = ':';
  600. }
  601. }
  602. }
  603. if (http_response_code) {
  604. sapi_update_response_code(http_response_code TSRMLS_CC);
  605. }
  606. if (sapi_module.header_handler) {
  607. retval = sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
  608. } else {
  609. retval = SAPI_HEADER_ADD;
  610. }
  611. if (retval & SAPI_HEADER_ADD) {
  612. /* in replace mode first remove the header if it already exists in the headers llist */
  613. if (op == SAPI_HEADER_REPLACE) {
  614. colon_offset = strchr(sapi_header.header, ':');
  615. if (colon_offset) {
  616. char sav;
  617. sav = *colon_offset;
  618. *colon_offset = 0;
  619. zend_llist_del_element(&SG(sapi_headers).headers, sapi_header.header, (int(*)(void*, void*))sapi_find_matching_header);
  620. *colon_offset = sav;
  621. }
  622. }
  623. zend_llist_add_element(&SG(sapi_headers).headers, (void *) &sapi_header);
  624. } else {
  625. sapi_free_header(&sapi_header);
  626. }
  627. return SUCCESS;
  628. }
  629. SAPI_API int sapi_send_headers(TSRMLS_D)
  630. {
  631. int retval;
  632. int ret = FAILURE;
  633. if (SG(headers_sent) || SG(request_info).no_headers) {
  634. return SUCCESS;
  635. }
  636. /* Success-oriented. We set headers_sent to 1 here to avoid an infinite loop
  637. * in case of an error situation.
  638. */
  639. if (SG(sapi_headers).send_default_content_type && sapi_module.send_headers) {
  640. sapi_header_struct default_header;
  641. sapi_get_default_content_type_header(&default_header TSRMLS_CC);
  642. sapi_add_header_ex(default_header.header, default_header.header_len, 0, 0 TSRMLS_CC);
  643. }
  644. SG(headers_sent) = 1;
  645. if (sapi_module.send_headers) {
  646. retval = sapi_module.send_headers(&SG(sapi_headers) TSRMLS_CC);
  647. } else {
  648. retval = SAPI_HEADER_DO_SEND;
  649. }
  650. switch (retval) {
  651. case SAPI_HEADER_SENT_SUCCESSFULLY:
  652. ret = SUCCESS;
  653. break;
  654. case SAPI_HEADER_DO_SEND: {
  655. sapi_header_struct http_status_line;
  656. char buf[255];
  657. if (SG(sapi_headers).http_status_line) {
  658. http_status_line.header = SG(sapi_headers).http_status_line;
  659. http_status_line.header_len = strlen(SG(sapi_headers).http_status_line);
  660. } else {
  661. http_status_line.header = buf;
  662. http_status_line.header_len = slprintf(buf, sizeof(buf), "HTTP/1.0 %d X", SG(sapi_headers).http_response_code);
  663. }
  664. sapi_module.send_header(&http_status_line, SG(server_context) TSRMLS_CC);
  665. }
  666. zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) sapi_module.send_header, SG(server_context) TSRMLS_CC);
  667. if(SG(sapi_headers).send_default_content_type) {
  668. sapi_header_struct default_header;
  669. sapi_get_default_content_type_header(&default_header TSRMLS_CC);
  670. sapi_module.send_header(&default_header, SG(server_context) TSRMLS_CC);
  671. sapi_free_header(&default_header);
  672. }
  673. sapi_module.send_header(NULL, SG(server_context) TSRMLS_CC);
  674. ret = SUCCESS;
  675. break;
  676. case SAPI_HEADER_SEND_FAILED:
  677. SG(headers_sent) = 0;
  678. ret = FAILURE;
  679. break;
  680. }
  681. sapi_send_headers_free(TSRMLS_C);
  682. return ret;
  683. }
  684. SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entries TSRMLS_DC)
  685. {
  686. sapi_post_entry *p=post_entries;
  687. while (p->content_type) {
  688. if (sapi_register_post_entry(p TSRMLS_CC) == FAILURE) {
  689. return FAILURE;
  690. }
  691. p++;
  692. }
  693. return SUCCESS;
  694. }
  695. SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
  696. {
  697. if (SG(sapi_started) && EG(in_execution)) {
  698. return FAILURE;
  699. }
  700. return zend_hash_add(&SG(known_post_content_types),
  701. post_entry->content_type, post_entry->content_type_len+1,
  702. (void *) post_entry, sizeof(sapi_post_entry), NULL);
  703. }
  704. SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
  705. {
  706. if (SG(sapi_started) && EG(in_execution)) {
  707. return;
  708. }
  709. zend_hash_del(&SG(known_post_content_types), post_entry->content_type,
  710. post_entry->content_type_len+1);
  711. }
  712. SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D))
  713. {
  714. TSRMLS_FETCH();
  715. if (SG(sapi_started) && EG(in_execution)) {
  716. return FAILURE;
  717. }
  718. sapi_module.default_post_reader = default_post_reader;
  719. return SUCCESS;
  720. }
  721. SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC))
  722. {
  723. TSRMLS_FETCH();
  724. if (SG(sapi_started) && EG(in_execution)) {
  725. return FAILURE;
  726. }
  727. sapi_module.treat_data = treat_data;
  728. return SUCCESS;
  729. }
  730. SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC), unsigned int (*input_filter_init)(TSRMLS_D))
  731. {
  732. TSRMLS_FETCH();
  733. if (SG(sapi_started) && EG(in_execution)) {
  734. return FAILURE;
  735. }
  736. sapi_module.input_filter = input_filter;
  737. sapi_module.input_filter_init = input_filter_init;
  738. return SUCCESS;
  739. }
  740. SAPI_API int sapi_flush(TSRMLS_D)
  741. {
  742. if (sapi_module.flush) {
  743. sapi_module.flush(SG(server_context));
  744. return SUCCESS;
  745. } else {
  746. return FAILURE;
  747. }
  748. }
  749. SAPI_API struct stat *sapi_get_stat(TSRMLS_D)
  750. {
  751. if (sapi_module.get_stat) {
  752. return sapi_module.get_stat(TSRMLS_C);
  753. } else {
  754. if (!SG(request_info).path_translated || (VCWD_STAT(SG(request_info).path_translated, &SG(global_stat)) == -1)) {
  755. return NULL;
  756. }
  757. return &SG(global_stat);
  758. }
  759. }
  760. SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC)
  761. {
  762. if (sapi_module.getenv) {
  763. char *value, *tmp = sapi_module.getenv(name, name_len TSRMLS_CC);
  764. if (tmp) {
  765. value = estrdup(tmp);
  766. } else {
  767. return NULL;
  768. }
  769. sapi_module.input_filter(PARSE_ENV, name, &value, strlen(value), NULL TSRMLS_CC);
  770. return value;
  771. }
  772. return NULL;
  773. }
  774. SAPI_API int sapi_get_fd(int *fd TSRMLS_DC)
  775. {
  776. if (sapi_module.get_fd) {
  777. return sapi_module.get_fd(fd TSRMLS_CC);
  778. } else {
  779. return FAILURE;
  780. }
  781. }
  782. SAPI_API int sapi_force_http_10(TSRMLS_D)
  783. {
  784. if (sapi_module.force_http_10) {
  785. return sapi_module.force_http_10(TSRMLS_C);
  786. } else {
  787. return FAILURE;
  788. }
  789. }
  790. SAPI_API int sapi_get_target_uid(uid_t *obj TSRMLS_DC)
  791. {
  792. if (sapi_module.get_target_uid) {
  793. return sapi_module.get_target_uid(obj TSRMLS_CC);
  794. } else {
  795. return FAILURE;
  796. }
  797. }
  798. SAPI_API int sapi_get_target_gid(gid_t *obj TSRMLS_DC)
  799. {
  800. if (sapi_module.get_target_gid) {
  801. return sapi_module.get_target_gid(obj TSRMLS_CC);
  802. } else {
  803. return FAILURE;
  804. }
  805. }
  806. SAPI_API time_t sapi_get_request_time(TSRMLS_D)
  807. {
  808. if(SG(global_request_time)) return SG(global_request_time);
  809. if (PG(use_sapi_time) && sapi_module.get_request_time && SG(server_context)) {
  810. SG(global_request_time) = sapi_module.get_request_time(TSRMLS_C);
  811. } else {
  812. SG(global_request_time) = time(0);
  813. }
  814. return SG(global_request_time);
  815. }
  816. SAPI_API void sapi_terminate_process(TSRMLS_D) {
  817. if (sapi_module.terminate_process) {
  818. sapi_module.terminate_process(TSRMLS_C);
  819. }
  820. }
  821. /*
  822. * Local variables:
  823. * tab-width: 4
  824. * c-basic-offset: 4
  825. * End:
  826. * vim600: sw=4 ts=4 fdm=marker
  827. * vim<600: sw=4 ts=4
  828. */