1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "android_webview/browser/network_service/aw_url_loader_throttle.h"
6
7 #include "android_webview/browser/aw_resource_context.h"
8 #include "android_webview/common/aw_features.h"
9 #include "base/feature_list.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/string_util.h"
12 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
13 #include "net/http/http_request_headers.h"
14 #include "net/url_request/redirect_info.h"
15 #include "services/network/public/cpp/resource_request.h"
16
17 namespace android_webview {
18
19 namespace {
20
21 // These values are logged to UMA. Entries should not be renumbered and
22 // numeric values should never be reused. Please keep in sync with
23 // "WebViewExtraHeadersRedirect" in src/tools/metrics/histograms/enums.xml.
24 enum class ExtraHeadersRedirect {
25 kSameOrigin = 0,
26 kSameDomain = 1,
27 kCrossDomain = 2,
28 kMaxValue = kCrossDomain
29 };
30
RecordExtraHeadersRedirectUMA(ExtraHeadersRedirect value)31 void RecordExtraHeadersRedirectUMA(ExtraHeadersRedirect value) {
32 UMA_HISTOGRAM_ENUMERATION("Android.WebView.ExtraHeadersRedirect", value);
33 }
34
35 } // namespace
36
AwURLLoaderThrottle(AwResourceContext * aw_resource_context)37 AwURLLoaderThrottle::AwURLLoaderThrottle(AwResourceContext* aw_resource_context)
38 : aw_resource_context_(aw_resource_context) {}
39
40 AwURLLoaderThrottle::~AwURLLoaderThrottle() = default;
41
WillStartRequest(network::ResourceRequest * request,bool * defer)42 void AwURLLoaderThrottle::WillStartRequest(network::ResourceRequest* request,
43 bool* defer) {
44 AddExtraHeadersIfNeeded(request->url, &request->headers);
45 if (!added_headers_.empty()) {
46 original_origin_ = url::Origin::Create(request->url);
47 }
48 }
49
WillRedirectRequest(net::RedirectInfo * redirect_info,const network::mojom::URLResponseHead & response_head,bool * defer,std::vector<std::string> * to_be_removed_request_headers,net::HttpRequestHeaders * modified_request_headers,net::HttpRequestHeaders * modified_cors_exempt_request_headers)50 void AwURLLoaderThrottle::WillRedirectRequest(
51 net::RedirectInfo* redirect_info,
52 const network::mojom::URLResponseHead& response_head,
53 bool* defer,
54 std::vector<std::string>* to_be_removed_request_headers,
55 net::HttpRequestHeaders* modified_request_headers,
56 net::HttpRequestHeaders* modified_cors_exempt_request_headers) {
57 bool same_origin_only = base::FeatureList::IsEnabled(
58 features::kWebViewExtraHeadersSameOriginOnly);
59 bool same_domain_only = base::FeatureList::IsEnabled(
60 features::kWebViewExtraHeadersSameDomainOnly);
61
62 if (!added_headers_.empty()) {
63 bool is_same_origin =
64 original_origin_.CanBeDerivedFrom(redirect_info->new_url);
65 bool is_same_domain = net::registry_controlled_domains::SameDomainOrHost(
66 redirect_info->new_url, original_origin_,
67 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
68
69 if (is_same_origin) {
70 RecordExtraHeadersRedirectUMA(ExtraHeadersRedirect::kSameOrigin);
71 } else if (is_same_domain) {
72 RecordExtraHeadersRedirectUMA(ExtraHeadersRedirect::kSameDomain);
73 } else {
74 RecordExtraHeadersRedirectUMA(ExtraHeadersRedirect::kCrossDomain);
75 }
76
77 if ((same_origin_only && !is_same_origin) ||
78 (same_domain_only && !is_same_domain)) {
79 // The headers we added must be removed.
80 to_be_removed_request_headers->insert(
81 to_be_removed_request_headers->end(),
82 std::make_move_iterator(added_headers_.begin()),
83 std::make_move_iterator(added_headers_.end()));
84 added_headers_.clear();
85 }
86 }
87
88 if (!same_origin_only && !same_domain_only) {
89 // The original behaviour added more headers if the redirect target had
90 // previously been loaded with extra headers; this is weird/surprising, so
91 // it's skipped when either feature is enabled.
92 AddExtraHeadersIfNeeded(redirect_info->new_url, modified_request_headers);
93 }
94 }
95
AddExtraHeadersIfNeeded(const GURL & url,net::HttpRequestHeaders * headers)96 void AwURLLoaderThrottle::AddExtraHeadersIfNeeded(
97 const GURL& url,
98 net::HttpRequestHeaders* headers) {
99 std::string extra_headers = aw_resource_context_->GetExtraHeaders(url);
100 if (extra_headers.empty())
101 return;
102
103 net::HttpRequestHeaders temp_headers;
104 temp_headers.AddHeadersFromString(extra_headers);
105 for (net::HttpRequestHeaders::Iterator it(temp_headers); it.GetNext();) {
106 if (headers->HasHeader(it.name()))
107 continue;
108
109 headers->SetHeader(it.name(), it.value());
110 added_headers_.push_back(it.name());
111 }
112 }
113
114 } // namespace android_webview
115