From 2448268d50e85f4d5f2e1b2e22eb0f12218b2a1f Mon Sep 17 00:00:00 2001 From: Huzaifa Al Mesbah Date: Sun, 11 Oct 2026 00:40:20 +0600 Subject: [PATCH 1/2] Tests: Add unit test coverage for WP_Http_Encoding. --- tests/phpunit/tests/http/wpHttpEncoding.php | 364 ++++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 tests/phpunit/tests/http/wpHttpEncoding.php diff --git a/tests/phpunit/tests/http/wpHttpEncoding.php b/tests/phpunit/tests/http/wpHttpEncoding.php new file mode 100644 index 0000000000000..243c940a05ef5 --- /dev/null +++ b/tests/phpunit/tests/http/wpHttpEncoding.php @@ -0,0 +1,364 @@ +assertNotSame( self::CONTENT, $compressed, 'The content should be compressed.' ); + $this->assertLessThan( strlen( self::CONTENT ), strlen( $compressed ), 'The compressed content should be shorter.' ); + $this->assertSame( self::CONTENT, gzinflate( $compressed ), 'The compressed content should be raw deflate data.' ); + } + + /** + * Tests that compress() respects the compression level. + * + * @ticket 65819 + * + * @covers ::compress + */ + public function test_compress_uses_compression_level() { + $stored = WP_Http_Encoding::compress( self::CONTENT, 0 ); + + $this->assertStringContainsString( self::CONTENT, $stored, 'Level 0 should store the content without compressing it.' ); + $this->assertSame( self::CONTENT, gzinflate( $stored ), 'The stored content should be raw deflate data.' ); + } + + /** + * Tests that decompress() handles each supported compression format. + * + * @ticket 65819 + * + * @covers ::decompress + * @covers ::compatible_gzinflate + * + * @dataProvider data_compressed_content + * + * @param string $compressed Compressed content. + */ + public function test_decompress( $compressed ) { + $this->assertSame( self::CONTENT, WP_Http_Encoding::decompress( $compressed ) ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_compressed_content() { + return array( + 'raw deflate' => array( gzdeflate( self::CONTENT ) ), + 'raw deflate without compression' => array( gzdeflate( self::CONTENT, 0 ) ), + 'zlib' => array( gzcompress( self::CONTENT ) ), + 'gzip' => array( gzencode( self::CONTENT ) ), + 'gzip with a file name' => array( self::build_gzip_stream( 8, "content.txt\0" ) ), + 'WP_Http_Encoding::compress()' => array( WP_Http_Encoding::compress( self::CONTENT ) ), + ); + } + + /** + * Tests that decompress() returns content it cannot decompress unchanged. + * + * @ticket 65819 + * + * @covers ::decompress + * + * @dataProvider data_content_that_is_not_compressed + * + * @param mixed $content Content. + */ + public function test_decompress_returns_uncompressed_content_unchanged( $content ) { + $this->assertSame( $content, WP_Http_Encoding::decompress( $content ) ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_content_that_is_not_compressed() { + return array( + 'plain text' => array( self::CONTENT ), + 'HTML' => array( 'Hello' ), + 'empty string' => array( '' ), + 'zero string' => array( '0' ), + 'false' => array( false ), + 'null' => array( null ), + 'truncated gzip' => array( "\x1f\x8b\x08" ), + ); + } + + /** + * Tests that compatible_gzinflate() skips the optional gzip header fields. + * + * @ticket 65819 + * + * @covers ::compatible_gzinflate + * + * @dataProvider data_gzip_streams + * + * @param string $gz_data Gzip stream. + */ + public function test_compatible_gzinflate_decodes_gzip_streams( $gz_data ) { + $this->assertSame( self::CONTENT, WP_Http_Encoding::compatible_gzinflate( $gz_data ) ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_gzip_streams() { + return array( + 'gzencode()' => array( gzencode( self::CONTENT ) ), + 'no optional fields' => array( self::build_gzip_stream( 0, '' ) ), + 'header checksum' => array( self::build_gzip_stream( 2, "\x12\x34" ) ), + 'file name' => array( self::build_gzip_stream( 8, "content.txt\0" ) ), + 'comment' => array( self::build_gzip_stream( 16, "A comment\0" ) ), + 'file name, comment and header checksum' => array( self::build_gzip_stream( 26, "content.txt\0" . "A comment\0" . "\x12\x34" ) ), + 'zlib stream with a two-byte header' => array( gzcompress( self::CONTENT ) ), + ); + } + + /** + * Tests that compatible_gzinflate() returns false for data it cannot decode. + * + * @ticket 65819 + * + * @covers ::compatible_gzinflate + * + * @dataProvider data_invalid_gzip_streams + * + * @param string $gz_data Data. + */ + public function test_compatible_gzinflate_returns_false_for_invalid_data( $gz_data ) { + $this->assertFalse( WP_Http_Encoding::compatible_gzinflate( $gz_data ) ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_invalid_gzip_streams() { + return array( + 'plain text' => array( self::CONTENT ), + 'empty string' => array( '' ), + 'gzip header without content' => array( "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03" ), + ); + } + + /** + * Tests the Accept-Encoding header value for different request arguments. + * + * @ticket 65819 + * + * @covers ::accept_encoding + * + * @dataProvider data_accept_encoding + * + * @param array $args Request arguments. + * @param string $expected Expected header value. + */ + public function test_accept_encoding( $args, $expected ) { + $this->assertSame( $expected, WP_Http_Encoding::accept_encoding( 'http://example.org/', $args ) ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_accept_encoding() { + $all = 'deflate;q=1.0, compress;q=0.5, gzip;q=0.5'; + + return array( + 'decompression enabled' => array( + array( + 'decompress' => true, + 'stream' => false, + ), + $all, + ), + 'limit_response_size is null' => array( + array( + 'decompress' => true, + 'stream' => false, + 'limit_response_size' => null, + ), + $all, + ), + 'decompression disabled' => array( + array( + 'decompress' => false, + 'stream' => false, + ), + '', + ), + 'streaming to a file' => array( + array( + 'decompress' => true, + 'stream' => true, + ), + '', + ), + 'limited response size' => array( + array( + 'decompress' => true, + 'stream' => false, + 'limit_response_size' => 1024, + ), + '', + ), + 'response size limited to zero' => array( + array( + 'decompress' => true, + 'stream' => false, + 'limit_response_size' => 0, + ), + '', + ), + ); + } + + /** + * Tests that the accepted encodings are filterable. + * + * @ticket 65819 + * + * @covers ::accept_encoding + */ + public function test_accept_encoding_is_filterable() { + $args = array( + 'decompress' => true, + 'stream' => false, + ); + + $filter = new MockAction(); + add_filter( 'wp_http_accept_encoding', array( $filter, 'filter' ), 10, 3 ); + add_filter( + 'wp_http_accept_encoding', + static function ( $type ) { + return array( $type[0], 'br;q=0.9' ); + }, + 20 + ); + + $this->assertSame( 'deflate;q=1.0, br;q=0.9', WP_Http_Encoding::accept_encoding( 'http://example.org/path', $args ), 'The filtered encodings should be used.' ); + $this->assertSame( + array( + array( + array( 'deflate;q=1.0', 'compress;q=0.5', 'gzip;q=0.5' ), + 'http://example.org/path', + $args, + ), + ), + $filter->get_args(), + 'The filter should receive the encodings, the URL and the request arguments.' + ); + } + + /** + * Tests the content encoding used for compressed request bodies. + * + * @ticket 65819 + * + * @covers ::content_encoding + */ + public function test_content_encoding() { + $this->assertSame( 'deflate', WP_Http_Encoding::content_encoding() ); + } + + /** + * Tests whether response headers indicate an encoded body. + * + * @ticket 65819 + * + * @covers ::should_decode + * + * @dataProvider data_should_decode + * + * @param mixed $headers Response headers. + * @param bool $expected Whether the body should be decoded. + */ + public function test_should_decode( $headers, $expected ) { + $this->assertSame( $expected, WP_Http_Encoding::should_decode( $headers ) ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_should_decode() { + return array( + 'array with content-encoding' => array( array( 'content-encoding' => 'gzip' ), true ), + 'array with other headers' => array( + array( + 'content-type' => 'text/html', + 'content-encoding' => 'deflate', + ), + true, + ), + 'array without content-encoding' => array( array( 'content-type' => 'text/html' ), false ), + 'array with empty content-encoding' => array( array( 'content-encoding' => '' ), false ), + 'array with null content-encoding' => array( array( 'content-encoding' => null ), false ), + 'array with zero content-encoding' => array( array( 'content-encoding' => '0' ), false ), + 'array with capitalized header name' => array( array( 'Content-Encoding' => 'gzip' ), false ), + 'empty array' => array( array(), false ), + 'string with content-encoding' => array( "Content-Type: text/html\r\nContent-Encoding: gzip\r\n", true ), + 'string with lowercase header name' => array( 'content-encoding: gzip', true ), + 'string with uppercase header name' => array( 'CONTENT-ENCODING: gzip', true ), + 'string without content-encoding' => array( "Content-Type: text/html\r\n", false ), + 'string with header name but no colon' => array( 'content-encoding', false ), + 'empty string' => array( '', false ), + 'null' => array( null, false ), + 'false' => array( false, false ), + 'true' => array( true, false ), + 'integer' => array( 1, false ), + ); + } + + /** + * Tests that compression is available when the zlib functions exist. + * + * @ticket 65819 + * + * @covers ::is_available + * + * @requires function gzinflate + */ + public function test_is_available() { + $this->assertTrue( WP_Http_Encoding::is_available() ); + } +} From 66eb3a3ea8fd6e343057f16b4aa2825486b551a9 Mon Sep 17 00:00:00 2001 From: Huzaifa Al Mesbah Date: Sun, 11 Oct 2026 01:14:52 +0600 Subject: [PATCH 2/2] Tests: Remove the truncated gzip header case from the WP_Http_Encoding tests. --- tests/phpunit/tests/http/wpHttpEncoding.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/phpunit/tests/http/wpHttpEncoding.php b/tests/phpunit/tests/http/wpHttpEncoding.php index 243c940a05ef5..a7ee93594f5a9 100644 --- a/tests/phpunit/tests/http/wpHttpEncoding.php +++ b/tests/phpunit/tests/http/wpHttpEncoding.php @@ -108,13 +108,12 @@ public function test_decompress_returns_uncompressed_content_unchanged( $content */ public static function data_content_that_is_not_compressed() { return array( - 'plain text' => array( self::CONTENT ), - 'HTML' => array( 'Hello' ), - 'empty string' => array( '' ), - 'zero string' => array( '0' ), - 'false' => array( false ), - 'null' => array( null ), - 'truncated gzip' => array( "\x1f\x8b\x08" ), + 'plain text' => array( self::CONTENT ), + 'HTML' => array( 'Hello' ), + 'empty string' => array( '' ), + 'zero string' => array( '0' ), + 'false' => array( false ), + 'null' => array( null ), ); }