@@ -392,4 +392,179 @@ public function wp_translate_php_url_constant_to_key_testcases() {
392392 );
393393 }
394394
395+ /**
396+ * Test that wp_http_validate_url validates URLs.
397+ *
398+ * @ticket 54331
399+ *
400+ * @dataProvider data_wp_http_validate_url_should_validate
401+ *
402+ * @covers ::wp_http_validate_url
403+ *
404+ * @param string $url The URL to validate.
405+ * @param false|string $cb_safe_ports The name of the callback to http_allowed_safe_ports or false if none.
406+ * Default false.
407+ * @param bool $external_host Whether or not the host is external.
408+ * Default false.
409+ */
410+ public function test_wp_http_validate_url_should_validate ( $ url , $ cb_safe_ports = false , $ external_host = false ) {
411+ if ( $ external_host ) {
412+ add_filter ( 'http_request_host_is_external ' , '__return_true ' );
413+ }
414+
415+ if ( $ cb_safe_ports ) {
416+ add_filter ( 'http_allowed_safe_ports ' , array ( $ this , $ cb_safe_ports ) );
417+ }
418+
419+ $ this ->assertSame ( $ url , wp_http_validate_url ( $ url ) );
420+ }
421+
422+ /**
423+ * Data provider.
424+ *
425+ * @return array
426+ */
427+ public function data_wp_http_validate_url_should_validate () {
428+ return array (
429+ 'no port specified ' => array (
430+ 'url ' => 'http://example.com/caniload.php ' ,
431+ ),
432+ 'an external request when allowed ' => array (
433+ 'url ' => 'http://172.20.0.123/caniload.php ' ,
434+ 'cb_safe_ports ' => false ,
435+ 'external_host ' => true ,
436+ ),
437+ 'a port considered safe by default ' => array (
438+ 'url ' => 'https://example.com:8080/caniload.php ' ,
439+ ),
440+ 'a port considered safe by filter ' => array (
441+ 'url ' => 'https://example.com:81/caniload.php ' ,
442+ 'cb_safe_ports ' => 'callback_custom_safe_ports ' ,
443+ ),
444+ );
445+ }
446+
447+ /**
448+ * Tests that wp_http_validate_url validates a url that uses an unsafe port
449+ * but which matches the host and port used by the site's home url.
450+ *
451+ * @ticket 54331
452+ *
453+ * @covers ::wp_http_validate_url
454+ */
455+ public function test_wp_http_validate_url_should_validate_with_an_unsafe_port_when_the_host_and_port_match_the_home_url () {
456+ $ original_home = get_option ( 'home ' );
457+ $ home_parsed = parse_url ( $ original_home );
458+ $ home_scheme_host = implode ( ':// ' , array_slice ( $ home_parsed , 0 , 2 ) );
459+ $ home_modified = $ home_scheme_host . ':83 ' ;
460+
461+ update_option ( 'home ' , $ home_modified );
462+
463+ $ url = $ home_modified . '/caniload.php ' ;
464+ $ this ->assertSame ( $ url , wp_http_validate_url ( $ url ) );
465+
466+ update_option ( 'home ' , $ original_home );
467+ }
468+
469+ /**
470+ * Test that wp_http_validate_url does not validate invalid URLs.
471+ *
472+ * @ticket 54331
473+ *
474+ * @dataProvider data_wp_http_validate_url_should_not_validate
475+ *
476+ * @covers ::wp_http_validate_url
477+ *
478+ * @param string $url The URL to validate.
479+ * @param false|string $cb_safe_ports The name of the callback to http_allowed_safe_ports or false if none.
480+ * Default false.
481+ * @param bool $external_host Whether or not the host is external.
482+ * Default false.
483+ */
484+ public function test_wp_http_validate_url_should_not_validate ( $ url , $ cb_safe_ports = false , $ external_host = false ) {
485+ if ( $ external_host ) {
486+ add_filter ( 'http_request_host_is_external ' , '__return_true ' );
487+ }
488+
489+ if ( $ cb_safe_ports ) {
490+ add_filter ( 'http_allowed_safe_ports ' , array ( $ this , $ cb_safe_ports ) );
491+ }
492+
493+ $ this ->assertFalse ( wp_http_validate_url ( $ url ) );
494+ }
495+
496+ /**
497+ * Data provider.
498+ *
499+ * @return array
500+ */
501+ public function data_wp_http_validate_url_should_not_validate () {
502+ return array (
503+ 'url as false ' => array (
504+ 'url ' => false ,
505+ ),
506+ 'url as null ' => array (
507+ 'url ' => null ,
508+ ),
509+ 'url as int 0 ' => array (
510+ 'url ' => 0 ,
511+ ),
512+ 'url as string 0 ' => array (
513+ 'url ' => '0 ' ,
514+ ),
515+ 'url as int 1 ' => array (
516+ 'url ' => 1 ,
517+ ),
518+ 'url as string 1 ' => array (
519+ 'url ' => '1 ' ,
520+ ),
521+ 'url as array() ' => array (
522+ 'url ' => array (),
523+ ),
524+ 'an empty url ' => array (
525+ 'url ' => '' ,
526+ ),
527+ 'a url with a non-http/https protocol ' => array (
528+ 'url ' => 'ftp://example.com:81/caniload.php ' ,
529+ ),
530+ 'a malformed url ' => array (
531+ 'url ' => 'http:///example.com:81/caniload.php ' ,
532+ ),
533+ 'a host that cannot be parsed ' => array (
534+ 'url ' => 'http:example.com/caniload.php ' ,
535+ ),
536+ 'login information ' => array (
537+ 'url ' => 'http://user:pass@example.com/caniload.php ' ,
538+ ),
539+ 'a host with invalid characters ' => array (
540+ 'url ' => 'http://[exam]ple.com/caniload.php ' ,
541+ ),
542+ 'a host whose IPv4 address cannot be resolved ' => array (
543+ 'url ' => 'http://exampleeeee.com/caniload.php ' ,
544+ ),
545+ 'an external request when not allowed ' => array (
546+ 'url ' => 'http://192.168.0.1/caniload.php ' ,
547+ 'external_host ' => false ,
548+ ),
549+ 'a port not considered safe by default ' => array (
550+ 'url ' => 'https://example.com:81/caniload.php ' ,
551+ ),
552+ 'a port not considered safe by filter ' => array (
553+ 'url ' => 'https://example.com:82/caniload.php ' ,
554+ 'cb_safe_ports ' => 'callback_custom_safe_ports ' ,
555+ ),
556+ 'all safe ports removed by filter ' => array (
557+ 'url ' => 'https://example.com:81/caniload.php ' ,
558+ 'cb_safe_ports ' => 'callback_remove_safe_ports ' ,
559+ ),
560+ );
561+ }
562+
563+ public function callback_custom_safe_ports ( $ ports ) {
564+ return array ( 81 , 444 , 8081 );
565+ }
566+
567+ public function callback_remove_safe_ports ( $ ports ) {
568+ return array ();
569+ }
395570}
0 commit comments