123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- //
- // 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"
- #include <gmock/gmock.h>
- #include <gtest/gtest.h>
- #include "absl/strings/str_join.h"
- #include "absl/strings/str_split.h"
- #include <grpc/grpc.h>
- #include <grpc/support/log.h>
- #include "test/core/util/test_config.h"
- using ::testing::ContainerEq;
- using ::testing::Contains;
- using ::testing::ElementsAre;
- using ::testing::Pair;
- 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());
- }
- 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", {}, {}, "");
- TestSucceeds("http://www.google.com:90", "http", "www.google.com:90", "", {},
- {}, "");
- TestSucceeds("a192.4-df:foo.coom", "a192.4-df", "", "foo.coom", {}, {}, "");
- TestSucceeds("a+b:foo.coom", "a+b", "", "foo.coom", {}, {}, "");
- TestSucceeds("zookeeper://127.0.0.1:2181/foo/bar", "zookeeper",
- "127.0.0.1:2181", "/foo/bar", {}, {}, "");
- TestSucceeds("dns:foo.com#fragment-all-the-things", "dns", "", "foo.com", {},
- {}, "fragment-all-the-things");
- TestSucceeds("http://localhost:8080/whatzit?mi_casa=su_casa", "http",
- "localhost:8080", "/whatzit", {{"mi_casa", "su_casa"}},
- {{"mi_casa", "su_casa"}}, "");
- TestSucceeds("http://localhost:8080/whatzit?1=2#buckle/my/shoe", "http",
- "localhost:8080", "/whatzit", {{"1", "2"}}, {{"1", "2"}},
- "buckle/my/shoe");
- }
- TEST_F(URIParserTest, UncommonValidExamplesAreParsedCorrectly) {
- TestSucceeds("scheme:path//is/ok", "scheme", "", "path//is/ok", {}, {}, "");
- TestSucceeds("http:?legit", "http", "", "", {{"legit", ""}}, {{"legit", ""}},
- "");
- TestSucceeds("unix:#this-is-ok-too", "unix", "", "", {}, {},
- "this-is-ok-too");
- 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_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_F(URIParserTest, ParserTreatsFirstEqualSignAsKVDelimiterInQueryString) {
- TestSucceeds(
- "http://localhost:8080/?too=many=equals&are=present=here#fragged", "http",
- "localhost:8080", "/", {{"are", "present=here"}, {"too", "many=equals"}},
- {{"too", "many=equals"}, {"are", "present=here"}}, "fragged");
- TestSucceeds("http://auth/path?foo=bar=baz&foobar===", "http", "auth",
- "/path", {{"foo", "bar=baz"}, {"foobar", "=="}},
- {{"foo", "bar=baz"}, {"foobar", "=="}}, "");
- }
- 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(URI::QueryParam{"a", "2"}, URI::QueryParam{"a", "1"},
- URI::QueryParam{"a", "3"}));
- }
- TEST_F(URIParserTest, QueryParamMapRemainsValiditAfterMovingTheURI) {
- URI uri_copy;
- {
- 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_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=:
- URI uri_copy;
- {
- 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")));
- 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_F(URIParserTest, AWSExternalAccountRegressionTest) {
- TestSucceeds(
- "https://foo.com:5555/v1/"
- "token-exchange?subject_token=eyJhbGciO&subject_token_type=urn:ietf:"
- "params:oauth:token-type:id_token",
- "https", "foo.com:5555", "/v1/token-exchange",
- {{"subject_token", "eyJhbGciO"},
- {"subject_token_type", "urn:ietf:params:oauth:token-type:id_token"}},
- {{"subject_token", "eyJhbGciO"},
- {"subject_token_type", "urn:ietf:params:oauth:token-type:id_token"}},
- "");
- }
- 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_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_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", ""}},
- {{"bar", ""}}, "lol?");
- TestSucceeds("http://foo?bar#lol?/", "http", "foo", "", {{"bar", ""}},
- {{"bar", ""}}, "lol?/");
- }
- 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_F(URIParserTest, InvalidPercentEncodingsArePassedThrough) {
- TestSucceeds("x:y?%xx", "x", "", "y", {{"%xx", ""}}, {{"%xx", ""}}, "");
- TestSucceeds("http:?dangling-pct-%0", "http", "", "",
- {{"dangling-pct-%0", ""}}, {{"dangling-pct-%0", ""}}, "");
- }
- TEST_F(URIParserTest, NullCharactersInURIStringAreSupported) {
- // Artificial examples to show that embedded nulls are supported.
- TestSucceeds(std::string("unix-abstract:\0should-be-ok", 27), "unix-abstract",
- "", std::string("\0should-be-ok", 13), {}, {}, "");
- }
- TEST_F(URIParserTest, EncodedNullsInURIStringAreSupported) {
- TestSucceeds("unix-abstract:%00x", "unix-abstract", "", std::string("\0x", 2),
- {}, {}, "");
- }
- TEST_F(URIParserTest, InvalidURIsResultInFailureStatuses) {
- TestFails("xyz");
- TestFails("http://foo?[bar]");
- TestFails("http://foo?x[bar]");
- TestFails("http://foo?bar#lol#");
- TestFails("");
- TestFails(":no_scheme");
- TestFails("0invalid_scheme:must_start/with?alpha");
- }
- 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);
- grpc_init();
- auto result = RUN_ALL_TESTS();
- grpc_shutdown();
- return result;
- }
|