diff --git a/chrome/browser/net/network_context_configuration_browsertest.cc b/chrome/browser/net/network_context_configuration_browsertest.cc index b350fb5aed2730..4a8ef21841132b 100644 --- a/chrome/browser/net/network_context_configuration_browsertest.cc +++ b/chrome/browser/net/network_context_configuration_browsertest.cc @@ -266,7 +266,7 @@ IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, PRE_DiskCache) { // Make a request whose response should be cached. content::ResourceRequest request; request.url = test_url; - request.headers = "foo: foopity foo\r\n\r\n"; + request.headers.SetHeader("foo", "foopity foo"); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( request, loader_factory(), TRAFFIC_ANNOTATION_FOR_TESTS, simple_loader_helper.GetCallback()); diff --git a/components/safe_browsing/DEPS b/components/safe_browsing/DEPS index aa87f2cc685e4f..227ca28a016462 100644 --- a/components/safe_browsing/DEPS +++ b/components/safe_browsing/DEPS @@ -8,6 +8,7 @@ include_rules = [ "+google_apis", "+mojo/public/cpp", "+net/base", + "+net/http", "+net/log", "+net/traffic_annotation", "+net/url_request", diff --git a/components/safe_browsing/browser/base_parallel_resource_throttle.cc b/components/safe_browsing/browser/base_parallel_resource_throttle.cc index a59be63c9a32cf..58399344ad158a 100644 --- a/components/safe_browsing/browser/base_parallel_resource_throttle.cc +++ b/components/safe_browsing/browser/base_parallel_resource_throttle.cc @@ -48,8 +48,8 @@ void BaseParallelResourceThrottle::WillStartRequest(bool* defer) { net::HttpRequestHeaders full_headers; resource_request.headers = request_->GetFullRequestHeaders(&full_headers) - ? full_headers.ToString() - : request_->extra_request_headers().ToString(); + ? full_headers + : request_->extra_request_headers(); resource_request.load_flags = request_->load_flags(); resource_request.resource_type = resource_type_; diff --git a/components/safe_browsing/browser/mojo_safe_browsing_impl.cc b/components/safe_browsing/browser/mojo_safe_browsing_impl.cc index c613b93a191c14..c4131c600764dd 100644 --- a/components/safe_browsing/browser/mojo_safe_browsing_impl.cc +++ b/components/safe_browsing/browser/mojo_safe_browsing_impl.cc @@ -83,7 +83,7 @@ void MojoSafeBrowsingImpl::CreateCheckerAndCheck( mojom::SafeBrowsingUrlCheckerRequest request, const GURL& url, const std::string& method, - const std::string& headers, + const net::HttpRequestHeaders& headers, int32_t load_flags, content::ResourceType resource_type, bool has_user_gesture, diff --git a/components/safe_browsing/browser/mojo_safe_browsing_impl.h b/components/safe_browsing/browser/mojo_safe_browsing_impl.h index 8e423f5ffd7f26..62b6f9b949f7a4 100644 --- a/components/safe_browsing/browser/mojo_safe_browsing_impl.h +++ b/components/safe_browsing/browser/mojo_safe_browsing_impl.h @@ -33,7 +33,7 @@ class MojoSafeBrowsingImpl : public mojom::SafeBrowsing { mojom::SafeBrowsingUrlCheckerRequest request, const GURL& url, const std::string& method, - const std::string& headers, + const net::HttpRequestHeaders& headers, int32_t load_flags, content::ResourceType resource_type, bool has_user_gesture, diff --git a/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc b/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc index 35387807cd9c2a..38fce0adfeca1b 100644 --- a/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc +++ b/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc @@ -37,7 +37,7 @@ SafeBrowsingUrlCheckerImpl::UrlInfo::UrlInfo(UrlInfo&& other) = default; SafeBrowsingUrlCheckerImpl::UrlInfo::~UrlInfo() = default; SafeBrowsingUrlCheckerImpl::SafeBrowsingUrlCheckerImpl( - const std::string& headers, + const net::HttpRequestHeaders& headers, int load_flags, content::ResourceType resource_type, bool has_user_gesture, @@ -142,12 +142,9 @@ void SafeBrowsingUrlCheckerImpl::OnCheckBrowseUrlResult( resource.web_contents_getter = web_contents_getter_; resource.threat_source = database_manager_->GetThreatSource(); - net::HttpRequestHeaders headers; - headers.AddHeadersFromString(headers_); - state_ = STATE_DISPLAYING_BLOCKING_PAGE; url_checker_delegate_->StartDisplayingBlockingPageHelper( - resource, urls_[next_index_].method, headers, + resource, urls_[next_index_].method, headers_, resource_type_ == content::RESOURCE_TYPE_MAIN_FRAME, has_user_gesture_); } diff --git a/components/safe_browsing/browser/safe_browsing_url_checker_impl.h b/components/safe_browsing/browser/safe_browsing_url_checker_impl.h index 83328e6980eaf9..d46949feafd01e 100644 --- a/components/safe_browsing/browser/safe_browsing_url_checker_impl.h +++ b/components/safe_browsing/browser/safe_browsing_url_checker_impl.h @@ -14,6 +14,7 @@ #include "components/safe_browsing/common/safe_browsing.mojom.h" #include "components/safe_browsing_db/database_manager.h" #include "content/public/common/resource_type.h" +#include "net/http/http_request_headers.h" #include "url/gurl.h" namespace content { @@ -34,7 +35,7 @@ class SafeBrowsingUrlCheckerImpl : public mojom::SafeBrowsingUrlChecker, public SafeBrowsingDatabaseManager::Client { public: SafeBrowsingUrlCheckerImpl( - const std::string& headers, + const net::HttpRequestHeaders& headers, int load_flags, content::ResourceType resource_type, bool has_user_gesture, @@ -102,7 +103,7 @@ class SafeBrowsingUrlCheckerImpl : public mojom::SafeBrowsingUrlChecker, CheckUrlCallback callback; }; - const std::string headers_; + const net::HttpRequestHeaders headers_; const int load_flags_; const content::ResourceType resource_type_; const bool has_user_gesture_; diff --git a/components/safe_browsing/common/BUILD.gn b/components/safe_browsing/common/BUILD.gn index 6de5638d5bcfcc..7fc71ce008e590 100644 --- a/components/safe_browsing/common/BUILD.gn +++ b/components/safe_browsing/common/BUILD.gn @@ -63,6 +63,7 @@ mojom("interfaces") { public_deps = [ "//content/public/common:resource_type_bindings", + "//services/network/public/interfaces", "//url/mojo:url_mojom_gurl", ] } diff --git a/components/safe_browsing/common/safe_browsing.mojom b/components/safe_browsing/common/safe_browsing.mojom index ee79cb2e9c86c1..fc1a84257637cd 100644 --- a/components/safe_browsing/common/safe_browsing.mojom +++ b/components/safe_browsing/common/safe_browsing.mojom @@ -5,6 +5,7 @@ module safe_browsing.mojom; import "content/public/common/resource_type.mojom"; +import "services/network/public/interfaces/http_request_headers.mojom"; import "url/mojo/url.mojom"; // Provided by the browser and used by renderers to perform SafeBrowsing URL @@ -32,7 +33,7 @@ interface SafeBrowsing { SafeBrowsingUrlChecker& request, url.mojom.Url url, string method, - string headers, + network.mojom.HttpRequestHeaders headers, int32 load_flags, content.mojom.ResourceType resource_type, bool has_user_gesture) => (bool proceed, bool showed_interstitial); diff --git a/components/safe_browsing/renderer/renderer_url_loader_throttle.cc b/components/safe_browsing/renderer/renderer_url_loader_throttle.cc index 32af062814b798..5f299b0ba2c04c 100644 --- a/components/safe_browsing/renderer/renderer_url_loader_throttle.cc +++ b/components/safe_browsing/renderer/renderer_url_loader_throttle.cc @@ -31,10 +31,12 @@ void RendererURLLoaderThrottle::WillStartRequest( pending_checks_++; // Use a weak pointer to self because |safe_browsing_| is not owned by this // object. + net::HttpRequestHeaders headers; + headers.CopyFrom(request.headers); safe_browsing_->CreateCheckerAndCheck( render_frame_id_, mojo::MakeRequest(&url_checker_), request.url, - request.method, request.headers, request.load_flags, - request.resource_type, request.has_user_gesture, + request.method, headers, request.load_flags, request.resource_type, + request.has_user_gesture, base::BindOnce(&RendererURLLoaderThrottle::OnCheckUrlResult, weak_factory_.GetWeakPtr())); safe_browsing_ = nullptr; diff --git a/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc b/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc index 5eb84dcc189b88..78863359f57972 100644 --- a/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc +++ b/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc @@ -15,6 +15,7 @@ #include "content/public/renderer/render_frame.h" #include "ipc/ipc_message.h" #include "mojo/public/cpp/bindings/interface_request.h" +#include "net/http/http_request_headers.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURL.h" @@ -60,7 +61,8 @@ void WebSocketSBHandshakeThrottle::ThrottleHandshake( start_time_ = base::TimeTicks::Now(); safe_browsing_->CreateCheckerAndCheck( render_frame_id, mojo::MakeRequest(&url_checker_), url, "GET", - std::string(), load_flags, content::RESOURCE_TYPE_SUB_RESOURCE, false, + net::HttpRequestHeaders(), load_flags, + content::RESOURCE_TYPE_SUB_RESOURCE, false, base::BindOnce(&WebSocketSBHandshakeThrottle::OnCheckResult, weak_factory_.GetWeakPtr())); diff --git a/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc b/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc index 6a760bb8efed62..d011d27247ac12 100644 --- a/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc +++ b/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc @@ -14,6 +14,7 @@ #include "content/public/common/resource_type.h" #include "ipc/ipc_message.h" #include "mojo/public/cpp/bindings/binding.h" +#include "net/http/http_request_headers.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebString.h" @@ -37,7 +38,7 @@ class FakeSafeBrowsing : public mojom::SafeBrowsing { mojom::SafeBrowsingUrlCheckerRequest request, const GURL& url, const std::string& method, - const std::string& headers, + const net::HttpRequestHeaders& headers, int32_t load_flags, content::ResourceType resource_type, bool has_user_gesture, @@ -60,7 +61,7 @@ class FakeSafeBrowsing : public mojom::SafeBrowsing { mojom::SafeBrowsingUrlCheckerRequest request_; GURL url_; std::string method_; - std::string headers_; + net::HttpRequestHeaders headers_; int32_t load_flags_; content::ResourceType resource_type_; bool has_user_gesture_; @@ -119,7 +120,7 @@ TEST_F(WebSocketSBHandshakeThrottleTest, CheckArguments) { EXPECT_EQ(MSG_ROUTING_NONE, safe_browsing_.render_frame_id_); EXPECT_EQ(GURL(kTestUrl), safe_browsing_.url_); EXPECT_EQ("GET", safe_browsing_.method_); - EXPECT_TRUE(safe_browsing_.headers_.empty()); + EXPECT_TRUE(safe_browsing_.headers_.GetHeaderVector().empty()); EXPECT_EQ(0, safe_browsing_.load_flags_); EXPECT_EQ(content::RESOURCE_TYPE_SUB_RESOURCE, safe_browsing_.resource_type_); EXPECT_FALSE(safe_browsing_.has_user_gesture_); diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc index d91219f363d0fc..05d1c39df9edcf 100644 --- a/content/browser/appcache/appcache_update_job_unittest.cc +++ b/content/browser/appcache/appcache_update_job_unittest.cc @@ -608,9 +608,7 @@ class MockURLLoaderFactory : public mojom::URLLoaderFactory { return; } - net::HttpRequestHeaders request_headers; - request_headers.AddHeadersFromString(url_request.headers); - HttpHeadersRequestTestJob::ValidateExtraHeaders(request_headers); + HttpHeadersRequestTestJob::ValidateExtraHeaders(url_request.headers); std::string headers; std::string body; diff --git a/content/browser/appcache/appcache_update_url_loader_request.cc b/content/browser/appcache/appcache_update_url_loader_request.cc index c6171c38a1f1f9..ae46c3ca297019 100644 --- a/content/browser/appcache/appcache_update_url_loader_request.cc +++ b/content/browser/appcache/appcache_update_url_loader_request.cc @@ -30,7 +30,7 @@ void AppCacheUpdateJob::UpdateURLLoaderRequest::Start() { void AppCacheUpdateJob::UpdateURLLoaderRequest::SetExtraRequestHeaders( const net::HttpRequestHeaders& headers) { - request_.headers = headers.ToString(); + request_.headers = headers; } GURL AppCacheUpdateJob::UpdateURLLoaderRequest::GetURL() const { diff --git a/content/browser/appcache/appcache_url_loader_job.cc b/content/browser/appcache/appcache_url_loader_job.cc index 74591da9b3952d..0dddb4be63043e 100644 --- a/content/browser/appcache/appcache_url_loader_job.cc +++ b/content/browser/appcache/appcache_url_loader_job.cc @@ -59,9 +59,7 @@ void AppCacheURLLoaderJob::DeliverAppCachedResponse(const GURL& manifest_url, is_fallback_ = is_fallback; // Handle range requests. - net::HttpRequestHeaders headers; - headers.AddHeadersFromString(request_.headers); - InitializeRangeRequestInfo(headers); + InitializeRangeRequestInfo(request_.headers); // TODO(ananta) // Implement the AppCacheServiceImpl::Observer interface or add weak pointer diff --git a/content/browser/blob_storage/blob_url_loader_factory.cc b/content/browser/blob_storage/blob_url_loader_factory.cc index e4d165545c3b19..a783374b447457 100644 --- a/content/browser/blob_storage/blob_url_loader_factory.cc +++ b/content/browser/blob_storage/blob_url_loader_factory.cc @@ -76,10 +76,8 @@ class BlobURLLoader : public storage::MojoBlobReader::Delegate, return; } - net::HttpRequestHeaders request_headers; - request_headers.AddHeadersFromString(request.headers); std::string range_header; - if (request_headers.GetHeader(net::HttpRequestHeaders::kRange, + if (request.headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { // We only care about "Range" header here. std::vector ranges; diff --git a/content/browser/blob_storage/blob_url_unittest.cc b/content/browser/blob_storage/blob_url_unittest.cc index da49844e97d06d..dbfa815e6b80b2 100644 --- a/content/browser/blob_storage/blob_url_unittest.cc +++ b/content/browser/blob_storage/blob_url_unittest.cc @@ -277,8 +277,7 @@ class BlobURLRequestJobTest : public testing::TestWithParam { ResourceRequest request; request.url = url; request.method = method; - if (!extra_headers.IsEmpty()) - request.headers = extra_headers.ToString(); + request.headers = extra_headers; mojom::URLLoaderPtr url_loader; TestURLLoaderClient url_loader_client; diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc index 8b406dc568da7f..a7970f9fec4268 100644 --- a/content/browser/devtools/protocol/network_handler.cc +++ b/content/browser/devtools/protocol/network_handler.cc @@ -788,9 +788,7 @@ void NetworkHandler::NavigationPreloadRequestSent( return; const std::string version_id(base::IntToString(worker_version_id)); std::unique_ptr headers_dict(DictionaryValue::create()); - net::HttpRequestHeaders headers; - headers.AddHeadersFromString(request.headers); - for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext();) + for (net::HttpRequestHeaders::Iterator it(request.headers); it.GetNext();) headers_dict->setString(it.name(), it.value()); frontend_->RequestWillBeSent( request_id, "" /* loader_id */, request.url.spec(), diff --git a/content/browser/download/download_utils.cc b/content/browser/download/download_utils.cc index 319a3fa09f4449..bb824e754bf3fe 100644 --- a/content/browser/download/download_utils.cc +++ b/content/browser/download/download_utils.cc @@ -212,8 +212,7 @@ std::unique_ptr CreateResourceRequest( // Add additional request headers. std::unique_ptr headers = GetAdditionalRequestHeaders(params); - if (!headers->IsEmpty()) - request->headers = headers->ToString(); + request->headers.Swap(headers.get()); return request; } diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc index 8a9139cc0c5323..2c04b2cd13cd6b 100644 --- a/content/browser/loader/navigation_url_loader_network_service.cc +++ b/content/browser/loader/navigation_url_loader_network_service.cc @@ -436,7 +436,7 @@ NavigationURLLoaderNetworkService::NavigationURLLoaderNetworkService( new_request->request_initiator = request_info->begin_params.initiator_origin; new_request->referrer = request_info->common_params.referrer.url; new_request->referrer_policy = request_info->common_params.referrer.policy; - new_request->headers = request_info->begin_params.headers; + new_request->headers.AddHeadersFromString(request_info->begin_params.headers); int load_flags = request_info->begin_params.load_flags; load_flags |= net::LOAD_VERIFY_EV_CERT; diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index a3ae030d861dd0..8014945301d5ff 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc @@ -1166,12 +1166,9 @@ void ResourceDispatcherHostImpl::BeginRequest( // Parse the headers before calling ShouldServiceRequest, so that they are // available to be validated. - net::HttpRequestHeaders headers; - headers.AddHeadersFromString(request_data.headers); - if (is_shutdown_ || - !ShouldServiceRequest(child_id, request_data, headers, requester_info, - resource_context)) { + !ShouldServiceRequest(child_id, request_data, request_data.headers, + requester_info, resource_context)) { AbortRequestBeforeItStarts(requester_info->filter(), sync_result_handler, request_id, std::move(url_loader_client)); return; @@ -1204,7 +1201,8 @@ void ResourceDispatcherHostImpl::BeginRequest( // yes then we need to mark the current request as pending and wait for the // interceptor to invoke the callback with a status code indicating whether // the request needs to be aborted or continued. - for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext();) { + for (net::HttpRequestHeaders::Iterator it(request_data.headers); + it.GetNext();) { HeaderInterceptorMap::iterator index = http_header_interceptor_map_.find(it.name()); if (index != http_header_interceptor_map_.end()) { @@ -1223,7 +1221,8 @@ void ResourceDispatcherHostImpl::BeginRequest( &ResourceDispatcherHostImpl::ContinuePendingBeginRequest, base::Unretained(this), make_scoped_refptr(requester_info), request_id, request_data, is_sync_load, sync_result_handler, - route_id, headers, base::Passed(std::move(mojo_request)), + route_id, request_data.headers, + base::Passed(std::move(mojo_request)), base::Passed(std::move(url_loader_client)), base::Passed(std::move(blob_handles)), traffic_annotation)); return; @@ -1231,11 +1230,12 @@ void ResourceDispatcherHostImpl::BeginRequest( } } } - ContinuePendingBeginRequest( - requester_info, request_id, request_data, is_sync_load, - sync_result_handler, route_id, headers, std::move(mojo_request), - std::move(url_loader_client), std::move(blob_handles), traffic_annotation, - HeaderInterceptorResult::CONTINUE); + ContinuePendingBeginRequest(requester_info, request_id, request_data, + is_sync_load, sync_result_handler, route_id, + request_data.headers, std::move(mojo_request), + std::move(url_loader_client), + std::move(blob_handles), traffic_annotation, + HeaderInterceptorResult::CONTINUE); } void ResourceDispatcherHostImpl::ContinuePendingBeginRequest( diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc index 241fcb550ffd48..95023029e755aa 100644 --- a/content/browser/security_exploit_browsertest.cc +++ b/content/browser/security_exploit_browsertest.cc @@ -139,7 +139,7 @@ ResourceRequest CreateXHRRequest(const char* url) { ResourceRequest CreateXHRRequestWithOrigin(const char* origin) { ResourceRequest request = CreateXHRRequest("http://bar.com/simple_page.html"); request.site_for_cookies = GURL(origin); - request.headers = base::StringPrintf("Origin: %s\r\n", origin); + request.headers.SetHeader(net::HttpRequestHeaders::kOrigin, origin); return request; } diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc index 19acfff5e20961..8be993b349657e 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler.cc +++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc @@ -213,9 +213,7 @@ void ServiceWorkerControlleeRequestHandler::MaybeCreateLoader( #if BUILDFLAG(ENABLE_OFFLINE_PAGES) // Fall back for the subsequent offline page interceptor to load the offline // snapshot of the page if required. - net::HttpRequestHeaders extra_request_headers; - extra_request_headers.AddHeadersFromString(resource_request.headers); - if (ShouldFallbackToLoadOfflinePage(extra_request_headers)) { + if (ShouldFallbackToLoadOfflinePage(resource_request.headers)) { std::move(callback).Run(StartLoaderCallback()); return; } diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc index 4e01ed4df0a20d..d4ffc47b385579 100644 --- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc +++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc @@ -654,9 +654,9 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload( version_->navigation_preload_state().header)); ServiceWorkerMetrics::RecordNavigationPreloadRequestHeaderSize( version_->navigation_preload_state().header.length()); - request.headers = "Service-Worker-Navigation-Preload: " + - version_->navigation_preload_state().header + "\r\n" + - original_request->extra_request_headers().ToString(); + request.headers.CopyFrom(original_request->extra_request_headers()); + request.headers.SetHeader("Service-Worker-Navigation-Preload", + version_->navigation_preload_state().header); const int request_id = ResourceDispatcherHostImpl::Get()->MakeRequestID(); DCHECK_LT(request_id, -1); diff --git a/content/browser/webui/web_ui_url_loader_factory.cc b/content/browser/webui/web_ui_url_loader_factory.cc index 3c49b85b04747f..82382f3806d159 100644 --- a/content/browser/webui/web_ui_url_loader_factory.cc +++ b/content/browser/webui/web_ui_url_loader_factory.cc @@ -156,10 +156,8 @@ void StartURLLoader(const ResourceRequest& request, std::string path; URLDataManagerBackend::URLToRequestPath(request.url, &path); - net::HttpRequestHeaders request_headers; - request_headers.AddHeadersFromString(request.headers); std::string origin_header; - request_headers.GetHeader(net::HttpRequestHeaders::kOrigin, &origin_header); + request.headers.GetHeader(net::HttpRequestHeaders::kOrigin, &origin_header); scoped_refptr headers = URLDataManagerBackend::GetHeaders(source, path, origin_header); diff --git a/content/child/web_url_request_util.cc b/content/child/web_url_request_util.cc index ce7efdab59b503..1081d7c137147e 100644 --- a/content/child/web_url_request_util.cc +++ b/content/child/web_url_request_util.cc @@ -14,6 +14,7 @@ #include "content/child/request_extra_data.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" +#include "net/http/http_util.h" #include "third_party/WebKit/public/platform/FilePathConversion.h" #include "third_party/WebKit/public/platform/WebCachePolicy.h" #include "third_party/WebKit/public/platform/WebData.h" @@ -31,6 +32,39 @@ namespace content { namespace { +std::string TrimLWSAndCRLF(const base::StringPiece& input) { + base::StringPiece string = net::HttpUtil::TrimLWS(input); + const char* begin = string.data(); + const char* end = string.data() + string.size(); + while (begin < end && (end[-1] == '\r' || end[-1] == '\n')) + --end; + return std::string(base::StringPiece(begin, end - begin)); +} + +class HttpRequestHeadersVisitor : public blink::WebHTTPHeaderVisitor { + public: + explicit HttpRequestHeadersVisitor(net::HttpRequestHeaders* headers) + : headers_(headers) {} + ~HttpRequestHeadersVisitor() override = default; + + void VisitHeader(const WebString& name, const WebString& value) override { + std::string name_latin1 = name.Latin1(); + std::string value_latin1 = TrimLWSAndCRLF(value.Latin1()); + + // Skip over referrer headers found in the header map because we already + // pulled it out as a separate parameter. + if (base::LowerCaseEqualsASCII(name_latin1, "referer")) + return; + + DCHECK(net::HttpUtil::IsValidHeaderName(name_latin1)) << name_latin1; + DCHECK(net::HttpUtil::IsValidHeaderValue(value_latin1)) << value_latin1; + headers_->SetHeader(name_latin1, value_latin1); + } + + private: + net::HttpRequestHeaders* const headers_; +}; + class HeaderFlattener : public blink::WebHTTPHeaderVisitor { public: HeaderFlattener() {} @@ -180,7 +214,16 @@ ResourceType WebURLRequestToResourceType(const WebURLRequest& request) { return WebURLRequestContextToResourceType(request_context); } -std::string GetWebURLRequestHeaders(const WebURLRequest& request) { +net::HttpRequestHeaders GetWebURLRequestHeaders( + const blink::WebURLRequest& request) { + net::HttpRequestHeaders headers; + HttpRequestHeadersVisitor visitor(&headers); + request.VisitHTTPHeaderFields(&visitor); + return headers; +} + +std::string GetWebURLRequestHeadersAsString( + const blink::WebURLRequest& request) { HeaderFlattener flattener; request.VisitHTTPHeaderFields(&flattener); return flattener.GetBuffer(); diff --git a/content/child/web_url_request_util.h b/content/child/web_url_request_util.h index 77c92cc86881fe..f7f8a8839f53b5 100644 --- a/content/child/web_url_request_util.h +++ b/content/child/web_url_request_util.h @@ -13,6 +13,7 @@ #include "content/public/common/resource_request_body.h" #include "content/public/common/resource_type.h" #include "content/public/common/service_worker_modes.h" +#include "net/http/http_request_headers.h" #include "third_party/WebKit/public/platform/WebMixedContentContextType.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" @@ -28,7 +29,11 @@ ResourceType WebURLRequestContextToResourceType( CONTENT_EXPORT ResourceType WebURLRequestToResourceType( const blink::WebURLRequest& request); -std::string GetWebURLRequestHeaders(const blink::WebURLRequest& request); +net::HttpRequestHeaders GetWebURLRequestHeaders( + const blink::WebURLRequest& request); + +std::string GetWebURLRequestHeadersAsString( + const blink::WebURLRequest& request); int GetLoadFlagsForWebURLRequest(const blink::WebURLRequest& request); diff --git a/content/network/url_loader_impl.cc b/content/network/url_loader_impl.cc index 40e38e5616fbd8..c6f6a6cf43b251 100644 --- a/content/network/url_loader_impl.cc +++ b/content/network/url_loader_impl.cc @@ -192,9 +192,7 @@ URLLoaderImpl::URLLoaderImpl( const Referrer referrer(request.referrer, request.referrer_policy); Referrer::SetReferrerForRequest(url_request_.get(), referrer); - net::HttpRequestHeaders headers; - headers.AddHeadersFromString(request.headers); - url_request_->SetExtraRequestHeaders(headers); + url_request_->SetExtraRequestHeaders(request.headers); // Resolve elements from request_body and prepare upload data. if (request.request_body.get()) { diff --git a/content/public/common/common_param_traits.cc b/content/public/common/common_param_traits.cc index 2a990c4c3119f0..281c1c29350016 100644 --- a/content/public/common/common_param_traits.cc +++ b/content/public/common/common_param_traits.cc @@ -13,6 +13,8 @@ #include "net/base/host_port_pair.h" #include "net/base/ip_address.h" #include "net/base/ip_endpoint.h" +#include "net/http/http_request_headers.h" +#include "net/http/http_util.h" namespace IPC { @@ -94,6 +96,43 @@ void ParamTraits::Log(const param_type& p, std::string* l) { l->append(p.ToString()); } +void ParamTraits::GetSize(base::PickleSizer* s, + const param_type& p) { + GetParamSize(s, static_cast(p.GetHeaderVector().size())); + for (size_t i = 0; i < p.GetHeaderVector().size(); ++i) + GetParamSize(s, p.GetHeaderVector()[i]); +} + +void ParamTraits::Write(base::Pickle* m, + const param_type& p) { + WriteParam(m, static_cast(p.GetHeaderVector().size())); + for (size_t i = 0; i < p.GetHeaderVector().size(); ++i) + WriteParam(m, p.GetHeaderVector()[i]); +} + +bool ParamTraits::Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r) { + // Sanity check. + int size; + if (!iter->ReadLength(&size)) + return false; + for (int i = 0; i < size; ++i) { + net::HttpRequestHeaders::HeaderKeyValuePair pair; + if (!ReadParam(m, iter, &pair) || + !net::HttpUtil::IsValidHeaderName(pair.key) || + !net::HttpUtil::IsValidHeaderValue(pair.value)) + return false; + r->SetHeader(pair.key, pair.value); + } + return true; +} + +void ParamTraits::Log(const param_type& p, + std::string* l) { + l->append(p.ToString()); +} + void ParamTraits::GetSize(base::PickleSizer* s, const param_type& p) { GetParamSize(s, p.address()); diff --git a/content/public/common/common_param_traits.h b/content/public/common/common_param_traits.h index 86659951f75208..3dcbcea77fc357 100644 --- a/content/public/common/common_param_traits.h +++ b/content/public/common/common_param_traits.h @@ -38,6 +38,7 @@ class PageState; namespace net { class HostPortPair; +class HttpRequestHeaders; class IPAddress; class IPEndPoint; } @@ -66,6 +67,17 @@ struct CONTENT_EXPORT ParamTraits { static void Log(const param_type& p, std::string* l); }; +template <> +struct CONTENT_EXPORT ParamTraits { + typedef net::HttpRequestHeaders param_type; + static void GetSize(base::PickleSizer* s, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); + static void Log(const param_type& p, std::string* l); +}; + template <> struct CONTENT_EXPORT ParamTraits { typedef net::IPEndPoint param_type; diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h index f0df22851a1c51..074c17220e9786 100644 --- a/content/public/common/common_param_traits_macros.h +++ b/content/public/common/common_param_traits_macros.h @@ -16,6 +16,7 @@ #include "ipc/ipc_message_macros.h" #include "net/base/network_change_notifier.h" #include "net/base/request_priority.h" +#include "net/http/http_request_headers.h" #include "net/nqe/effective_connection_type.h" #include "third_party/WebKit/public/platform/WebPoint.h" #include "third_party/WebKit/public/platform/WebRect.h" @@ -290,4 +291,9 @@ IPC_STRUCT_TRAITS_BEGIN(ui::AXRelativeBounds) IPC_STRUCT_TRAITS_MEMBER(transform) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_TRAITS_BEGIN(net::HttpRequestHeaders::HeaderKeyValuePair) + IPC_STRUCT_TRAITS_MEMBER(key) + IPC_STRUCT_TRAITS_MEMBER(value) +IPC_STRUCT_TRAITS_END() + #endif // CONTENT_PUBLIC_COMMON_COMMON_PARAM_TRAITS_MACROS_H_ diff --git a/content/public/common/resource_request.h b/content/public/common/resource_request.h index f776dfc97ed2f9..f5fb4e3d47846c 100644 --- a/content/public/common/resource_request.h +++ b/content/public/common/resource_request.h @@ -18,6 +18,7 @@ #include "content/public/common/resource_type.h" #include "content/public/common/service_worker_modes.h" #include "net/base/request_priority.h" +#include "net/http/http_request_headers.h" #include "third_party/WebKit/public/platform/WebMixedContentContextType.h" #include "third_party/WebKit/public/platform/WebPageVisibilityState.h" #include "third_party/WebKit/public/platform/WebReferrerPolicy.h" @@ -61,12 +62,7 @@ struct CONTENT_EXPORT ResourceRequest { blink::kWebPageVisibilityStateVisible; // Additional HTTP request headers. - // - // For HTTP(S) requests, the headers parameter can be a \r\n-delimited and - // \r\n-terminated list of MIME headers. They should be ASCII-encoded using - // the standard MIME header encoding rules. The headers parameter can also - // be null if no extra request headers need to be set. - std::string headers; + net::HttpRequestHeaders headers; // net::URLRequest load flags (0 by default). int load_flags = 0; diff --git a/content/public/common/simple_url_loader_unittest.cc b/content/public/common/simple_url_loader_unittest.cc index 6e43aad46fd291..00460a94277ada 100644 --- a/content/public/common/simple_url_loader_unittest.cc +++ b/content/public/common/simple_url_loader_unittest.cc @@ -239,7 +239,7 @@ TEST_F(SimpleURLLoaderTest, BasicRequest) { // Use a more interesting request than "/echo", just to verify more than the // request URL is hooked up. resource_request.url = test_server_.GetURL("/echoheader?foo"); - resource_request.headers = "foo: Expected Response"; + resource_request.headers.SetHeader("foo", "Expected Response"); WaitForStringHelper string_helper; string_helper.RunRequest(url_loader_factory_.get(), resource_request); diff --git a/content/renderer/fetchers/resource_fetcher_impl.cc b/content/renderer/fetchers/resource_fetcher_impl.cc index 9e19b19b2c0bdf..29c1899bb212a0 100644 --- a/content/renderer/fetchers/resource_fetcher_impl.cc +++ b/content/renderer/fetchers/resource_fetcher_impl.cc @@ -279,7 +279,7 @@ void ResourceFetcherImpl::SetHeader(const std::string& header, DCHECK(request_.referrer.is_valid()); request_.referrer_policy = blink::kWebReferrerPolicyDefault; } else { - headers_.SetHeader(header, value); + request_.headers.SetHeader(header, value); } } @@ -344,9 +344,6 @@ void ResourceFetcherImpl::Start( SetHeader(kAccessControlAllowOriginHeader, blink::WebSecurityOrigin::CreateUnique().ToString().Ascii()); } - if (!headers_.IsEmpty()) - request_.headers = headers_.ToString(); - request_.resource_type = WebURLRequestContextToResourceType(request_context); client_ = base::MakeUnique(this, callback, maximum_download_size); diff --git a/content/renderer/fetchers/resource_fetcher_impl.h b/content/renderer/fetchers/resource_fetcher_impl.h index ec91621924260a..74a8cefae29904 100644 --- a/content/renderer/fetchers/resource_fetcher_impl.h +++ b/content/renderer/fetchers/resource_fetcher_impl.h @@ -60,11 +60,6 @@ class ResourceFetcherImpl : public ResourceFetcher { // Request to send. ResourceRequest request_; - // HTTP headers to build a header string for |request_|. - // TODO(toyoshim): Remove this member once ResourceRequest uses - // net::HttpRequestHeaders instead of std::string for headers. - net::HttpRequestHeaders headers_; - // Limit how long to wait for the server. base::OneShotTimer timeout_timer_; diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 7fc594620793bf..66e30fc4379b76 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -5983,7 +5983,7 @@ void RenderFrameImpl::OpenURL(const NavigationPolicyInfo& info, params.uses_post = IsHttpPost(info.url_request); params.resource_request_body = GetRequestBodyForWebURLRequest(info.url_request); - params.extra_headers = GetWebURLRequestHeaders(info.url_request); + params.extra_headers = GetWebURLRequestHeadersAsString(info.url_request); params.referrer = send_referrer ? RenderViewImpl::GetReferrerFromRequest( frame_, info.url_request) : content::Referrer(); @@ -6469,7 +6469,7 @@ void RenderFrameImpl::BeginNavigation(const NavigationPolicyInfo& info) { info.navigation_type == blink::kWebNavigationTypeFormResubmitted; BeginNavigationParams begin_navigation_params( - GetWebURLRequestHeaders(info.url_request), load_flags, + GetWebURLRequestHeadersAsString(info.url_request), load_flags, info.url_request.HasUserGesture(), info.url_request.GetServiceWorkerMode() != blink::WebURLRequest::ServiceWorkerMode::kAll, diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc index c754839797661e..fd083b0fa60cbb 100644 --- a/content/renderer/render_frame_proxy.cc +++ b/content/renderer/render_frame_proxy.cc @@ -535,7 +535,7 @@ void RenderFrameProxy::Navigate(const blink::WebURLRequest& request, params.url = request.Url(); params.uses_post = request.HttpMethod().Utf8() == "POST"; params.resource_request_body = GetRequestBodyForWebURLRequest(request); - params.extra_headers = GetWebURLRequestHeaders(request); + params.extra_headers = GetWebURLRequestHeadersAsString(request); params.referrer = Referrer(blink::WebStringToGURL(request.HttpHeaderField( blink::WebString::FromUTF8("Referer"))), request.GetReferrerPolicy()); diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni index 6fe236dcf45371..976edf30688ab2 100644 --- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni +++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni @@ -30,6 +30,7 @@ _typemap_imports = [ "//net/interfaces/typemaps.gni", "//services/device/public/interfaces/typemaps.gni", "//services/identity/public/cpp/typemaps.gni", + "//services/network/public/cpp/typemaps.gni", "//services/preferences/public/cpp/typemaps.gni", "//services/resource_coordinator/public/cpp/typemaps.gni", "//services/service_manager/public/cpp/typemaps.gni", diff --git a/net/http/http_request_headers.cc b/net/http/http_request_headers.cc index b2fec436b08504..65659b4c219812 100644 --- a/net/http/http_request_headers.cc +++ b/net/http/http_request_headers.cc @@ -94,13 +94,9 @@ void HttpRequestHeaders::Clear() { void HttpRequestHeaders::SetHeader(const base::StringPiece& key, const base::StringPiece& value) { - DCHECK(HttpUtil::IsValidHeaderName(key)); - DCHECK(HttpUtil::IsValidHeaderValue(value)); - HeaderVector::iterator it = FindHeader(key); - if (it != headers_.end()) - it->value.assign(value.data(), value.size()); - else - headers_.push_back(HeaderKeyValuePair(key, value)); + DCHECK(HttpUtil::IsValidHeaderName(key)) << key; + DCHECK(HttpUtil::IsValidHeaderValue(value)) << key << ":" << value; + SetHeaderInternal(key, value); } void HttpRequestHeaders::SetHeaderIfMissing(const base::StringPiece& key, @@ -229,4 +225,13 @@ HttpRequestHeaders::FindHeader(const base::StringPiece& key) const { return headers_.end(); } +void HttpRequestHeaders::SetHeaderInternal(const base::StringPiece& key, + const base::StringPiece& value) { + HeaderVector::iterator it = FindHeader(key); + if (it != headers_.end()) + it->value.assign(value.data(), value.size()); + else + headers_.push_back(HeaderKeyValuePair(key, value)); +} + } // namespace net diff --git a/net/http/http_request_headers.h b/net/http/http_request_headers.h index 3c8a46ce796390..c246f4f10c86ba 100644 --- a/net/http/http_request_headers.h +++ b/net/http/http_request_headers.h @@ -28,7 +28,7 @@ class NetLogCaptureMode; class NET_EXPORT HttpRequestHeaders { public: - struct HeaderKeyValuePair { + struct NET_EXPORT HeaderKeyValuePair { HeaderKeyValuePair(); HeaderKeyValuePair(const base::StringPiece& key, const base::StringPiece& value); @@ -112,6 +112,12 @@ class NET_EXPORT HttpRequestHeaders { // |value| passes HttpUtil::IsValidHeaderValue(). void SetHeader(const base::StringPiece& key, const base::StringPiece& value); + // Does the same as above but without internal DCHECKs for validations. + void SetHeaderWithoutCheckForTesting(const base::StringPiece& key, + const base::StringPiece& value) { + SetHeaderInternal(key, value); + } + // Sets the header value pair for |key| and |value|, if |key| does not exist. // If |key| already exists, the call is a no-op. // When comparing |key|, case is ignored. @@ -167,10 +173,15 @@ class NET_EXPORT HttpRequestHeaders { const std::string* request_line, NetLogCaptureMode capture_mode) const; + const HeaderVector& GetHeaderVector() const { return headers_; } + private: HeaderVector::iterator FindHeader(const base::StringPiece& key); HeaderVector::const_iterator FindHeader(const base::StringPiece& key) const; + void SetHeaderInternal(const base::StringPiece& key, + const base::StringPiece& value); + HeaderVector headers_; // Allow the copy construction and operator= to facilitate copying in diff --git a/services/BUILD.gn b/services/BUILD.gn index 36ede309438141..cc25a7a01122b5 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -19,6 +19,7 @@ service_test("services_unittests") { # section below. If you are unsure, contact blundell@chromium.org. deps = [ "//services/identity:tests", + "//services/network/public/cpp:tests", ] if (!is_ios) { diff --git a/services/network/public/cpp/BUILD.gn b/services/network/public/cpp/BUILD.gn index cc1393612c445d..65b5ac6377d61c 100644 --- a/services/network/public/cpp/BUILD.gn +++ b/services/network/public/cpp/BUILD.gn @@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//mojo/public/tools/bindings/mojom.gni") + static_library("cpp") { sources = [ "net_adapters.cc", @@ -14,3 +16,27 @@ static_library("cpp") { "//net", ] } + +mojom("test_interfaces") { + sources = [ + "network_traits_test_service.mojom", + ] + public_deps = [ + "//services/network/public/interfaces", + ] +} + +source_set("tests") { + testonly = true + + sources = [ + "network_struct_traits_unittest.cc", + ] + deps = [ + ":test_interfaces", + "//base", + "//mojo/public/cpp/bindings", + "//net", + "//testing/gtest", + ] +} diff --git a/services/network/public/cpp/OWNERS b/services/network/public/cpp/OWNERS new file mode 100644 index 00000000000000..2c44a463856dd1 --- /dev/null +++ b/services/network/public/cpp/OWNERS @@ -0,0 +1,6 @@ +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS +per-file *_struct_traits*.*=set noparent +per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS +per-file *.typemap=set noparent +per-file *.typemap=file://ipc/SECURITY_OWNERS diff --git a/services/network/public/cpp/http_request_headers.typemap b/services/network/public/cpp/http_request_headers.typemap new file mode 100644 index 00000000000000..90c8e67ba2af86 --- /dev/null +++ b/services/network/public/cpp/http_request_headers.typemap @@ -0,0 +1,15 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +mojom = "//services/network/public/interfaces/http_request_headers.mojom" +public_headers = [ "//net/http/http_request_headers.h" ] +traits_headers = + [ "//services/network/public/cpp/http_request_headers_struct_traits.h" ] +sources = [ + "//services/network/public/cpp/http_request_headers_struct_traits.cc", +] +public_deps = [ + "//net", +] +type_mappings = [ "network.mojom.HttpRequestHeaders=net::HttpRequestHeaders" ] diff --git a/services/network/public/cpp/http_request_headers_struct_traits.cc b/services/network/public/cpp/http_request_headers_struct_traits.cc new file mode 100644 index 00000000000000..5debd751aa918d --- /dev/null +++ b/services/network/public/cpp/http_request_headers_struct_traits.cc @@ -0,0 +1,45 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/network/public/cpp/http_request_headers_struct_traits.h" + +#include "net/http/http_util.h" + +namespace mojo { + +// static +bool StructTraits:: + Read(network::mojom::HttpRequestHeaderKeyValuePairDataView data, + net::HttpRequestHeaders::HeaderKeyValuePair* item) { + if (!data.ReadKey(&item->key)) + return false; + if (!net::HttpUtil::IsValidHeaderName(item->key)) + return false; + if (!data.ReadValue(&item->value)) + return false; + item->value = std::string(net::HttpUtil::TrimLWS(item->value)); + if (!net::HttpUtil::IsValidHeaderValue(item->value)) + return false; + return true; +} + +// static +bool StructTraits:: + Read(network::mojom::HttpRequestHeadersDataView data, + net::HttpRequestHeaders* headers) { + ArrayDataView + data_view; + data.GetHeadersDataView(&data_view); + for (size_t i = 0; i < data_view.size(); ++i) { + net::HttpRequestHeaders::HeaderKeyValuePair pair; + if (!data_view.Read(i, &pair)) + return false; + headers->SetHeader(pair.key, pair.value); + } + return true; +} + +} // namespace mojo diff --git a/services/network/public/cpp/http_request_headers_struct_traits.h b/services/network/public/cpp/http_request_headers_struct_traits.h new file mode 100644 index 00000000000000..07b17356c3f87e --- /dev/null +++ b/services/network/public/cpp/http_request_headers_struct_traits.h @@ -0,0 +1,42 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_NETWORK_PUBLIC_CPP_HTTP_REQUEST_HEADERS_STRUCT_TRAITS_H_ +#define SERVICES_NETWORK_PUBLIC_CPP_HTTP_REQUEST_HEADERS_STRUCT_TRAITS_H_ + +#include "mojo/public/cpp/bindings/struct_traits.h" +#include "net/http/http_request_headers.h" +#include "services/network/public/interfaces/http_request_headers.mojom.h" + +namespace mojo { + +template <> +struct StructTraits { + static const std::string& key( + const net::HttpRequestHeaders::HeaderKeyValuePair& item) { + return item.key; + } + static const std::string& value( + const net::HttpRequestHeaders::HeaderKeyValuePair& item) { + return item.value; + } + static bool Read(network::mojom::HttpRequestHeaderKeyValuePairDataView data, + net::HttpRequestHeaders::HeaderKeyValuePair* item); +}; + +template <> +struct StructTraits { + static net::HttpRequestHeaders::HeaderVector headers( + const net::HttpRequestHeaders& data) { + return data.GetHeaderVector(); + } + static bool Read(network::mojom::HttpRequestHeadersDataView data, + net::HttpRequestHeaders* headers); +}; + +} // namespace mojo + +#endif // SERVICES_NETWORK_PUBLIC_CPP_HTTP_REQUEST_HEADERS_STRUCT_TRAITS_H_ diff --git a/services/network/public/cpp/network_struct_traits_unittest.cc b/services/network/public/cpp/network_struct_traits_unittest.cc new file mode 100644 index 00000000000000..2acaf6c5d36116 --- /dev/null +++ b/services/network/public/cpp/network_struct_traits_unittest.cc @@ -0,0 +1,110 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/message_loop/message_loop.h" +#include "base/strings/string_util.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "services/network/public/cpp/http_request_headers_struct_traits.h" +#include "services/network/public/cpp/network_traits_test_service.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace network { + +namespace { + +class NetworkStructTraitsTest : public testing::Test, + public mojom::TraitsTestService { + protected: + NetworkStructTraitsTest() = default; + + mojom::TraitsTestServicePtr GetTraitsTestProxy() { + mojom::TraitsTestServicePtr proxy; + traits_test_bindings_.AddBinding(this, mojo::MakeRequest(&proxy)); + return proxy; + } + + private: + // TraitsTestService: + void EchoHttpRequestHeaders( + const net::HttpRequestHeaders& header, + EchoHttpRequestHeadersCallback callback) override { + std::move(callback).Run(header); + } + + base::MessageLoop loop_; + mojo::BindingSet traits_test_bindings_; + DISALLOW_COPY_AND_ASSIGN(NetworkStructTraitsTest); +}; + +} // namespace + +TEST_F(NetworkStructTraitsTest, HttpRequestHeaders_Basic) { + net::HttpRequestHeaders headers; + net::HttpRequestHeaders output; + headers.SetHeader("Foo", "bar"); + mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); + proxy->EchoHttpRequestHeaders(headers, &output); + std::string value; + EXPECT_TRUE(output.GetHeader("Foo", &value)); + EXPECT_EQ("bar", value); + EXPECT_FALSE(output.HasHeader("Fo")); +} + +TEST_F(NetworkStructTraitsTest, HttpRequestHeaders_InvalidHeaderName) { + // Check that non-token chars are disallowed. + const unsigned char invalid_name_chars[] = { + 0x80, 0x19, '(', ')', '<', '>', '@', ',', ';', ':', + '\\', '"', '/', '[', ']', '?', '=', '{', '}'}; + for (char c : invalid_name_chars) { + std::string invalid_name("foo"); + invalid_name.push_back(c); + net::HttpRequestHeaders header; + net::HttpRequestHeaders output; + header.SetHeaderWithoutCheckForTesting(invalid_name, "foo"); + mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); + proxy->EchoHttpRequestHeaders(header, &output); + std::string value; + EXPECT_TRUE(output.IsEmpty()); + } +} + +// Test cases are copied from HttpUtilTest.IsValidHeaderValue. +TEST_F(NetworkStructTraitsTest, HttpRequestHeaders_InvalidHeaderValue) { + const char* const invalid_values[] = { + "X-Requested-With: chrome${NUL}Sec-Unsafe: injected", + "X-Requested-With: chrome\r\nSec-Unsafe: injected", + "X-Requested-With: chrome\nSec-Unsafe: injected", + "X-Requested-With: chrome\rSec-Unsafe: injected", + }; + + for (const std::string& value : invalid_values) { + std::string replaced = value; + base::ReplaceSubstringsAfterOffset(&replaced, 0, "${NUL}", + std::string(1, '\0')); + net::HttpRequestHeaders header; + net::HttpRequestHeaders output; + header.SetHeaderWithoutCheckForTesting("Foo", replaced); + mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); + proxy->EchoHttpRequestHeaders(header, &output); + EXPECT_FALSE(output.HasHeader("Foo")); + } + + // Check that all characters permitted by RFC7230 3.2.6 are allowed. + std::string allowed = "\t"; + for (char c = '\x20'; c < '\x7F'; ++c) { + allowed.append(1, c); + } + for (int c = 0x80; c <= 0xFF; ++c) { + allowed.append(1, static_cast(c)); + } + + net::HttpRequestHeaders header; + net::HttpRequestHeaders output; + header.SetHeaderWithoutCheckForTesting("Foo", allowed); + mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); + proxy->EchoHttpRequestHeaders(header, &output); + EXPECT_TRUE(output.HasHeader("Foo")); +} + +} // namespace network diff --git a/services/network/public/cpp/network_traits_test_service.mojom b/services/network/public/cpp/network_traits_test_service.mojom new file mode 100644 index 00000000000000..ab8dae7e6e089f --- /dev/null +++ b/services/network/public/cpp/network_traits_test_service.mojom @@ -0,0 +1,12 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module network.mojom; + +import "services/network/public/interfaces/http_request_headers.mojom"; + +interface TraitsTestService { + [Sync] + EchoHttpRequestHeaders(HttpRequestHeaders headers) => (HttpRequestHeaders pass); +}; diff --git a/services/network/public/cpp/typemaps.gni b/services/network/public/cpp/typemaps.gni new file mode 100644 index 00000000000000..91ef4571ea4a85 --- /dev/null +++ b/services/network/public/cpp/typemaps.gni @@ -0,0 +1,5 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +typemaps = [ "//services/network/public/cpp/http_request_headers.typemap" ] diff --git a/services/network/public/interfaces/BUILD.gn b/services/network/public/interfaces/BUILD.gn index f89b5a861916a5..8df1de01625728 100644 --- a/services/network/public/interfaces/BUILD.gn +++ b/services/network/public/interfaces/BUILD.gn @@ -7,5 +7,6 @@ import("//mojo/public/tools/bindings/mojom.gni") mojom("interfaces") { sources = [ "fetch_api.mojom", + "http_request_headers.mojom", ] } diff --git a/services/network/public/interfaces/http_request_headers.mojom b/services/network/public/interfaces/http_request_headers.mojom new file mode 100644 index 00000000000000..5e38006e3e1cb7 --- /dev/null +++ b/services/network/public/interfaces/http_request_headers.mojom @@ -0,0 +1,14 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module network.mojom; + +struct HttpRequestHeaderKeyValuePair { + string key; + string value; +}; + +struct HttpRequestHeaders { + array headers; +};