2015-01-03 17:22:58 +08:00
|
|
|
/*
|
1999-05-07 05:58:49 +08:00
|
|
|
+----------------------------------------------------------------------+
|
2014-09-20 00:33:14 +08:00
|
|
|
| PHP Version 7 |
|
1999-05-07 05:58:49 +08:00
|
|
|
+----------------------------------------------------------------------+
|
2019-01-30 17:03:12 +08:00
|
|
|
| Copyright (c) The PHP Group |
|
1999-05-07 05:58:49 +08:00
|
|
|
+----------------------------------------------------------------------+
|
2006-01-01 20:51:34 +08:00
|
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
1999-07-16 21:13:16 +08:00
|
|
|
| that is bundled with this package in the file LICENSE, and is |
|
2003-06-11 04:04:29 +08:00
|
|
|
| available through the world-wide-web at the following url: |
|
2006-01-01 20:51:34 +08:00
|
|
|
| http://www.php.net/license/3_01.txt |
|
1999-07-16 21:13:16 +08:00
|
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
|
|
| license@php.net so we can mail you a copy immediately. |
|
1999-05-07 05:58:49 +08:00
|
|
|
+----------------------------------------------------------------------+
|
2000-02-11 04:13:08 +08:00
|
|
|
| Original design: Shane Caraveo <shane@caraveo.com> |
|
2018-11-02 00:30:28 +08:00
|
|
|
| Authors: Andi Gutmans <andi@php.net> |
|
|
|
|
| Zeev Suraski <zeev@php.net> |
|
1999-05-07 05:58:49 +08:00
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
*/
|
|
|
|
|
1999-05-30 00:20:55 +08:00
|
|
|
#include <ctype.h>
|
2000-02-11 01:26:57 +08:00
|
|
|
#include <sys/stat.h>
|
1999-05-07 05:58:49 +08:00
|
|
|
|
1999-09-06 03:04:40 +08:00
|
|
|
#include "php.h"
|
1999-04-26 03:36:57 +08:00
|
|
|
#include "SAPI.h"
|
2006-05-11 05:19:32 +08:00
|
|
|
#include "php_variables.h"
|
2003-02-11 03:04:44 +08:00
|
|
|
#include "php_ini.h"
|
2001-10-21 06:01:56 +08:00
|
|
|
#include "ext/standard/php_string.h"
|
|
|
|
#include "ext/standard/pageinfo.h"
|
|
|
|
#include "ext/pcre/php_pcre.h"
|
1999-04-26 22:00:49 +08:00
|
|
|
#ifdef ZTS
|
1999-04-26 03:36:57 +08:00
|
|
|
#include "TSRM.h"
|
1999-04-26 22:00:49 +08:00
|
|
|
#endif
|
2004-08-11 01:40:00 +08:00
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
|
|
#include <sys/time.h>
|
2010-11-22 23:43:46 +08:00
|
|
|
#elif defined(PHP_WIN32)
|
|
|
|
#include "win32/time.h"
|
2004-08-11 01:40:00 +08:00
|
|
|
#endif
|
1999-04-26 03:36:57 +08:00
|
|
|
|
1999-05-26 06:28:24 +08:00
|
|
|
#include "rfc1867.h"
|
|
|
|
|
2000-07-05 16:57:37 +08:00
|
|
|
#include "php_content_types.h"
|
1999-04-26 03:36:57 +08:00
|
|
|
|
|
|
|
#ifdef ZTS
|
reworked the patch, less new stuff but worky
TLS is already used in TSRM, the way exporting the tsrm cache through
a thread local variable is not portable. Additionally, the current
patch suffers from bugs which are hard to find, but prevent it to
be worky with apache. What is done here is mainly uses the idea
from the RFC patch, but
- __thread variable is removed
- offset math and declarations are removed
- extra macros and definitions are removed
What is done merely is
- use an inline function to access the tsrm cache. The function uses
the portable tsrm_tls_get macro which is cheap
- all the TSRM_* macros are set to placebo. Thus this opens the way
remove them later
Except that, the logic is old. TSRMLS_FETCH will have to be done once
per thread, then tsrm_get_ls_cache() can be used. Things seeming to be
worky are cli, cli server and apache. I also tried to enable bz2
shared and it has worked out of the box. The change is yet minimal
diffing to the current master bus is a worky start, IMHO. Though will
have to recheck the other previously done SAPIs - embed and cgi.
The offsets can be added to the tsrm_resource_type struct, then
it'll not be needed to declare them in the userspace. Even the
"done" member type can be changed to int16 or smaller, then adding
the offset as int16 will not change the struct size. As well on the
todo might be removing the hashed storage, thread_id != thread_id and
linked list logic in favour of the explicit TLS operations.
2014-09-26 00:48:27 +08:00
|
|
|
SAPI_API int sapi_globals_id;
|
2019-03-14 08:01:01 +08:00
|
|
|
SAPI_API size_t sapi_globals_offset;
|
1999-04-27 01:26:37 +08:00
|
|
|
#else
|
|
|
|
sapi_globals_struct sapi_globals;
|
1999-04-26 03:36:57 +08:00
|
|
|
#endif
|
|
|
|
|
2014-02-17 21:59:18 +08:00
|
|
|
static void _type_dtor(zval *zv)
|
|
|
|
{
|
|
|
|
free(Z_PTR_P(zv));
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static void sapi_globals_ctor(sapi_globals_struct *sapi_globals)
|
2000-03-06 05:37:47 +08:00
|
|
|
{
|
2001-07-28 19:36:37 +08:00
|
|
|
memset(sapi_globals, 0, sizeof(*sapi_globals));
|
2014-04-21 22:25:34 +08:00
|
|
|
zend_hash_init_ex(&sapi_globals->known_post_content_types, 8, NULL, _type_dtor, 1, 0);
|
2014-12-14 06:06:14 +08:00
|
|
|
php_setup_sapi_content_types();
|
2005-02-21 23:14:02 +08:00
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static void sapi_globals_dtor(sapi_globals_struct *sapi_globals)
|
2005-02-21 23:14:02 +08:00
|
|
|
{
|
|
|
|
zend_hash_destroy(&sapi_globals->known_post_content_types);
|
2000-03-06 05:37:47 +08:00
|
|
|
}
|
|
|
|
|
1999-05-07 05:58:49 +08:00
|
|
|
/* True globals (no need for thread safety) */
|
2001-01-03 06:49:31 +08:00
|
|
|
SAPI_API sapi_module_struct sapi_module;
|
1999-04-26 03:36:57 +08:00
|
|
|
|
1999-05-06 02:25:20 +08:00
|
|
|
|
1999-05-03 02:07:41 +08:00
|
|
|
SAPI_API void sapi_startup(sapi_module_struct *sf)
|
1999-04-26 03:36:57 +08:00
|
|
|
{
|
2006-09-20 04:33:12 +08:00
|
|
|
sf->ini_entries = NULL;
|
1999-05-03 02:07:41 +08:00
|
|
|
sapi_module = *sf;
|
1999-09-17 07:18:15 +08:00
|
|
|
|
1999-04-26 03:36:57 +08:00
|
|
|
#ifdef ZTS
|
2019-03-14 08:01:01 +08:00
|
|
|
ts_allocate_fast_id(&sapi_globals_id, &sapi_globals_offset, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor);
|
2011-03-16 01:14:32 +08:00
|
|
|
# ifdef PHP_WIN32
|
2011-03-16 01:13:44 +08:00
|
|
|
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
2011-03-16 01:14:32 +08:00
|
|
|
# endif
|
2000-03-17 05:23:24 +08:00
|
|
|
#else
|
2005-02-22 04:57:18 +08:00
|
|
|
sapi_globals_ctor(&sapi_globals);
|
1999-04-26 03:36:57 +08:00
|
|
|
#endif
|
2000-03-17 05:23:24 +08:00
|
|
|
|
2001-04-28 00:41:53 +08:00
|
|
|
#ifdef PHP_WIN32
|
|
|
|
tsrm_win32_startup();
|
|
|
|
#endif
|
|
|
|
|
2000-01-06 03:25:19 +08:00
|
|
|
reentrancy_startup();
|
1999-09-04 01:46:39 +08:00
|
|
|
}
|
1999-05-06 02:25:20 +08:00
|
|
|
|
1999-12-06 00:25:32 +08:00
|
|
|
SAPI_API void sapi_shutdown(void)
|
1999-05-29 06:41:48 +08:00
|
|
|
{
|
2005-02-21 23:14:02 +08:00
|
|
|
#ifdef ZTS
|
2005-02-22 13:07:37 +08:00
|
|
|
ts_free_id(sapi_globals_id);
|
2005-02-21 23:14:02 +08:00
|
|
|
#else
|
2005-02-22 04:57:18 +08:00
|
|
|
sapi_globals_dtor(&sapi_globals);
|
2005-02-21 23:14:02 +08:00
|
|
|
#endif
|
|
|
|
|
2000-01-06 03:25:19 +08:00
|
|
|
reentrancy_shutdown();
|
2004-10-05 08:42:25 +08:00
|
|
|
|
2001-04-28 00:41:53 +08:00
|
|
|
#ifdef PHP_WIN32
|
|
|
|
tsrm_win32_shutdown();
|
|
|
|
#endif
|
1999-05-29 06:41:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-12-10 20:38:20 +08:00
|
|
|
SAPI_API void sapi_free_header(sapi_header_struct *sapi_header)
|
1999-05-06 02:25:20 +08:00
|
|
|
{
|
|
|
|
efree(sapi_header->header);
|
|
|
|
}
|
|
|
|
|
2011-02-04 00:47:28 +08:00
|
|
|
/* {{{ proto bool header_register_callback(mixed callback)
|
|
|
|
call a header function */
|
|
|
|
PHP_FUNCTION(header_register_callback)
|
|
|
|
{
|
|
|
|
zval *callback_func;
|
2014-02-25 20:03:34 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &callback_func) == FAILURE) {
|
2011-02-04 00:47:28 +08:00
|
|
|
return;
|
|
|
|
}
|
2015-01-03 17:22:58 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (!zend_is_callable(callback_func, 0, NULL)) {
|
2011-02-04 00:47:28 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2014-01-01 20:58:18 +08:00
|
|
|
|
2014-02-10 14:04:30 +08:00
|
|
|
if (Z_TYPE(SG(callback_func)) != IS_UNDEF) {
|
2011-02-04 00:47:28 +08:00
|
|
|
zval_ptr_dtor(&SG(callback_func));
|
|
|
|
SG(fci_cache) = empty_fcall_info_cache;
|
|
|
|
}
|
|
|
|
|
2014-02-10 14:04:30 +08:00
|
|
|
ZVAL_COPY(&SG(callback_func), callback_func);
|
2014-01-01 20:58:18 +08:00
|
|
|
|
2011-02-04 00:47:28 +08:00
|
|
|
RETURN_TRUE;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2015-12-11 17:26:31 +08:00
|
|
|
static void sapi_run_header_callback(zval *callback)
|
2011-02-04 00:47:28 +08:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
zend_fcall_info fci;
|
2014-01-01 20:58:18 +08:00
|
|
|
char *callback_error = NULL;
|
2014-02-10 14:04:30 +08:00
|
|
|
zval retval;
|
2015-01-03 17:22:58 +08:00
|
|
|
|
2015-12-11 17:26:31 +08:00
|
|
|
if (zend_fcall_info_init(callback, 0, &fci, &SG(fci_cache), NULL, &callback_error) == SUCCESS) {
|
2014-02-10 14:04:30 +08:00
|
|
|
fci.retval = &retval;
|
2015-01-03 17:22:58 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
error = zend_call_function(&fci, &SG(fci_cache));
|
2014-01-01 20:58:18 +08:00
|
|
|
if (error == FAILURE) {
|
|
|
|
goto callback_failed;
|
2014-02-10 14:04:30 +08:00
|
|
|
} else {
|
|
|
|
zval_ptr_dtor(&retval);
|
2014-01-01 20:58:18 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
callback_failed:
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Could not call the sapi_header_callback");
|
2011-02-04 00:47:28 +08:00
|
|
|
}
|
2015-01-03 17:22:58 +08:00
|
|
|
|
2014-01-01 20:58:18 +08:00
|
|
|
if (callback_error) {
|
|
|
|
efree(callback_error);
|
2015-01-03 17:22:58 +08:00
|
|
|
}
|
2011-02-04 00:47:28 +08:00
|
|
|
}
|
1999-05-06 02:25:20 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API void sapi_handle_post(void *arg)
|
2000-02-18 04:23:59 +08:00
|
|
|
{
|
2001-03-18 16:00:10 +08:00
|
|
|
if (SG(request_info).post_entry && SG(request_info).content_type_dup) {
|
2014-12-14 06:06:14 +08:00
|
|
|
SG(request_info).post_entry->post_handler(SG(request_info).content_type_dup, arg);
|
2000-02-18 04:23:59 +08:00
|
|
|
efree(SG(request_info).content_type_dup);
|
|
|
|
SG(request_info).content_type_dup = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static void sapi_read_post_data(void)
|
1999-05-26 05:14:54 +08:00
|
|
|
{
|
2000-02-18 04:23:59 +08:00
|
|
|
sapi_post_entry *post_entry;
|
2016-11-26 22:18:42 +08:00
|
|
|
uint32_t content_type_length = (uint32_t)strlen(SG(request_info).content_type);
|
1999-05-26 05:14:54 +08:00
|
|
|
char *content_type = estrndup(SG(request_info).content_type, content_type_length);
|
1999-05-26 06:28:24 +08:00
|
|
|
char *p;
|
|
|
|
char oldchar=0;
|
2014-12-14 06:06:14 +08:00
|
|
|
void (*post_reader_func)(void) = NULL;
|
1999-09-17 07:18:15 +08:00
|
|
|
|
1999-05-26 06:28:24 +08:00
|
|
|
|
|
|
|
/* dedicated implementation for increased performance:
|
|
|
|
* - Make the content type lowercase
|
|
|
|
* - Trim descriptive data, stay with the content-type only
|
|
|
|
*/
|
|
|
|
for (p=content_type; p<content_type+content_type_length; p++) {
|
|
|
|
switch (*p) {
|
|
|
|
case ';':
|
|
|
|
case ',':
|
|
|
|
case ' ':
|
|
|
|
content_type_length = p-content_type;
|
|
|
|
oldchar = *p;
|
|
|
|
*p = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*p = tolower(*p);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1999-05-26 05:14:54 +08:00
|
|
|
|
2002-11-08 16:41:52 +08:00
|
|
|
/* now try to find an appropriate POST content handler */
|
2014-02-10 14:04:30 +08:00
|
|
|
if ((post_entry = zend_hash_str_find_ptr(&SG(known_post_content_types), content_type,
|
|
|
|
content_type_length)) != NULL) {
|
2002-11-08 16:41:52 +08:00
|
|
|
/* found one, register it for use */
|
2000-02-18 04:23:59 +08:00
|
|
|
SG(request_info).post_entry = post_entry;
|
|
|
|
post_reader_func = post_entry->post_reader;
|
1999-09-17 07:18:15 +08:00
|
|
|
} else {
|
2002-11-08 16:41:52 +08:00
|
|
|
/* fallback */
|
|
|
|
SG(request_info).post_entry = NULL;
|
1999-09-17 07:18:15 +08:00
|
|
|
if (!sapi_module.default_post_reader) {
|
2002-11-08 16:41:52 +08:00
|
|
|
/* no default reader ? */
|
2003-11-23 05:10:47 +08:00
|
|
|
SG(request_info).content_type_dup = NULL;
|
2000-09-09 23:02:15 +08:00
|
|
|
sapi_module.sapi_error(E_WARNING, "Unsupported content type: '%s'", content_type);
|
1999-09-17 07:18:15 +08:00
|
|
|
return;
|
|
|
|
}
|
1999-05-26 05:14:54 +08:00
|
|
|
}
|
1999-05-26 06:28:24 +08:00
|
|
|
if (oldchar) {
|
|
|
|
*(p-1) = oldchar;
|
|
|
|
}
|
2001-09-03 10:31:56 +08:00
|
|
|
|
2000-02-18 04:23:59 +08:00
|
|
|
SG(request_info).content_type_dup = content_type;
|
2001-09-03 10:31:56 +08:00
|
|
|
|
|
|
|
if(post_reader_func) {
|
2014-12-14 06:06:14 +08:00
|
|
|
post_reader_func();
|
2002-10-22 00:41:06 +08:00
|
|
|
}
|
2001-09-03 10:31:56 +08:00
|
|
|
|
2002-11-13 02:29:11 +08:00
|
|
|
if(sapi_module.default_post_reader) {
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_module.default_post_reader();
|
2001-07-18 00:46:07 +08:00
|
|
|
}
|
1999-05-26 05:14:54 +08:00
|
|
|
}
|
|
|
|
|
2015-03-25 04:15:15 +08:00
|
|
|
SAPI_API size_t sapi_read_post_block(char *buffer, size_t buflen)
|
1999-05-10 02:40:59 +08:00
|
|
|
{
|
2015-03-25 04:15:15 +08:00
|
|
|
size_t read_bytes;
|
1999-05-10 02:40:59 +08:00
|
|
|
|
2013-09-10 19:13:33 +08:00
|
|
|
if (!sapi_module.read_post) {
|
2015-03-25 04:15:15 +08:00
|
|
|
return 0;
|
2013-09-10 19:13:33 +08:00
|
|
|
}
|
|
|
|
|
2015-03-25 04:15:15 +08:00
|
|
|
read_bytes = sapi_module.read_post(buffer, buflen);
|
2013-09-10 19:13:33 +08:00
|
|
|
|
|
|
|
if (read_bytes > 0) {
|
|
|
|
/* gogo */
|
|
|
|
SG(read_post_bytes) += read_bytes;
|
|
|
|
}
|
|
|
|
if (read_bytes < buflen) {
|
|
|
|
/* done */
|
|
|
|
SG(post_read) = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return read_bytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data)
|
|
|
|
{
|
2010-10-27 22:56:51 +08:00
|
|
|
if ((SG(post_max_size) > 0) && (SG(request_info).content_length > SG(post_max_size))) {
|
2016-06-21 21:00:37 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "POST Content-Length of " ZEND_LONG_FMT " bytes exceeds the limit of " ZEND_LONG_FMT " bytes",
|
2000-09-09 23:02:15 +08:00
|
|
|
SG(request_info).content_length, SG(post_max_size));
|
|
|
|
return;
|
|
|
|
}
|
2013-09-10 19:13:33 +08:00
|
|
|
|
2013-09-17 19:52:25 +08:00
|
|
|
|
2014-07-02 20:35:20 +08:00
|
|
|
SG(request_info).request_body = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir));
|
1999-05-10 02:40:59 +08:00
|
|
|
|
2013-08-14 20:42:36 +08:00
|
|
|
if (sapi_module.read_post) {
|
2015-03-25 04:15:15 +08:00
|
|
|
size_t read_bytes;
|
2013-09-10 19:13:33 +08:00
|
|
|
|
2013-08-14 20:42:36 +08:00
|
|
|
for (;;) {
|
|
|
|
char buffer[SAPI_POST_BLOCK_SIZE];
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
read_bytes = sapi_read_post_block(buffer, SAPI_POST_BLOCK_SIZE);
|
2013-09-10 19:13:33 +08:00
|
|
|
|
|
|
|
if (read_bytes > 0) {
|
2015-08-10 07:33:20 +08:00
|
|
|
if (php_stream_write(SG(request_info).request_body, buffer, read_bytes) != read_bytes) {
|
|
|
|
/* if parts of the stream can't be written, purge it completely */
|
|
|
|
php_stream_truncate_set_size(SG(request_info).request_body, 0);
|
2015-08-11 07:42:25 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "POST data can't be buffered; all data discarded");
|
2015-08-10 07:33:20 +08:00
|
|
|
break;
|
|
|
|
}
|
2013-08-14 20:42:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((SG(post_max_size) > 0) && (SG(read_post_bytes) > SG(post_max_size))) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Actual POST length does not match Content-Length, and exceeds " ZEND_LONG_FMT " bytes", SG(post_max_size));
|
2013-08-14 20:42:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (read_bytes < SAPI_POST_BLOCK_SIZE) {
|
|
|
|
/* done */
|
|
|
|
break;
|
|
|
|
}
|
1999-05-10 02:40:59 +08:00
|
|
|
}
|
2013-09-10 19:13:33 +08:00
|
|
|
php_stream_rewind(SG(request_info).request_body);
|
1999-05-10 02:40:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-11-26 22:18:42 +08:00
|
|
|
static inline char *get_default_content_type(uint32_t prefix_len, uint32_t *len)
|
2000-02-26 05:27:03 +08:00
|
|
|
{
|
|
|
|
char *mimetype, *charset, *content_type;
|
2016-11-26 22:18:42 +08:00
|
|
|
uint32_t mimetype_len, charset_len;
|
2000-02-26 05:27:03 +08:00
|
|
|
|
2010-07-14 23:20:44 +08:00
|
|
|
if (SG(default_mimetype)) {
|
|
|
|
mimetype = SG(default_mimetype);
|
2016-11-26 22:18:42 +08:00
|
|
|
mimetype_len = (uint32_t)strlen(SG(default_mimetype));
|
2010-07-14 23:20:44 +08:00
|
|
|
} else {
|
|
|
|
mimetype = SAPI_DEFAULT_MIMETYPE;
|
|
|
|
mimetype_len = sizeof(SAPI_DEFAULT_MIMETYPE) - 1;
|
|
|
|
}
|
|
|
|
if (SG(default_charset)) {
|
|
|
|
charset = SG(default_charset);
|
2016-11-26 22:18:42 +08:00
|
|
|
charset_len = (uint32_t)strlen(SG(default_charset));
|
2010-07-14 23:20:44 +08:00
|
|
|
} else {
|
|
|
|
charset = SAPI_DEFAULT_CHARSET;
|
|
|
|
charset_len = sizeof(SAPI_DEFAULT_CHARSET) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*charset && strncasecmp(mimetype, "text/", 5) == 0) {
|
|
|
|
char *p;
|
2000-02-26 05:27:03 +08:00
|
|
|
|
2010-07-14 23:20:44 +08:00
|
|
|
*len = prefix_len + mimetype_len + sizeof("; charset=") - 1 + charset_len;
|
|
|
|
content_type = (char*)emalloc(*len + 1);
|
|
|
|
p = content_type + prefix_len;
|
|
|
|
memcpy(p, mimetype, mimetype_len);
|
|
|
|
p += mimetype_len;
|
|
|
|
memcpy(p, "; charset=", sizeof("; charset=") - 1);
|
|
|
|
p += sizeof("; charset=") - 1;
|
|
|
|
memcpy(p, charset, charset_len + 1);
|
2000-02-26 05:27:03 +08:00
|
|
|
} else {
|
2010-07-14 23:20:44 +08:00
|
|
|
*len = prefix_len + mimetype_len;
|
|
|
|
content_type = (char*)emalloc(*len + 1);
|
|
|
|
memcpy(content_type + prefix_len, mimetype, mimetype_len + 1);
|
2000-02-26 05:27:03 +08:00
|
|
|
}
|
|
|
|
return content_type;
|
|
|
|
}
|
|
|
|
|
2000-02-26 13:03:41 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API char *sapi_get_default_content_type(void)
|
2010-07-14 23:20:44 +08:00
|
|
|
{
|
2016-11-26 22:18:42 +08:00
|
|
|
uint32_t len;
|
2010-07-14 23:20:44 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
return get_default_content_type(0, &len);
|
2010-07-14 23:20:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API void sapi_get_default_content_type_header(sapi_header_struct *default_header)
|
2000-02-26 13:03:41 +08:00
|
|
|
{
|
2016-11-26 22:18:42 +08:00
|
|
|
uint32_t len;
|
2010-07-14 23:20:44 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
default_header->header = get_default_content_type(sizeof("Content-type: ")-1, &len);
|
2010-07-14 23:20:44 +08:00
|
|
|
default_header->header_len = len;
|
|
|
|
memcpy(default_header->header, "Content-type: ", sizeof("Content-type: ") - 1);
|
2000-02-26 13:03:41 +08:00
|
|
|
}
|
|
|
|
|
2000-02-25 06:00:47 +08:00
|
|
|
/*
|
2000-02-26 05:27:03 +08:00
|
|
|
* Add charset on content-type header if the MIME type starts with
|
2000-02-26 22:29:27 +08:00
|
|
|
* "text/", the default_charset directive is not empty and
|
2000-02-26 05:27:03 +08:00
|
|
|
* there is not already a charset option in there.
|
|
|
|
*
|
|
|
|
* If "mimetype" is non-NULL, it should point to a pointer allocated
|
|
|
|
* with emalloc(). If a charset is added, the string will be
|
|
|
|
* re-allocated and the new length is returned. If mimetype is
|
|
|
|
* unchanged, 0 is returned.
|
|
|
|
*
|
2000-02-25 06:00:47 +08:00
|
|
|
*/
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API size_t sapi_apply_default_charset(char **mimetype, size_t len)
|
1999-05-06 02:25:20 +08:00
|
|
|
{
|
2000-02-26 05:27:03 +08:00
|
|
|
char *charset, *newtype;
|
2000-10-21 03:10:27 +08:00
|
|
|
size_t newlen;
|
2000-02-26 05:27:03 +08:00
|
|
|
charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
|
|
|
|
|
2002-08-06 02:32:05 +08:00
|
|
|
if (*mimetype != NULL) {
|
|
|
|
if (*charset && strncmp(*mimetype, "text/", 5) == 0 && strstr(*mimetype, "charset=") == NULL) {
|
|
|
|
newlen = len + (sizeof(";charset=")-1) + strlen(charset);
|
|
|
|
newtype = emalloc(newlen + 1);
|
|
|
|
PHP_STRLCPY(newtype, *mimetype, newlen + 1, len);
|
|
|
|
strlcat(newtype, ";charset=", newlen + 1);
|
2002-09-08 09:06:29 +08:00
|
|
|
strlcat(newtype, charset, newlen + 1);
|
2000-02-26 05:27:03 +08:00
|
|
|
efree(*mimetype);
|
2002-08-06 02:32:05 +08:00
|
|
|
*mimetype = newtype;
|
|
|
|
return newlen;
|
2000-02-26 05:27:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2000-02-25 06:00:47 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API void sapi_activate_headers_only(void)
|
2002-11-18 08:59:23 +08:00
|
|
|
{
|
2003-01-15 19:30:39 +08:00
|
|
|
if (SG(request_info).headers_read == 1)
|
|
|
|
return;
|
|
|
|
SG(request_info).headers_read = 1;
|
2015-01-03 17:22:58 +08:00
|
|
|
zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct),
|
2003-01-15 19:30:39 +08:00
|
|
|
(void (*)(void *)) sapi_free_header, 0);
|
|
|
|
SG(sapi_headers).send_default_content_type = 1;
|
|
|
|
|
2015-01-03 17:22:58 +08:00
|
|
|
/* SG(sapi_headers).http_response_code = 200; */
|
2003-01-15 19:30:39 +08:00
|
|
|
SG(sapi_headers).http_status_line = NULL;
|
2007-12-04 00:04:36 +08:00
|
|
|
SG(sapi_headers).mimetype = NULL;
|
2004-11-28 21:32:29 +08:00
|
|
|
SG(read_post_bytes) = 0;
|
2013-08-14 20:42:36 +08:00
|
|
|
SG(request_info).request_body = NULL;
|
2003-01-15 19:30:39 +08:00
|
|
|
SG(request_info).current_user = NULL;
|
|
|
|
SG(request_info).current_user_length = 0;
|
|
|
|
SG(request_info).no_headers = 0;
|
2004-08-20 04:26:39 +08:00
|
|
|
SG(request_info).post_entry = NULL;
|
2004-11-28 21:32:29 +08:00
|
|
|
SG(global_request_time) = 0;
|
2003-01-15 19:30:39 +08:00
|
|
|
|
|
|
|
/*
|
2015-01-03 17:22:58 +08:00
|
|
|
* It's possible to override this general case in the activate() callback,
|
2003-01-15 19:30:39 +08:00
|
|
|
* if necessary.
|
|
|
|
*/
|
|
|
|
if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
|
|
|
|
SG(request_info).headers_only = 1;
|
|
|
|
} else {
|
|
|
|
SG(request_info).headers_only = 0;
|
|
|
|
}
|
|
|
|
if (SG(server_context)) {
|
2014-12-14 06:06:14 +08:00
|
|
|
SG(request_info).cookie_data = sapi_module.read_cookies();
|
2003-01-15 19:30:39 +08:00
|
|
|
if (sapi_module.activate) {
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_module.activate();
|
2003-01-15 19:30:39 +08:00
|
|
|
}
|
|
|
|
}
|
2009-04-29 05:30:23 +08:00
|
|
|
if (sapi_module.input_filter_init ) {
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_module.input_filter_init();
|
2009-04-29 05:30:23 +08:00
|
|
|
}
|
2002-11-18 08:59:23 +08:00
|
|
|
}
|
2000-02-26 05:27:03 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Called from php_request_startup() for every request.
|
|
|
|
*/
|
2002-11-18 08:59:23 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API void sapi_activate(void)
|
2000-02-26 05:27:03 +08:00
|
|
|
{
|
1999-05-06 02:25:20 +08:00
|
|
|
zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), (void (*)(void *)) sapi_free_header, 0);
|
1999-05-09 16:48:05 +08:00
|
|
|
SG(sapi_headers).send_default_content_type = 1;
|
2000-02-25 06:00:47 +08:00
|
|
|
|
2000-08-03 06:48:45 +08:00
|
|
|
/*
|
1999-05-06 02:25:20 +08:00
|
|
|
SG(sapi_headers).http_response_code = 200;
|
2000-08-03 06:48:45 +08:00
|
|
|
*/
|
2000-08-03 06:53:55 +08:00
|
|
|
SG(sapi_headers).http_status_line = NULL;
|
2007-12-04 00:04:36 +08:00
|
|
|
SG(sapi_headers).mimetype = NULL;
|
1999-05-06 03:53:15 +08:00
|
|
|
SG(headers_sent) = 0;
|
2014-02-10 14:04:30 +08:00
|
|
|
ZVAL_UNDEF(&SG(callback_func));
|
1999-05-10 02:40:59 +08:00
|
|
|
SG(read_post_bytes) = 0;
|
2013-08-14 20:42:36 +08:00
|
|
|
SG(request_info).request_body = NULL;
|
2000-02-11 04:13:08 +08:00
|
|
|
SG(request_info).current_user = NULL;
|
|
|
|
SG(request_info).current_user_length = 0;
|
2000-11-14 02:54:37 +08:00
|
|
|
SG(request_info).no_headers = 0;
|
2004-11-28 21:32:29 +08:00
|
|
|
SG(request_info).post_entry = NULL;
|
2005-03-15 03:25:39 +08:00
|
|
|
SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
|
2004-08-11 14:18:25 +08:00
|
|
|
SG(global_request_time) = 0;
|
2014-05-06 17:59:41 +08:00
|
|
|
SG(post_read) = 0;
|
2010-12-16 20:25:27 +08:00
|
|
|
/* It's possible to override this general case in the activate() callback, if necessary. */
|
1999-05-26 05:14:54 +08:00
|
|
|
if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
|
|
|
|
SG(request_info).headers_only = 1;
|
|
|
|
} else {
|
|
|
|
SG(request_info).headers_only = 0;
|
|
|
|
}
|
2000-09-09 23:02:15 +08:00
|
|
|
SG(rfc1867_uploaded_files) = NULL;
|
1999-05-26 05:14:54 +08:00
|
|
|
|
2010-12-16 20:25:27 +08:00
|
|
|
/* Handle request method */
|
1999-05-09 16:48:05 +08:00
|
|
|
if (SG(server_context)) {
|
2013-09-10 19:13:33 +08:00
|
|
|
if (PG(enable_post_data_reading)
|
|
|
|
&& SG(request_info).content_type
|
|
|
|
&& SG(request_info).request_method
|
|
|
|
&& !strcmp(SG(request_info).request_method, "POST")) {
|
|
|
|
/* HTTP POST may contain form data to be processed into variables
|
|
|
|
* depending on given content type */
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_read_post_data();
|
2000-02-18 09:52:11 +08:00
|
|
|
} else {
|
|
|
|
SG(request_info).content_type_dup = NULL;
|
1999-05-10 04:58:26 +08:00
|
|
|
}
|
2002-10-22 00:41:06 +08:00
|
|
|
|
|
|
|
/* Cookies */
|
2014-12-14 06:06:14 +08:00
|
|
|
SG(request_info).cookie_data = sapi_module.read_cookies();
|
2016-07-12 05:28:14 +08:00
|
|
|
}
|
|
|
|
if (sapi_module.activate) {
|
|
|
|
sapi_module.activate();
|
2000-02-11 00:44:59 +08:00
|
|
|
}
|
2010-12-16 20:25:27 +08:00
|
|
|
if (sapi_module.input_filter_init) {
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_module.input_filter_init();
|
2009-04-29 05:30:23 +08:00
|
|
|
}
|
1999-05-06 02:25:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static void sapi_send_headers_free(void)
|
2002-08-01 17:00:30 +08:00
|
|
|
{
|
|
|
|
if (SG(sapi_headers).http_status_line) {
|
|
|
|
efree(SG(sapi_headers).http_status_line);
|
|
|
|
SG(sapi_headers).http_status_line = NULL;
|
|
|
|
}
|
|
|
|
}
|
2015-01-03 17:22:58 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API void sapi_deactivate(void)
|
1999-05-06 02:25:20 +08:00
|
|
|
{
|
|
|
|
zend_llist_destroy(&SG(sapi_headers).headers);
|
2013-08-14 20:42:36 +08:00
|
|
|
if (SG(request_info).request_body) {
|
|
|
|
SG(request_info).request_body = NULL;
|
2013-09-10 19:13:33 +08:00
|
|
|
} else if (SG(server_context)) {
|
|
|
|
if (!SG(post_read)) {
|
2002-11-13 02:29:11 +08:00
|
|
|
/* make sure we've consumed all request input data */
|
2002-10-22 00:41:06 +08:00
|
|
|
char dummy[SAPI_POST_BLOCK_SIZE];
|
2015-03-25 04:15:15 +08:00
|
|
|
size_t read_bytes;
|
2002-11-21 18:29:11 +08:00
|
|
|
|
2013-09-10 19:13:33 +08:00
|
|
|
do {
|
2014-12-14 06:06:14 +08:00
|
|
|
read_bytes = sapi_read_post_block(dummy, SAPI_POST_BLOCK_SIZE);
|
2013-09-10 19:13:33 +08:00
|
|
|
} while (SAPI_POST_BLOCK_SIZE == read_bytes);
|
2002-10-22 00:41:06 +08:00
|
|
|
}
|
1999-05-06 05:29:26 +08:00
|
|
|
}
|
2000-02-16 07:31:10 +08:00
|
|
|
if (SG(request_info).auth_user) {
|
|
|
|
efree(SG(request_info).auth_user);
|
|
|
|
}
|
|
|
|
if (SG(request_info).auth_password) {
|
|
|
|
efree(SG(request_info).auth_password);
|
|
|
|
}
|
2005-04-04 23:06:36 +08:00
|
|
|
if (SG(request_info).auth_digest) {
|
|
|
|
efree(SG(request_info).auth_digest);
|
|
|
|
}
|
2000-02-18 04:23:59 +08:00
|
|
|
if (SG(request_info).content_type_dup) {
|
|
|
|
efree(SG(request_info).content_type_dup);
|
|
|
|
}
|
2000-02-11 04:13:08 +08:00
|
|
|
if (SG(request_info).current_user) {
|
|
|
|
efree(SG(request_info).current_user);
|
|
|
|
}
|
2000-02-11 00:44:59 +08:00
|
|
|
if (sapi_module.deactivate) {
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_module.deactivate();
|
2000-02-11 00:44:59 +08:00
|
|
|
}
|
2000-09-09 05:56:47 +08:00
|
|
|
if (SG(rfc1867_uploaded_files)) {
|
2014-12-14 06:06:14 +08:00
|
|
|
destroy_uploaded_files_hash();
|
2000-09-09 05:56:47 +08:00
|
|
|
}
|
2002-08-06 02:32:05 +08:00
|
|
|
if (SG(sapi_headers).mimetype) {
|
|
|
|
efree(SG(sapi_headers).mimetype);
|
|
|
|
SG(sapi_headers).mimetype = NULL;
|
|
|
|
}
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_send_headers_free();
|
2003-01-15 19:30:39 +08:00
|
|
|
SG(sapi_started) = 0;
|
|
|
|
SG(headers_sent) = 0;
|
|
|
|
SG(request_info).headers_read = 0;
|
2004-08-11 14:18:25 +08:00
|
|
|
SG(global_request_time) = 0;
|
1999-05-06 02:25:20 +08:00
|
|
|
}
|
|
|
|
|
2000-02-18 04:23:59 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API void sapi_initialize_empty_request(void)
|
2000-02-18 04:23:59 +08:00
|
|
|
{
|
|
|
|
SG(server_context) = NULL;
|
|
|
|
SG(request_info).request_method = NULL;
|
2005-07-13 00:53:30 +08:00
|
|
|
SG(request_info).auth_digest = SG(request_info).auth_user = SG(request_info).auth_password = NULL;
|
2000-02-18 04:23:59 +08:00
|
|
|
SG(request_info).content_type_dup = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-10-05 02:07:46 +08:00
|
|
|
static int sapi_extract_response_code(const char *header_line)
|
|
|
|
{
|
|
|
|
int code = 200;
|
|
|
|
const char *ptr;
|
|
|
|
|
|
|
|
for (ptr = header_line; *ptr; ptr++) {
|
|
|
|
if (*ptr == ' ' && *(ptr + 1) != ' ') {
|
|
|
|
code = atoi(ptr + 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-01-03 17:22:58 +08:00
|
|
|
|
1999-10-05 02:07:46 +08:00
|
|
|
return code;
|
|
|
|
}
|
1999-05-06 02:25:20 +08:00
|
|
|
|
2002-07-03 18:42:31 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static void sapi_update_response_code(int ncode)
|
2002-07-03 18:42:31 +08:00
|
|
|
{
|
2003-06-03 18:06:45 +08:00
|
|
|
/* if the status code did not change, we do not want
|
|
|
|
to change the status line, and no need to change the code */
|
|
|
|
if (SG(sapi_headers).http_response_code == ncode) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-07-03 18:42:31 +08:00
|
|
|
if (SG(sapi_headers).http_status_line) {
|
|
|
|
efree(SG(sapi_headers).http_status_line);
|
|
|
|
SG(sapi_headers).http_status_line = NULL;
|
|
|
|
}
|
|
|
|
SG(sapi_headers).http_response_code = ncode;
|
|
|
|
}
|
|
|
|
|
2015-01-03 17:22:58 +08:00
|
|
|
/*
|
2012-04-04 16:14:28 +08:00
|
|
|
* since zend_llist_del_element only remove one matched item once,
|
|
|
|
* we should remove them by ourself
|
|
|
|
*/
|
2015-03-25 01:49:54 +08:00
|
|
|
static void sapi_remove_header(zend_llist *l, char *name, size_t len) {
|
2012-04-04 16:14:28 +08:00
|
|
|
sapi_header_struct *header;
|
|
|
|
zend_llist_element *next;
|
|
|
|
zend_llist_element *current=l->head;
|
|
|
|
|
|
|
|
while (current) {
|
|
|
|
header = (sapi_header_struct *)(current->data);
|
|
|
|
next = current->next;
|
|
|
|
if (header->header_len > len && header->header[len] == ':'
|
|
|
|
&& !strncasecmp(header->header, name, len)) {
|
|
|
|
if (current->prev) {
|
|
|
|
current->prev->next = next;
|
|
|
|
} else {
|
|
|
|
l->head = next;
|
|
|
|
}
|
|
|
|
if (next) {
|
|
|
|
next->prev = current->prev;
|
|
|
|
} else {
|
|
|
|
l->tail = current->prev;
|
|
|
|
}
|
|
|
|
sapi_free_header(header);
|
|
|
|
efree(current);
|
|
|
|
--l->count;
|
|
|
|
}
|
|
|
|
current = next;
|
|
|
|
}
|
2002-06-18 18:16:36 +08:00
|
|
|
}
|
|
|
|
|
2015-03-25 01:49:54 +08:00
|
|
|
SAPI_API int sapi_add_header_ex(char *header_line, size_t header_line_len, zend_bool duplicate, zend_bool replace)
|
2002-07-03 18:42:31 +08:00
|
|
|
{
|
|
|
|
sapi_header_line ctr = {0};
|
|
|
|
int r;
|
2015-01-03 17:22:58 +08:00
|
|
|
|
2002-07-03 18:42:31 +08:00
|
|
|
ctr.line = header_line;
|
|
|
|
ctr.line_len = header_line_len;
|
|
|
|
|
|
|
|
r = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD,
|
2014-12-14 06:06:14 +08:00
|
|
|
&ctr);
|
2002-07-03 18:42:31 +08:00
|
|
|
|
|
|
|
if (!duplicate)
|
|
|
|
efree(header_line);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static void sapi_header_add_op(sapi_header_op_enum op, sapi_header_struct *sapi_header)
|
2010-07-14 23:20:44 +08:00
|
|
|
{
|
|
|
|
if (!sapi_module.header_handler ||
|
2014-12-14 06:06:14 +08:00
|
|
|
(SAPI_HEADER_ADD & sapi_module.header_handler(sapi_header, op, &SG(sapi_headers)))) {
|
2010-07-14 23:20:44 +08:00
|
|
|
if (op == SAPI_HEADER_REPLACE) {
|
|
|
|
char *colon_offset = strchr(sapi_header->header, ':');
|
|
|
|
|
|
|
|
if (colon_offset) {
|
|
|
|
char sav = *colon_offset;
|
|
|
|
|
|
|
|
*colon_offset = 0;
|
2017-07-09 21:15:17 +08:00
|
|
|
sapi_remove_header(&SG(sapi_headers).headers, sapi_header->header, strlen(sapi_header->header));
|
2010-07-14 23:20:44 +08:00
|
|
|
*colon_offset = sav;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
zend_llist_add_element(&SG(sapi_headers).headers, (void *) sapi_header);
|
|
|
|
} else {
|
|
|
|
sapi_free_header(sapi_header);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg)
|
1999-05-06 02:25:20 +08:00
|
|
|
{
|
|
|
|
sapi_header_struct sapi_header;
|
1999-05-12 02:36:35 +08:00
|
|
|
char *colon_offset;
|
2002-07-03 18:42:31 +08:00
|
|
|
char *header_line;
|
2015-03-25 01:49:54 +08:00
|
|
|
size_t header_line_len;
|
2002-07-03 18:42:31 +08:00
|
|
|
int http_response_code;
|
2011-02-04 00:47:28 +08:00
|
|
|
|
2000-11-14 02:54:37 +08:00
|
|
|
if (SG(headers_sent) && !SG(request_info).no_headers) {
|
2014-12-14 06:06:14 +08:00
|
|
|
const char *output_start_filename = php_output_get_start_filename();
|
|
|
|
int output_start_lineno = php_output_get_start_lineno();
|
2000-02-04 22:54:30 +08:00
|
|
|
|
|
|
|
if (output_start_filename) {
|
2002-07-03 18:42:31 +08:00
|
|
|
sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)",
|
2000-02-04 22:54:30 +08:00
|
|
|
output_start_filename, output_start_lineno);
|
|
|
|
} else {
|
2002-07-03 18:42:31 +08:00
|
|
|
sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent");
|
2000-04-28 21:03:13 +08:00
|
|
|
}
|
1999-05-07 05:58:49 +08:00
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
2002-07-03 18:42:31 +08:00
|
|
|
switch (op) {
|
2006-12-18 20:32:08 +08:00
|
|
|
case SAPI_HEADER_SET_STATUS:
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_update_response_code((int)(zend_intptr_t) arg);
|
2006-12-18 20:32:08 +08:00
|
|
|
return SUCCESS;
|
|
|
|
|
Added header_remove() (chsc at peytz dotdk, Arnaud)
[DOC] proto void header_remove([string header_name])
Removes an HTTP header previously set using header()
The header_name parameter is optionnal, all headers are
removed if it is not set
[SAPIs] The header_handler callback in sapi_module_struct has
been changed, it now take a new argument.
When it is set to SAPI_HEADER_DELETE, sapi_header->header is
the name of an header, header_handler has to delete it.
When it is set to SAPI_HEADER_DELETE_ALL, header_handler has
to delete all headers.
When sapi_header_op_enum is SAPI_HEADER_ADD or _REPLACE,
sapi_header->header is in the form "Name: value", header_handler
has to add or replace the given header.
In all cases, header_handler must not free sapi_header or
sapi_header->header. SAPI_HEADER_ADD must be returned if the
header has been added or replaced, or 0 in other cases.
2008-11-13 18:14:04 +08:00
|
|
|
case SAPI_HEADER_ADD:
|
2006-12-18 20:32:08 +08:00
|
|
|
case SAPI_HEADER_REPLACE:
|
Added header_remove() (chsc at peytz dotdk, Arnaud)
[DOC] proto void header_remove([string header_name])
Removes an HTTP header previously set using header()
The header_name parameter is optionnal, all headers are
removed if it is not set
[SAPIs] The header_handler callback in sapi_module_struct has
been changed, it now take a new argument.
When it is set to SAPI_HEADER_DELETE, sapi_header->header is
the name of an header, header_handler has to delete it.
When it is set to SAPI_HEADER_DELETE_ALL, header_handler has
to delete all headers.
When sapi_header_op_enum is SAPI_HEADER_ADD or _REPLACE,
sapi_header->header is in the form "Name: value", header_handler
has to add or replace the given header.
In all cases, header_handler must not free sapi_header or
sapi_header->header. SAPI_HEADER_ADD must be returned if the
header has been added or replaced, or 0 in other cases.
2008-11-13 18:14:04 +08:00
|
|
|
case SAPI_HEADER_DELETE: {
|
2006-12-18 20:32:08 +08:00
|
|
|
sapi_header_line *p = arg;
|
|
|
|
|
|
|
|
if (!p->line || !p->line_len) {
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
header_line = p->line;
|
|
|
|
header_line_len = p->line_len;
|
|
|
|
http_response_code = p->response_code;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
Added header_remove() (chsc at peytz dotdk, Arnaud)
[DOC] proto void header_remove([string header_name])
Removes an HTTP header previously set using header()
The header_name parameter is optionnal, all headers are
removed if it is not set
[SAPIs] The header_handler callback in sapi_module_struct has
been changed, it now take a new argument.
When it is set to SAPI_HEADER_DELETE, sapi_header->header is
the name of an header, header_handler has to delete it.
When it is set to SAPI_HEADER_DELETE_ALL, header_handler has
to delete all headers.
When sapi_header_op_enum is SAPI_HEADER_ADD or _REPLACE,
sapi_header->header is in the form "Name: value", header_handler
has to add or replace the given header.
In all cases, header_handler must not free sapi_header or
sapi_header->header. SAPI_HEADER_ADD must be returned if the
header has been added or replaced, or 0 in other cases.
2008-11-13 18:14:04 +08:00
|
|
|
case SAPI_HEADER_DELETE_ALL:
|
|
|
|
if (sapi_module.header_handler) {
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers));
|
Added header_remove() (chsc at peytz dotdk, Arnaud)
[DOC] proto void header_remove([string header_name])
Removes an HTTP header previously set using header()
The header_name parameter is optionnal, all headers are
removed if it is not set
[SAPIs] The header_handler callback in sapi_module_struct has
been changed, it now take a new argument.
When it is set to SAPI_HEADER_DELETE, sapi_header->header is
the name of an header, header_handler has to delete it.
When it is set to SAPI_HEADER_DELETE_ALL, header_handler has
to delete all headers.
When sapi_header_op_enum is SAPI_HEADER_ADD or _REPLACE,
sapi_header->header is in the form "Name: value", header_handler
has to add or replace the given header.
In all cases, header_handler must not free sapi_header or
sapi_header->header. SAPI_HEADER_ADD must be returned if the
header has been added or replaced, or 0 in other cases.
2008-11-13 18:14:04 +08:00
|
|
|
}
|
|
|
|
zend_llist_clean(&SG(sapi_headers).headers);
|
|
|
|
return SUCCESS;
|
|
|
|
|
2006-12-18 20:32:08 +08:00
|
|
|
default:
|
2005-11-02 22:38:13 +08:00
|
|
|
return FAILURE;
|
2000-04-28 21:03:13 +08:00
|
|
|
}
|
2000-04-29 00:47:19 +08:00
|
|
|
|
2002-07-03 18:42:31 +08:00
|
|
|
header_line = estrndup(header_line, header_line_len);
|
|
|
|
|
2014-04-13 07:55:55 +08:00
|
|
|
/* cut off trailing spaces, linefeeds and carriage-returns */
|
2010-07-14 23:20:44 +08:00
|
|
|
if (header_line_len && isspace(header_line[header_line_len-1])) {
|
|
|
|
do {
|
|
|
|
header_line_len--;
|
|
|
|
} while(header_line_len && isspace(header_line[header_line_len-1]));
|
2011-02-25 19:28:33 +08:00
|
|
|
header_line[header_line_len]='\0';
|
2010-07-14 23:20:44 +08:00
|
|
|
}
|
2015-01-03 17:22:58 +08:00
|
|
|
|
Added header_remove() (chsc at peytz dotdk, Arnaud)
[DOC] proto void header_remove([string header_name])
Removes an HTTP header previously set using header()
The header_name parameter is optionnal, all headers are
removed if it is not set
[SAPIs] The header_handler callback in sapi_module_struct has
been changed, it now take a new argument.
When it is set to SAPI_HEADER_DELETE, sapi_header->header is
the name of an header, header_handler has to delete it.
When it is set to SAPI_HEADER_DELETE_ALL, header_handler has
to delete all headers.
When sapi_header_op_enum is SAPI_HEADER_ADD or _REPLACE,
sapi_header->header is in the form "Name: value", header_handler
has to add or replace the given header.
In all cases, header_handler must not free sapi_header or
sapi_header->header. SAPI_HEADER_ADD must be returned if the
header has been added or replaced, or 0 in other cases.
2008-11-13 18:14:04 +08:00
|
|
|
if (op == SAPI_HEADER_DELETE) {
|
|
|
|
if (strchr(header_line, ':')) {
|
|
|
|
efree(header_line);
|
|
|
|
sapi_module.sapi_error(E_WARNING, "Header to delete may not contain colon.");
|
|
|
|
return FAILURE;
|
|
|
|
}
|
2010-07-14 23:20:44 +08:00
|
|
|
if (sapi_module.header_handler) {
|
|
|
|
sapi_header.header = header_line;
|
|
|
|
sapi_header.header_len = header_line_len;
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers));
|
2010-07-14 23:20:44 +08:00
|
|
|
}
|
2012-04-04 16:14:28 +08:00
|
|
|
sapi_remove_header(&SG(sapi_headers).headers, header_line, header_line_len);
|
2010-07-14 23:20:44 +08:00
|
|
|
efree(header_line);
|
|
|
|
return SUCCESS;
|
Added header_remove() (chsc at peytz dotdk, Arnaud)
[DOC] proto void header_remove([string header_name])
Removes an HTTP header previously set using header()
The header_name parameter is optionnal, all headers are
removed if it is not set
[SAPIs] The header_handler callback in sapi_module_struct has
been changed, it now take a new argument.
When it is set to SAPI_HEADER_DELETE, sapi_header->header is
the name of an header, header_handler has to delete it.
When it is set to SAPI_HEADER_DELETE_ALL, header_handler has
to delete all headers.
When sapi_header_op_enum is SAPI_HEADER_ADD or _REPLACE,
sapi_header->header is in the form "Name: value", header_handler
has to add or replace the given header.
In all cases, header_handler must not free sapi_header or
sapi_header->header. SAPI_HEADER_ADD must be returned if the
header has been added or replaced, or 0 in other cases.
2008-11-13 18:14:04 +08:00
|
|
|
} else {
|
2012-03-07 15:49:56 +08:00
|
|
|
/* new line/NUL character safety check */
|
2016-11-26 22:18:42 +08:00
|
|
|
uint32_t i;
|
2012-03-07 15:49:56 +08:00
|
|
|
for (i = 0; i < header_line_len; i++) {
|
2015-02-04 17:11:00 +08:00
|
|
|
/* RFC 7230 ch. 3.2.4 deprecates folding support */
|
|
|
|
if (header_line[i] == '\n' || header_line[i] == '\r') {
|
2012-03-07 15:49:56 +08:00
|
|
|
efree(header_line);
|
|
|
|
sapi_module.sapi_error(E_WARNING, "Header may not contain "
|
|
|
|
"more than a single header, new line detected");
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
if (header_line[i] == '\0') {
|
|
|
|
efree(header_line);
|
|
|
|
sapi_module.sapi_error(E_WARNING, "Header may not contain NUL bytes");
|
|
|
|
return FAILURE;
|
2005-12-06 11:39:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-04-29 00:47:19 +08:00
|
|
|
|
1999-05-07 05:58:49 +08:00
|
|
|
sapi_header.header = header_line;
|
1999-05-06 02:25:20 +08:00
|
|
|
sapi_header.header_len = header_line_len;
|
Added header_remove() (chsc at peytz dotdk, Arnaud)
[DOC] proto void header_remove([string header_name])
Removes an HTTP header previously set using header()
The header_name parameter is optionnal, all headers are
removed if it is not set
[SAPIs] The header_handler callback in sapi_module_struct has
been changed, it now take a new argument.
When it is set to SAPI_HEADER_DELETE, sapi_header->header is
the name of an header, header_handler has to delete it.
When it is set to SAPI_HEADER_DELETE_ALL, header_handler has
to delete all headers.
When sapi_header_op_enum is SAPI_HEADER_ADD or _REPLACE,
sapi_header->header is in the form "Name: value", header_handler
has to add or replace the given header.
In all cases, header_handler must not free sapi_header or
sapi_header->header. SAPI_HEADER_ADD must be returned if the
header has been added or replaced, or 0 in other cases.
2008-11-13 18:14:04 +08:00
|
|
|
|
1999-05-12 04:38:16 +08:00
|
|
|
/* Check the header for a few cases that we have special support for in SAPI */
|
2015-01-03 17:22:58 +08:00
|
|
|
if (header_line_len>=5
|
2000-07-02 02:06:11 +08:00
|
|
|
&& !strncasecmp(header_line, "HTTP/", 5)) {
|
1999-10-05 02:07:46 +08:00
|
|
|
/* filter out the response code */
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_update_response_code(sapi_extract_response_code(header_line));
|
2008-01-29 00:09:08 +08:00
|
|
|
/* sapi_update_response_code doesn't free the status line if the code didn't change */
|
|
|
|
if (SG(sapi_headers).http_status_line) {
|
|
|
|
efree(SG(sapi_headers).http_status_line);
|
|
|
|
}
|
1999-05-12 04:38:16 +08:00
|
|
|
SG(sapi_headers).http_status_line = header_line;
|
1999-08-10 01:40:28 +08:00
|
|
|
return SUCCESS;
|
1999-05-12 04:38:16 +08:00
|
|
|
} else {
|
|
|
|
colon_offset = strchr(header_line, ':');
|
|
|
|
if (colon_offset) {
|
|
|
|
*colon_offset = 0;
|
2015-09-01 03:43:24 +08:00
|
|
|
if (!strcasecmp(header_line, "Content-Type")) {
|
2002-06-18 23:04:58 +08:00
|
|
|
char *ptr = colon_offset+1, *mimetype = NULL, *newheader;
|
2000-02-26 05:27:03 +08:00
|
|
|
size_t len = header_line_len - (ptr - header_line), newlen;
|
2004-03-25 16:42:00 +08:00
|
|
|
while (*ptr == ' ') {
|
2002-08-02 05:12:09 +08:00
|
|
|
ptr++;
|
2004-03-25 16:42:00 +08:00
|
|
|
len--;
|
2002-08-02 05:12:09 +08:00
|
|
|
}
|
2009-08-18 00:54:39 +08:00
|
|
|
|
|
|
|
/* Disable possible output compression for images */
|
|
|
|
if (!strncmp(ptr, "image/", sizeof("image/")-1)) {
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_string *key = zend_string_init("zlib.output_compression", sizeof("zlib.output_compression")-1, 0);
|
2014-09-02 00:57:33 +08:00
|
|
|
zend_alter_ini_entry_chars(key, "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
|
2018-05-28 21:27:12 +08:00
|
|
|
zend_string_release_ex(key, 0);
|
2002-07-28 22:08:08 +08:00
|
|
|
}
|
2009-08-18 00:54:39 +08:00
|
|
|
|
2000-02-26 05:27:03 +08:00
|
|
|
mimetype = estrdup(ptr);
|
2014-12-14 06:06:14 +08:00
|
|
|
newlen = sapi_apply_default_charset(&mimetype, len);
|
2002-07-27 21:58:16 +08:00
|
|
|
if (!SG(sapi_headers).mimetype){
|
|
|
|
SG(sapi_headers).mimetype = estrdup(mimetype);
|
|
|
|
}
|
|
|
|
|
2000-02-26 05:27:03 +08:00
|
|
|
if (newlen != 0) {
|
|
|
|
newlen += sizeof("Content-type: ");
|
|
|
|
newheader = emalloc(newlen);
|
2000-08-27 17:48:03 +08:00
|
|
|
PHP_STRLCPY(newheader, "Content-type: ", newlen, sizeof("Content-type: ")-1);
|
|
|
|
strlcat(newheader, mimetype, newlen);
|
2000-02-26 05:27:03 +08:00
|
|
|
sapi_header.header = newheader;
|
2016-11-26 22:18:42 +08:00
|
|
|
sapi_header.header_len = (uint32_t)(newlen - 1);
|
2002-06-18 23:04:58 +08:00
|
|
|
efree(header_line);
|
2000-02-26 05:27:03 +08:00
|
|
|
}
|
|
|
|
efree(mimetype);
|
1999-05-12 04:38:16 +08:00
|
|
|
SG(sapi_headers).send_default_content_type = 0;
|
2015-09-01 03:43:24 +08:00
|
|
|
} else if (!strcasecmp(header_line, "Content-Length")) {
|
2010-10-26 10:16:21 +08:00
|
|
|
/* Script is setting Content-length. The script cannot reasonably
|
|
|
|
* know the size of the message body after compression, so it's best
|
|
|
|
* do disable compression altogether. This contributes to making scripts
|
|
|
|
* portable between setups that have and don't have zlib compression
|
|
|
|
* enabled globally. See req #44164 */
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_string *key = zend_string_init("zlib.output_compression", sizeof("zlib.output_compression")-1, 0);
|
2014-09-02 00:57:33 +08:00
|
|
|
zend_alter_ini_entry_chars(key,
|
2010-10-26 10:16:21 +08:00
|
|
|
"0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
|
2018-05-28 21:27:12 +08:00
|
|
|
zend_string_release_ex(key, 0);
|
2015-09-01 03:43:24 +08:00
|
|
|
} else if (!strcasecmp(header_line, "Location")) {
|
2003-08-12 03:36:26 +08:00
|
|
|
if ((SG(sapi_headers).http_response_code < 300 ||
|
2014-06-13 08:35:05 +08:00
|
|
|
SG(sapi_headers).http_response_code > 399) &&
|
2003-08-12 03:36:26 +08:00
|
|
|
SG(sapi_headers).http_response_code != 201) {
|
2002-06-21 17:31:21 +08:00
|
|
|
/* Return a Found Redirect if one is not already specified */
|
2007-01-01 03:22:01 +08:00
|
|
|
if (http_response_code) { /* user specified redirect code */
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_update_response_code(http_response_code);
|
2015-01-03 17:22:58 +08:00
|
|
|
} else if (SG(request_info).proto_num > 1000 &&
|
|
|
|
SG(request_info).request_method &&
|
2005-03-15 03:25:39 +08:00
|
|
|
strcmp(SG(request_info).request_method, "HEAD") &&
|
|
|
|
strcmp(SG(request_info).request_method, "GET")) {
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_update_response_code(303);
|
2005-03-15 03:25:39 +08:00
|
|
|
} else {
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_update_response_code(302);
|
2005-03-15 03:25:39 +08:00
|
|
|
}
|
2002-06-21 17:31:21 +08:00
|
|
|
}
|
2015-09-01 03:43:24 +08:00
|
|
|
} else if (!strcasecmp(header_line, "WWW-Authenticate")) { /* HTTP Authentication */
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_update_response_code(401); /* authentication-required */
|
1999-05-12 04:38:16 +08:00
|
|
|
}
|
2001-12-17 07:21:52 +08:00
|
|
|
if (sapi_header.header==header_line) {
|
|
|
|
*colon_offset = ':';
|
|
|
|
}
|
1999-05-12 02:36:35 +08:00
|
|
|
}
|
|
|
|
}
|
2002-06-21 17:31:21 +08:00
|
|
|
if (http_response_code) {
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_update_response_code(http_response_code);
|
2002-06-21 17:31:21 +08:00
|
|
|
}
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_header_add_op(op, &sapi_header);
|
1999-05-06 02:25:20 +08:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API int sapi_send_headers(void)
|
1999-05-06 02:25:20 +08:00
|
|
|
{
|
1999-05-06 03:53:15 +08:00
|
|
|
int retval;
|
1999-10-05 02:07:46 +08:00
|
|
|
int ret = FAILURE;
|
1999-05-06 02:25:20 +08:00
|
|
|
|
2015-12-11 17:26:31 +08:00
|
|
|
if (SG(headers_sent) || SG(request_info).no_headers) {
|
1999-05-06 03:53:15 +08:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2000-08-20 00:38:19 +08:00
|
|
|
/* Success-oriented. We set headers_sent to 1 here to avoid an infinite loop
|
|
|
|
* in case of an error situation.
|
|
|
|
*/
|
2005-10-20 04:33:33 +08:00
|
|
|
if (SG(sapi_headers).send_default_content_type && sapi_module.send_headers) {
|
2016-11-26 22:18:42 +08:00
|
|
|
uint32_t len = 0;
|
2016-03-27 13:50:11 +08:00
|
|
|
char *default_mimetype = get_default_content_type(0, &len);
|
|
|
|
|
|
|
|
if (default_mimetype && len) {
|
|
|
|
sapi_header_struct default_header;
|
|
|
|
|
|
|
|
SG(sapi_headers).mimetype = default_mimetype;
|
|
|
|
|
|
|
|
default_header.header_len = sizeof("Content-type: ") - 1 + len;
|
|
|
|
default_header.header = emalloc(default_header.header_len + 1);
|
|
|
|
|
|
|
|
memcpy(default_header.header, "Content-type: ", sizeof("Content-type: ") - 1);
|
|
|
|
memcpy(default_header.header + sizeof("Content-type: ") - 1, SG(sapi_headers).mimetype, len + 1);
|
2017-12-31 12:35:25 +08:00
|
|
|
|
2016-03-27 13:50:11 +08:00
|
|
|
sapi_header_add_op(SAPI_HEADER_ADD, &default_header);
|
|
|
|
} else {
|
|
|
|
efree(default_mimetype);
|
|
|
|
}
|
2010-07-14 23:20:44 +08:00
|
|
|
SG(sapi_headers).send_default_content_type = 0;
|
2005-10-20 04:33:33 +08:00
|
|
|
}
|
|
|
|
|
2015-12-11 17:26:31 +08:00
|
|
|
if (Z_TYPE(SG(callback_func)) != IS_UNDEF) {
|
|
|
|
zval cb;
|
|
|
|
ZVAL_COPY_VALUE(&cb, &SG(callback_func));
|
|
|
|
ZVAL_UNDEF(&SG(callback_func));
|
|
|
|
sapi_run_header_callback(&cb);
|
|
|
|
zval_ptr_dtor(&cb);
|
2011-02-04 00:47:28 +08:00
|
|
|
}
|
|
|
|
|
2000-08-20 00:38:19 +08:00
|
|
|
SG(headers_sent) = 1;
|
|
|
|
|
1999-05-06 03:53:15 +08:00
|
|
|
if (sapi_module.send_headers) {
|
2014-12-14 06:06:14 +08:00
|
|
|
retval = sapi_module.send_headers(&SG(sapi_headers));
|
1999-05-06 03:53:15 +08:00
|
|
|
} else {
|
|
|
|
retval = SAPI_HEADER_DO_SEND;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (retval) {
|
1999-05-06 02:25:20 +08:00
|
|
|
case SAPI_HEADER_SENT_SUCCESSFULLY:
|
1999-10-05 20:06:35 +08:00
|
|
|
ret = SUCCESS;
|
1999-05-06 02:25:20 +08:00
|
|
|
break;
|
2002-07-03 18:42:31 +08:00
|
|
|
case SAPI_HEADER_DO_SEND: {
|
1999-05-12 04:38:16 +08:00
|
|
|
sapi_header_struct http_status_line;
|
2002-07-03 18:42:31 +08:00
|
|
|
char buf[255];
|
1999-05-12 04:38:16 +08:00
|
|
|
|
2002-07-03 18:42:31 +08:00
|
|
|
if (SG(sapi_headers).http_status_line) {
|
|
|
|
http_status_line.header = SG(sapi_headers).http_status_line;
|
2016-11-26 22:18:42 +08:00
|
|
|
http_status_line.header_len = (uint32_t)strlen(SG(sapi_headers).http_status_line);
|
2002-07-03 18:42:31 +08:00
|
|
|
} else {
|
|
|
|
http_status_line.header = buf;
|
2007-02-27 11:28:17 +08:00
|
|
|
http_status_line.header_len = slprintf(buf, sizeof(buf), "HTTP/1.0 %d X", SG(sapi_headers).http_response_code);
|
2002-07-03 18:42:31 +08:00
|
|
|
}
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_module.send_header(&http_status_line, SG(server_context));
|
1999-05-12 04:38:16 +08:00
|
|
|
}
|
2014-12-14 06:06:14 +08:00
|
|
|
zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) sapi_module.send_header, SG(server_context));
|
1999-12-19 10:04:20 +08:00
|
|
|
if(SG(sapi_headers).send_default_content_type) {
|
2000-02-26 13:03:41 +08:00
|
|
|
sapi_header_struct default_header;
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_get_default_content_type_header(&default_header);
|
|
|
|
sapi_module.send_header(&default_header, SG(server_context));
|
2000-02-26 13:03:41 +08:00
|
|
|
sapi_free_header(&default_header);
|
1999-12-19 10:04:20 +08:00
|
|
|
}
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_module.send_header(NULL, SG(server_context));
|
1999-10-05 02:07:46 +08:00
|
|
|
ret = SUCCESS;
|
1999-05-06 02:25:20 +08:00
|
|
|
break;
|
|
|
|
case SAPI_HEADER_SEND_FAILED:
|
2000-08-20 00:38:19 +08:00
|
|
|
SG(headers_sent) = 0;
|
1999-10-05 02:07:46 +08:00
|
|
|
ret = FAILURE;
|
1999-05-06 02:25:20 +08:00
|
|
|
break;
|
|
|
|
}
|
2002-08-01 01:55:15 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_send_headers_free();
|
2002-08-01 01:55:15 +08:00
|
|
|
|
1999-10-05 02:07:46 +08:00
|
|
|
return ret;
|
1999-05-06 02:25:20 +08:00
|
|
|
}
|
1999-05-26 05:14:54 +08:00
|
|
|
|
|
|
|
|
2017-12-15 03:14:36 +08:00
|
|
|
SAPI_API int sapi_register_post_entries(const sapi_post_entry *post_entries)
|
1999-09-17 07:18:15 +08:00
|
|
|
{
|
2017-12-15 03:14:36 +08:00
|
|
|
const sapi_post_entry *p=post_entries;
|
1999-09-17 07:18:15 +08:00
|
|
|
|
|
|
|
while (p->content_type) {
|
2014-12-14 06:06:14 +08:00
|
|
|
if (sapi_register_post_entry(p) == FAILURE) {
|
1999-09-17 07:18:15 +08:00
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-15 03:14:36 +08:00
|
|
|
SAPI_API int sapi_register_post_entry(const sapi_post_entry *post_entry)
|
1999-05-26 05:14:54 +08:00
|
|
|
{
|
2017-11-03 05:34:18 +08:00
|
|
|
int ret;
|
|
|
|
zend_string *key;
|
2014-07-03 05:02:25 +08:00
|
|
|
if (SG(sapi_started) && EG(current_execute_data)) {
|
2007-04-25 16:40:07 +08:00
|
|
|
return FAILURE;
|
|
|
|
}
|
2017-11-03 05:34:18 +08:00
|
|
|
key = zend_string_init(post_entry->content_type, post_entry->content_type_len, 1);
|
|
|
|
GC_MAKE_PERSISTENT_LOCAL(key);
|
|
|
|
ret = zend_hash_add_mem(&SG(known_post_content_types), key,
|
2014-02-10 14:04:30 +08:00
|
|
|
(void *) post_entry, sizeof(sapi_post_entry)) ? SUCCESS : FAILURE;
|
2018-05-28 21:27:12 +08:00
|
|
|
zend_string_release_ex(key, 1);
|
2017-11-03 05:34:18 +08:00
|
|
|
return ret;
|
1999-05-26 05:14:54 +08:00
|
|
|
}
|
1999-05-26 05:19:46 +08:00
|
|
|
|
2017-12-15 03:14:36 +08:00
|
|
|
SAPI_API void sapi_unregister_post_entry(const sapi_post_entry *post_entry)
|
1999-05-26 05:19:46 +08:00
|
|
|
{
|
2014-07-03 05:02:25 +08:00
|
|
|
if (SG(sapi_started) && EG(current_execute_data)) {
|
2007-04-25 16:40:07 +08:00
|
|
|
return;
|
|
|
|
}
|
2014-02-10 14:04:30 +08:00
|
|
|
zend_hash_str_del(&SG(known_post_content_types), post_entry->content_type,
|
|
|
|
post_entry->content_type_len);
|
1999-05-29 06:41:48 +08:00
|
|
|
}
|
1999-09-17 07:18:15 +08:00
|
|
|
|
2000-10-13 20:13:35 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(void))
|
1999-09-17 07:18:15 +08:00
|
|
|
{
|
2014-07-03 05:02:25 +08:00
|
|
|
if (SG(sapi_started) && EG(current_execute_data)) {
|
2007-04-25 16:40:07 +08:00
|
|
|
return FAILURE;
|
|
|
|
}
|
1999-09-17 07:18:15 +08:00
|
|
|
sapi_module.default_post_reader = default_post_reader;
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2000-01-14 01:37:25 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray))
|
2002-08-02 14:53:48 +08:00
|
|
|
{
|
2014-07-03 05:02:25 +08:00
|
|
|
if (SG(sapi_started) && EG(current_execute_data)) {
|
2007-04-25 16:40:07 +08:00
|
|
|
return FAILURE;
|
|
|
|
}
|
2002-08-02 14:53:48 +08:00
|
|
|
sapi_module.treat_data = treat_data;
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_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))
|
2003-02-20 03:41:09 +08:00
|
|
|
{
|
2014-07-03 05:02:25 +08:00
|
|
|
if (SG(sapi_started) && EG(current_execute_data)) {
|
2007-04-25 16:40:07 +08:00
|
|
|
return FAILURE;
|
|
|
|
}
|
2003-02-20 03:41:09 +08:00
|
|
|
sapi_module.input_filter = input_filter;
|
2009-04-29 05:30:23 +08:00
|
|
|
sapi_module.input_filter_init = input_filter_init;
|
2003-02-20 03:41:09 +08:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
2002-08-02 14:53:48 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API int sapi_flush(void)
|
2000-01-14 01:37:25 +08:00
|
|
|
{
|
|
|
|
if (sapi_module.flush) {
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_module.flush(SG(server_context));
|
2000-02-11 03:29:21 +08:00
|
|
|
return SUCCESS;
|
|
|
|
} else {
|
|
|
|
return FAILURE;
|
2000-01-14 01:37:25 +08:00
|
|
|
}
|
|
|
|
}
|
2000-02-11 01:26:57 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API zend_stat_t *sapi_get_stat(void)
|
2000-02-11 01:26:57 +08:00
|
|
|
{
|
2000-02-11 02:19:04 +08:00
|
|
|
if (sapi_module.get_stat) {
|
2014-12-14 06:06:14 +08:00
|
|
|
return sapi_module.get_stat();
|
2000-02-11 01:26:57 +08:00
|
|
|
} else {
|
2003-02-11 03:45:34 +08:00
|
|
|
if (!SG(request_info).path_translated || (VCWD_STAT(SG(request_info).path_translated, &SG(global_stat)) == -1)) {
|
2000-02-11 02:19:04 +08:00
|
|
|
return NULL;
|
2000-02-11 01:26:57 +08:00
|
|
|
}
|
2000-02-11 02:19:04 +08:00
|
|
|
return &SG(global_stat);
|
2000-02-11 01:26:57 +08:00
|
|
|
}
|
|
|
|
}
|
2000-02-11 01:55:01 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API char *sapi_getenv(char *name, size_t name_len)
|
2000-02-11 01:55:01 +08:00
|
|
|
{
|
2016-07-11 07:17:54 +08:00
|
|
|
if (!strncasecmp(name, "HTTP_PROXY", name_len)) {
|
2016-07-13 12:35:02 +08:00
|
|
|
/* Ugly fix for HTTP_PROXY issue, see bug #72573 */
|
2016-07-11 07:17:54 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2015-01-03 17:22:58 +08:00
|
|
|
if (sapi_module.getenv) {
|
2014-12-14 06:06:14 +08:00
|
|
|
char *value, *tmp = sapi_module.getenv(name, name_len);
|
2006-12-22 05:49:22 +08:00
|
|
|
if (tmp) {
|
|
|
|
value = estrdup(tmp);
|
2017-11-29 03:31:48 +08:00
|
|
|
#ifdef PHP_WIN32
|
|
|
|
if (strlen(sapi_module.name) == sizeof("cgi-fcgi") - 1 && !strcmp(sapi_module.name, "cgi-fcgi")) {
|
|
|
|
/* XXX more modules to go, if needed. */
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
#endif
|
2006-12-22 05:49:22 +08:00
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-04-06 21:42:40 +08:00
|
|
|
if (sapi_module.input_filter) {
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_module.input_filter(PARSE_STRING, name, &value, strlen(value), NULL);
|
2012-04-06 21:42:40 +08:00
|
|
|
}
|
2006-05-11 05:19:32 +08:00
|
|
|
return value;
|
2006-12-22 05:49:22 +08:00
|
|
|
}
|
|
|
|
return NULL;
|
2000-02-25 06:00:47 +08:00
|
|
|
}
|
2000-02-26 05:27:03 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API int sapi_get_fd(int *fd)
|
2002-11-26 13:15:55 +08:00
|
|
|
{
|
|
|
|
if (sapi_module.get_fd) {
|
2014-12-14 06:06:14 +08:00
|
|
|
return sapi_module.get_fd(fd);
|
2002-11-26 13:15:55 +08:00
|
|
|
} else {
|
2003-02-10 05:15:55 +08:00
|
|
|
return FAILURE;
|
2002-11-26 13:15:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API int sapi_force_http_10(void)
|
2002-12-01 11:28:21 +08:00
|
|
|
{
|
|
|
|
if (sapi_module.force_http_10) {
|
2014-12-14 06:06:14 +08:00
|
|
|
return sapi_module.force_http_10();
|
2002-12-01 11:28:21 +08:00
|
|
|
} else {
|
2003-02-10 05:15:55 +08:00
|
|
|
return FAILURE;
|
2002-12-01 11:28:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-21 19:03:58 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API int sapi_get_target_uid(uid_t *obj)
|
2003-01-21 19:03:58 +08:00
|
|
|
{
|
|
|
|
if (sapi_module.get_target_uid) {
|
2014-12-14 06:06:14 +08:00
|
|
|
return sapi_module.get_target_uid(obj);
|
2003-01-21 19:03:58 +08:00
|
|
|
} else {
|
2003-02-10 05:15:55 +08:00
|
|
|
return FAILURE;
|
2003-01-21 19:03:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API int sapi_get_target_gid(gid_t *obj)
|
2003-01-21 19:03:58 +08:00
|
|
|
{
|
|
|
|
if (sapi_module.get_target_gid) {
|
2014-12-14 06:06:14 +08:00
|
|
|
return sapi_module.get_target_gid(obj);
|
2003-01-21 19:03:58 +08:00
|
|
|
} else {
|
2003-02-10 05:15:55 +08:00
|
|
|
return FAILURE;
|
2003-01-21 19:03:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API double sapi_get_request_time(void)
|
2004-08-11 01:40:00 +08:00
|
|
|
{
|
2007-05-25 17:12:35 +08:00
|
|
|
if(SG(global_request_time)) return SG(global_request_time);
|
|
|
|
|
2007-05-25 17:20:01 +08:00
|
|
|
if (sapi_module.get_request_time && SG(server_context)) {
|
2014-12-14 06:06:14 +08:00
|
|
|
SG(global_request_time) = sapi_module.get_request_time();
|
2004-08-11 01:40:00 +08:00
|
|
|
} else {
|
2010-11-07 01:14:21 +08:00
|
|
|
struct timeval tp = {0};
|
|
|
|
if (!gettimeofday(&tp, NULL)) {
|
|
|
|
SG(global_request_time) = (double)(tp.tv_sec + tp.tv_usec / 1000000.00);
|
|
|
|
} else {
|
|
|
|
SG(global_request_time) = (double)time(0);
|
|
|
|
}
|
2004-08-11 01:40:00 +08:00
|
|
|
}
|
2007-05-25 17:12:35 +08:00
|
|
|
return SG(global_request_time);
|
2004-08-11 01:40:00 +08:00
|
|
|
}
|
2003-01-21 19:03:58 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
SAPI_API void sapi_terminate_process(void) {
|
2008-03-19 05:42:50 +08:00
|
|
|
if (sapi_module.terminate_process) {
|
2014-12-14 06:06:14 +08:00
|
|
|
sapi_module.terminate_process();
|
2008-03-19 05:42:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-04 14:48:38 +08:00
|
|
|
SAPI_API void sapi_add_request_header(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg) /* {{{ */
|
|
|
|
{
|
|
|
|
zval *return_value = (zval*)arg;
|
|
|
|
char *str = NULL;
|
|
|
|
|
|
|
|
ALLOCA_FLAG(use_heap)
|
|
|
|
|
|
|
|
if (var_len > 5 &&
|
|
|
|
var[0] == 'H' &&
|
|
|
|
var[1] == 'T' &&
|
|
|
|
var[2] == 'T' &&
|
|
|
|
var[3] == 'P' &&
|
|
|
|
var[4] == '_') {
|
|
|
|
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
var_len -= 5;
|
|
|
|
p = var + 5;
|
|
|
|
var = str = do_alloca(var_len + 1, use_heap);
|
|
|
|
*str++ = *p++;
|
|
|
|
while (*p) {
|
|
|
|
if (*p == '_') {
|
|
|
|
*str++ = '-';
|
|
|
|
p++;
|
|
|
|
if (*p) {
|
|
|
|
*str++ = *p++;
|
|
|
|
}
|
|
|
|
} else if (*p >= 'A' && *p <= 'Z') {
|
|
|
|
*str++ = (*p++ - 'A' + 'a');
|
|
|
|
} else {
|
|
|
|
*str++ = *p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*str = 0;
|
|
|
|
} else if (var_len == sizeof("CONTENT_TYPE")-1 &&
|
|
|
|
memcmp(var, "CONTENT_TYPE", sizeof("CONTENT_TYPE")-1) == 0) {
|
|
|
|
var = "Content-Type";
|
|
|
|
} else if (var_len == sizeof("CONTENT_LENGTH")-1 &&
|
|
|
|
memcmp(var, "CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1) == 0) {
|
|
|
|
var = "Content-Length";
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
add_assoc_stringl_ex(return_value, var, var_len, val, val_len);
|
|
|
|
if (str) {
|
|
|
|
free_alloca(var, use_heap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|