@ -1,20 +1,18 @@
/*
*
* Copyright 2015 gRPC authors .
*
* Licensed under the Apache License , Version 2.0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*
*/
//
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
# include "src/core/lib/uri/uri_parser.h"
@ -34,28 +32,33 @@ using ::testing::Contains;
using : : testing : : ElementsAre ;
using : : testing : : Pair ;
static void TestSucceeds (
absl : : string_view uri_text , absl : : string_view scheme ,
absl : : string_view authority , absl : : string_view path ,
const std : : map < absl : : string_view , absl : : string_view > & query_param_map ,
const std : : vector < grpc_core : : URI : : QueryParam > & query_param_pairs ,
absl : : string_view fragment ) {
absl : : StatusOr < grpc_core : : URI > uri = grpc_core : : URI : : Parse ( uri_text ) ;
ASSERT_TRUE ( uri . ok ( ) ) ;
EXPECT_EQ ( scheme , uri - > scheme ( ) ) ;
EXPECT_EQ ( authority , uri - > authority ( ) ) ;
EXPECT_EQ ( path , uri - > path ( ) ) ;
EXPECT_THAT ( uri - > query_parameter_map ( ) , ContainerEq ( query_param_map ) ) ;
EXPECT_THAT ( uri - > query_parameter_pairs ( ) , ContainerEq ( query_param_pairs ) ) ;
EXPECT_EQ ( fragment , uri - > fragment ( ) ) ;
}
static void TestFails ( absl : : string_view uri_text ) {
absl : : StatusOr < grpc_core : : URI > uri = grpc_core : : URI : : Parse ( uri_text ) ;
ASSERT_FALSE ( uri . ok ( ) ) ;
}
namespace grpc_core {
class URIParserTest : public testing : : Test {
protected :
static void TestSucceeds (
absl : : string_view uri_text , absl : : string_view scheme ,
absl : : string_view authority , absl : : string_view path ,
const std : : map < absl : : string_view , absl : : string_view > & query_param_map ,
const std : : vector < URI : : QueryParam > & query_param_pairs ,
absl : : string_view fragment ) {
absl : : StatusOr < URI > uri = URI : : Parse ( uri_text ) ;
ASSERT_TRUE ( uri . ok ( ) ) < < uri . status ( ) . ToString ( ) ;
EXPECT_EQ ( scheme , uri - > scheme ( ) ) ;
EXPECT_EQ ( authority , uri - > authority ( ) ) ;
EXPECT_EQ ( path , uri - > path ( ) ) ;
EXPECT_THAT ( uri - > query_parameter_map ( ) , ContainerEq ( query_param_map ) ) ;
EXPECT_THAT ( uri - > query_parameter_pairs ( ) , ContainerEq ( query_param_pairs ) ) ;
EXPECT_EQ ( fragment , uri - > fragment ( ) ) ;
}
TEST ( URIParserTest , BasicExamplesAreParsedCorrectly ) {
static void TestFails ( absl : : string_view uri_text ) {
absl : : StatusOr < URI > uri = URI : : Parse ( uri_text ) ;
ASSERT_FALSE ( uri . ok ( ) ) ;
}
} ;
TEST_F ( URIParserTest , BasicExamplesAreParsedCorrectly ) {
TestSucceeds ( " http://www.google.com " , " http " , " www.google.com " , " " , { } , { } ,
" " ) ;
TestSucceeds ( " dns:///foo " , " dns " , " " , " /foo " , { } , { } , " " ) ;
@ -75,7 +78,7 @@ TEST(URIParserTest, BasicExamplesAreParsedCorrectly) {
" buckle/my/shoe " ) ;
}
TEST ( URIParserTest , UncommonValidExamplesAreParsedCorrectly ) {
TEST_F ( URIParserTest , UncommonValidExamplesAreParsedCorrectly ) {
TestSucceeds ( " scheme:path//is/ok " , " scheme " , " " , " path//is/ok " , { } , { } , " " ) ;
TestSucceeds ( " http:?legit " , " http " , " " , " " , { { " legit " , " " } } , { { " legit " , " " } } ,
" " ) ;
@ -84,15 +87,18 @@ TEST(URIParserTest, UncommonValidExamplesAreParsedCorrectly) {
TestSucceeds ( " http:?legit#twice " , " http " , " " , " " , { { " legit " , " " } } ,
{ { " legit " , " " } } , " twice " ) ;
TestSucceeds ( " fake:/// " , " fake " , " " , " / " , { } , { } , " " ) ;
TestSucceeds ( " http://local%25host:8080/whatz%25it?1%25=2%25#fragment " , " http " ,
" local%host:8080 " , " /whatz%it " , { { " 1% " , " 2% " } } , { { " 1% " , " 2% " } } ,
" fragment " ) ;
}
TEST ( URIParserTest , VariousKeyValueAndNonKVQueryParamsAreParsedCorrectly ) {
TEST_F ( URIParserTest , VariousKeyValueAndNonKVQueryParamsAreParsedCorrectly ) {
TestSucceeds ( " http://foo/path?a&b=B&c=&#frag " , " http " , " foo " , " /path " ,
{ { " c " , " " } , { " a " , " " } , { " b " , " B " } } ,
{ { " a " , " " } , { " b " , " B " } , { " c " , " " } } , " frag " ) ;
}
TEST ( URIParserTest , ParserTreatsFirstEqualSignAsKVDelimiterInQueryString ) {
TEST_F ( URIParserTest , ParserTreatsFirstEqualSignAsKVDelimiterInQueryString ) {
TestSucceeds (
" http://localhost:8080/?too=many=equals&are=present=here#fragged " , " http " ,
" localhost:8080 " , " / " , { { " are " , " present=here " } , { " too " , " many=equals " } } ,
@ -102,52 +108,48 @@ TEST(URIParserTest, ParserTreatsFirstEqualSignAsKVDelimiterInQueryString) {
{ { " foo " , " bar=baz " } , { " foobar " , " == " } } , " " ) ;
}
TEST ( URIParserTest ,
RepeatedQueryParamsAreSupportedInOrderedPairsButDeduplicatedInTheMap ) {
absl : : StatusOr < grpc_core : : URI > uri =
grpc_core : : URI : : Parse ( " http://foo/path?a=2&a=1&a=3 " ) ;
ASSERT_TRUE ( uri . ok ( ) ) ;
TEST_F ( URIParserTest ,
RepeatedQueryParamsAreSupportedInOrderedPairsButDeduplicatedInTheMap ) {
absl : : StatusOr < URI > uri = URI : : Parse ( " http://foo/path?a=2&a=1&a=3 " ) ;
ASSERT_TRUE ( uri . ok ( ) ) < < uri . status ( ) . ToString ( ) ;
// The map stores the last found value.
ASSERT_THAT ( uri - > query_parameter_map ( ) , ElementsAre ( Pair ( " a " , " 3 " ) ) ) ;
// Order matters for query parameter pairs
ASSERT_THAT ( uri - > query_parameter_pairs ( ) ,
ElementsAre ( grpc_core : : URI : : QueryParam { " a " , " 2 " } ,
grpc_core : : URI : : QueryParam { " a " , " 1 " } ,
grpc_core : : URI : : QueryParam { " a " , " 3 " } ) ) ;
ElementsAre ( URI : : QueryParam { " a " , " 2 " } , URI : : QueryParam { " a " , " 1 " } ,
URI : : QueryParam { " a " , " 3 " } ) ) ;
}
TEST ( URIParserTest , QueryParamMapRemainsValiditAfterMovingTheURI ) {
grpc_core : : URI uri_copy ;
TEST_F ( URIParserTest , QueryParamMapRemainsValiditAfterMovingTheURI ) {
URI uri_copy ;
{
absl : : StatusOr < grpc_core : : URI > uri =
grpc_core : : URI : : Parse ( " http://foo/path?a=2&b=1&c=3 " ) ;
ASSERT_TRUE ( uri . ok ( ) ) ;
absl : : StatusOr < URI > uri = URI : : Parse ( " http://foo/path?a=2&b=1&c=3 " ) ;
ASSERT_TRUE ( uri . ok ( ) ) < < uri . status ( ) . ToString ( ) ;
uri_copy = std : : move ( * uri ) ;
}
// ASSERT_EQ(uri_copy.query_parameter_map().find("a")->second, "2");
ASSERT_THAT ( uri_copy . query_parameter_map ( ) , Contains ( Pair ( " a " , " 2 " ) ) ) ;
}
TEST ( URIParserTest , QueryParamMapRemainsValidAfterCopyingTheURI ) {
TEST_F ( URIParserTest , QueryParamMapRemainsValidAfterCopyingTheURI ) {
// Since the query parameter map points to objects stored in the param pair
// vector, this test checks that the param map pointers remain valid after
// a copy. Ideally {a,m}san will catch this if there's a problem.
// testing copy operator=:
grpc_core : : URI uri_copy ;
URI uri_copy ;
{
absl : : StatusOr < grpc_core : : URI > del_uri =
grpc_core : : URI : : Parse ( " http://foo/path?a=2&b=1&c=3 " ) ;
ASSERT_TRUE ( del_uri . ok ( ) ) ;
absl : : StatusOr < URI > del_uri = URI : : Parse ( " http://foo/path?a=2&b=1&c=3 " ) ;
ASSERT_TRUE ( del_uri . ok ( ) ) < < del_uri . status ( ) . ToString ( ) ;
uri_copy = * del_uri ;
}
ASSERT_THAT ( uri_copy . query_parameter_map ( ) , Contains ( Pair ( " a " , " 2 " ) ) ) ;
grpc_core : : URI * del_uri2 = new grpc_core : : URI ( uri_copy ) ;
grpc_core : : URI uri_copy2 ( * del_uri2 ) ;
URI * del_uri2 = new URI ( uri_copy ) ;
URI uri_copy2 ( * del_uri2 ) ;
delete del_uri2 ;
ASSERT_THAT ( uri_copy2 . query_parameter_map ( ) , Contains ( Pair ( " a " , " 2 " ) ) ) ;
}
TEST ( URIParserTest , AWSExternalAccountRegressionTest ) {
TEST_F ( URIParserTest , AWSExternalAccountRegressionTest ) {
TestSucceeds (
" https://foo.com:5555/v1/ "
" token-exchange?subject_token=eyJhbGciO&subject_token_type=urn:ietf: "
@ -160,20 +162,21 @@ TEST(URIParserTest, AWSExternalAccountRegressionTest) {
" " ) ;
}
TEST ( URIParserTest , NonKeyValueQueryStringsWork ) {
TEST_F ( URIParserTest , NonKeyValueQueryStringsWork ) {
TestSucceeds ( " http://www.google.com?yay-i'm-using-queries " , " http " ,
" www.google.com " , " " , { { " yay-i'm-using-queries " , " " } } ,
{ { " yay-i'm-using-queries " , " " } } , " " ) ;
}
TEST ( URIParserTest , IPV6StringsAreParsedCorrectly ) {
TEST_F ( URIParserTest , IPV6StringsAreParsedCorrectly ) {
TestSucceeds ( " ipv6:[2001:db8::1%252]:12345 " , " ipv6 " , " " ,
" [2001:db8::1%2]:12345 " , { } , { } , " " ) ;
TestSucceeds ( " ipv6:[fe80::90%eth1.sky1]:6010 " , " ipv6 " , " " ,
" [fe80::90%eth1.sky1]:6010 " , { } , { } , " " ) ;
}
TEST ( URIParserTest , PreviouslyReservedCharactersInUnrelatedURIPartsAreIgnored ) {
TEST_F ( URIParserTest ,
PreviouslyReservedCharactersInUnrelatedURIPartsAreIgnored ) {
// The '?' and '/' characters are not reserved delimiter characters in the
// fragment. See http://go/rfc/3986#section-3.5
TestSucceeds ( " http://foo?bar#lol? " , " http " , " foo " , " " , { { " bar " , " " } } ,
@ -182,30 +185,30 @@ TEST(URIParserTest, PreviouslyReservedCharactersInUnrelatedURIPartsAreIgnored) {
{ { " bar " , " " } } , " lol?/ " ) ;
}
TEST ( URIParserTest , EncodedCharactersInQueryStringAreParsedCorrectly ) {
TEST_F ( URIParserTest , EncodedCharactersInQueryStringAreParsedCorrectly ) {
TestSucceeds ( " https://www.google.com/?a=1%26b%3D2&c=3 " , " https " ,
" www.google.com " , " / " , { { " c " , " 3 " } , { " a " , " 1&b=2 " } } ,
{ { " a " , " 1&b=2 " } , { " c " , " 3 " } } , " " ) ;
}
TEST ( URIParserTest , InvalidPercentEncodingsArePassedThrough ) {
TEST_F ( URIParserTest , InvalidPercentEncodingsArePassedThrough ) {
TestSucceeds ( " x:y?%xx " , " x " , " " , " y " , { { " %xx " , " " } } , { { " %xx " , " " } } , " " ) ;
TestSucceeds ( " http:?dangling-pct-%0 " , " http " , " " , " " ,
{ { " dangling-pct-%0 " , " " } } , { { " dangling-pct-%0 " , " " } } , " " ) ;
}
TEST ( URIParserTest , NullCharactersInURIStringAreSupported ) {
TEST_F ( URIParserTest , NullCharactersInURIStringAreSupported ) {
// Artificial examples to show that embedded nulls are supported.
TestSucceeds ( std : : string ( " unix-abstract: \0 should-be-ok " , 27 ) , " unix-abstract " ,
" " , std : : string ( " \0 should-be-ok " , 13 ) , { } , { } , " " ) ;
}
TEST ( URIParserTest , EncodedNullsInURIStringAreSupported ) {
TEST_F ( URIParserTest , EncodedNullsInURIStringAreSupported ) {
TestSucceeds ( " unix-abstract:%00x " , " unix-abstract " , " " , std : : string ( " \0 x " , 2 ) ,
{ } , { } , " " ) ;
}
TEST ( URIParserTest , InvalidURIsResultInFailureStatuses ) {
TEST_F ( URIParserTest , InvalidURIsResultInFailureStatuses ) {
TestFails ( " xyz " ) ;
TestFails ( " http://foo?[bar] " ) ;
TestFails ( " http://foo?x[bar] " ) ;
@ -215,13 +218,253 @@ TEST(URIParserTest, InvalidURIsResultInFailureStatuses) {
TestFails ( " 0invalid_scheme:must_start/with?alpha " ) ;
}
TEST ( URIParserTest , PercentEncode ) {
// Ensure "?" and "=" are percent encoded; and ":" is escaped.
std : : string input = " 127.0.0.1:22222?psm_project_id=1234 " ;
EXPECT_EQ ( " 127.0.0.1:22222%3fpsm_project_id%3d1234 " ,
grpc_core : : URI : : PercentEncode ( input ) ) ;
TEST ( URITest , PercentEncodePath ) {
EXPECT_EQ ( URI : : PercentEncodePath (
// These chars are allowed.
" abcdefghijklmnopqrstuvwxyz "
" ABCDEFGHIJKLMNOPQRSTUVWXYZ "
" 0123456789 "
" /:@-._~!$&'()*+,;= "
// These chars will be escaped.
" \\ ?%#[]^ " ) ,
" abcdefghijklmnopqrstuvwxyz "
" ABCDEFGHIJKLMNOPQRSTUVWXYZ "
" 0123456789 "
" /:@-._~!$&'()*+,;= "
" %5C%3F%25%23%5B%5D%5E " ) ;
}
TEST ( URITest , Basic ) {
auto uri =
URI : : Create ( " http " , " server.example.com " , " /path/to/file.html " , { } , " " ) ;
ASSERT_TRUE ( uri . ok ( ) ) < < uri . status ( ) . ToString ( ) ;
EXPECT_EQ ( uri - > scheme ( ) , " http " ) ;
EXPECT_EQ ( uri - > authority ( ) , " server.example.com " ) ;
EXPECT_EQ ( uri - > path ( ) , " /path/to/file.html " ) ;
EXPECT_THAT ( uri - > query_parameter_pairs ( ) , testing : : ElementsAre ( ) ) ;
EXPECT_THAT ( uri - > query_parameter_map ( ) , testing : : ElementsAre ( ) ) ;
EXPECT_EQ ( uri - > fragment ( ) , " " ) ;
EXPECT_EQ ( " http://server.example.com/path/to/file.html " , uri - > ToString ( ) ) ;
}
TEST ( URITest , NoAuthority ) {
auto uri = URI : : Create ( " http " , " " , " /path/to/file.html " , { } , " " ) ;
ASSERT_TRUE ( uri . ok ( ) ) < < uri . status ( ) . ToString ( ) ;
EXPECT_EQ ( uri - > scheme ( ) , " http " ) ;
EXPECT_EQ ( uri - > authority ( ) , " " ) ;
EXPECT_EQ ( uri - > path ( ) , " /path/to/file.html " ) ;
EXPECT_THAT ( uri - > query_parameter_pairs ( ) , testing : : ElementsAre ( ) ) ;
EXPECT_THAT ( uri - > query_parameter_map ( ) , testing : : ElementsAre ( ) ) ;
EXPECT_EQ ( uri - > fragment ( ) , " " ) ;
EXPECT_EQ ( " http:/path/to/file.html " , uri - > ToString ( ) ) ;
}
TEST ( URITest , NoAuthorityRelativePath ) {
auto uri = URI : : Create ( " http " , " " , " path/to/file.html " , { } , " " ) ;
ASSERT_TRUE ( uri . ok ( ) ) < < uri . status ( ) . ToString ( ) ;
EXPECT_EQ ( uri - > scheme ( ) , " http " ) ;
EXPECT_EQ ( uri - > authority ( ) , " " ) ;
EXPECT_EQ ( uri - > path ( ) , " path/to/file.html " ) ;
EXPECT_THAT ( uri - > query_parameter_pairs ( ) , testing : : ElementsAre ( ) ) ;
EXPECT_THAT ( uri - > query_parameter_map ( ) , testing : : ElementsAre ( ) ) ;
EXPECT_EQ ( uri - > fragment ( ) , " " ) ;
EXPECT_EQ ( " http:path/to/file.html " , uri - > ToString ( ) ) ;
}
TEST ( URITest , AuthorityRelativePath ) {
auto uri =
URI : : Create ( " http " , " server.example.com " , " path/to/file.html " , { } , " " ) ;
ASSERT_FALSE ( uri . ok ( ) ) ;
EXPECT_EQ ( uri . status ( ) . code ( ) , absl : : StatusCode : : kInvalidArgument ) ;
EXPECT_EQ ( uri . status ( ) . message ( ) ,
" if authority is present, path must start with a '/' " ) ;
}
TEST ( URITest , QueryParams ) {
auto uri = URI : : Create ( " http " , " server.example.com " , " /path/to/file.html " ,
{ { " key " , " value " } , { " key2 " , " value2 " } } , " " ) ;
ASSERT_TRUE ( uri . ok ( ) ) < < uri . status ( ) . ToString ( ) ;
EXPECT_EQ ( uri - > scheme ( ) , " http " ) ;
EXPECT_EQ ( uri - > authority ( ) , " server.example.com " ) ;
EXPECT_EQ ( uri - > path ( ) , " /path/to/file.html " ) ;
EXPECT_THAT (
uri - > query_parameter_pairs ( ) ,
testing : : ElementsAre (
testing : : AllOf ( testing : : Field ( & URI : : QueryParam : : key , " key " ) ,
testing : : Field ( & URI : : QueryParam : : value , " value " ) ) ,
testing : : AllOf ( testing : : Field ( & URI : : QueryParam : : key , " key2 " ) ,
testing : : Field ( & URI : : QueryParam : : value , " value2 " ) ) ) ) ;
EXPECT_THAT ( uri - > query_parameter_map ( ) ,
testing : : ElementsAre ( testing : : Pair ( " key " , " value " ) ,
testing : : Pair ( " key2 " , " value2 " ) ) ) ;
EXPECT_EQ ( uri - > fragment ( ) , " " ) ;
EXPECT_EQ ( " http://server.example.com/path/to/file.html?key=value&key2=value2 " ,
uri - > ToString ( ) ) ;
}
TEST ( URITest , DuplicateQueryParams ) {
auto uri = URI : : Create (
" http " , " server.example.com " , " /path/to/file.html " ,
{ { " key " , " value " } , { " key2 " , " value2 " } , { " key " , " other_value " } } , " " ) ;
ASSERT_TRUE ( uri . ok ( ) ) < < uri . status ( ) . ToString ( ) ;
EXPECT_EQ ( uri - > scheme ( ) , " http " ) ;
EXPECT_EQ ( uri - > authority ( ) , " server.example.com " ) ;
EXPECT_EQ ( uri - > path ( ) , " /path/to/file.html " ) ;
EXPECT_THAT (
uri - > query_parameter_pairs ( ) ,
testing : : ElementsAre (
testing : : AllOf ( testing : : Field ( & URI : : QueryParam : : key , " key " ) ,
testing : : Field ( & URI : : QueryParam : : value , " value " ) ) ,
testing : : AllOf ( testing : : Field ( & URI : : QueryParam : : key , " key2 " ) ,
testing : : Field ( & URI : : QueryParam : : value , " value2 " ) ) ,
testing : : AllOf (
testing : : Field ( & URI : : QueryParam : : key , " key " ) ,
testing : : Field ( & URI : : QueryParam : : value , " other_value " ) ) ) ) ;
EXPECT_THAT ( uri - > query_parameter_map ( ) ,
testing : : ElementsAre ( testing : : Pair ( " key " , " other_value " ) ,
testing : : Pair ( " key2 " , " value2 " ) ) ) ;
EXPECT_EQ ( uri - > fragment ( ) , " " ) ;
EXPECT_EQ (
" http://server.example.com/path/to/file.html "
" ?key=value&key2=value2&key=other_value " ,
uri - > ToString ( ) ) ;
}
TEST ( URITest , Fragment ) {
auto uri = URI : : Create ( " http " , " server.example.com " , " /path/to/file.html " , { } ,
" fragment " ) ;
ASSERT_TRUE ( uri . ok ( ) ) < < uri . status ( ) . ToString ( ) ;
EXPECT_EQ ( uri - > scheme ( ) , " http " ) ;
EXPECT_EQ ( uri - > authority ( ) , " server.example.com " ) ;
EXPECT_EQ ( uri - > path ( ) , " /path/to/file.html " ) ;
EXPECT_THAT ( uri - > query_parameter_pairs ( ) , testing : : ElementsAre ( ) ) ;
EXPECT_THAT ( uri - > query_parameter_map ( ) , testing : : ElementsAre ( ) ) ;
EXPECT_EQ ( uri - > fragment ( ) , " fragment " ) ;
EXPECT_EQ ( " http://server.example.com/path/to/file.html#fragment " ,
uri - > ToString ( ) ) ;
}
TEST ( URITest , QueryParamsAndFragment ) {
auto uri = URI : : Create ( " http " , " server.example.com " , " /path/to/file.html " ,
{ { " key " , " value " } , { " key2 " , " value2 " } } , " fragment " ) ;
ASSERT_TRUE ( uri . ok ( ) ) < < uri . status ( ) . ToString ( ) ;
EXPECT_EQ ( uri - > scheme ( ) , " http " ) ;
EXPECT_EQ ( uri - > authority ( ) , " server.example.com " ) ;
EXPECT_EQ ( uri - > path ( ) , " /path/to/file.html " ) ;
EXPECT_THAT (
uri - > query_parameter_pairs ( ) ,
testing : : ElementsAre (
testing : : AllOf ( testing : : Field ( & URI : : QueryParam : : key , " key " ) ,
testing : : Field ( & URI : : QueryParam : : value , " value " ) ) ,
testing : : AllOf ( testing : : Field ( & URI : : QueryParam : : key , " key2 " ) ,
testing : : Field ( & URI : : QueryParam : : value , " value2 " ) ) ) ) ;
EXPECT_THAT ( uri - > query_parameter_map ( ) ,
testing : : ElementsAre ( testing : : Pair ( " key " , " value " ) ,
testing : : Pair ( " key2 " , " value2 " ) ) ) ;
EXPECT_EQ ( uri - > fragment ( ) , " fragment " ) ;
EXPECT_EQ (
" http://server.example.com/path/to/ "
" file.html?key=value&key2=value2#fragment " ,
uri - > ToString ( ) ) ;
}
TEST ( URITest , ToStringPercentEncoding ) {
auto uri = URI : : Create (
// Scheme allowed chars.
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-. "
// Scheme escaped chars.
" %:/?#[]@!$&'()*,;= " ,
// Authority allowed chars.
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -.+~!$&'()*+,;=:[]@ "
// Authority escaped chars.
" %/?# " ,
// Path allowed chars.
" /abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$&'()*+,;=:@ "
// Path escaped chars.
" %?#[] " ,
{ { // Query allowed chars.
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$'()*+,;:@/? "
// Query escaped chars.
" %=&#[] " ,
// Query allowed chars.
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$'()*+,;:@/? "
// Query escaped chars.
" %=&#[] " } } ,
// Fragment allowed chars.
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$'()*+,;:@/?=& "
// Fragment escaped chars.
" %#[] " ) ;
ASSERT_TRUE ( uri . ok ( ) ) < < uri . status ( ) . ToString ( ) ;
EXPECT_EQ ( uri - > scheme ( ) ,
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-. "
" %:/?#[]@!$&'()*,;= " ) ;
EXPECT_EQ ( uri - > authority ( ) ,
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -.+~!$&'()*+,;=:[]@ "
" %/?# " ) ;
EXPECT_EQ ( uri - > path ( ) ,
" /abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$&'()*+,;=:@ "
" %?#[] " ) ;
EXPECT_THAT (
uri - > query_parameter_pairs ( ) ,
testing : : ElementsAre ( testing : : AllOf (
testing : : Field (
& URI : : QueryParam : : key ,
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$'()*+,;:@/? "
" %=&#[] " ) ,
testing : : Field (
& URI : : QueryParam : : value ,
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$'()*+,;:@/? "
" %=&#[] " ) ) ) ) ;
EXPECT_THAT (
uri - > query_parameter_map ( ) ,
testing : : ElementsAre ( testing : : Pair (
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$'()*+,;:@/? "
" %=&#[] " ,
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$'()*+,;:@/? "
" %=&#[] " ) ) ) ;
EXPECT_EQ ( uri - > fragment ( ) ,
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$'()*+,;:@/?=& "
" %#[] " ) ;
EXPECT_EQ (
// Scheme
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-. "
" %25%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2C%3B%3D "
// Authority
" ://abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -.+~!$&'()*+,;=:[]@ "
" %25%2F%3F%23 "
// Path
" /abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$&'()*+,;=:@ "
" %25%3F%23%5B%5D "
// Query
" ?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$'()*+,;:@/? "
" %25%3D%26%23%5B%5D "
" =abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$'()*+,;:@/? "
" %25%3D%26%23%5B%5D "
// Fragment
" #abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
" -._~!$'()*+,;:@/?=& "
" %25%23%5B%5D " ,
uri - > ToString ( ) ) ;
}
} // namespace grpc_core
int main ( int argc , char * * argv ) {
testing : : InitGoogleTest ( & argc , argv ) ;
grpc : : testing : : TestEnvironment env ( argc , argv ) ;