From 250b62478e3d19ec45c5a58b7f9b8c5aa451d961 Mon Sep 17 00:00:00 2001 From: Brad Lassey Date: Mon, 10 Jul 2017 14:19:57 +0000 Subject: [PATCH] Add Brotli support to iOS Cronet This adds a getter and setter to enable and disable brotli. The test tests that brotli is advertised (or not) and that encoded data can be decoded correctly. Bug = 737231 Bug: 737231 Change-Id: I63e58f97725764b74f51a86edc2ed0eefafe7476 Reviewed-on: https://chromium-review.googlesource.com/563857 Commit-Queue: Brad Lassey Reviewed-by: smut Reviewed-by: Sylvain Defresne Reviewed-by: Misha Efimov Cr-Commit-Position: refs/heads/master@{#485262} --- components/cronet/ios/Cronet.h | 4 ++ components/cronet/ios/Cronet.mm | 7 +++ components/cronet/ios/cronet_environment.h | 7 ++- components/cronet/ios/cronet_environment.mm | 2 + .../cronet/ios/test/cronet_http_test.mm | 46 +++++++++++++++++++ components/cronet/ios/test/test_server.cc | 33 +++++++++++++ components/cronet/ios/test/test_server.h | 3 ++ components/cronet/tools/cr_cronet.py | 1 + .../chromium.mac/ios-simulator-cronet.json | 2 +- 9 files changed, 102 insertions(+), 3 deletions(-) diff --git a/components/cronet/ios/Cronet.h b/components/cronet/ios/Cronet.h index 920cace56513c6..9275b4545964fa 100644 --- a/components/cronet/ios/Cronet.h +++ b/components/cronet/ios/Cronet.h @@ -51,6 +51,10 @@ GRPC_SUPPORT_EXPORT // any effect before |start| is called. + (void)setQuicEnabled:(BOOL)quicEnabled; +// Sets whether Brotli should be supported by CronetEngine. This method only has +// any effect before |start| is called. ++ (void)setBrotliEnabled:(BOOL)brotliEnabled; + // Set HTTP Cache type to be used by CronetEngine. This method only has any // effect before |start| is called. See HttpCacheType enum for available // options. diff --git a/components/cronet/ios/Cronet.mm b/components/cronet/ios/Cronet.mm index e7cc88b0469e83..5c4e76c81a752d 100644 --- a/components/cronet/ios/Cronet.mm +++ b/components/cronet/ios/Cronet.mm @@ -43,6 +43,7 @@ // sane. BOOL gHttp2Enabled = YES; BOOL gQuicEnabled = NO; +BOOL gBrotliEnabled = NO; cronet::URLRequestContextConfig::HttpCacheType gHttpCache = cronet::URLRequestContextConfig::HttpCacheType::DISK; QuicHintVector gQuicHints; @@ -179,6 +180,11 @@ + (void)setQuicEnabled:(BOOL)quicEnabled { gQuicEnabled = quicEnabled; } ++ (void)setBrotliEnabled:(BOOL)brotliEnabled { + [self checkNotStarted]; + gBrotliEnabled = brotliEnabled; +} + + (void)addQuicHint:(NSString*)host port:(int)port altPort:(int)altPort { [self checkNotStarted]; gQuicHints.push_back( @@ -281,6 +287,7 @@ + (void)startInternal { gChromeNet.Get()->set_http2_enabled(gHttp2Enabled); gChromeNet.Get()->set_quic_enabled(gQuicEnabled); + gChromeNet.Get()->set_brotli_enabled(gBrotliEnabled); gChromeNet.Get()->set_experimental_options( base::SysNSStringToUTF8(gExperimentalOptions)); gChromeNet.Get()->set_http_cache(gHttpCache); diff --git a/components/cronet/ios/cronet_environment.h b/components/cronet/ios/cronet_environment.h index 8f4adc78fa9c6a..bed027bed8b84e 100644 --- a/components/cronet/ios/cronet_environment.h +++ b/components/cronet/ios/cronet_environment.h @@ -68,13 +68,15 @@ class CronetEnvironment { void AddQuicHint(const std::string& host, int port, int alternate_port); // Setters and getters for |http2_enabled_|, |quic_enabled_|, and - // |forced_quic_origin_|. These only have any effect before Start() is - // called. + // |brotli_enabled| These only have any effect + // before Start() is called. void set_http2_enabled(bool enabled) { http2_enabled_ = enabled; } void set_quic_enabled(bool enabled) { quic_enabled_ = enabled; } + void set_brotli_enabled(bool enabled) { brotli_enabled_ = enabled; } bool http2_enabled() const { return http2_enabled_; } bool quic_enabled() const { return quic_enabled_; } + bool brotli_enabled() const { return brotli_enabled_; } void set_quic_user_agent_id(const std::string& quic_user_agent_id) { quic_user_agent_id_ = quic_user_agent_id; @@ -145,6 +147,7 @@ class CronetEnvironment { bool http2_enabled_; bool quic_enabled_; + bool brotli_enabled_; std::string quic_user_agent_id_; std::string accept_language_; std::string experimental_options_; diff --git a/components/cronet/ios/cronet_environment.mm b/components/cronet/ios/cronet_environment.mm index 1e04229ff3b4f5..dd3c96f455aab8 100644 --- a/components/cronet/ios/cronet_environment.mm +++ b/components/cronet/ios/cronet_environment.mm @@ -219,6 +219,7 @@ bool user_agent_partial) : http2_enabled_(false), quic_enabled_(false), + brotli_enabled_(false), http_cache_(URLRequestContextConfig::HttpCacheType::DISK), user_agent_(user_agent), user_agent_partial_(user_agent_partial), @@ -348,6 +349,7 @@ context_builder.SetHttpServerProperties(std::move(http_server_properties)); + context_builder.set_enable_brotli(brotli_enabled_); main_context_ = context_builder.Build(); main_context_->transport_security_state() diff --git a/components/cronet/ios/test/cronet_http_test.mm b/components/cronet/ios/test/cronet_http_test.mm index 99feb490efe3ab..e94154a6a2a930 100644 --- a/components/cronet/ios/test/cronet_http_test.mm +++ b/components/cronet/ios/test/cronet_http_test.mm @@ -372,4 +372,50 @@ void TearDown() override { EXPECT_TRUE([[delegate_ responseBody] containsString:testString]); } +TEST_F(HttpTest, BrotliAdvertisedTest) { + [Cronet shutdownForTesting]; + + [Cronet setBrotliEnabled:YES]; + + StartCronet(grpc_support::GetQuicTestServerPort()); + + NSURL* url = + net::NSURLWithGURL(GURL(TestServer::GetEchoHeaderURL("Accept-Encoding"))); + NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; + StartDataTaskAndWaitForCompletion(task); + EXPECT_EQ(nil, [delegate_ error]); + EXPECT_TRUE([[delegate_ responseBody] containsString:@"br"]); +} + +TEST_F(HttpTest, BrotliNotAdvertisedTest) { + [Cronet shutdownForTesting]; + + [Cronet setBrotliEnabled:NO]; + + StartCronet(grpc_support::GetQuicTestServerPort()); + + NSURL* url = + net::NSURLWithGURL(GURL(TestServer::GetEchoHeaderURL("Accept-Encoding"))); + NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; + StartDataTaskAndWaitForCompletion(task); + EXPECT_EQ(nil, [delegate_ error]); + EXPECT_FALSE([[delegate_ responseBody] containsString:@"br"]); +} + +TEST_F(HttpTest, BrotliHandleDecoding) { + [Cronet shutdownForTesting]; + + [Cronet setBrotliEnabled:YES]; + + StartCronet(grpc_support::GetQuicTestServerPort()); + + NSURL* url = + net::NSURLWithGURL(GURL(TestServer::GetUseEncodingURL("brotli"))); + NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; + StartDataTaskAndWaitForCompletion(task); + EXPECT_EQ(nil, [delegate_ error]); + EXPECT_STREQ(base::SysNSStringToUTF8([delegate_ responseBody]).c_str(), + "The quick brown fox jumps over the lazy dog"); +} + } // namespace cronet diff --git a/components/cronet/ios/test/test_server.cc b/components/cronet/ios/test/test_server.cc index 0a5385bae5c069..d41fa24855a062 100644 --- a/components/cronet/ios/test/test_server.cc +++ b/components/cronet/ios/test/test_server.cc @@ -22,6 +22,7 @@ namespace { const char kEchoHeaderPath[] = "/EchoHeader?"; const char kSetCookiePath[] = "/SetCookie?"; const char kBigDataPath[] = "/BigData?"; +const char kUseEncodingPath[] = "/UseEncoding?"; std::unique_ptr g_test_server; base::LazyInstance::Leaky g_big_data_body = @@ -43,6 +44,29 @@ std::unique_ptr EchoHeaderInRequest( return std::move(http_response); } +std::unique_ptr UseEncodingInResponse( + const net::test_server::HttpRequest& request) { + std::string encoding; + DCHECK(base::StartsWith(request.relative_url, kUseEncodingPath, + base::CompareCase::INSENSITIVE_ASCII)); + + encoding = request.relative_url.substr(strlen(kUseEncodingPath)); + auto http_response = base::MakeUnique(); + if (!encoding.compare("brotli")) { + const char quickfoxCompressed[] = { + 0x0b, 0x15, -0x80, 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, + 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20, 0x66, 0x6f, 0x78, 0x20, 0x6a, + 0x75, 0x6d, 0x70, 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67, 0x03}; + std::string quickfoxCompressedStr(quickfoxCompressed, + sizeof(quickfoxCompressed)); + http_response->set_content(quickfoxCompressedStr); + http_response->AddCustomHeader(std::string("content-encoding"), + std::string("br")); + } + return std::move(http_response); +} + std::unique_ptr ReturnBigDataInResponse( const net::test_server::HttpRequest& request) { DCHECK(base::StartsWith(request.relative_url, kBigDataPath, @@ -81,6 +105,10 @@ std::unique_ptr CronetTestRequestHandler( base::CompareCase::INSENSITIVE_ASCII)) { return ReturnBigDataInResponse(request); } + if (base::StartsWith(request.relative_url, kUseEncodingPath, + base::CompareCase::INSENSITIVE_ASCII)) { + return UseEncodingInResponse(request); + } return base::MakeUnique(); } @@ -108,6 +136,11 @@ std::string TestServer::GetEchoHeaderURL(const std::string& header_name) { return g_test_server->GetURL(kEchoHeaderPath + header_name).spec(); } +std::string TestServer::GetUseEncodingURL(const std::string& header_name) { + DCHECK(g_test_server); + return g_test_server->GetURL(kUseEncodingPath + header_name).spec(); +} + std::string TestServer::GetSetCookieURL(const std::string& cookie_line) { DCHECK(g_test_server); return g_test_server->GetURL(kSetCookiePath + cookie_line).spec(); diff --git a/components/cronet/ios/test/test_server.h b/components/cronet/ios/test/test_server.h index a0b7b8a94967e3..668dbe70260b08 100644 --- a/components/cronet/ios/test/test_server.h +++ b/components/cronet/ios/test/test_server.h @@ -17,6 +17,9 @@ class TestServer { // Returns URL which respond with echo of header with |header_name| in // response body. static std::string GetEchoHeaderURL(const std::string& header_name); + // Returns URL which responds with "The quick brown fox jumps over the lazy + // dog" in specified encoding. + static std::string GetUseEncodingURL(const std::string& header_name); // Returns URL which respond with setting cookie to |cookie_line| and echo it // in response body. static std::string GetSetCookieURL(const std::string& cookie_line); diff --git a/components/cronet/tools/cr_cronet.py b/components/cronet/tools/cr_cronet.py index d424b93a93c447..891c895bc77a8c 100755 --- a/components/cronet/tools/cr_cronet.py +++ b/components/cronet/tools/cr_cronet.py @@ -101,6 +101,7 @@ def main(): gn_args += 'target_os="' + target_os + '" enable_websockets=false '+ \ 'disable_file_support=true disable_ftp_support=true '+ \ + 'disable_brotli_filter=false ' + \ 'use_platform_icu_alternatives=true '+ \ 'enable_reporting=false '+ \ 'is_component_build=false ' + \ diff --git a/ios/build/bots/chromium.mac/ios-simulator-cronet.json b/ios/build/bots/chromium.mac/ios-simulator-cronet.json index 7dd030a18c59b4..0ae0e8e3b3446f 100644 --- a/ios/build/bots/chromium.mac/ios-simulator-cronet.json +++ b/ios/build/bots/chromium.mac/ios-simulator-cronet.json @@ -6,7 +6,7 @@ "xcode version": "8.0", "gn_args": [ "additional_target_cpus=[\"x86\"]", - "disable_brotli_filter=true", + "disable_brotli_filter=false", "disable_file_support=true", "disable_ftp_support=true", "enable_websockets=false",