diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c index 3ffa67cfb910..69ab56169c40 100644 --- a/ext/soap/php_sdl.c +++ b/ext/soap/php_sdl.c @@ -198,6 +198,75 @@ static int is_wsdl_element(xmlNodePtr node) return 1; } +// Which headers need to be redacted +#define REDACT_NONE 0 +#define REDACT_AUTHORIZATION (1 << 0) +#define REDACT_PROXY_AUTH (1 << 1) +#define REDACT_COOKIE (1 << 2) + +static uint32_t header_needs_redaction(zend_string *header) { + uint32_t redaction = REDACT_NONE; + /* The various loops are so that if the first use of "authorization" is in + * some other header, we still redact the actual "authorization" header. + * + * We check if the character before the start of the header is a '\n' but + * not if the character before that was a `\r`; per RFC9112 while the + * separator is officially both (CRLF) recipients "MAY" recognize just a + * '\n' (LF) as a line terminator. A recipient "MUST" treat a bare '\r' (CR) + * as invalid or replace it, so a '\r' on its own does not start a new + * header. + */ + char *auth_start = strstr(ZSTR_VAL(header), "authorization:"); + while (auth_start && *auth_start) { + if (auth_start == ZSTR_VAL(header) || *(auth_start - 1) == '\n') { + redaction |= REDACT_AUTHORIZATION; + break; + } + auth_start = strstr(auth_start + 1, "authorization:"); + } + + char *proxy_start = strstr(ZSTR_VAL(header), "proxy-authorization:"); + while (proxy_start && *proxy_start) { + if (proxy_start == ZSTR_VAL(header) || *(proxy_start - 1) == '\n') { + redaction |= REDACT_PROXY_AUTH; + break; + } + proxy_start = strstr(proxy_start + 1, "proxy-authorization:"); + } + + char *cookie_start = strstr(ZSTR_VAL(header), "cookie:"); + while (cookie_start && *cookie_start) { + if (cookie_start == ZSTR_VAL(header) || *(cookie_start - 1) == '\n') { + redaction |= REDACT_COOKIE; + break; + } + cookie_start = strstr(cookie_start + 1, "cookie:"); + } + return redaction; +} + +static bool redact_header(char *header_start, uint32_t to_redact) { + /* When redacting, we don't remove the REDACT_* flag from to_redact, because + * a header might have been specified multiple times and we want to remove + * all of those uses. */ + if (to_redact & REDACT_AUTHORIZATION + && strncmp(header_start, "authorization:", strlen("authorization:")) == 0 + ) { + return true; + } + if (to_redact & REDACT_PROXY_AUTH + && strncmp(header_start, "proxy-authorization:", strlen("proxy-authorization:")) == 0 + ) { + return true; + } + if (to_redact & REDACT_COOKIE + && strncmp(header_start, "cookie:", strlen("cookie:")) == 0 + ) { + return true; + } + return false; +} + void sdl_set_uri_credentials(sdlCtx *ctx, char *uri) { char *s; @@ -248,36 +317,132 @@ void sdl_set_uri_credentials(sdlCtx *ctx, char *uri) l2 -= 4; } } - if (l1 != l2 || memcmp(ctx->sdl->source, uri, l1) != 0) { - /* another server. clear authentication credentals */ - php_libxml_switch_context(NULL, &context); - php_libxml_switch_context(&context, NULL); - if (Z_TYPE(context) != IS_UNDEF) { - zval *context_ptr = &context; - ctx->context = php_stream_context_from_zval(context_ptr, 1); - - if (ctx->context && - (header = php_stream_context_get_option(ctx->context, "http", "header")) != NULL && - Z_TYPE_P(header) == IS_STRING) { - /* TODO: should support header as an array, but this code path is untested */ - s = strstr(Z_STRVAL_P(header), "Authorization: Basic"); - if (s && (s == Z_STRVAL_P(header) || *(s-1) == '\n' || *(s-1) == '\r')) { - char *rest = strstr(s, "\r\n"); - if (rest) { - zval new_header; - - rest += 2; - ZVAL_NEW_STR(&new_header, zend_string_alloc(Z_STRLEN_P(header) - (rest - s), 0)); - memcpy(Z_STRVAL(new_header), Z_STRVAL_P(header), s - Z_STRVAL_P(header)); - memcpy(Z_STRVAL(new_header) + (s - Z_STRVAL_P(header)), rest, Z_STRLEN_P(header) - (rest - Z_STRVAL_P(header)) + 1); - ZVAL_COPY(&ctx->old_header, header); - php_stream_context_set_option(ctx->context, "http", "header", &new_header); - zval_ptr_dtor(&new_header); - } + if (l1 == l2 && memcmp(ctx->sdl->source, uri, l1) == 0) { + return; + } + /* another server. clear authentication credentals */ + php_libxml_switch_context(NULL, &context); + php_libxml_switch_context(&context, NULL); + if (Z_TYPE(context) == IS_UNDEF) { + return; + } + zval *context_ptr = &context; + ctx->context = php_stream_context_from_zval(context_ptr, 1); + + if (!ctx->context) { + return; + } + + header = php_stream_context_get_option(ctx->context, "http", "header"); + if (header == NULL) { + return; + } + + zend_string *flat_headers; + if (Z_TYPE_P(header) == IS_STRING) { + flat_headers = zend_string_copy(Z_STR_P(header)); + } else if (Z_TYPE_P(header) == IS_ARRAY) { + smart_str buf = {0}; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(header), zval *value) { + if (Z_TYPE_P(value) == IS_STRING && Z_STRLEN_P(value)) { + if (buf.s) { + smart_str_appendl(&buf, "\r\n", 2); } + smart_str_append(&buf, Z_STR_P(value)); + } + } ZEND_HASH_FOREACH_END(); + flat_headers = smart_str_extract(&buf); + } else { + return; + } + zend_string *lc_headers = zend_string_tolower(flat_headers); + // Fast path: no redaction needed + uint32_t redaction = header_needs_redaction(lc_headers); + if (ctx->headers_to_keep & WSDL_HEADER_KEEP_AUTHORIZATION) { + redaction &= ~REDACT_AUTHORIZATION; + } + if (ctx->headers_to_keep & WSDL_HEADER_KEEP_PROXY_AUTHORIZATION) { + redaction &= ~REDACT_PROXY_AUTH; + } + if (ctx->headers_to_keep & WSDL_HEADER_KEEP_COOKIES) { + redaction &= ~REDACT_COOKIE; + } + if (redaction == REDACT_NONE) { + zend_string_release(lc_headers); + zend_string_release(flat_headers); + return; + } + // At least one of the headers needs to be stripped. To avoid repeated + // copying and case comparisons, we go through the headers one at a time. + // Will be allocated on the first header that should be kept. + zend_string *redacted = NULL; + // Pointer to the current read location + char *read_ptr = ZSTR_VAL(flat_headers); + // Offset from the start of the read location + size_t read_offset = 0; + // Offset from the start of the write location + size_t write_offset = 0; + + while (true) { + if (redact_header(ZSTR_VAL(lc_headers) + read_offset, redaction)) { + /* Current header should be skipped + * As with header_needs_redaction() we treat a '\n' as the end + * of the header even if not preceded by '\r'. */ + char *header_end = memchr(read_ptr, '\n', ZSTR_LEN(flat_headers) - read_offset); + if (header_end) { + // Skip the current header and the \n + size_t header_length = (header_end - read_ptr) + 1; + read_offset += header_length; + read_ptr += header_length; + } else { + // This is the end + break; + } + } else { + // Current header (from `read_offset`) should be kept + if (redacted == NULL) { + // This will over allocate the redacted header string but + // that isn't a big deal, the headers should be fairly short + redacted = zend_string_alloc(ZSTR_LEN(flat_headers), false); + } + char *header_end = memchr(read_ptr, '\n', ZSTR_LEN(flat_headers) - read_offset); + if (header_end) { + // Copy the current header and the \n + size_t header_length = (header_end - read_ptr) + 1; + memcpy(ZSTR_VAL(redacted) + write_offset, read_ptr, header_length); + // Update offsets + read_offset += header_length; + read_ptr += header_length; + write_offset += header_length; + } else { + // Copy until the end of the headers + size_t header_length = ZSTR_LEN(lc_headers) - read_offset; + memcpy(ZSTR_VAL(redacted) + write_offset, read_ptr, header_length); + write_offset += header_length; + break; } } } + zend_string_release(lc_headers); + zend_string_release(flat_headers); + + ZVAL_COPY(&ctx->old_header, header); + zval new_header; + if (redacted == NULL) { + // All headers were redacted + ZVAL_EMPTY_STRING(&new_header); + } else { + // Only some headers were redacted + // The zval_ptr_dtor call will ensure that the redacted headers + // are freed; + // Make sure that we don't read garbage + ZSTR_VAL(redacted)[write_offset] = '\0'; + ZSTR_LEN(redacted) = write_offset; + + ZVAL_STR(&new_header, redacted); + } + php_stream_context_set_option(ctx->context, "http", "header", &new_header); + zval_ptr_dtor(&new_header); } void sdl_restore_uri_credentials(sdlCtx *ctx) @@ -707,6 +872,11 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri) zend_hash_init(&ctx.portTypes, 0, NULL, NULL, 0); zend_hash_init(&ctx.services, 0, NULL, NULL, 0); + ctx.headers_to_keep = 0; + if (instanceof_function(Z_OBJCE_P(this_ptr), soap_class_entry)) { + ctx.headers_to_keep = Z_LVAL_P(Z_CLIENT_KEEP_HEADERS_P(this_ptr)); + } + zend_try { load_wsdl_ex(this_ptr, struri, &ctx, false); schema_pass2(&ctx); diff --git a/ext/soap/php_sdl.h b/ext/soap/php_sdl.h index 7249f094f165..b076285ebb60 100644 --- a/ext/soap/php_sdl.h +++ b/ext/soap/php_sdl.h @@ -74,6 +74,7 @@ typedef struct sdlCtx { HashTable fixupInProgress; php_stream_context *context; zval old_header; + zend_long headers_to_keep; /* Bitmask of WSDL_HEADER_KEEP_* from php_soap.h */ } sdlCtx; struct _sdlBinding { diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h index d3c273615eb6..c067b633f488 100644 --- a/ext/soap/php_soap.h +++ b/ext/soap/php_soap.h @@ -151,6 +151,11 @@ struct _soapService { #define SOAP_MAX_XML_DEPTH 2048 #define SOAP_MAX_DECODE_DEPTH (SOAP_MAX_XML_DEPTH * 2) +/* Some headers are redacted on requests to other hosts unless requested otherwise */ +#define WSDL_HEADER_KEEP_AUTHORIZATION (1 << 0) +#define WSDL_HEADER_KEEP_PROXY_AUTHORIZATION (1 << 1) +#define WSDL_HEADER_KEEP_COOKIES (1 << 2) + ZEND_BEGIN_MODULE_GLOBALS(soap) HashTable *typemap; int cur_uniq_ns; @@ -255,6 +260,7 @@ static zend_always_inline zval *php_soap_deref(zval *zv) { #define Z_CLIENT_LAST_RESPONSE_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 32) #define Z_CLIENT_LAST_REQUEST_HEADERS_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 33) #define Z_CLIENT_LAST_RESPONSE_HEADERS_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 34) +#define Z_CLIENT_KEEP_HEADERS_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 35) typedef struct soap_url_object { php_uri *uri; diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 97a653955825..2dc6802310b0 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -2106,6 +2106,7 @@ PHP_METHOD(SoapClient, __construct) sdlPtr sdl = NULL; HashTable *typemap_ht = NULL; zval *this_ptr = ZEND_THIS; + zend_long keep_headers = 0; if (zend_parse_parameters(ZEND_NUM_ARGS(), "S!|a", &wsdl, &options) == FAILURE) { RETURN_THROWS(); @@ -2303,6 +2304,26 @@ PHP_METHOD(SoapClient, __construct) "The \"ssl_method\" option is deprecated. " "Use \"ssl\" stream context options instead"); } + + if ((tmp = zend_hash_str_find(ht, "keep_headers", sizeof("keep_headers")-1)) != NULL + && Z_TYPE_P(tmp) == IS_ARRAY + ) { + ZEND_HASH_FOREACH_VAL(Z_ARR_P(tmp), zval *to_keep) { + if (Z_TYPE_P(to_keep) != IS_STRING) { + continue; + } + zend_string *header_name = Z_STR_P(to_keep); + if (zend_string_equals_literal_ci(header_name, "authorization")) { + keep_headers |= WSDL_HEADER_KEEP_AUTHORIZATION; + } else if (zend_string_equals_literal_ci(header_name, "proxy-authorization")) { + keep_headers |= WSDL_HEADER_KEEP_PROXY_AUTHORIZATION; + } else if (zend_string_equals_literal_ci(header_name, "cookie")) { + keep_headers |= WSDL_HEADER_KEEP_COOKIES; + } + } ZEND_HASH_FOREACH_END(); + ZVAL_LONG(Z_CLIENT_KEEP_HEADERS_P(this_ptr), keep_headers); + + } } else if (!wsdl) { php_error_docref(NULL, E_ERROR, "'location' and 'uri' options are required in nonWSDL mode"); } diff --git a/ext/soap/soap.stub.php b/ext/soap/soap.stub.php index fdd4a46e109f..d614fe8d963d 100644 --- a/ext/soap/soap.stub.php +++ b/ext/soap/soap.stub.php @@ -572,6 +572,7 @@ class SoapClient private ?string $__last_response = null; private ?string $__last_request_headers = null; private ?string $__last_response_headers = null; + private int $_keep_headers = 0; public function __construct(?string $wsdl, array $options = []) {} diff --git a/ext/soap/soap_arginfo.h b/ext/soap/soap_arginfo.h index f6b146d779d6..5757cea7e361 100644 --- a/ext/soap/soap_arginfo.h +++ b/ext/soap/soap_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit soap.stub.php instead. - * Stub hash: 14c74a5d6f547837f536920d5abb741e2b6e4373 */ + * Stub hash: c3509a1552db7edabc48d89eea67ff2e1e7d9115 */ #include "zend_attributes.h" #include "zend_constants.h" @@ -748,5 +748,11 @@ static zend_class_entry *register_class_SoapClient(void) zend_declare_typed_property(class_entry, property___last_response_headers_name, &property___last_response_headers_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); zend_string_release_ex(property___last_response_headers_name, true); + zval property__keep_headers_default_value; + ZVAL_LONG(&property__keep_headers_default_value, 0); + zend_string *property__keep_headers_name = zend_string_init("_keep_headers", sizeof("_keep_headers") - 1, true); + zend_declare_typed_property(class_entry, property__keep_headers_name, &property__keep_headers_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(property__keep_headers_name, true); + return class_entry; } diff --git a/ext/soap/tests/bugs/gh21421.phpt b/ext/soap/tests/bugs/gh21421.phpt index 1b8bb3be716f..e20b79aed56b 100644 --- a/ext/soap/tests/bugs/gh21421.phpt +++ b/ext/soap/tests/bugs/gh21421.phpt @@ -15,7 +15,7 @@ $client = new SoapClient(NULL, $options); var_dump($client); ?> --EXPECTF-- -object(SoapClient)#%d (35) { +object(SoapClient)#%d (36) { ["uri":"SoapClient":private]=> string(26) "http://schemas.nothing.com" ["style":"SoapClient":private]=> @@ -87,4 +87,6 @@ object(SoapClient)#%d (35) { NULL ["__last_response_headers":"SoapClient":private]=> NULL + ["_keep_headers":"SoapClient":private]=> + int(0) } diff --git a/ext/soap/tests/gh23686/check_headers.inc b/ext/soap/tests/gh23686/check_headers.inc new file mode 100644 index 000000000000..707d12844322 --- /dev/null +++ b/ext/soap/tests/gh23686/check_headers.inc @@ -0,0 +1,113 @@ + switches to a different server, check the headers that the + * second server recieves + */ +function check_headers_for_import( + string $logs_path, + $context, + array $options = [], + bool $verbose_failure = true, +) { + $code = file_get_contents(__DIR__ . "/soap-respond-with-headers.inc"); + $code = substr($code, strpos($code, "port, $wsdl); + + // We cannot just load the SoapClient directly from the WSDL because + // otherwise the credentials are not stripped because we are not switching + // to another host in the . + $server_code = "echo <<port; + + foreach ([SOAP_1_1, SOAP_1_2] as $version) { + try { + $client = new SoapClient("http://localhost:$wsdl_server_port", [ + 'soap_version' => $version, + 'stream_context' => $context, + ...$options, + ]); + } catch (SoapFault $e) { + if ($verbose_failure) { + var_dump($e); + echo "--- Raw Server Response Body ---\n"; + var_dump(file_get_contents("http://localhost:$wsdl_server_port", false, $context)); + } else { + echo get_class($e) . ': ' . $e->getMessage() . "\n"; + } + } + + var_dump(@file_get_contents($logs_path)); + } +} + +/** + * When an leads to a on a different server, check the + * headers that the *third* server recieves + */ +function check_headers_for_schema( + string $logs_path, + $context, + array $options = [], + bool $verbose_failure = true +) { + $code = file_get_contents(__DIR__ . "/schema-respond-with-headers.inc"); + $code = substr($code, strpos($code, "port, $schema_wsdl); + $schema_server_code = "echo <<port; + + $import_wsdl = file_get_contents(__DIR__ . "/wsdl-with-import.wsdl"); + $import_wsdl = str_replace("{TARGET_PORT}", $schema_wsdl_server_port, $import_wsdl); + $import_server_code = "echo <<port; + + foreach ([SOAP_1_1, SOAP_1_2] as $version) { + try { + $client = new SoapClient("http://localhost:$import_wsdl_server_port", [ + 'soap_version' => $version, + 'stream_context' => $context, + ...$options, + ]); + } catch (SoapFault $e) { + if ($verbose_failure) { + var_dump($e); + echo "--- Raw Server Response Body ---\n"; + var_dump(file_get_contents("http://localhost:$import_wsdl_server_port", false, $context)); + } else { + echo get_class($e) . ': ' . $e->getMessage() . "\n"; + } + } + + var_dump(@file_get_contents($logs_path)); + } +} diff --git a/ext/soap/tests/gh23686/header-from-stringable.phpt b/ext/soap/tests/gh23686/header-from-stringable.phpt new file mode 100644 index 000000000000..4e2d7f02aa9c --- /dev/null +++ b/ext/soap/tests/gh23686/header-from-stringable.phpt @@ -0,0 +1,108 @@ +--TEST-- +GH-23686: Confirm that headers set with stringable objects are ignored +--DESCRIPTION-- +If these objects were converted to strings and the headers used, then they might +need to be redacted, but php_stream_url_wrap_http_ex() only cares about strings +and string elements in arrays as of PHP 8.6. This test means that if that were +to ever change, this test would fail and developers would know to update +the redaction logic in the soap extension. +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- +val; } +} + +// Headers reach sdl_set_uri_credentials() as a string +$context = stream_context_create([ + 'http' => ['header' => [ + new StringWrapper("Authorization: Foo"), + new StringWrapper("Bar: Baz"), + "X-non-object: value", + ]], +]); + +echo "Headers are in a string:\n"; +check_headers_for_import(LOGS_PATH, $context); +check_headers_for_schema(LOGS_PATH, $context); + +// Headers reach sdl_set_uri_credentials() as an array +$context = stream_context_create([ + 'http' => [ + // having a protocol here means that SOAP won't add it itself + 'protocol_version' => 1.1, + 'header' => [ + new StringWrapper("Authorization: Foo"), + new StringWrapper("Bar: Baz"), + "X-non-object: value", + ] + ], +]); + +echo "Headers are in an array:\n"; +check_headers_for_import(LOGS_PATH, $context); +check_headers_for_schema(LOGS_PATH, $context); + +?> +--EXPECTF-- +Headers are in a string: +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-non-object' => 'value', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-non-object' => 'value', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-non-object' => 'value', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-non-object' => 'value', +)" +Headers are in an array: +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-non-object' => 'value', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-non-object' => 'value', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-non-object' => 'value', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-non-object' => 'value', +)" diff --git a/ext/soap/tests/gh23686/header-just-lf-separator.phpt b/ext/soap/tests/gh23686/header-just-lf-separator.phpt new file mode 100644 index 000000000000..fc743aaed77b --- /dev/null +++ b/ext/soap/tests/gh23686/header-just-lf-separator.phpt @@ -0,0 +1,97 @@ +--TEST-- +GH-23686: Confirm that headers separated with just LF are separated +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Basic\nFoo: bar\nProxy-Authorization: Something\nBaz: Qux\nCookie: Tasty"], +]); + +echo "Headers are in a string:\n"; +check_headers_for_import(LOGS_PATH, $context); +check_headers_for_schema(LOGS_PATH, $context); + +// Headers reach sdl_set_uri_credentials() as an array +$context = stream_context_create([ + 'http' => [ + // having a protocol here means that SOAP won't add it itself + 'protocol_version' => 1.1, + 'header' => "Authorization: Basic\nFoo: bar\nProxy-Authorization: Something\nBaz: Qux\nCookie: Tasty" + ], +]); + +echo "Headers are in an array:\n"; +check_headers_for_import(LOGS_PATH, $context); +check_headers_for_schema(LOGS_PATH, $context); + +?> +--EXPECTF-- +Headers are in a string: +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Foo' => 'bar', + 'Baz' => 'Qux', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Foo' => 'bar', + 'Baz' => 'Qux', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Foo' => 'bar', + 'Baz' => 'Qux', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Foo' => 'bar', + 'Baz' => 'Qux', +)" +Headers are in an array: +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Foo' => 'bar', + 'Baz' => 'Qux', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Foo' => 'bar', + 'Baz' => 'Qux', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Foo' => 'bar', + 'Baz' => 'Qux', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Foo' => 'bar', + 'Baz' => 'Qux', +)" diff --git a/ext/soap/tests/gh23686/import-authorization-basic-lowercase.phpt b/ext/soap/tests/gh23686/import-authorization-basic-lowercase.phpt new file mode 100644 index 000000000000..7d0c694dc638 --- /dev/null +++ b/ext/soap/tests/gh23686/import-authorization-basic-lowercase.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-23686: Regression test for `Authorization: Basic` but lowercase (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "authorization: Basic foo bar"], +]); + +check_headers_for_import(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/import-authorization-basic.phpt b/ext/soap/tests/gh23686/import-authorization-basic.phpt new file mode 100644 index 000000000000..aa04078851fd --- /dev/null +++ b/ext/soap/tests/gh23686/import-authorization-basic.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-23686: Regression test for `Authorization: Basic` (which was stripped) (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Basic foo bar"], +]); + +check_headers_for_import(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/import-authorization-bearer.phpt b/ext/soap/tests/gh23686/import-authorization-bearer.phpt new file mode 100644 index 000000000000..e8445e8b3264 --- /dev/null +++ b/ext/soap/tests/gh23686/import-authorization-bearer.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-23686: Regression test for `Authorization: Bearer` (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Bearer secret-token"], +]); + +check_headers_for_import(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/import-authorization-digest.phpt b/ext/soap/tests/gh23686/import-authorization-digest.phpt new file mode 100644 index 000000000000..ff3374b0c848 --- /dev/null +++ b/ext/soap/tests/gh23686/import-authorization-digest.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-23686: Regression test for `Authorization: Digest` (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Digest secret-token"], +]); + +check_headers_for_import(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/import-cookies.phpt b/ext/soap/tests/gh23686/import-cookies.phpt new file mode 100644 index 000000000000..7871ca0874fe --- /dev/null +++ b/ext/soap/tests/gh23686/import-cookies.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-23686: Regression test for cookie headers (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Cookie: foo=bar"], +]); + +check_headers_for_import(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/import-keep-authorization.phpt b/ext/soap/tests/gh23686/import-keep-authorization.phpt new file mode 100644 index 000000000000..cc545e812931 --- /dev/null +++ b/ext/soap/tests/gh23686/import-keep-authorization.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-23686: `Authorization` header kept but others removed (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Bearer secret-token\r\nProxy-Authorization: FooBar\r\nCookie: foo=bar"], +]); + +check_headers_for_import(LOGS_PATH, $context, ["keep_headers" => ["authorization"]]); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Authorization' => 'Bearer secret-token', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Authorization' => 'Bearer secret-token', +)" diff --git a/ext/soap/tests/gh23686/import-keep-cookies.phpt b/ext/soap/tests/gh23686/import-keep-cookies.phpt new file mode 100644 index 000000000000..0732e3585bd6 --- /dev/null +++ b/ext/soap/tests/gh23686/import-keep-cookies.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-23686: `Cookie` header kept but others removed (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Bearer secret-token\r\nProxy-Authorization: FooBar\r\nCookie: foo=bar"], +]); + +check_headers_for_import(LOGS_PATH, $context, ["keep_headers" => ["cookie"]]); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Cookie' => 'foo=bar', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Cookie' => 'foo=bar', +)" diff --git a/ext/soap/tests/gh23686/import-keep-proxy-auth.phpt b/ext/soap/tests/gh23686/import-keep-proxy-auth.phpt new file mode 100644 index 000000000000..5dcf75f3502a --- /dev/null +++ b/ext/soap/tests/gh23686/import-keep-proxy-auth.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-23686: `Proxy-Authorization` header kept but others removed (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Bearer secret-token\r\nProxy-Authorization: FooBar\r\nCookie: foo=bar"], +]); + +check_headers_for_import(LOGS_PATH, $context, ["keep_headers" => ["proxy-authorization"]]); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Proxy-Authorization' => 'FooBar', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Proxy-Authorization' => 'FooBar', +)" diff --git a/ext/soap/tests/gh23686/import-proxy-authorization.phpt b/ext/soap/tests/gh23686/import-proxy-authorization.phpt new file mode 100644 index 000000000000..f4356f312840 --- /dev/null +++ b/ext/soap/tests/gh23686/import-proxy-authorization.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-23686: Regression test for proxy authorization (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Proxy-Authorization: FooBar"], +]); + +check_headers_for_import(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/import-repeated-authorization.phpt b/ext/soap/tests/gh23686/import-repeated-authorization.phpt new file mode 100644 index 000000000000..2263e538ba96 --- /dev/null +++ b/ext/soap/tests/gh23686/import-repeated-authorization.phpt @@ -0,0 +1,42 @@ +--TEST-- +GH-23686: Regression tests for repeated authorization headers (which previously didn't work) (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => [ + "Authorization: Foo", + "aUTHORIZATION: Bar", + ]], +]); + +check_headers_for_import(LOGS_PATH, $context, [], false); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/import-repeated-cookies.phpt b/ext/soap/tests/gh23686/import-repeated-cookies.phpt new file mode 100644 index 000000000000..4a7734547f4c --- /dev/null +++ b/ext/soap/tests/gh23686/import-repeated-cookies.phpt @@ -0,0 +1,42 @@ +--TEST-- +GH-23686: Regression tests for repeated cookies headers (which previously didn't work) (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => [ + "Cookie: Foo", + "cOOKIE: Bar", + ]], +]); + +check_headers_for_import(LOGS_PATH, $context, [], false); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/import-repeated-proxy-auth.phpt b/ext/soap/tests/gh23686/import-repeated-proxy-auth.phpt new file mode 100644 index 000000000000..9dca3e1a0bbb --- /dev/null +++ b/ext/soap/tests/gh23686/import-repeated-proxy-auth.phpt @@ -0,0 +1,42 @@ +--TEST-- +GH-23686: Regression tests for repeated proxy authorization headers (which previously didn't work) (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => [ + "Proxy-Authorization: Foo", + "pROXY-aUTHORIZATION: Bar", + ]], +]); + +check_headers_for_import(LOGS_PATH, $context, [], false); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/redact-array-headers.phpt b/ext/soap/tests/gh23686/redact-array-headers.phpt new file mode 100644 index 000000000000..ca27bf278a65 --- /dev/null +++ b/ext/soap/tests/gh23686/redact-array-headers.phpt @@ -0,0 +1,74 @@ +--TEST-- +GH-23686: Verify that a header is redacted when it reaches sdl_set_uri_credentials() as an array +--DESCRIPTION-- +Most of the time soap will add its own headers and in the process convert user headers +from an array to a string, check for the case when that does not happen +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + [ + // having a protocol here means that SOAP won't add it itself + 'protocol_version' => 1.1, + 'header' => [ + "X-Authorization: This should be kept", + "Authorization: This should be removed", + "X-Proxy-Authorization: This should also be kept", + "Proxy-Authorization: This should also be removed", + "X-Cookie: Last one to keep", + "Cookie: Last one to remove", + ] + ], +]); + +check_headers_for_import(LOGS_PATH, $context); +check_headers_for_schema(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-Authorization' => 'This should be kept', + 'X-Proxy-Authorization' => 'This should also be kept', + 'X-Cookie' => 'Last one to keep', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-Authorization' => 'This should be kept', + 'X-Proxy-Authorization' => 'This should also be kept', + 'X-Cookie' => 'Last one to keep', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-Authorization' => 'This should be kept', + 'X-Proxy-Authorization' => 'This should also be kept', + 'X-Cookie' => 'Last one to keep', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-Authorization' => 'This should be kept', + 'X-Proxy-Authorization' => 'This should also be kept', + 'X-Cookie' => 'Last one to keep', +)" diff --git a/ext/soap/tests/gh23686/redact-not-first.phpt b/ext/soap/tests/gh23686/redact-not-first.phpt new file mode 100644 index 000000000000..f85b80f47b56 --- /dev/null +++ b/ext/soap/tests/gh23686/redact-not-first.phpt @@ -0,0 +1,67 @@ +--TEST-- +GH-23686: Verify that a header is redacted when it isn't the first use of the name +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => [ + "X-Authorization: This should be kept", + "Authorization: This should be removed", + "X-Proxy-Authorization: This should also be kept", + "Proxy-Authorization: This should also be removed", + "X-Cookie: Last one to keep", + "Cookie: Last one to remove", + ]], +]); + +check_headers_for_import(LOGS_PATH, $context); +check_headers_for_schema(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-Authorization' => 'This should be kept', + 'X-Proxy-Authorization' => 'This should also be kept', + 'X-Cookie' => 'Last one to keep', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-Authorization' => 'This should be kept', + 'X-Proxy-Authorization' => 'This should also be kept', + 'X-Cookie' => 'Last one to keep', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-Authorization' => 'This should be kept', + 'X-Proxy-Authorization' => 'This should also be kept', + 'X-Cookie' => 'Last one to keep', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'X-Authorization' => 'This should be kept', + 'X-Proxy-Authorization' => 'This should also be kept', + 'X-Cookie' => 'Last one to keep', +)" diff --git a/ext/soap/tests/gh23686/schema-authorization-basic-lowercase.phpt b/ext/soap/tests/gh23686/schema-authorization-basic-lowercase.phpt new file mode 100644 index 000000000000..8a55c870d7af --- /dev/null +++ b/ext/soap/tests/gh23686/schema-authorization-basic-lowercase.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-23686: Regression test for `Authorization: Basic` but lowercase (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "authorization: Basic foo bar"], +]); + +check_headers_for_schema(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/schema-authorization-basic.phpt b/ext/soap/tests/gh23686/schema-authorization-basic.phpt new file mode 100644 index 000000000000..22a0ecb311ab --- /dev/null +++ b/ext/soap/tests/gh23686/schema-authorization-basic.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-23686: Regression test for `Authorization: Basic` (which was stripped) (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Basic foo bar"], +]); + +check_headers_for_schema(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/schema-authorization-bearer.phpt b/ext/soap/tests/gh23686/schema-authorization-bearer.phpt new file mode 100644 index 000000000000..8b575c74edd8 --- /dev/null +++ b/ext/soap/tests/gh23686/schema-authorization-bearer.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-23686: Regression test for `Authorization: Bearer` (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Bearer secret-token"], +]); + +check_headers_for_schema(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/schema-authorization-digest.phpt b/ext/soap/tests/gh23686/schema-authorization-digest.phpt new file mode 100644 index 000000000000..a218e694d77c --- /dev/null +++ b/ext/soap/tests/gh23686/schema-authorization-digest.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-23686: Regression test for `Authorization: Digest` (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Digest secret-token"], +]); + +check_headers_for_schema(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/schema-cookies.phpt b/ext/soap/tests/gh23686/schema-cookies.phpt new file mode 100644 index 000000000000..57c5984eee8a --- /dev/null +++ b/ext/soap/tests/gh23686/schema-cookies.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-23686: Regression test for cookie headers (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Cookie: foo=bar"], +]); + +check_headers_for_schema(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/schema-keep-authorization.phpt b/ext/soap/tests/gh23686/schema-keep-authorization.phpt new file mode 100644 index 000000000000..676e0f818849 --- /dev/null +++ b/ext/soap/tests/gh23686/schema-keep-authorization.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-23686: `Authorization` header kept but others removed (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Bearer secret-token\r\nProxy-Authorization: FooBar\r\nCookie: foo=bar"], +]); + +check_headers_for_schema(LOGS_PATH, $context, ["keep_headers" => ["authorization"]]); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Authorization' => 'Bearer secret-token', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Authorization' => 'Bearer secret-token', +)" diff --git a/ext/soap/tests/gh23686/schema-keep-cookies.phpt b/ext/soap/tests/gh23686/schema-keep-cookies.phpt new file mode 100644 index 000000000000..6ba48e3fc24f --- /dev/null +++ b/ext/soap/tests/gh23686/schema-keep-cookies.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-23686: `Cookie` header kept but others removed (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Bearer secret-token\r\nProxy-Authorization: FooBar\r\nCookie: foo=bar"], +]); + +check_headers_for_schema(LOGS_PATH, $context, ["keep_headers" => ["cookie"]]); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Cookie' => 'foo=bar', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Cookie' => 'foo=bar', +)" diff --git a/ext/soap/tests/gh23686/schema-keep-proxy-auth.phpt b/ext/soap/tests/gh23686/schema-keep-proxy-auth.phpt new file mode 100644 index 000000000000..ae45bb74b217 --- /dev/null +++ b/ext/soap/tests/gh23686/schema-keep-proxy-auth.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-23686: `Proxy-Authorization` header kept but others removed (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Authorization: Bearer secret-token\r\nProxy-Authorization: FooBar\r\nCookie: foo=bar"], +]); + +check_headers_for_schema(LOGS_PATH, $context, ["keep_headers" => ["proxy-authorization"]]); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Proxy-Authorization' => 'FooBar', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', + 'Proxy-Authorization' => 'FooBar', +)" diff --git a/ext/soap/tests/gh23686/schema-proxy-authorization.phpt b/ext/soap/tests/gh23686/schema-proxy-authorization.phpt new file mode 100644 index 000000000000..51920558c9b8 --- /dev/null +++ b/ext/soap/tests/gh23686/schema-proxy-authorization.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-23686: Regression test for proxy authorization (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => "Proxy-Authorization: FooBar"], +]); + +check_headers_for_schema(LOGS_PATH, $context); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/schema-repeated-authorization.phpt b/ext/soap/tests/gh23686/schema-repeated-authorization.phpt new file mode 100644 index 000000000000..d23d2592d8ca --- /dev/null +++ b/ext/soap/tests/gh23686/schema-repeated-authorization.phpt @@ -0,0 +1,42 @@ +--TEST-- +GH-23686: Regression tests for repeated authorization headers (which previously didn't work) (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => [ + "Authorization: Foo", + "aUTHORIZATION: Bar", + ]], +]); + +check_headers_for_schema(LOGS_PATH, $context, [], false); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/schema-repeated-cookies.phpt b/ext/soap/tests/gh23686/schema-repeated-cookies.phpt new file mode 100644 index 000000000000..dfc01e966a62 --- /dev/null +++ b/ext/soap/tests/gh23686/schema-repeated-cookies.phpt @@ -0,0 +1,42 @@ +--TEST-- +GH-23686: Regression tests for repeated cookies headers (which previously didn't work) (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => [ + "Cookie: Foo", + "cOOKIE: Bar", + ]], +]); + +check_headers_for_schema(LOGS_PATH, $context, [], false); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/schema-repeated-proxy-auth.phpt b/ext/soap/tests/gh23686/schema-repeated-proxy-auth.phpt new file mode 100644 index 000000000000..ea83b7ad9e85 --- /dev/null +++ b/ext/soap/tests/gh23686/schema-repeated-proxy-auth.phpt @@ -0,0 +1,42 @@ +--TEST-- +GH-23686: Regression tests for repeated proxy authorization headers (which previously didn't work) (``) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--CLEAN-- + +--SKIPIF-- + +--FILE-- + ['header' => [ + "Proxy-Authorization: Foo", + "pROXY-aUTHORIZATION: Bar", + ]], +]); + +check_headers_for_schema(LOGS_PATH, $context, [], false); + +?> +--EXPECTF-- +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" +string(%d) "array ( + 'Host' => 'localhost:%d', + 'Connection' => 'close', +)" diff --git a/ext/soap/tests/gh23686/schema-respond-with-headers.inc b/ext/soap/tests/gh23686/schema-respond-with-headers.inc new file mode 100644 index 000000000000..a2e97c217792 --- /dev/null +++ b/ext/soap/tests/gh23686/schema-respond-with-headers.inc @@ -0,0 +1,9 @@ + + + +END; \ No newline at end of file diff --git a/ext/soap/tests/gh23686/soap-respond-with-headers.inc b/ext/soap/tests/gh23686/soap-respond-with-headers.inc new file mode 100644 index 000000000000..a85da1071cfd --- /dev/null +++ b/ext/soap/tests/gh23686/soap-respond-with-headers.inc @@ -0,0 +1,16 @@ + + + + + + + + + + +END; \ No newline at end of file diff --git a/ext/soap/tests/gh23686/wsdl-with-import.wsdl b/ext/soap/tests/gh23686/wsdl-with-import.wsdl new file mode 100644 index 000000000000..97a4806fea82 --- /dev/null +++ b/ext/soap/tests/gh23686/wsdl-with-import.wsdl @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/ext/soap/tests/gh23686/wsdl-with-schema.wsdl b/ext/soap/tests/gh23686/wsdl-with-schema.wsdl new file mode 100644 index 000000000000..114d7f6c5d63 --- /dev/null +++ b/ext/soap/tests/gh23686/wsdl-with-schema.wsdl @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sapi/cli/tests/php_cli_server.inc b/sapi/cli/tests/php_cli_server.inc index ec370753573c..6e5449f5eb15 100644 --- a/sapi/cli/tests/php_cli_server.inc +++ b/sapi/cli/tests/php_cli_server.inc @@ -6,6 +6,7 @@ class CliServerInfo { public string $docRoot, public $processHandle, public $outputFile, + public int $port, ) {} } @@ -119,7 +120,7 @@ function php_cli_server_start( define("PHP_CLI_SERVER_PORT", $port); define("PHP_CLI_SERVER_ADDRESS", PHP_CLI_SERVER_HOSTNAME.":".PHP_CLI_SERVER_PORT); - return new CliServerInfo($doc_root, $handle, $output_file); + return new CliServerInfo($doc_root, $handle, $output_file, $port); } function php_cli_server_connect() {