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