From: Amir Sarabadani Date: Mon, 12 Jun 2017 13:45:51 +0000 (+0430) Subject: Move HttpAccept* to libs X-Git-Tag: 1.31.0-rc.0~3010 X-Git-Url: http://git.cyclocoop.org/?a=commitdiff_plain;h=bc74afc67e192196ea7830ecb12e5eb81170863a;p=lhc%2Fweb%2Fwiklou.git Move HttpAccept* to libs Bug: T163923 Change-Id: I4984f6b77843669950afeff82351827cd416a80d --- diff --git a/autoload.php b/autoload.php index 3632b5528c..6c5aff5d3d 100644 --- a/autoload.php +++ b/autoload.php @@ -872,8 +872,6 @@ $wgAutoloadLocalClasses = [ 'MediaWiki\\Diff\\ComplexityException' => __DIR__ . '/includes/diff/ComplexityException.php', 'MediaWiki\\Diff\\WordAccumulator' => __DIR__ . '/includes/diff/WordAccumulator.php', 'MediaWiki\\HeaderCallback' => __DIR__ . '/includes/HeaderCallback.php', - 'MediaWiki\\Http\\HttpAcceptNegotiator' => __DIR__ . '/includes/http/HttpAcceptNegotiator.php', - 'MediaWiki\\Http\\HttpAcceptParser' => __DIR__ . '/includes/http/HttpAcceptParser.php', 'MediaWiki\\Interwiki\\ClassicInterwikiLookup' => __DIR__ . '/includes/interwiki/ClassicInterwikiLookup.php', 'MediaWiki\\Interwiki\\InterwikiLookup' => __DIR__ . '/includes/interwiki/InterwikiLookup.php', 'MediaWiki\\Interwiki\\InterwikiLookupAdapter' => __DIR__ . '/includes/interwiki/InterwikiLookupAdapter.php', @@ -1610,6 +1608,8 @@ $wgAutoloadLocalClasses = [ 'WikiRevision' => __DIR__ . '/includes/import/WikiRevision.php', 'WikiStatsOutput' => __DIR__ . '/maintenance/language/StatOutputs.php', 'WikiTextStructure' => __DIR__ . '/includes/content/WikiTextStructure.php', + 'Wikimedia\\Http\\HttpAcceptNegotiator' => __DIR__ . '/includes/libs/http/HttpAcceptNegotiator.php', + 'Wikimedia\\Http\\HttpAcceptParser' => __DIR__ . '/includes/libs/http/HttpAcceptParser.php', 'Wikimedia\\Rdbms\\Blob' => __DIR__ . '/includes/libs/rdbms/encasing/Blob.php', 'Wikimedia\\Rdbms\\ChronologyProtector' => __DIR__ . '/includes/libs/rdbms/ChronologyProtector.php', 'Wikimedia\\Rdbms\\ConnectionManager' => __DIR__ . '/includes/libs/rdbms/connectionmanager/ConnectionManager.php', diff --git a/includes/http/HttpAcceptNegotiator.php b/includes/http/HttpAcceptNegotiator.php deleted file mode 100644 index 399aa34a86..0000000000 --- a/includes/http/HttpAcceptNegotiator.php +++ /dev/null @@ -1,139 +0,0 @@ -supportedValues = $supported; - $this->defaultValue = reset( $supported ); - } - - /** - * Returns the best supported key from the given weight map. Of the keys from the - * $weights parameter that are also in the list of supported values supplied to - * the constructor, this returns the key that has the highest weight associated - * with it. If two keys have the same weight, the more specific key is preferred, - * as required by RFC2616 section 14. Keys that map to 0 or false are ignored. - * If no matching key is found, $default is returned. - * - * @param float[] $weights An associative array mapping accepted values to their - * respective weights. - * - * @param null|string $default The value to return if non of the keys in $weights - * is supported (null per default). - * - * @return null|string The best supported key from the $weights parameter. - */ - public function getBestSupportedKey( array $weights, $default = null ) { - // Make sure we correctly bias against wildcards and ranges, see RFC2616, section 14. - foreach ( $weights as $name => &$weight ) { - if ( $name === '*' || $name === '*/*' ) { - $weight -= 0.000002; - } elseif ( substr( $name, -2 ) === '/*' ) { - $weight -= 0.000001; - } - } - - // Sort $weights by value and... - asort( $weights ); - - // remove any keys with values equal to 0 or false (HTTP/1.1 section 3.9) - $weights = array_filter( $weights ); - - // ...use the ordered list of keys - $preferences = array_reverse( array_keys( $weights ) ); - - $value = $this->getFirstSupportedValue( $preferences, $default ); - return $value; - } - - /** - * Returns the first supported value from the given preference list. Of the values from - * the $preferences parameter that are also in the list of supported values supplied - * to the constructor, this returns the value that has the lowest index in the list. - * If no such value is found, $default is returned. - * - * @param string[] $preferences A list of acceptable values, in order of preference. - * - * @param null|string $default The value to return if non of the keys in $weights - * is supported (null per default). - * - * @return null|string The best supported key from the $weights parameter. - */ - public function getFirstSupportedValue( array $preferences, $default = null ) { - foreach ( $preferences as $value ) { - foreach ( $this->supportedValues as $supported ) { - if ( $this->valueMatches( $value, $supported ) ) { - return $supported; - } - } - } - - return $default; - } - - /** - * Returns true if the given acceptable value matches the given supported value, - * according to the HTTP specification. The following rules are used: - * - * - comparison is case-insensitive - * - if $accepted and $supported are equal, they match - * - if $accepted is `*` or `*` followed by `/*`, it matches any $supported value. - * - if both $accepted and $supported contain a `/`, and $accepted ends with `/*`, - * they match if the part before the first `/` is equal. - * - * @param string $accepted An accepted value (may contain wildcards) - * @param string $supported A supported value. - * - * @return bool Whether the given supported value matches the given accepted value. - */ - private function valueMatches( $accepted, $supported ) { - // RDF 2045: MIME types are case insensitive. - // full match - if ( strcasecmp( $accepted, $supported ) === 0 ) { - return true; - } - - // wildcard match (HTTP/1.1 section 14.1, 14.2, 14.3) - if ( $accepted === '*' || $accepted === '*/*' ) { - return true; - } - - // wildcard match (HTTP/1.1 section 14.1) - if ( substr( $accepted, -2 ) === '/*' - && strncasecmp( $accepted, $supported, strlen( $accepted ) - 2 ) === 0 - ) { - return true; - } - - return false; - } - -} diff --git a/includes/http/HttpAcceptParser.php b/includes/http/HttpAcceptParser.php deleted file mode 100644 index 304c9831e6..0000000000 --- a/includes/http/HttpAcceptParser.php +++ /dev/null @@ -1,78 +0,0 @@ - 0.8 - $weights = array_combine( $values, $qvalues ); - - return $weights; - } - -} diff --git a/includes/libs/http/HttpAcceptNegotiator.php b/includes/libs/http/HttpAcceptNegotiator.php new file mode 100644 index 0000000000..5f8d9a69e1 --- /dev/null +++ b/includes/libs/http/HttpAcceptNegotiator.php @@ -0,0 +1,139 @@ +supportedValues = $supported; + $this->defaultValue = reset( $supported ); + } + + /** + * Returns the best supported key from the given weight map. Of the keys from the + * $weights parameter that are also in the list of supported values supplied to + * the constructor, this returns the key that has the highest weight associated + * with it. If two keys have the same weight, the more specific key is preferred, + * as required by RFC2616 section 14. Keys that map to 0 or false are ignored. + * If no matching key is found, $default is returned. + * + * @param float[] $weights An associative array mapping accepted values to their + * respective weights. + * + * @param null|string $default The value to return if non of the keys in $weights + * is supported (null per default). + * + * @return null|string The best supported key from the $weights parameter. + */ + public function getBestSupportedKey( array $weights, $default = null ) { + // Make sure we correctly bias against wildcards and ranges, see RFC2616, section 14. + foreach ( $weights as $name => &$weight ) { + if ( $name === '*' || $name === '*/*' ) { + $weight -= 0.000002; + } elseif ( substr( $name, -2 ) === '/*' ) { + $weight -= 0.000001; + } + } + + // Sort $weights by value and... + asort( $weights ); + + // remove any keys with values equal to 0 or false (HTTP/1.1 section 3.9) + $weights = array_filter( $weights ); + + // ...use the ordered list of keys + $preferences = array_reverse( array_keys( $weights ) ); + + $value = $this->getFirstSupportedValue( $preferences, $default ); + return $value; + } + + /** + * Returns the first supported value from the given preference list. Of the values from + * the $preferences parameter that are also in the list of supported values supplied + * to the constructor, this returns the value that has the lowest index in the list. + * If no such value is found, $default is returned. + * + * @param string[] $preferences A list of acceptable values, in order of preference. + * + * @param null|string $default The value to return if non of the keys in $weights + * is supported (null per default). + * + * @return null|string The best supported key from the $weights parameter. + */ + public function getFirstSupportedValue( array $preferences, $default = null ) { + foreach ( $preferences as $value ) { + foreach ( $this->supportedValues as $supported ) { + if ( $this->valueMatches( $value, $supported ) ) { + return $supported; + } + } + } + + return $default; + } + + /** + * Returns true if the given acceptable value matches the given supported value, + * according to the HTTP specification. The following rules are used: + * + * - comparison is case-insensitive + * - if $accepted and $supported are equal, they match + * - if $accepted is `*` or `*` followed by `/*`, it matches any $supported value. + * - if both $accepted and $supported contain a `/`, and $accepted ends with `/*`, + * they match if the part before the first `/` is equal. + * + * @param string $accepted An accepted value (may contain wildcards) + * @param string $supported A supported value. + * + * @return bool Whether the given supported value matches the given accepted value. + */ + private function valueMatches( $accepted, $supported ) { + // RDF 2045: MIME types are case insensitive. + // full match + if ( strcasecmp( $accepted, $supported ) === 0 ) { + return true; + } + + // wildcard match (HTTP/1.1 section 14.1, 14.2, 14.3) + if ( $accepted === '*' || $accepted === '*/*' ) { + return true; + } + + // wildcard match (HTTP/1.1 section 14.1) + if ( substr( $accepted, -2 ) === '/*' + && strncasecmp( $accepted, $supported, strlen( $accepted ) - 2 ) === 0 + ) { + return true; + } + + return false; + } + +} diff --git a/includes/libs/http/HttpAcceptParser.php b/includes/libs/http/HttpAcceptParser.php new file mode 100644 index 0000000000..bce071e726 --- /dev/null +++ b/includes/libs/http/HttpAcceptParser.php @@ -0,0 +1,78 @@ + 0.8 + $weights = array_combine( $values, $qvalues ); + + return $weights; + } + +} diff --git a/includes/linkeddata/PageDataRequestHandler.php b/includes/linkeddata/PageDataRequestHandler.php index 8fc32b9181..9804b2d651 100644 --- a/includes/linkeddata/PageDataRequestHandler.php +++ b/includes/linkeddata/PageDataRequestHandler.php @@ -1,7 +1,7 @@ getFirstSupportedValue( $accepted, $default ); - - $this->assertEquals( $expected, $actual ); - } - - public function provideGetBestSupportedKey() { - return [ - [ // #0: empty - [], // supported - [], // accepted - null, // default - null, // expected - ], - [ // #1: simple - [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported - [ 'text/xzy' => 1, 'text/bar' => 0.5 ], // accepted - null, // default - 'text/BAR', // expected - ], - [ // #2: default - [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported - [ 'text/xzy' => 1, 'text/xoo' => 0.5 ], // accepted - 'X', // default - 'X', // expected - ], - [ // #3: weighted - [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported - [ 'text/foo' => 0.3, 'text/BAR' => 0.8, 'application/zuul' => 0.5 ], // accepted - null, // default - 'text/BAR', // expected - ], - [ // #4: zero weight - [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported - [ 'text/foo' => 0, 'text/xoo' => 1 ], // accepted - null, // default - null, // expected - ], - [ // #5: * wildcard - [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported - [ 'text/xoo' => 0.5, '*' => 0.1 ], // accepted - null, // default - 'text/foo', // expected - ], - [ // #6: */* wildcard - [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported - [ 'text/xoo' => 0.5, '*/*' => 0.1 ], // accepted - null, // default - 'text/foo', // expected - ], - [ // #7: text/* wildcard - [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported - [ 'text/foo' => 0.3, 'application/*' => 0.8 ], // accepted - null, // default - 'application/zuul', // expected - ], - [ // #8: Test specific format preferred over wildcard (T133314) - [ 'application/rdf+xml', 'text/json', 'text/html' ], // supported - [ '*/*' => 1, 'text/html' => 1 ], // accepted - null, // default - 'text/html', // expected - ], - [ // #9: Test specific format preferred over range (T133314) - [ 'application/rdf+xml', 'text/json', 'text/html' ], // supported - [ 'text/*' => 1, 'text/html' => 1 ], // accepted - null, // default - 'text/html', // expected - ], - [ // #10: Test range preferred over wildcard (T133314) - [ 'application/rdf+xml', 'text/html' ], // supported - [ '*/*' => 1, 'text/*' => 1 ], // accepted - null, // default - 'text/html', // expected - ], - ]; - } - - /** - * @dataProvider provideGetBestSupportedKey - */ - public function testGetBestSupportedKey( $supported, $accepted, $default, $expected ) { - $negotiator = new HttpAcceptNegotiator( $supported ); - $actual = $negotiator->getBestSupportedKey( $accepted, $default ); - - $this->assertEquals( $expected, $actual ); - } - -} diff --git a/tests/phpunit/includes/http/HttpAcceptParserTest.php b/tests/phpunit/includes/http/HttpAcceptParserTest.php deleted file mode 100644 index 7e5fc74692..0000000000 --- a/tests/phpunit/includes/http/HttpAcceptParserTest.php +++ /dev/null @@ -1,57 +0,0 @@ - 1 ] - ], - [ // #2 - 'Accept: text/plain', - [ 'text/plain' => 1 ] - ], - [ // #3 - 'Accept: application/vnd.php.serialized, application/rdf+xml', - [ 'application/vnd.php.serialized' => 1, 'application/rdf+xml' => 1 ] - ], - [ // #4 - 'foo; q=0.2, xoo; q=0,text/n3', - [ 'text/n3' => 1, 'foo' => 0.2 ] - ], - [ // #5 - '*; q=0.2, */*; q=0.1,text/*', - [ 'text/*' => 1, '*' => 0.2, '*/*' => 0.1 ] - ], - // TODO: nicely ignore additional type paramerters - //[ // #6 - // 'Foo; q=0.2, Xoo; level=3, Bar; charset=xyz; q=0.4', - // [ 'xoo' => 1, 'bar' => 0.4, 'foo' => 0.1 ] - //], - ]; - } - - /** - * @dataProvider provideParseWeights - */ - public function testParseWeights( $header, $expected ) { - $parser = new HttpAcceptParser(); - $actual = $parser->parseWeights( $header ); - - $this->assertEquals( $expected, $actual ); // shouldn't be sensitive to order - } - -} diff --git a/tests/phpunit/includes/libs/http/HttpAcceptNegotiatorTest.php b/tests/phpunit/includes/libs/http/HttpAcceptNegotiatorTest.php new file mode 100644 index 0000000000..4415bc9717 --- /dev/null +++ b/tests/phpunit/includes/libs/http/HttpAcceptNegotiatorTest.php @@ -0,0 +1,151 @@ +getFirstSupportedValue( $accepted, $default ); + + $this->assertEquals( $expected, $actual ); + } + + public function provideGetBestSupportedKey() { + return [ + [ // #0: empty + [], // supported + [], // accepted + null, // default + null, // expected + ], + [ // #1: simple + [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported + [ 'text/xzy' => 1, 'text/bar' => 0.5 ], // accepted + null, // default + 'text/BAR', // expected + ], + [ // #2: default + [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported + [ 'text/xzy' => 1, 'text/xoo' => 0.5 ], // accepted + 'X', // default + 'X', // expected + ], + [ // #3: weighted + [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported + [ 'text/foo' => 0.3, 'text/BAR' => 0.8, 'application/zuul' => 0.5 ], // accepted + null, // default + 'text/BAR', // expected + ], + [ // #4: zero weight + [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported + [ 'text/foo' => 0, 'text/xoo' => 1 ], // accepted + null, // default + null, // expected + ], + [ // #5: * wildcard + [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported + [ 'text/xoo' => 0.5, '*' => 0.1 ], // accepted + null, // default + 'text/foo', // expected + ], + [ // #6: */* wildcard + [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported + [ 'text/xoo' => 0.5, '*/*' => 0.1 ], // accepted + null, // default + 'text/foo', // expected + ], + [ // #7: text/* wildcard + [ 'text/foo', 'text/BAR', 'application/zuul' ], // supported + [ 'text/foo' => 0.3, 'application/*' => 0.8 ], // accepted + null, // default + 'application/zuul', // expected + ], + [ // #8: Test specific format preferred over wildcard (T133314) + [ 'application/rdf+xml', 'text/json', 'text/html' ], // supported + [ '*/*' => 1, 'text/html' => 1 ], // accepted + null, // default + 'text/html', // expected + ], + [ // #9: Test specific format preferred over range (T133314) + [ 'application/rdf+xml', 'text/json', 'text/html' ], // supported + [ 'text/*' => 1, 'text/html' => 1 ], // accepted + null, // default + 'text/html', // expected + ], + [ // #10: Test range preferred over wildcard (T133314) + [ 'application/rdf+xml', 'text/html' ], // supported + [ '*/*' => 1, 'text/*' => 1 ], // accepted + null, // default + 'text/html', // expected + ], + ]; + } + + /** + * @dataProvider provideGetBestSupportedKey + */ + public function testGetBestSupportedKey( $supported, $accepted, $default, $expected ) { + $negotiator = new HttpAcceptNegotiator( $supported ); + $actual = $negotiator->getBestSupportedKey( $accepted, $default ); + + $this->assertEquals( $expected, $actual ); + } + +} diff --git a/tests/phpunit/includes/libs/http/HttpAcceptParserTest.php b/tests/phpunit/includes/libs/http/HttpAcceptParserTest.php new file mode 100644 index 0000000000..5bd9425305 --- /dev/null +++ b/tests/phpunit/includes/libs/http/HttpAcceptParserTest.php @@ -0,0 +1,57 @@ + 1 ] + ], + [ // #2 + 'Accept: text/plain', + [ 'text/plain' => 1 ] + ], + [ // #3 + 'Accept: application/vnd.php.serialized, application/rdf+xml', + [ 'application/vnd.php.serialized' => 1, 'application/rdf+xml' => 1 ] + ], + [ // #4 + 'foo; q=0.2, xoo; q=0,text/n3', + [ 'text/n3' => 1, 'foo' => 0.2 ] + ], + [ // #5 + '*; q=0.2, */*; q=0.1,text/*', + [ 'text/*' => 1, '*' => 0.2, '*/*' => 0.1 ] + ], + // TODO: nicely ignore additional type paramerters + //[ // #6 + // 'Foo; q=0.2, Xoo; level=3, Bar; charset=xyz; q=0.4', + // [ 'xoo' => 1, 'bar' => 0.4, 'foo' => 0.1 ] + //], + ]; + } + + /** + * @dataProvider provideParseWeights + */ + public function testParseWeights( $header, $expected ) { + $parser = new HttpAcceptParser(); + $actual = $parser->parseWeights( $header ); + + $this->assertEquals( $expected, $actual ); // shouldn't be sensitive to order + } + +}