Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ PHP NEWS
. Fixed bug #68422 (Incorrect argument reflection info for array_multisort()).
(Alexander Lisachenko)
. Fixed bug #68446 (Array constant not accepted for array parameter default). (Bob)
. Fixed bug #68091 (Some Zend headers lack appropriate extern "C" blocks).
(Adam)
. Fixed bug #68370 ("unset($this)" can make the program crash). (Laruence)

- FPM:
. Fixed bug #68381 (fpm_unix_init_main ignores log_level).
Expand All @@ -35,6 +38,7 @@ PHP NEWS

- GMP:
. Fixed bug #68419 (build error with gmp 4.1). (Remi)
. Fixed bug #68478 (access.log don't use prefix). (Remi)

- PDO_pgsql:
. Fixed bug #67462 (PDO_PGSQL::beginTransaction() wrongly throws exception
Expand All @@ -49,6 +53,8 @@ PHP NEWS
- Session:
. Fixed bug #68331 (Session custom storage callable functions not being called)
(Yasuo Ohgaki)
. Fixed bug #68091 (Some Zend headers lack appropriate extern "C" blocks).
(Adam)

- SOAP:
. Fixed bug #68361 (Segmentation fault on SoapClient::__getTypes).
Expand Down
48 changes: 48 additions & 0 deletions main/SAPI.c
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,54 @@ SAPI_API void sapi_terminate_process(TSRMLS_D) {
}
}

SAPI_API void sapi_add_request_header(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg TSRMLS_DC) /* {{{ */
{
zval *return_value = (zval*)arg;
char *str = NULL;
char *p;
ALLOCA_FLAG(use_heap)

if (var_len > 5 &&
var[0] == 'H' &&
var[1] == 'T' &&
var[2] == 'T' &&
var[3] == 'P' &&
var[4] == '_') {
Copy link
Contributor

@hikari-no-yume hikari-no-yume Jul 21, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way to actually preserve the header case? This naïve algorithm won't work properly for certain headers, and would break poorly-written code that relies on header case.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't checked for FPM, but doing a "strace" on a FastCGI-only process shows that the headers are transmitted in upper case, no matter what they looked like in the original request. I guess FPM will receive the same data when using mod_fastcgi on Apache.

Might be different with other implementations, like mod_proxy_fcgi (or other web server), but an existing case sensitive code would already not work is most cases.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's unfortunate :/

OK then. Could this code be shared with the other places in PHP that use the same algorithm? CGI and FastCGI already have way too much copy-pasting.


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, 1);
if (str) {
free_alloca(var, use_heap);
}
}

/*
* Local variables:
* tab-width: 4
Expand Down
1 change: 1 addition & 0 deletions main/SAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ SAPI_API int sapi_get_target_uid(uid_t * TSRMLS_DC);
SAPI_API int sapi_get_target_gid(gid_t * TSRMLS_DC);
SAPI_API double sapi_get_request_time(TSRMLS_D);
SAPI_API void sapi_terminate_process(TSRMLS_D);
SAPI_API void sapi_add_request_header(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg TSRMLS_DC);
END_EXTERN_C()

struct _sapi_module_struct {
Expand Down
50 changes: 1 addition & 49 deletions sapi/cgi/cgi_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1530,54 +1530,6 @@ PHP_FUNCTION(apache_child_terminate) /* {{{ */
}
/* }}} */

static void add_request_header(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg TSRMLS_DC) /* {{{ */
{
zval *return_value = (zval*)arg;
char *str = NULL;
char *p;
ALLOCA_FLAG(use_heap)

if (var_len > 5 &&
var[0] == 'H' &&
var[1] == 'T' &&
var[2] == 'T' &&
var[3] == 'P' &&
var[4] == '_') {

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+1, val, val_len, 1);
if (str) {
free_alloca(var, use_heap);
}
}
/* }}} */

PHP_FUNCTION(apache_request_headers) /* {{{ */
{
if (ZEND_NUM_ARGS() > 0) {
Expand All @@ -1587,7 +1539,7 @@ PHP_FUNCTION(apache_request_headers) /* {{{ */
if (fcgi_is_fastcgi()) {
fcgi_request *request = (fcgi_request*) SG(server_context);

fcgi_loadenv(request, add_request_header, return_value TSRMLS_CC);
fcgi_loadenv(request, sapi_add_request_header, return_value TSRMLS_CC);
} else {
char buf[128];
char **env, *p, *q, *var, *val, *t = buf;
Expand Down
37 changes: 36 additions & 1 deletion sapi/fpm/fpm/fpm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ struct sigaction act, old_term, old_quit, old_int;

static void (*php_php_import_environment_variables)(zval *array_ptr TSRMLS_DC);

typedef void (*fcgi_apply_func)(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg TSRMLS_DC);

#ifndef PHP_WIN32
/* these globals used for forking children on unix systems */

Expand Down Expand Up @@ -1546,8 +1548,41 @@ PHP_FUNCTION(fastcgi_finish_request) /* {{{ */
}
/* }}} */

static inline void fcgi_hash_apply(HashTable *h, fcgi_apply_func func, void *arg TSRMLS_DC) /* {{{ */
{
Bucket *p = h->pListHead;

while (p) {
if (EXPECTED(p->arKey != NULL)) {
/* Since request->env already has the terminating char, -1 to var_len */
func((char*)p->arKey, p->nKeyLength, *(char**)p->pData, strlen(*(char**)p->pData), arg TSRMLS_CC);
}
p = p->pListNext;
}
} /* }}} */

PHP_FUNCTION(apache_request_headers) /* {{{ */
{
fcgi_request *request;

if (zend_parse_parameters_none() == FAILURE) {
return;
}

array_init(return_value);

if ((request = (fcgi_request*) SG(server_context))) {
fcgi_hash_apply(request->env, sapi_add_request_header, return_value TSRMLS_CC);
}
} /* }}} */

ZEND_BEGIN_ARG_INFO(cgi_fcgi_sapi_no_arginfo, 0)
ZEND_END_ARG_INFO()

static const zend_function_entry cgi_fcgi_sapi_functions[] = {
PHP_FE(fastcgi_finish_request, NULL)
PHP_FE(fastcgi_finish_request, cgi_fcgi_sapi_no_arginfo)
PHP_FE(apache_request_headers, cgi_fcgi_sapi_no_arginfo)
PHP_FALIAS(getallheaders, apache_request_headers, cgi_fcgi_sapi_no_arginfo)
{NULL, NULL, NULL}
};

Expand Down
76 changes: 76 additions & 0 deletions sapi/fpm/tests/018.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
--TEST--
FPM: Test getallheaders() function
--SKIPIF--
<?php include "skipif.inc"; ?>
--FILE--
<?php

include "include.inc";

$logfile = __DIR__.'/php-fpm.log.tmp';
$srcfile = __DIR__.'/php-fpm.tmp.php';
$port = 9000+PHP_INT_SIZE;

$cfg = <<<EOT
[global]
error_log = $logfile
[unconfined]
listen = 127.0.0.1:$port
pm = dynamic
pm.max_children = 5
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 3
EOT;

$code = <<<EOT
<?php
echo "Test Start\n";
var_dump(getallheaders());
echo "Test End\n";
EOT;
file_put_contents($srcfile, $code);

$fpm = run_fpm($cfg, $tail);
if (is_resource($fpm)) {
fpm_display_log($tail, 2);
try {
$headers = [
'HTTP_X_FOO' => 'BAR',
'HTTP_CONTENT_TYPE' => 'text/html; charset=UTF-8',
];
$req = run_request('127.0.0.1', $port, $srcfile, '');
echo strstr($req, "Test Start");
echo "Request ok\n";
} catch (Exception $e) {
echo "Request error\n";
}
proc_terminate($fpm);
echo stream_get_contents($tail);
fclose($tail);
proc_close($fpm);
}

?>
Done
--EXPECTF--
[%s] NOTICE: fpm is running, pid %d
[%s] NOTICE: ready to handle connections
Test Start
array(1) {
["X-Foo"]=>
string(4) "Bar"
}
Test End

Request ok
[%s] NOTICE: Terminating ...
[%s] NOTICE: exiting, bye-bye!
Done
--CLEAN--
<?php
$logfile = __DIR__.'/php-fpm.log.tmp';
$srcfile = __DIR__.'/php-fpm.log.tmp';
@unlink($logfile);
@unlink($srcfile);
?>
6 changes: 3 additions & 3 deletions sapi/fpm/tests/include.inc
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ function fpm_display_log($tail, $n=1, $ignore='systemd') {
}
}

function run_request($host, $port, $uri='/ping', $query='') {
function run_request($host, $port, $uri='/ping', $query='', $headers=array()) {
require_once 'fcgi.inc';
$client = new Adoy\FastCGI\Client($host, $port);
$params = array(
$params = array_merge(array(
'GATEWAY_INTERFACE' => 'FastCGI/1.0',
'REQUEST_METHOD' => 'GET',
'SCRIPT_FILENAME' => $uri,
Expand All @@ -106,6 +106,6 @@ function run_request($host, $port, $uri='/ping', $query='') {
'SERVER_PROTOCOL' => 'HTTP/1.1',
'CONTENT_TYPE' => '',
'CONTENT_LENGTH' => 0
);
), $headers);
return $client->request($params, false)."\n";
}