Fix bug #61525: SOAP functions require at least one space after HTTP header colon

HTTP/1.1 does not require a single whitespace after the colon, and
SoapServer does implement HTTP/1.1. The header value is already correctly
whitespace-trimmed, so no behaviour change happens w.r.t. header values.

Closes GH-15793.
This commit is contained in:
Niels Dossche 2024-09-08 00:06:22 +02:00
parent 0f3b2e506b
commit 7771ec07e5
No known key found for this signature in database
GPG key ID: A17A7C526FE17078
3 changed files with 49 additions and 12 deletions

4
NEWS
View file

@ -49,6 +49,10 @@ PHP NEWS
. Fixed bug GH-15718 (Segfault on ReflectionProperty::get{Hook,Hooks}() on . Fixed bug GH-15718 (Segfault on ReflectionProperty::get{Hook,Hooks}() on
dynamic properties). (DanielEScherzer) dynamic properties). (DanielEScherzer)
- SOAP:
. Fixed bug #61525 (SOAP functions require at least one space after HTTP
header colon). (nielsdos)
- Standard: - Standard:
. Fixed bug GH-15552 (Signed integer overflow in ext/standard/scanf.c). (cmb) . Fixed bug GH-15552 (Signed integer overflow in ext/standard/scanf.c). (cmb)
. Implemented GH-15685 (improve proc_open error reporting on Windows). (cmb) . Implemented GH-15685 (improve proc_open error reporting on Windows). (cmb)

View file

@ -980,7 +980,7 @@ try_again:
*/ */
cookie_itt = ZSTR_VAL(http_headers); cookie_itt = ZSTR_VAL(http_headers);
while ((cookie_itt = get_http_header_value_nodup(cookie_itt, "Set-Cookie: ", &cookie_len))) { while ((cookie_itt = get_http_header_value_nodup(cookie_itt, "Set-Cookie:", &cookie_len))) {
zval *cookies = Z_CLIENT_COOKIES_P(this_ptr); zval *cookies = Z_CLIENT_COOKIES_P(this_ptr);
SEPARATE_ARRAY(cookies); SEPARATE_ARRAY(cookies);
@ -1049,7 +1049,7 @@ try_again:
if (http_1_1) { if (http_1_1) {
http_close = FALSE; http_close = FALSE;
if (use_proxy && !use_ssl) { if (use_proxy && !use_ssl) {
connection = get_http_header_value(ZSTR_VAL(http_headers), "Proxy-Connection: "); connection = get_http_header_value(ZSTR_VAL(http_headers), "Proxy-Connection:");
if (connection) { if (connection) {
if (strncasecmp(connection, "close", sizeof("close")-1) == 0) { if (strncasecmp(connection, "close", sizeof("close")-1) == 0) {
http_close = TRUE; http_close = TRUE;
@ -1058,7 +1058,7 @@ try_again:
} }
} }
if (http_close == FALSE) { if (http_close == FALSE) {
connection = get_http_header_value(ZSTR_VAL(http_headers), "Connection: "); connection = get_http_header_value(ZSTR_VAL(http_headers), "Connection:");
if (connection) { if (connection) {
if (strncasecmp(connection, "close", sizeof("close")-1) == 0) { if (strncasecmp(connection, "close", sizeof("close")-1) == 0) {
http_close = TRUE; http_close = TRUE;
@ -1069,7 +1069,7 @@ try_again:
} else { } else {
http_close = TRUE; http_close = TRUE;
if (use_proxy && !use_ssl) { if (use_proxy && !use_ssl) {
connection = get_http_header_value(ZSTR_VAL(http_headers), "Proxy-Connection: "); connection = get_http_header_value(ZSTR_VAL(http_headers), "Proxy-Connection:");
if (connection) { if (connection) {
if (strncasecmp(connection, "Keep-Alive", sizeof("Keep-Alive")-1) == 0) { if (strncasecmp(connection, "Keep-Alive", sizeof("Keep-Alive")-1) == 0) {
http_close = FALSE; http_close = FALSE;
@ -1078,7 +1078,7 @@ try_again:
} }
} }
if (http_close == TRUE) { if (http_close == TRUE) {
connection = get_http_header_value(ZSTR_VAL(http_headers), "Connection: "); connection = get_http_header_value(ZSTR_VAL(http_headers), "Connection:");
if (connection) { if (connection) {
if (strncasecmp(connection, "Keep-Alive", sizeof("Keep-Alive")-1) == 0) { if (strncasecmp(connection, "Keep-Alive", sizeof("Keep-Alive")-1) == 0) {
http_close = FALSE; http_close = FALSE;
@ -1121,7 +1121,7 @@ try_again:
if (http_status >= 300 && http_status < 400) { if (http_status >= 300 && http_status < 400) {
char *loc; char *loc;
if ((loc = get_http_header_value(ZSTR_VAL(http_headers), "Location: ")) != NULL) { if ((loc = get_http_header_value(ZSTR_VAL(http_headers), "Location:")) != NULL) {
php_url *new_url = php_url_parse(loc); php_url *new_url = php_url_parse(loc);
if (new_url != NULL) { if (new_url != NULL) {
@ -1170,7 +1170,7 @@ try_again:
zval *digest = Z_CLIENT_DIGEST_P(this_ptr); zval *digest = Z_CLIENT_DIGEST_P(this_ptr);
zval *login = Z_CLIENT_LOGIN_P(this_ptr); zval *login = Z_CLIENT_LOGIN_P(this_ptr);
zval *password = Z_CLIENT_PASSWORD_P(this_ptr); zval *password = Z_CLIENT_PASSWORD_P(this_ptr);
char *auth = get_http_header_value(ZSTR_VAL(http_headers), "WWW-Authenticate: "); char *auth = get_http_header_value(ZSTR_VAL(http_headers), "WWW-Authenticate:");
if (auth && strstr(auth, "Digest") == auth && Z_TYPE_P(digest) != IS_ARRAY if (auth && strstr(auth, "Digest") == auth && Z_TYPE_P(digest) != IS_ARRAY
&& Z_TYPE_P(login) == IS_STRING && Z_TYPE_P(password) == IS_STRING) { && Z_TYPE_P(login) == IS_STRING && Z_TYPE_P(password) == IS_STRING) {
char *s; char *s;
@ -1240,7 +1240,7 @@ try_again:
smart_str_free(&soap_headers_z); smart_str_free(&soap_headers_z);
/* Check and see if the server even sent a xml document */ /* Check and see if the server even sent a xml document */
content_type = get_http_header_value(ZSTR_VAL(http_headers), "Content-Type: "); content_type = get_http_header_value(ZSTR_VAL(http_headers), "Content-Type:");
if (content_type) { if (content_type) {
char *pos = NULL; char *pos = NULL;
int cmplen; int cmplen;
@ -1270,7 +1270,7 @@ try_again:
} }
/* Decompress response */ /* Decompress response */
content_encoding = get_http_header_value(ZSTR_VAL(http_headers), "Content-Encoding: "); content_encoding = get_http_header_value(ZSTR_VAL(http_headers), "Content-Encoding:");
if (content_encoding) { if (content_encoding) {
zval func; zval func;
zval retval; zval retval;
@ -1430,18 +1430,18 @@ static zend_string* get_http_body(php_stream *stream, int close, char *headers)
int header_close = close, header_chunked = 0, header_length = 0, http_buf_size = 0; int header_close = close, header_chunked = 0, header_length = 0, http_buf_size = 0;
if (!close) { if (!close) {
header = get_http_header_value(headers, "Connection: "); header = get_http_header_value(headers, "Connection:");
if (header) { if (header) {
if(!strncasecmp(header, "close", sizeof("close")-1)) header_close = 1; if(!strncasecmp(header, "close", sizeof("close")-1)) header_close = 1;
efree(header); efree(header);
} }
} }
header = get_http_header_value(headers, "Transfer-Encoding: "); header = get_http_header_value(headers, "Transfer-Encoding:");
if (header) { if (header) {
if(!strncasecmp(header, "chunked", sizeof("chunked")-1)) header_chunked = 1; if(!strncasecmp(header, "chunked", sizeof("chunked")-1)) header_chunked = 1;
efree(header); efree(header);
} }
header = get_http_header_value(headers, "Content-Length: "); header = get_http_header_value(headers, "Content-Length:");
if (header) { if (header) {
header_length = atoi(header); header_length = atoi(header);
efree(header); efree(header);

View file

@ -0,0 +1,33 @@
--TEST--
Bug #61525 (SOAP functions require at least one space after HTTP header colon)
--EXTENSIONS--
soap
--SKIPIF--
<?php
if (@!include __DIR__."/../../../standard/tests/http/server.inc") die('skip server.inc not available');
http_server_skipif();
?>
--FILE--
<?php
require __DIR__."/../../../standard/tests/http/server.inc";
$response = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://testuri.org" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:AddResponse>
<return xsi:type="xsd:int">7</return>
</ns1:AddResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
XML;
$length = strlen($response);
$server_response = "data://text/xml;base64," . base64_encode("HTTP/1.1 200 OK\r\nConnection:close\r\nContent-Length:$length\r\n\r\n$response");
['pid' => $pid, 'uri' => $uri] = http_server([$server_response]);
$client = new SoapClient(NULL, ['location' => $uri, 'uri' => $uri]);
var_dump($client->Add(3, 4));
http_server_kill($pid);
?>
--EXPECT--
int(7)