1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2015 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$ */
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#ifdef ZTS
36#include "TSRM.h"
37#endif
38#ifdef HAVE_SYS_TIME_H
39#include <sys/time.h>
40#elif defined(PHP_WIN32)
41#include "win32/time.h"
42#endif
43
44#include "rfc1867.h"
45
46#ifdef PHP_WIN32
47#define STRCASECMP stricmp
48#else
49#define STRCASECMP strcasecmp
50#endif
51
52#include "php_content_types.h"
53
54#ifdef ZTS
55SAPI_API int sapi_globals_id;
56#else
57sapi_globals_struct sapi_globals;
58#endif
59
60static void _type_dtor(zval *zv)
61{
62    free(Z_PTR_P(zv));
63}
64
65static void sapi_globals_ctor(sapi_globals_struct *sapi_globals)
66{
67#ifdef ZTS
68    ZEND_TSRMLS_CACHE_UPDATE();
69#endif
70    memset(sapi_globals, 0, sizeof(*sapi_globals));
71    zend_hash_init_ex(&sapi_globals->known_post_content_types, 8, NULL, _type_dtor, 1, 0);
72    php_setup_sapi_content_types();
73}
74
75static void sapi_globals_dtor(sapi_globals_struct *sapi_globals)
76{
77    zend_hash_destroy(&sapi_globals->known_post_content_types);
78}
79
80/* True globals (no need for thread safety) */
81SAPI_API sapi_module_struct sapi_module;
82
83
84SAPI_API void sapi_startup(sapi_module_struct *sf)
85{
86    sf->ini_entries = NULL;
87    sapi_module = *sf;
88
89#ifdef ZTS
90    ts_allocate_id(&sapi_globals_id, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor);
91# ifdef PHP_WIN32
92    _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
93# endif
94#else
95    sapi_globals_ctor(&sapi_globals);
96#endif
97
98#ifdef PHP_WIN32
99    tsrm_win32_startup();
100#endif
101
102    reentrancy_startup();
103}
104
105SAPI_API void sapi_shutdown(void)
106{
107#ifdef ZTS
108    ts_free_id(sapi_globals_id);
109#else
110    sapi_globals_dtor(&sapi_globals);
111#endif
112
113    reentrancy_shutdown();
114
115#ifdef PHP_WIN32
116    tsrm_win32_shutdown();
117#endif
118}
119
120
121SAPI_API void sapi_free_header(sapi_header_struct *sapi_header)
122{
123    efree(sapi_header->header);
124}
125
126/* {{{ proto bool header_register_callback(mixed callback)
127   call a header function */
128PHP_FUNCTION(header_register_callback)
129{
130    zval *callback_func;
131
132    if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &callback_func) == FAILURE) {
133        return;
134    }
135
136    if (!zend_is_callable(callback_func, 0, NULL)) {
137        RETURN_FALSE;
138    }
139
140    if (Z_TYPE(SG(callback_func)) != IS_UNDEF) {
141        zval_ptr_dtor(&SG(callback_func));
142        SG(fci_cache) = empty_fcall_info_cache;
143    }
144
145    ZVAL_COPY(&SG(callback_func), callback_func);
146
147    RETURN_TRUE;
148}
149/* }}} */
150
151static void sapi_run_header_callback(void)
152{
153    int   error;
154    zend_fcall_info fci;
155    char *callback_error = NULL;
156    zval retval;
157
158    if (zend_fcall_info_init(&SG(callback_func), 0, &fci, &SG(fci_cache), NULL, &callback_error) == SUCCESS) {
159        fci.retval = &retval;
160
161        error = zend_call_function(&fci, &SG(fci_cache));
162        if (error == FAILURE) {
163            goto callback_failed;
164        } else {
165            zval_ptr_dtor(&retval);
166        }
167    } else {
168callback_failed:
169        php_error_docref(NULL, E_WARNING, "Could not call the sapi_header_callback");
170    }
171
172    if (callback_error) {
173        efree(callback_error);
174    }
175}
176
177SAPI_API void sapi_handle_post(void *arg)
178{
179    if (SG(request_info).post_entry && SG(request_info).content_type_dup) {
180        SG(request_info).post_entry->post_handler(SG(request_info).content_type_dup, arg);
181        efree(SG(request_info).content_type_dup);
182        SG(request_info).content_type_dup = NULL;
183    }
184}
185
186static void sapi_read_post_data(void)
187{
188    sapi_post_entry *post_entry;
189    uint content_type_length = (uint)strlen(SG(request_info).content_type);
190    char *content_type = estrndup(SG(request_info).content_type, content_type_length);
191    char *p;
192    char oldchar=0;
193    void (*post_reader_func)(void) = NULL;
194
195
196    /* dedicated implementation for increased performance:
197     * - Make the content type lowercase
198     * - Trim descriptive data, stay with the content-type only
199     */
200    for (p=content_type; p<content_type+content_type_length; p++) {
201        switch (*p) {
202            case ';':
203            case ',':
204            case ' ':
205                content_type_length = p-content_type;
206                oldchar = *p;
207                *p = 0;
208                break;
209            default:
210                *p = tolower(*p);
211                break;
212        }
213    }
214
215    /* now try to find an appropriate POST content handler */
216    if ((post_entry = zend_hash_str_find_ptr(&SG(known_post_content_types), content_type,
217            content_type_length)) != NULL) {
218        /* found one, register it for use */
219        SG(request_info).post_entry = post_entry;
220        post_reader_func = post_entry->post_reader;
221    } else {
222        /* fallback */
223        SG(request_info).post_entry = NULL;
224        if (!sapi_module.default_post_reader) {
225            /* no default reader ? */
226            SG(request_info).content_type_dup = NULL;
227            sapi_module.sapi_error(E_WARNING, "Unsupported content type:  '%s'", content_type);
228            return;
229        }
230    }
231    if (oldchar) {
232        *(p-1) = oldchar;
233    }
234
235    SG(request_info).content_type_dup = content_type;
236
237    if(post_reader_func) {
238        post_reader_func();
239    }
240
241    if(sapi_module.default_post_reader) {
242        sapi_module.default_post_reader();
243    }
244}
245
246SAPI_API size_t sapi_read_post_block(char *buffer, size_t buflen)
247{
248    size_t read_bytes;
249
250    if (!sapi_module.read_post) {
251        return 0;
252    }
253
254    read_bytes = sapi_module.read_post(buffer, buflen);
255
256    if (read_bytes > 0) {
257        /* gogo */
258        SG(read_post_bytes) += read_bytes;
259    }
260    if (read_bytes < buflen) {
261        /* done */
262        SG(post_read) = 1;
263    }
264
265    return read_bytes;
266}
267
268SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data)
269{
270    if ((SG(post_max_size) > 0) && (SG(request_info).content_length > SG(post_max_size))) {
271        php_error_docref(NULL, E_WARNING, "POST Content-Length of %pd bytes exceeds the limit of %pd bytes",
272                    SG(request_info).content_length, SG(post_max_size));
273        return;
274    }
275
276
277    SG(request_info).request_body = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir));
278
279    if (sapi_module.read_post) {
280        size_t read_bytes;
281
282        for (;;) {
283            char buffer[SAPI_POST_BLOCK_SIZE];
284
285            read_bytes = sapi_read_post_block(buffer, SAPI_POST_BLOCK_SIZE);
286
287            if (read_bytes > 0) {
288                php_stream_write(SG(request_info).request_body, buffer, read_bytes);
289            }
290
291            if ((SG(post_max_size) > 0) && (SG(read_post_bytes) > SG(post_max_size))) {
292                php_error_docref(NULL, E_WARNING, "Actual POST length does not match Content-Length, and exceeds " ZEND_LONG_FMT " bytes", SG(post_max_size));
293                break;
294            }
295
296            if (read_bytes < SAPI_POST_BLOCK_SIZE) {
297                /* done */
298                break;
299            }
300        }
301        php_stream_rewind(SG(request_info).request_body);
302    }
303}
304
305
306static inline char *get_default_content_type(uint prefix_len, uint *len)
307{
308    char *mimetype, *charset, *content_type;
309    uint mimetype_len, charset_len;
310
311    if (SG(default_mimetype)) {
312        mimetype = SG(default_mimetype);
313        mimetype_len = (uint)strlen(SG(default_mimetype));
314    } else {
315        mimetype = SAPI_DEFAULT_MIMETYPE;
316        mimetype_len = sizeof(SAPI_DEFAULT_MIMETYPE) - 1;
317    }
318    if (SG(default_charset)) {
319        charset = SG(default_charset);
320        charset_len = (uint)strlen(SG(default_charset));
321    } else {
322        charset = SAPI_DEFAULT_CHARSET;
323        charset_len = sizeof(SAPI_DEFAULT_CHARSET) - 1;
324    }
325
326    if (*charset && strncasecmp(mimetype, "text/", 5) == 0) {
327        char *p;
328
329        *len = prefix_len + mimetype_len + sizeof("; charset=") - 1 + charset_len;
330        content_type = (char*)emalloc(*len + 1);
331        p = content_type + prefix_len;
332        memcpy(p, mimetype, mimetype_len);
333        p += mimetype_len;
334        memcpy(p, "; charset=", sizeof("; charset=") - 1);
335        p += sizeof("; charset=") - 1;
336        memcpy(p, charset, charset_len + 1);
337    } else {
338        *len = prefix_len + mimetype_len;
339        content_type = (char*)emalloc(*len + 1);
340        memcpy(content_type + prefix_len, mimetype, mimetype_len + 1);
341    }
342    return content_type;
343}
344
345
346SAPI_API char *sapi_get_default_content_type(void)
347{
348    uint len;
349
350    return get_default_content_type(0, &len);
351}
352
353
354SAPI_API void sapi_get_default_content_type_header(sapi_header_struct *default_header)
355{
356    uint len;
357
358    default_header->header = get_default_content_type(sizeof("Content-type: ")-1, &len);
359    default_header->header_len = len;
360    memcpy(default_header->header, "Content-type: ", sizeof("Content-type: ") - 1);
361}
362
363/*
364 * Add charset on content-type header if the MIME type starts with
365 * "text/", the default_charset directive is not empty and
366 * there is not already a charset option in there.
367 *
368 * If "mimetype" is non-NULL, it should point to a pointer allocated
369 * with emalloc().  If a charset is added, the string will be
370 * re-allocated and the new length is returned.  If mimetype is
371 * unchanged, 0 is returned.
372 *
373 */
374SAPI_API size_t sapi_apply_default_charset(char **mimetype, size_t len)
375{
376    char *charset, *newtype;
377    size_t newlen;
378    charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
379
380    if (*mimetype != NULL) {
381        if (*charset && strncmp(*mimetype, "text/", 5) == 0 && strstr(*mimetype, "charset=") == NULL) {
382            newlen = len + (sizeof(";charset=")-1) + strlen(charset);
383            newtype = emalloc(newlen + 1);
384            PHP_STRLCPY(newtype, *mimetype, newlen + 1, len);
385            strlcat(newtype, ";charset=", newlen + 1);
386            strlcat(newtype, charset, newlen + 1);
387            efree(*mimetype);
388            *mimetype = newtype;
389            return newlen;
390        }
391    }
392    return 0;
393}
394
395SAPI_API void sapi_activate_headers_only(void)
396{
397    if (SG(request_info).headers_read == 1)
398        return;
399    SG(request_info).headers_read = 1;
400    zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct),
401            (void (*)(void *)) sapi_free_header, 0);
402    SG(sapi_headers).send_default_content_type = 1;
403
404    /* SG(sapi_headers).http_response_code = 200; */
405    SG(sapi_headers).http_status_line = NULL;
406    SG(sapi_headers).mimetype = NULL;
407    SG(read_post_bytes) = 0;
408    SG(request_info).request_body = NULL;
409    SG(request_info).current_user = NULL;
410    SG(request_info).current_user_length = 0;
411    SG(request_info).no_headers = 0;
412    SG(request_info).post_entry = NULL;
413    SG(global_request_time) = 0;
414
415    /*
416     * It's possible to override this general case in the activate() callback,
417     * if necessary.
418     */
419    if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
420        SG(request_info).headers_only = 1;
421    } else {
422        SG(request_info).headers_only = 0;
423    }
424    if (SG(server_context)) {
425        SG(request_info).cookie_data = sapi_module.read_cookies();
426        if (sapi_module.activate) {
427            sapi_module.activate();
428        }
429    }
430    if (sapi_module.input_filter_init ) {
431        sapi_module.input_filter_init();
432    }
433}
434
435/*
436 * Called from php_request_startup() for every request.
437 */
438
439SAPI_API void sapi_activate(void)
440{
441    zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), (void (*)(void *)) sapi_free_header, 0);
442    SG(sapi_headers).send_default_content_type = 1;
443
444    /*
445    SG(sapi_headers).http_response_code = 200;
446    */
447    SG(sapi_headers).http_status_line = NULL;
448    SG(sapi_headers).mimetype = NULL;
449    SG(headers_sent) = 0;
450    SG(callback_run) = 0;
451    ZVAL_UNDEF(&SG(callback_func));
452    SG(read_post_bytes) = 0;
453    SG(request_info).request_body = NULL;
454    SG(request_info).current_user = NULL;
455    SG(request_info).current_user_length = 0;
456    SG(request_info).no_headers = 0;
457    SG(request_info).post_entry = NULL;
458    SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
459    SG(global_request_time) = 0;
460    SG(post_read) = 0;
461    /* It's possible to override this general case in the activate() callback, if necessary. */
462    if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
463        SG(request_info).headers_only = 1;
464    } else {
465        SG(request_info).headers_only = 0;
466    }
467    SG(rfc1867_uploaded_files) = NULL;
468
469    /* Handle request method */
470    if (SG(server_context)) {
471        if (PG(enable_post_data_reading)
472        &&  SG(request_info).content_type
473        &&  SG(request_info).request_method
474        && !strcmp(SG(request_info).request_method, "POST")) {
475            /* HTTP POST may contain form data to be processed into variables
476             * depending on given content type */
477            sapi_read_post_data();
478        } else {
479            SG(request_info).content_type_dup = NULL;
480        }
481
482        /* Cookies */
483        SG(request_info).cookie_data = sapi_module.read_cookies();
484
485        if (sapi_module.activate) {
486            sapi_module.activate();
487        }
488    }
489    if (sapi_module.input_filter_init) {
490        sapi_module.input_filter_init();
491    }
492}
493
494
495static void sapi_send_headers_free(void)
496{
497    if (SG(sapi_headers).http_status_line) {
498        efree(SG(sapi_headers).http_status_line);
499        SG(sapi_headers).http_status_line = NULL;
500    }
501}
502
503SAPI_API void sapi_deactivate(void)
504{
505    zend_llist_destroy(&SG(sapi_headers).headers);
506    if (SG(request_info).request_body) {
507        SG(request_info).request_body = NULL;
508    } else if (SG(server_context)) {
509        if (!SG(post_read)) {
510            /* make sure we've consumed all request input data */
511            char dummy[SAPI_POST_BLOCK_SIZE];
512            size_t read_bytes;
513
514            do {
515                read_bytes = sapi_read_post_block(dummy, SAPI_POST_BLOCK_SIZE);
516            } while (SAPI_POST_BLOCK_SIZE == read_bytes);
517        }
518    }
519    if (SG(request_info).auth_user) {
520        efree(SG(request_info).auth_user);
521    }
522    if (SG(request_info).auth_password) {
523        efree(SG(request_info).auth_password);
524    }
525    if (SG(request_info).auth_digest) {
526        efree(SG(request_info).auth_digest);
527    }
528    if (SG(request_info).content_type_dup) {
529        efree(SG(request_info).content_type_dup);
530    }
531    if (SG(request_info).current_user) {
532        efree(SG(request_info).current_user);
533    }
534    if (sapi_module.deactivate) {
535        sapi_module.deactivate();
536    }
537    if (SG(rfc1867_uploaded_files)) {
538        destroy_uploaded_files_hash();
539    }
540    if (SG(sapi_headers).mimetype) {
541        efree(SG(sapi_headers).mimetype);
542        SG(sapi_headers).mimetype = NULL;
543    }
544    sapi_send_headers_free();
545    SG(sapi_started) = 0;
546    SG(headers_sent) = 0;
547    SG(callback_run) = 0;
548    zval_ptr_dtor(&SG(callback_func));
549    SG(request_info).headers_read = 0;
550    SG(global_request_time) = 0;
551}
552
553
554SAPI_API void sapi_initialize_empty_request(void)
555{
556    SG(server_context) = NULL;
557    SG(request_info).request_method = NULL;
558    SG(request_info).auth_digest = SG(request_info).auth_user = SG(request_info).auth_password = NULL;
559    SG(request_info).content_type_dup = NULL;
560}
561
562
563static int sapi_extract_response_code(const char *header_line)
564{
565    int code = 200;
566    const char *ptr;
567
568    for (ptr = header_line; *ptr; ptr++) {
569        if (*ptr == ' ' && *(ptr + 1) != ' ') {
570            code = atoi(ptr + 1);
571            break;
572        }
573    }
574
575    return code;
576}
577
578
579static void sapi_update_response_code(int ncode)
580{
581    /* if the status code did not change, we do not want
582       to change the status line, and no need to change the code */
583    if (SG(sapi_headers).http_response_code == ncode) {
584        return;
585    }
586
587    if (SG(sapi_headers).http_status_line) {
588        efree(SG(sapi_headers).http_status_line);
589        SG(sapi_headers).http_status_line = NULL;
590    }
591    SG(sapi_headers).http_response_code = ncode;
592}
593
594/*
595 * since zend_llist_del_element only remove one matched item once,
596 * we should remove them by ourself
597 */
598static void sapi_remove_header(zend_llist *l, char *name, size_t len) {
599    sapi_header_struct *header;
600    zend_llist_element *next;
601    zend_llist_element *current=l->head;
602
603    while (current) {
604        header = (sapi_header_struct *)(current->data);
605        next = current->next;
606        if (header->header_len > len && header->header[len] == ':'
607                && !strncasecmp(header->header, name, len)) {
608            if (current->prev) {
609                current->prev->next = next;
610            } else {
611                l->head = next;
612            }
613            if (next) {
614                next->prev = current->prev;
615            } else {
616                l->tail = current->prev;
617            }
618            sapi_free_header(header);
619            efree(current);
620            --l->count;
621        }
622        current = next;
623    }
624}
625
626SAPI_API int sapi_add_header_ex(char *header_line, size_t header_line_len, zend_bool duplicate, zend_bool replace)
627{
628    sapi_header_line ctr = {0};
629    int r;
630
631    ctr.line = header_line;
632    ctr.line_len = header_line_len;
633
634    r = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD,
635            &ctr);
636
637    if (!duplicate)
638        efree(header_line);
639
640    return r;
641}
642
643static void sapi_header_add_op(sapi_header_op_enum op, sapi_header_struct *sapi_header)
644{
645    if (!sapi_module.header_handler ||
646        (SAPI_HEADER_ADD & sapi_module.header_handler(sapi_header, op, &SG(sapi_headers)))) {
647        if (op == SAPI_HEADER_REPLACE) {
648            char *colon_offset = strchr(sapi_header->header, ':');
649
650            if (colon_offset) {
651                char sav = *colon_offset;
652
653                *colon_offset = 0;
654                sapi_remove_header(&SG(sapi_headers).headers, sapi_header->header, (int)strlen(sapi_header->header));
655                *colon_offset = sav;
656            }
657        }
658        zend_llist_add_element(&SG(sapi_headers).headers, (void *) sapi_header);
659    } else {
660        sapi_free_header(sapi_header);
661    }
662}
663
664SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg)
665{
666    sapi_header_struct sapi_header;
667    char *colon_offset;
668    char *header_line;
669    size_t header_line_len;
670    int http_response_code;
671
672    if (SG(headers_sent) && !SG(request_info).no_headers) {
673        const char *output_start_filename = php_output_get_start_filename();
674        int output_start_lineno = php_output_get_start_lineno();
675
676        if (output_start_filename) {
677            sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)",
678                output_start_filename, output_start_lineno);
679        } else {
680            sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent");
681        }
682        return FAILURE;
683    }
684
685    switch (op) {
686        case SAPI_HEADER_SET_STATUS:
687            sapi_update_response_code((int)(zend_intptr_t) arg);
688            return SUCCESS;
689
690        case SAPI_HEADER_ADD:
691        case SAPI_HEADER_REPLACE:
692        case SAPI_HEADER_DELETE: {
693                sapi_header_line *p = arg;
694
695                if (!p->line || !p->line_len) {
696                    return FAILURE;
697                }
698                header_line = p->line;
699                header_line_len = p->line_len;
700                http_response_code = p->response_code;
701                break;
702            }
703
704        case SAPI_HEADER_DELETE_ALL:
705            if (sapi_module.header_handler) {
706                sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers));
707            }
708            zend_llist_clean(&SG(sapi_headers).headers);
709            return SUCCESS;
710
711        default:
712            return FAILURE;
713    }
714
715    header_line = estrndup(header_line, header_line_len);
716
717    /* cut off trailing spaces, linefeeds and carriage-returns */
718    if (header_line_len && isspace(header_line[header_line_len-1])) {
719        do {
720            header_line_len--;
721        } while(header_line_len && isspace(header_line[header_line_len-1]));
722        header_line[header_line_len]='\0';
723    }
724
725    if (op == SAPI_HEADER_DELETE) {
726        if (strchr(header_line, ':')) {
727            efree(header_line);
728            sapi_module.sapi_error(E_WARNING, "Header to delete may not contain colon.");
729            return FAILURE;
730        }
731        if (sapi_module.header_handler) {
732            sapi_header.header = header_line;
733            sapi_header.header_len = header_line_len;
734            sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers));
735        }
736        sapi_remove_header(&SG(sapi_headers).headers, header_line, header_line_len);
737        efree(header_line);
738        return SUCCESS;
739    } else {
740        /* new line/NUL character safety check */
741        uint i;
742        for (i = 0; i < header_line_len; i++) {
743            /* RFC 7230 ch. 3.2.4 deprecates folding support */
744            if (header_line[i] == '\n' || header_line[i] == '\r') {
745                efree(header_line);
746                sapi_module.sapi_error(E_WARNING, "Header may not contain "
747                        "more than a single header, new line detected");
748                return FAILURE;
749            }
750            if (header_line[i] == '\0') {
751                efree(header_line);
752                sapi_module.sapi_error(E_WARNING, "Header may not contain NUL bytes");
753                return FAILURE;
754            }
755        }
756    }
757
758    sapi_header.header = header_line;
759    sapi_header.header_len = header_line_len;
760
761    /* Check the header for a few cases that we have special support for in SAPI */
762    if (header_line_len>=5
763        && !strncasecmp(header_line, "HTTP/", 5)) {
764        /* filter out the response code */
765        sapi_update_response_code(sapi_extract_response_code(header_line));
766        /* sapi_update_response_code doesn't free the status line if the code didn't change */
767        if (SG(sapi_headers).http_status_line) {
768            efree(SG(sapi_headers).http_status_line);
769        }
770        SG(sapi_headers).http_status_line = header_line;
771        return SUCCESS;
772    } else {
773        colon_offset = strchr(header_line, ':');
774        if (colon_offset) {
775            *colon_offset = 0;
776            if (!STRCASECMP(header_line, "Content-Type")) {
777                char *ptr = colon_offset+1, *mimetype = NULL, *newheader;
778                size_t len = header_line_len - (ptr - header_line), newlen;
779                while (*ptr == ' ') {
780                    ptr++;
781                    len--;
782                }
783
784                /* Disable possible output compression for images */
785                if (!strncmp(ptr, "image/", sizeof("image/")-1)) {
786                    zend_string *key = zend_string_init("zlib.output_compression", sizeof("zlib.output_compression")-1, 0);
787                    zend_alter_ini_entry_chars(key, "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
788                    zend_string_release(key);
789                }
790
791                mimetype = estrdup(ptr);
792                newlen = sapi_apply_default_charset(&mimetype, len);
793                if (!SG(sapi_headers).mimetype){
794                    SG(sapi_headers).mimetype = estrdup(mimetype);
795                }
796
797                if (newlen != 0) {
798                    newlen += sizeof("Content-type: ");
799                    newheader = emalloc(newlen);
800                    PHP_STRLCPY(newheader, "Content-type: ", newlen, sizeof("Content-type: ")-1);
801                    strlcat(newheader, mimetype, newlen);
802                    sapi_header.header = newheader;
803                    sapi_header.header_len = (uint)(newlen - 1);
804                    efree(header_line);
805                }
806                efree(mimetype);
807                SG(sapi_headers).send_default_content_type = 0;
808            } else if (!STRCASECMP(header_line, "Content-Length")) {
809                /* Script is setting Content-length. The script cannot reasonably
810                 * know the size of the message body after compression, so it's best
811                 * do disable compression altogether. This contributes to making scripts
812                 * portable between setups that have and don't have zlib compression
813                 * enabled globally. See req #44164 */
814                zend_string *key = zend_string_init("zlib.output_compression", sizeof("zlib.output_compression")-1, 0);
815                zend_alter_ini_entry_chars(key,
816                    "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
817                zend_string_release(key);
818            } else if (!STRCASECMP(header_line, "Location")) {
819                if ((SG(sapi_headers).http_response_code < 300 ||
820                    SG(sapi_headers).http_response_code > 399) &&
821                    SG(sapi_headers).http_response_code != 201) {
822                    /* Return a Found Redirect if one is not already specified */
823                    if (http_response_code) { /* user specified redirect code */
824                        sapi_update_response_code(http_response_code);
825                    } else if (SG(request_info).proto_num > 1000 &&
826                       SG(request_info).request_method &&
827                       strcmp(SG(request_info).request_method, "HEAD") &&
828                       strcmp(SG(request_info).request_method, "GET")) {
829                        sapi_update_response_code(303);
830                    } else {
831                        sapi_update_response_code(302);
832                    }
833                }
834            } else if (!STRCASECMP(header_line, "WWW-Authenticate")) { /* HTTP Authentication */
835                sapi_update_response_code(401); /* authentication-required */
836            }
837            if (sapi_header.header==header_line) {
838                *colon_offset = ':';
839            }
840        }
841    }
842    if (http_response_code) {
843        sapi_update_response_code(http_response_code);
844    }
845    sapi_header_add_op(op, &sapi_header);
846    return SUCCESS;
847}
848
849
850SAPI_API int sapi_send_headers(void)
851{
852    int retval;
853    int ret = FAILURE;
854
855    if (SG(headers_sent) || SG(request_info).no_headers || SG(callback_run)) {
856        return SUCCESS;
857    }
858
859    /* Success-oriented.  We set headers_sent to 1 here to avoid an infinite loop
860     * in case of an error situation.
861     */
862    if (SG(sapi_headers).send_default_content_type && sapi_module.send_headers) {
863        sapi_header_struct default_header;
864        uint len;
865
866        SG(sapi_headers).mimetype = get_default_content_type(0, &len);
867        default_header.header_len = sizeof("Content-type: ") - 1 + len;
868        default_header.header = emalloc(default_header.header_len + 1);
869        memcpy(default_header.header, "Content-type: ", sizeof("Content-type: ") - 1);
870        memcpy(default_header.header + sizeof("Content-type: ") - 1, SG(sapi_headers).mimetype, len + 1);
871        sapi_header_add_op(SAPI_HEADER_ADD, &default_header);
872        SG(sapi_headers).send_default_content_type = 0;
873    }
874
875    if (Z_TYPE(SG(callback_func)) != IS_UNDEF && !SG(callback_run)) {
876        SG(callback_run) = 1;
877        sapi_run_header_callback();
878    }
879
880    SG(headers_sent) = 1;
881
882    if (sapi_module.send_headers) {
883        retval = sapi_module.send_headers(&SG(sapi_headers));
884    } else {
885        retval = SAPI_HEADER_DO_SEND;
886    }
887
888    switch (retval) {
889        case SAPI_HEADER_SENT_SUCCESSFULLY:
890            ret = SUCCESS;
891            break;
892        case SAPI_HEADER_DO_SEND: {
893                sapi_header_struct http_status_line;
894                char buf[255];
895
896                if (SG(sapi_headers).http_status_line) {
897                    http_status_line.header = SG(sapi_headers).http_status_line;
898                    http_status_line.header_len = (uint)strlen(SG(sapi_headers).http_status_line);
899                } else {
900                    http_status_line.header = buf;
901                    http_status_line.header_len = slprintf(buf, sizeof(buf), "HTTP/1.0 %d X", SG(sapi_headers).http_response_code);
902                }
903                sapi_module.send_header(&http_status_line, SG(server_context));
904            }
905            zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) sapi_module.send_header, SG(server_context));
906            if(SG(sapi_headers).send_default_content_type) {
907                sapi_header_struct default_header;
908
909                sapi_get_default_content_type_header(&default_header);
910                sapi_module.send_header(&default_header, SG(server_context));
911                sapi_free_header(&default_header);
912            }
913            sapi_module.send_header(NULL, SG(server_context));
914            ret = SUCCESS;
915            break;
916        case SAPI_HEADER_SEND_FAILED:
917            SG(headers_sent) = 0;
918            ret = FAILURE;
919            break;
920    }
921
922    sapi_send_headers_free();
923
924    return ret;
925}
926
927
928SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entries)
929{
930    sapi_post_entry *p=post_entries;
931
932    while (p->content_type) {
933        if (sapi_register_post_entry(p) == FAILURE) {
934            return FAILURE;
935        }
936        p++;
937    }
938    return SUCCESS;
939}
940
941
942SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry)
943{
944    if (SG(sapi_started) && EG(current_execute_data)) {
945        return FAILURE;
946    }
947    return zend_hash_str_add_mem(&SG(known_post_content_types),
948            post_entry->content_type, post_entry->content_type_len,
949            (void *) post_entry, sizeof(sapi_post_entry)) ? SUCCESS : FAILURE;
950}
951
952SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry)
953{
954    if (SG(sapi_started) && EG(current_execute_data)) {
955        return;
956    }
957    zend_hash_str_del(&SG(known_post_content_types), post_entry->content_type,
958            post_entry->content_type_len);
959}
960
961
962SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(void))
963{
964    if (SG(sapi_started) && EG(current_execute_data)) {
965        return FAILURE;
966    }
967    sapi_module.default_post_reader = default_post_reader;
968    return SUCCESS;
969}
970
971
972SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray))
973{
974    if (SG(sapi_started) && EG(current_execute_data)) {
975        return FAILURE;
976    }
977    sapi_module.treat_data = treat_data;
978    return SUCCESS;
979}
980
981SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, size_t val_len, size_t *new_val_len), unsigned int (*input_filter_init)(void))
982{
983    if (SG(sapi_started) && EG(current_execute_data)) {
984        return FAILURE;
985    }
986    sapi_module.input_filter = input_filter;
987    sapi_module.input_filter_init = input_filter_init;
988    return SUCCESS;
989}
990
991SAPI_API int sapi_flush(void)
992{
993    if (sapi_module.flush) {
994        sapi_module.flush(SG(server_context));
995        return SUCCESS;
996    } else {
997        return FAILURE;
998    }
999}
1000
1001SAPI_API zend_stat_t *sapi_get_stat(void)
1002{
1003    if (sapi_module.get_stat) {
1004        return sapi_module.get_stat();
1005    } else {
1006        if (!SG(request_info).path_translated || (VCWD_STAT(SG(request_info).path_translated, &SG(global_stat)) == -1)) {
1007            return NULL;
1008        }
1009        return &SG(global_stat);
1010    }
1011}
1012
1013SAPI_API char *sapi_getenv(char *name, size_t name_len)
1014{
1015    if (sapi_module.getenv) {
1016        char *value, *tmp = sapi_module.getenv(name, name_len);
1017        if (tmp) {
1018            value = estrdup(tmp);
1019        } else {
1020            return NULL;
1021        }
1022        if (sapi_module.input_filter) {
1023            sapi_module.input_filter(PARSE_STRING, name, &value, strlen(value), NULL);
1024        }
1025        return value;
1026    }
1027    return NULL;
1028}
1029
1030SAPI_API int sapi_get_fd(int *fd)
1031{
1032    if (sapi_module.get_fd) {
1033        return sapi_module.get_fd(fd);
1034    } else {
1035        return FAILURE;
1036    }
1037}
1038
1039SAPI_API int sapi_force_http_10(void)
1040{
1041    if (sapi_module.force_http_10) {
1042        return sapi_module.force_http_10();
1043    } else {
1044        return FAILURE;
1045    }
1046}
1047
1048
1049SAPI_API int sapi_get_target_uid(uid_t *obj)
1050{
1051    if (sapi_module.get_target_uid) {
1052        return sapi_module.get_target_uid(obj);
1053    } else {
1054        return FAILURE;
1055    }
1056}
1057
1058SAPI_API int sapi_get_target_gid(gid_t *obj)
1059{
1060    if (sapi_module.get_target_gid) {
1061        return sapi_module.get_target_gid(obj);
1062    } else {
1063        return FAILURE;
1064    }
1065}
1066
1067SAPI_API double sapi_get_request_time(void)
1068{
1069    if(SG(global_request_time)) return SG(global_request_time);
1070
1071    if (sapi_module.get_request_time && SG(server_context)) {
1072        SG(global_request_time) = sapi_module.get_request_time();
1073    } else {
1074        struct timeval tp = {0};
1075        if (!gettimeofday(&tp, NULL)) {
1076            SG(global_request_time) = (double)(tp.tv_sec + tp.tv_usec / 1000000.00);
1077        } else {
1078            SG(global_request_time) = (double)time(0);
1079        }
1080    }
1081    return SG(global_request_time);
1082}
1083
1084SAPI_API void sapi_terminate_process(void) {
1085    if (sapi_module.terminate_process) {
1086        sapi_module.terminate_process();
1087    }
1088}
1089
1090/*
1091 * Local variables:
1092 * tab-width: 4
1093 * c-basic-offset: 4
1094 * End:
1095 * vim600: sw=4 ts=4 fdm=marker
1096 * vim<600: sw=4 ts=4
1097 */
1098