Skip to content

Commit a1dc3ab

Browse files
committed
Tests: Use local fixtures for HTTP header and cookie checks.
Use the local redirection script for cookie handling and requests to an IP address with a custom `Host` header. Assert the header received by the server and retain the live endpoint fallback when the local fixture is unavailable. Preserve parent-domain cookie acceptance coverage through a simulated transport while exercising real cookie parsing and redirect handling. Developed in: #15184 Props shailu25. See #63914. git-svn-id: https://develop.svn.wordpress.org/trunk@65084 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 3cdbc6a commit a1dc3ab

2 files changed

Lines changed: 236 additions & 20 deletions

File tree

‎tests/phpunit/data/WPHTTP-testcase-redirection-script.php‎

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,42 @@ function is_ssl() {
9797
}
9898

9999
if ( isset( $_GET['cookie-test'] ) ) {
100+
/*
101+
* Live api.wordpress.org keeps the historical Domain/Path attributes, including
102+
* parent-domain acceptance via Domain=.wordpress.org.
103+
*
104+
* The local HTTP fixture (typically 127.0.0.1) cannot set a meaningful parent
105+
* Domain attribute, so it only covers host-only / wrong-host / expired cookies.
106+
* Parent-domain acceptance is covered by
107+
* WP_HTTP_UnitTestCase::test_parent_domain_cookie_is_sent_on_redirect().
108+
*/
109+
$request_host = isset( $_SERVER['HTTP_HOST'] ) ? $_SERVER['HTTP_HOST'] : '';
110+
$request_host = preg_replace( '/:\d+$/', '', $request_host );
111+
$is_wp_org = (bool) preg_match( '/(^|\.)wordpress\.org$/i', $request_host );
112+
100113
if ( 'test-cookie' != $_GET['cookie-test'] ) {
101-
setcookie( 'api_test_cookie', 'value', time() + 365*24*60*60, '/core/tests/1.0/', 'api.wordpress.org' );
102-
setcookie( 'api_test_cookie_minimal', 'value' );
103-
setcookie( 'api_test_cookie_wrong_host', 'value', time() + 365*24*60*60, '/', 'example.com' );
104-
setcookie( 'api_test_wildcard_domain', 'value', time() + 365*24*60*60, '/', '.wordpress.org' );
105-
setcookie( 'api_test_cookie_expired', 'value', time() - 365*24*60*60, '/', '.wordpress.org' );
114+
if ( $is_wp_org ) {
115+
setcookie( 'api_test_cookie', 'value', time() + 365*24*60*60, '/core/tests/1.0/', 'api.wordpress.org' );
116+
setcookie( 'api_test_cookie_minimal', 'value' );
117+
setcookie( 'api_test_cookie_wrong_host', 'value', time() + 365*24*60*60, '/', 'example.com' );
118+
setcookie( 'api_test_wildcard_domain', 'value', time() + 365*24*60*60, '/', '.wordpress.org' );
119+
setcookie( 'api_test_cookie_expired', 'value', time() - 365*24*60*60, '/', '.wordpress.org' );
120+
} else {
121+
$request_path = parse_url( $url, PHP_URL_PATH );
122+
$cookie_path = '/';
123+
if ( is_string( $request_path ) && '' !== $request_path && '/' !== $request_path ) {
124+
$cookie_path = rtrim( str_replace( '\\', '/', dirname( $request_path ) ), '/' ) . '/';
125+
if ( '/' !== $cookie_path[0] ) {
126+
$cookie_path = '/' . $cookie_path;
127+
}
128+
}
129+
130+
setcookie( 'api_test_cookie', 'value', time() + 365*24*60*60, $cookie_path );
131+
setcookie( 'api_test_cookie_minimal', 'value' );
132+
setcookie( 'api_test_cookie_wrong_host', 'value', time() + 365*24*60*60, '/', 'example.com' );
133+
setcookie( 'api_test_cookie_expired', 'value', time() - 365*24*60*60, '/' );
134+
}
135+
106136
header( "Location: $url?cookie-test=test-cookie" );
107137
exit;
108138
}
@@ -113,7 +143,7 @@ function is_ssl() {
113143
die( 'FAIL_NO_MINIMAL' );
114144
if ( isset( $_COOKIE['api_test_cookie_wrong_host'] ) )
115145
die( 'FAIL_WRONG_HOST' );
116-
if ( empty( $_COOKIE['api_test_wildcard_domain'] ) )
146+
if ( $is_wp_org && empty( $_COOKIE['api_test_wildcard_domain'] ) )
117147
die( 'FAIL_NO_WILDCARD' );
118148
if ( isset( $_COOKIE['api_test_cookie_expired'] ) )
119149
die( 'FAIL_EXPIRED_COOKIE' );

‎tests/phpunit/tests/http/base.php‎

Lines changed: 200 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,31 @@ public function test_no_redirection_on_PUT() {
473473
$this->assertNotEmpty( $res['headers']['location'] );
474474
}
475475

476+
/**
477+
* Parses the plain-text body from the redirection script `header-check` endpoint.
478+
*
479+
* @param string $body Response body.
480+
* @return array Header name => value pairs.
481+
*/
482+
protected function parse_header_check_body( $body ) {
483+
$headers = array();
484+
485+
foreach ( explode( "\n", $body ) as $line ) {
486+
if ( empty( $line ) ) {
487+
continue;
488+
}
489+
490+
$parts = explode( ':', $line, 2 );
491+
if ( 2 !== count( $parts ) ) {
492+
continue;
493+
}
494+
495+
$headers[ $parts[0] ] = $parts[1];
496+
}
497+
498+
return $headers;
499+
}
500+
476501
/**
477502
* @ticket 11888
478503
*
@@ -489,15 +514,7 @@ public function test_send_headers() {
489514

490515
$this->assertNotWPError( $res );
491516

492-
$headers = array();
493-
foreach ( explode( "\n", $res['body'] ) as $key => $value ) {
494-
if ( empty( $value ) ) {
495-
continue;
496-
}
497-
$parts = explode( ':', $value, 2 );
498-
unset( $headers[ $key ] );
499-
$headers[ $parts[0] ] = $parts[1];
500-
}
517+
$headers = $this->parse_header_check_body( $res['body'] );
501518

502519
$this->assertArrayHasKey( 'test1', $headers );
503520
$this->assertSame( 'test', $headers['test1'] );
@@ -665,17 +682,49 @@ public static function data_post_redirect_to_method_300() {
665682
/**
666683
* Test HTTP Requests using an IP URL, with a HOST header specified.
667684
*
685+
* Prefers the local redirection fixture when available. Falls back to the
686+
* live api.wordpress.org script only when the fixture was not started.
687+
*
688+
* Uses `header-check` so the assertion proves the custom Host header reached
689+
* the server, not only that some response body was returned.
690+
*
668691
* @ticket 24182
692+
* @ticket 63914
669693
*
670694
* @covers ::wp_remote_get
671695
* @covers ::wp_remote_retrieve_body
672696
*/
673697
public function test_ip_url_with_host_header() {
674-
$ip = gethostbyname( 'api.wordpress.org' );
675-
$url = 'http://' . $ip . '/core/tests/1.0/redirection.php?print-pass=1';
698+
$parts = wp_parse_url( $this->redirection_script );
699+
$this->assertIsArray( $parts );
700+
$this->assertNotEmpty( $parts['host'] );
701+
$this->assertNotEmpty( $parts['path'] );
702+
703+
$host = $parts['host'];
704+
$port = isset( $parts['port'] ) ? (int) $parts['port'] : null;
705+
706+
if ( filter_var( $host, FILTER_VALIDATE_IP ) ) {
707+
/*
708+
* Local fixture host is already an IP. Send a different Host value so
709+
* the test fails if the transport ignores the caller-supplied header.
710+
*/
711+
$ip = $host;
712+
$host_header = 'localhost';
713+
} else {
714+
$ip = gethostbyname( $host );
715+
$host_header = $host;
716+
}
717+
718+
$url = 'http://' . $ip;
719+
if ( $port ) {
720+
$url .= ':' . $port;
721+
$host_header .= ':' . $port;
722+
}
723+
$url .= $parts['path'] . '?header-check';
724+
676725
$args = array(
677726
'headers' => array(
678-
'Host' => 'api.wordpress.org',
727+
'Host' => $host_header,
679728
),
680729
'timeout' => 30,
681730
'redirection' => 0,
@@ -684,7 +733,11 @@ public function test_ip_url_with_host_header() {
684733
$res = $this->wp_remote_get( $url, $args );
685734

686735
$this->assertNotWPError( $res );
687-
$this->assertSame( 'PASS', wp_remote_retrieve_body( $res ) );
736+
737+
$received_headers = $this->parse_header_check_body( wp_remote_retrieve_body( $res ) );
738+
739+
$this->assertArrayHasKey( 'host', $received_headers );
740+
$this->assertSame( $host_header, $received_headers['host'] );
688741
}
689742

690743
/**
@@ -713,20 +766,66 @@ public function test_https_url_without_ssl_verification() {
713766
/**
714767
* Test HTTP Cookie handling.
715768
*
769+
* Uses the local redirection fixture when available so cookie acceptance and
770+
* rejection checks do not depend on a live api.wordpress.org request.
771+
*
772+
* Parent-domain cookie acceptance is covered by
773+
* test_parent_domain_cookie_is_sent_on_redirect().
774+
*
716775
* @ticket 21182
776+
* @ticket 63914
717777
*
718778
* @covers ::wp_remote_get
719779
* @covers ::wp_remote_retrieve_body
720780
*/
721781
public function test_cookie_handling() {
722-
$url = 'http://api.wordpress.org/core/tests/1.0/redirection.php?cookie-test=1';
782+
$url = $this->redirection_script . '?cookie-test=1';
723783

724784
$res = $this->wp_remote_get( $url );
725785

726786
$this->assertNotWPError( $res );
727787
$this->assertSame( 'PASS', wp_remote_retrieve_body( $res ) );
728788
}
729789

790+
/**
791+
* Verifies parent-domain cookies are accepted and sent on redirect.
792+
*
793+
* Complements test_cookie_handling(): the IP-based local fixture intentionally
794+
* omits parent-domain cookies, so this named-origin mock keeps Domain=.example.test
795+
* acceptance deterministic without a live network request.
796+
*
797+
* @ticket 21182
798+
* @ticket 63914
799+
*
800+
* @covers ::wp_remote_get
801+
* @covers WP_Http::normalize_cookies
802+
*/
803+
public function test_parent_domain_cookie_is_sent_on_redirect() {
804+
add_action( 'requests-requests.before_request', array( $this, 'inject_parent_domain_cookie_test_transport' ), 10, 5 );
805+
806+
try {
807+
$res = $this->wp_remote_get( 'http://api.example.test/cookie-wildcard-test' );
808+
} finally {
809+
remove_action( 'requests-requests.before_request', array( $this, 'inject_parent_domain_cookie_test_transport' ), 10 );
810+
}
811+
812+
$this->assertNotWPError( $res );
813+
$this->assertSame( 'PASS', wp_remote_retrieve_body( $res ) );
814+
}
815+
816+
/**
817+
* Injects the parent-domain cookie test transport into Requests options.
818+
*
819+
* @param string $url Request URL.
820+
* @param array $headers Request headers.
821+
* @param string|array $data Request data.
822+
* @param string $type HTTP method.
823+
* @param array $options Request options (passed by reference).
824+
*/
825+
public function inject_parent_domain_cookie_test_transport( $url, $headers, $data, $type, &$options ) {
826+
$options['transport'] = new WP_HTTP_Parent_Domain_Cookie_Test_Transport();
827+
}
828+
730829
/**
731830
* Test if HTTPS support works.
732831
*
@@ -761,3 +860,90 @@ public function test_url_with_double_slashes_path() {
761860
$this->assertNotWPError( $res );
762861
}
763862
}
863+
864+
/**
865+
* Test-only Requests transport for parent-domain cookie acceptance.
866+
*
867+
* Used by WP_HTTP_UnitTestCase::test_parent_domain_cookie_is_sent_on_redirect().
868+
*/
869+
class WP_HTTP_Parent_Domain_Cookie_Test_Transport implements WpOrg\Requests\Transport {
870+
871+
/**
872+
* Performs a request against the canned cookie-redirect responses.
873+
*
874+
* @param string $url URL to request.
875+
* @param array $headers Associative array of request headers.
876+
* @param string|array $data Request data.
877+
* @param array $options Request options.
878+
* @return string Raw HTTP response.
879+
*
880+
* @throws WpOrg\Requests\Exception When no canned response exists for the URL.
881+
*/
882+
public function request( $url, $headers = array(), $data = array(), $options = array() ) {
883+
if ( 'http://api.example.test/cookie-wildcard-test' === $url ) {
884+
return "HTTP/1.1 302 Found\r\n"
885+
. "Set-Cookie: api_test_wildcard_domain=value; Domain=.example.test; Path=/\r\n"
886+
. "Set-Cookie: api_test_cookie_wrong_host=value; Domain=example.com; Path=/\r\n"
887+
. "Location: http://api.example.test/cookie-wildcard-test?done=1\r\n\r\n";
888+
}
889+
890+
if ( 'http://api.example.test/cookie-wildcard-test?done=1' === $url ) {
891+
$cookie_header = '';
892+
foreach ( $headers as $header_name => $header_value ) {
893+
if ( 0 !== strcasecmp( (string) $header_name, 'Cookie' ) ) {
894+
continue;
895+
}
896+
897+
$cookie_header = is_array( $header_value ) ? implode( '; ', $header_value ) : (string) $header_value;
898+
break;
899+
}
900+
901+
if ( false === strpos( $cookie_header, 'api_test_wildcard_domain=value' ) ) {
902+
return "HTTP/1.1 200 OK\r\n\r\nFAIL_NO_WILDCARD";
903+
}
904+
905+
if ( false !== strpos( $cookie_header, 'api_test_cookie_wrong_host=' ) ) {
906+
return "HTTP/1.1 200 OK\r\n\r\nFAIL_WRONG_HOST";
907+
}
908+
909+
return "HTTP/1.1 200 OK\r\n\r\nPASS";
910+
}
911+
912+
throw new WpOrg\Requests\Exception(
913+
sprintf( 'Unexpected HTTP request for URL: %s', $url ),
914+
'testtransport.unhandled'
915+
);
916+
}
917+
918+
/**
919+
* Performs multiple requests sequentially.
920+
*
921+
* @param array $requests Request data.
922+
* @param array $options Global options.
923+
* @return array Array of responses.
924+
*/
925+
public function request_multiple( $requests, $options ) {
926+
$responses = array();
927+
928+
foreach ( $requests as $key => $request ) {
929+
$responses[ $key ] = $this->request(
930+
$request['url'],
931+
$request['headers'],
932+
$request['data'],
933+
$request['options']
934+
);
935+
}
936+
937+
return $responses;
938+
}
939+
940+
/**
941+
* Self-test whether the transport can be used.
942+
*
943+
* @param array<string, bool> $capabilities Optional. Capabilities to test against.
944+
* @return bool Always true for the test transport.
945+
*/
946+
public static function test( $capabilities = array() ) {
947+
return true;
948+
}
949+
}

0 commit comments

Comments
 (0)