123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- <?php
- /**
- * @group https-detection
- */
- class Tests_HTTPS_Detection extends WP_UnitTestCase {
- private $last_request_url;
- public function setUp() {
- parent::setUp();
- remove_all_filters( 'option_home' );
- remove_all_filters( 'option_siteurl' );
- remove_all_filters( 'home_url' );
- remove_all_filters( 'site_url' );
- }
- /**
- * @ticket 47577
- */
- public function test_wp_is_using_https() {
- update_option( 'home', 'http://example.com/' );
- update_option( 'siteurl', 'http://example.com/' );
- $this->assertFalse( wp_is_using_https() );
- // Expect false if only one of the two relevant URLs is HTTPS.
- update_option( 'siteurl', 'https://example.com/' );
- $this->assertFalse( wp_is_using_https() );
- update_option( 'home', 'https://example.com/' );
- $this->assertTrue( wp_is_using_https() );
- // Test that the manually included 'site_url' filter works as expected
- // by using it to set the URL to use HTTP.
- add_filter( 'site_url', $this->filter_set_url_scheme( 'http' ) );
- $this->assertFalse( wp_is_using_https() );
- }
- /**
- * @ticket 47577
- */
- public function test_wp_is_https_supported() {
- // The function works with cached errors, so only test that here.
- $wp_error = new WP_Error();
- // No errors, so HTTPS is supported.
- update_option( 'https_detection_errors', $wp_error->errors );
- $this->assertTrue( wp_is_https_supported() );
- // Errors, so HTTPS is not supported.
- $wp_error->add( 'ssl_verification_failed', 'SSL verification failed.' );
- update_option( 'https_detection_errors', $wp_error->errors );
- $this->assertFalse( wp_is_https_supported() );
- }
- /**
- * @ticket 47577
- * @ticket 52484
- */
- public function test_wp_update_https_detection_errors() {
- // Set HTTP URL, the request below should use its HTTPS version.
- update_option( 'home', 'http://example.com/' );
- add_filter( 'pre_http_request', array( $this, 'record_request_url' ), 10, 3 );
- // If initial request succeeds, all good.
- add_filter( 'pre_http_request', array( $this, 'mock_success_with_sslverify' ), 10, 2 );
- wp_update_https_detection_errors();
- $this->assertSame( array(), get_option( 'https_detection_errors' ) );
- // If initial request fails and request without SSL verification succeeds,
- // return 'ssl_verification_failed' error.
- add_filter( 'pre_http_request', array( $this, 'mock_error_with_sslverify' ), 10, 2 );
- add_filter( 'pre_http_request', array( $this, 'mock_success_without_sslverify' ), 10, 2 );
- wp_update_https_detection_errors();
- $this->assertSame(
- array( 'ssl_verification_failed' => array( __( 'SSL verification failed.' ) ) ),
- get_option( 'https_detection_errors' )
- );
- // If both initial request and request without SSL verification fail,
- // return 'https_request_failed' error.
- add_filter( 'pre_http_request', array( $this, 'mock_error_with_sslverify' ), 10, 2 );
- add_filter( 'pre_http_request', array( $this, 'mock_error_without_sslverify' ), 10, 2 );
- wp_update_https_detection_errors();
- $this->assertSame(
- array( 'https_request_failed' => array( __( 'HTTPS request failed.' ) ) ),
- get_option( 'https_detection_errors' )
- );
- // If request succeeds, but response is not 200, return error with
- // 'bad_response_code' error code.
- add_filter( 'pre_http_request', array( $this, 'mock_not_found' ), 10, 2 );
- wp_update_https_detection_errors();
- $this->assertSame(
- array( 'bad_response_code' => array( 'Not Found' ) ),
- get_option( 'https_detection_errors' )
- );
- // If request succeeds, but response was not generated by this
- // WordPress site, return error with 'bad_response_source' error code.
- add_filter( 'pre_http_request', array( $this, 'mock_bad_source' ), 10, 2 );
- wp_update_https_detection_errors();
- $this->assertSame(
- array( 'bad_response_source' => array( 'It looks like the response did not come from this site.' ) ),
- get_option( 'https_detection_errors' )
- );
- // Check that the requests are made to the correct URL.
- $this->assertSame( 'https://example.com/', $this->last_request_url );
- }
- /**
- * @ticket 47577
- */
- public function test_pre_wp_update_https_detection_errors() {
- // Override to enforce no errors being detected.
- add_filter(
- 'pre_wp_update_https_detection_errors',
- function() {
- return new WP_Error();
- }
- );
- wp_update_https_detection_errors();
- $this->assertSame( array(), get_option( 'https_detection_errors' ) );
- // Override to enforce an error being detected.
- add_filter(
- 'pre_wp_update_https_detection_errors',
- function() {
- return new WP_Error(
- 'ssl_verification_failed',
- 'Bad SSL certificate.'
- );
- }
- );
- wp_update_https_detection_errors();
- $this->assertSame(
- array( 'ssl_verification_failed' => array( 'Bad SSL certificate.' ) ),
- get_option( 'https_detection_errors' )
- );
- }
- /**
- * @ticket 47577
- */
- public function test_wp_schedule_https_detection() {
- wp_schedule_https_detection();
- $this->assertSame( 'twicedaily', wp_get_schedule( 'wp_https_detection' ) );
- }
- /**
- * @ticket 47577
- */
- public function test_wp_cron_conditionally_prevent_sslverify() {
- // If URL is not using HTTPS, don't set 'sslverify' to false.
- $request = array(
- 'url' => 'http://example.com/',
- 'args' => array( 'sslverify' => true ),
- );
- $this->assertSame( $request, wp_cron_conditionally_prevent_sslverify( $request ) );
- // If URL is using HTTPS, set 'sslverify' to false.
- $request = array(
- 'url' => 'https://example.com/',
- 'args' => array( 'sslverify' => true ),
- );
- $expected = $request;
- $expected['args']['sslverify'] = false;
- $this->assertSame( $expected, wp_cron_conditionally_prevent_sslverify( $request ) );
- }
- /**
- * @ticket 47577
- * @ticket 52542
- */
- public function test_wp_is_local_html_output_via_rsd_link() {
- // HTML includes RSD link.
- $head_tag = get_echo( 'rsd_link' );
- $html = $this->get_sample_html_string( $head_tag );
- $this->assertTrue( wp_is_local_html_output( $html ) );
- // HTML includes modified RSD link but same URL.
- $head_tag = str_replace( ' />', '>', get_echo( 'rsd_link' ) );
- $html = $this->get_sample_html_string( $head_tag );
- $this->assertTrue( wp_is_local_html_output( $html ) );
- // HTML includes RSD link with alternative URL scheme.
- $head_tag = get_echo( 'rsd_link' );
- $head_tag = false !== strpos( $head_tag, 'https://' ) ? str_replace( 'https://', 'http://', $head_tag ) : str_replace( 'http://', 'https://', $head_tag );
- $html = $this->get_sample_html_string( $head_tag );
- $this->assertTrue( wp_is_local_html_output( $html ) );
- // HTML does not include RSD link.
- $html = $this->get_sample_html_string();
- $this->assertFalse( wp_is_local_html_output( $html ) );
- }
- /**
- * @ticket 47577
- */
- public function test_wp_is_local_html_output_via_wlwmanifest_link() {
- remove_action( 'wp_head', 'rsd_link' );
- // HTML includes WLW manifest link.
- $head_tag = get_echo( 'wlwmanifest_link' );
- $html = $this->get_sample_html_string( $head_tag );
- $this->assertTrue( wp_is_local_html_output( $html ) );
- // HTML includes modified WLW manifest link but same URL.
- $head_tag = str_replace( ' />', '>', get_echo( 'wlwmanifest_link' ) );
- $html = $this->get_sample_html_string( $head_tag );
- $this->assertTrue( wp_is_local_html_output( $html ) );
- // HTML includes WLW manifest link with alternative URL scheme.
- $head_tag = get_echo( 'wlwmanifest_link' );
- $head_tag = false !== strpos( $head_tag, 'https://' ) ? str_replace( 'https://', 'http://', $head_tag ) : str_replace( 'http://', 'https://', $head_tag );
- $html = $this->get_sample_html_string( $head_tag );
- $this->assertTrue( wp_is_local_html_output( $html ) );
- // HTML does not include WLW manifest link.
- $html = $this->get_sample_html_string();
- $this->assertFalse( wp_is_local_html_output( $html ) );
- }
- /**
- * @ticket 47577
- */
- public function test_wp_is_local_html_output_via_rest_link() {
- remove_action( 'wp_head', 'rsd_link' );
- remove_action( 'wp_head', 'wlwmanifest_link' );
- // HTML includes REST API link.
- $head_tag = get_echo( 'rest_output_link_wp_head' );
- $html = $this->get_sample_html_string( $head_tag );
- $this->assertTrue( wp_is_local_html_output( $html ) );
- // HTML includes modified REST API link but same URL.
- $head_tag = str_replace( ' />', '>', get_echo( 'rest_output_link_wp_head' ) );
- $html = $this->get_sample_html_string( $head_tag );
- $this->assertTrue( wp_is_local_html_output( $html ) );
- // HTML includes REST API link with alternative URL scheme.
- $head_tag = get_echo( 'rest_output_link_wp_head' );
- $head_tag = false !== strpos( $head_tag, 'https://' ) ? str_replace( 'https://', 'http://', $head_tag ) : str_replace( 'http://', 'https://', $head_tag );
- $html = $this->get_sample_html_string( $head_tag );
- $this->assertTrue( wp_is_local_html_output( $html ) );
- // HTML does not include REST API link.
- $html = $this->get_sample_html_string();
- $this->assertFalse( wp_is_local_html_output( $html ) );
- }
- /**
- * @ticket 47577
- */
- public function test_wp_is_local_html_output_cannot_determine() {
- remove_action( 'wp_head', 'rsd_link' );
- remove_action( 'wp_head', 'wlwmanifest_link' );
- remove_action( 'wp_head', 'rest_output_link_wp_head' );
- // The HTML here doesn't matter because all hooks are removed.
- $html = $this->get_sample_html_string();
- $this->assertNull( wp_is_local_html_output( $html ) );
- }
- public function record_request_url( $preempt, $parsed_args, $url ) {
- $this->last_request_url = $url;
- return $preempt;
- }
- public function mock_success_with_sslverify( $preempt, $parsed_args ) {
- if ( ! empty( $parsed_args['sslverify'] ) ) {
- return $this->mock_success();
- }
- return $preempt;
- }
- public function mock_error_with_sslverify( $preempt, $parsed_args ) {
- if ( ! empty( $parsed_args['sslverify'] ) ) {
- return $this->mock_error();
- }
- return $preempt;
- }
- public function mock_success_without_sslverify( $preempt, $parsed_args ) {
- if ( empty( $parsed_args['sslverify'] ) ) {
- return $this->mock_success();
- }
- return $preempt;
- }
- public function mock_error_without_sslverify( $preempt, $parsed_args ) {
- if ( empty( $parsed_args['sslverify'] ) ) {
- return $this->mock_error();
- }
- return $preempt;
- }
- public function mock_not_found() {
- return array(
- 'body' => '<!DOCTYPE html><html><head><title>404</title></head><body>Not Found</body></html>',
- 'response' => array(
- 'code' => 404,
- 'message' => 'Not Found',
- ),
- );
- }
- public function mock_bad_source() {
- // Looks like a success response, but is not generated by WordPress (e.g. missing RSD link).
- return array(
- 'body' => $this->get_sample_html_string(),
- 'response' => array(
- 'code' => 200,
- 'message' => 'OK',
- ),
- );
- }
- private function mock_success() {
- // Success response containing RSD link.
- return array(
- 'body' => $this->get_sample_html_string( get_echo( 'rsd_link' ) ),
- 'response' => array(
- 'code' => 200,
- 'message' => 'OK',
- ),
- );
- }
- private function mock_error() {
- return new WP_Error( 'bad_ssl_certificate', 'Bad SSL certificate.' );
- }
- private function get_sample_html_string( $head_tag = '' ) {
- return '<!DOCTYPE html><html><head><title>Page Title</title>' . $head_tag . '</head><body>Page Content.</body></html>';
- }
- /**
- * Returns a filter callback that expects a URL and will set the URL scheme
- * to the provided $scheme.
- *
- * @param string $scheme URL scheme to set.
- * @return callable Filter callback.
- */
- private function filter_set_url_scheme( $scheme ) {
- return function( $url ) use ( $scheme ) {
- return set_url_scheme( $url, $scheme );
- };
- }
- }
|