xref: /aosp_15_r20/external/cronet/net/url_request/url_request_filter.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2011 The Chromium Authors
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 "net/url_request/url_request_filter.h"
6 
7 #include "base/logging.h"
8 #include "base/task/current_thread.h"
9 #include "net/url_request/url_request.h"
10 #include "net/url_request/url_request_job.h"
11 #include "net/url_request/url_request_job_factory.h"
12 
13 namespace net {
14 
15 namespace {
16 
17 // When adding interceptors, DCHECK that this function returns true.
OnMessageLoopForInterceptorAddition()18 bool OnMessageLoopForInterceptorAddition() {
19   // Return true if called on a MessageLoopForIO or if there is no MessageLoop.
20   // Checking for a MessageLoopForIO is a best effort at determining whether the
21   // current thread is a networking thread.  Allowing cases without a
22   // MessageLoop is required for some tests where there is no chance to insert
23   // an interceptor between a networking thread being started and a resource
24   // request being issued.
25   return base::CurrentIOThread::IsSet() || !base::CurrentThread::IsSet();
26 }
27 
28 // When removing interceptors, DCHECK that this function returns true.
OnMessageLoopForInterceptorRemoval()29 bool OnMessageLoopForInterceptorRemoval() {
30   // Checking for a CurrentIOThread is a best effort at determining
31   // whether the current thread is a networking thread.
32   return base::CurrentIOThread::IsSet();
33 }
34 
35 }  // namespace
36 
37 URLRequestFilter* URLRequestFilter::shared_instance_ = nullptr;
38 
39 // static
GetInstance()40 URLRequestFilter* URLRequestFilter::GetInstance() {
41   DCHECK(OnMessageLoopForInterceptorAddition());
42   if (!shared_instance_)
43     shared_instance_ = new URLRequestFilter;
44   return shared_instance_;
45 }
46 
AddHostnameInterceptor(const std::string & scheme,const std::string & hostname,std::unique_ptr<URLRequestInterceptor> interceptor)47 void URLRequestFilter::AddHostnameInterceptor(
48     const std::string& scheme,
49     const std::string& hostname,
50     std::unique_ptr<URLRequestInterceptor> interceptor) {
51   DCHECK(OnMessageLoopForInterceptorAddition());
52   DCHECK_EQ(0u, hostname_interceptor_map_.count(std::pair(scheme, hostname)));
53   hostname_interceptor_map_[std::pair(scheme, hostname)] =
54       std::move(interceptor);
55 
56 #ifndef NDEBUG
57   // Check to see if we're masking URLs in the url_interceptor_map_.
58   for (const auto& pair : url_interceptor_map_) {
59     const GURL& url = GURL(pair.first);
60     HostnameInterceptorMap::const_iterator host_it =
61         hostname_interceptor_map_.find(std::pair(url.scheme(), url.host()));
62     if (host_it != hostname_interceptor_map_.end())
63       NOTREACHED();
64   }
65 #endif  // !NDEBUG
66 }
67 
RemoveHostnameHandler(const std::string & scheme,const std::string & hostname)68 void URLRequestFilter::RemoveHostnameHandler(const std::string& scheme,
69                                              const std::string& hostname) {
70   DCHECK(OnMessageLoopForInterceptorRemoval());
71   int removed = hostname_interceptor_map_.erase(std::pair(scheme, hostname));
72   DCHECK(removed);
73 }
74 
AddUrlInterceptor(const GURL & url,std::unique_ptr<URLRequestInterceptor> interceptor)75 bool URLRequestFilter::AddUrlInterceptor(
76     const GURL& url,
77     std::unique_ptr<URLRequestInterceptor> interceptor) {
78   DCHECK(OnMessageLoopForInterceptorAddition());
79   if (!url.is_valid())
80     return false;
81   DCHECK_EQ(0u, url_interceptor_map_.count(url.spec()));
82   url_interceptor_map_[url.spec()] = std::move(interceptor);
83 
84   // Check to see if this URL is masked by a hostname handler.
85   DCHECK_EQ(
86       0u, hostname_interceptor_map_.count(std::pair(url.scheme(), url.host())));
87 
88   return true;
89 }
90 
RemoveUrlHandler(const GURL & url)91 void URLRequestFilter::RemoveUrlHandler(const GURL& url) {
92   DCHECK(OnMessageLoopForInterceptorRemoval());
93   size_t removed = url_interceptor_map_.erase(url.spec());
94   DCHECK(removed);
95 }
96 
ClearHandlers()97 void URLRequestFilter::ClearHandlers() {
98   DCHECK(OnMessageLoopForInterceptorRemoval());
99   url_interceptor_map_.clear();
100   hostname_interceptor_map_.clear();
101   hit_count_ = 0;
102 }
103 
MaybeInterceptRequest(URLRequest * request) const104 std::unique_ptr<URLRequestJob> URLRequestFilter::MaybeInterceptRequest(
105     URLRequest* request) const {
106   DCHECK(base::CurrentIOThread::Get());
107   if (!request->url().is_valid())
108     return nullptr;
109 
110   std::unique_ptr<URLRequestJob> job;
111 
112   // Check the hostname map first.
113   const std::string hostname = request->url().host();
114   const std::string scheme = request->url().scheme();
115 
116   {
117     auto it = hostname_interceptor_map_.find(std::pair(scheme, hostname));
118     if (it != hostname_interceptor_map_.end())
119       job = it->second->MaybeInterceptRequest(request);
120   }
121 
122   if (!job) {
123     // Not in the hostname map, check the url map.
124     const std::string& url = request->url().spec();
125     auto it = url_interceptor_map_.find(url);
126     if (it != url_interceptor_map_.end())
127       job = it->second->MaybeInterceptRequest(request);
128   }
129   if (job) {
130     DVLOG(1) << "URLRequestFilter hit for " << request->url().spec();
131     hit_count_++;
132   }
133   return job;
134 }
135 
URLRequestFilter()136 URLRequestFilter::URLRequestFilter() {
137   DCHECK(OnMessageLoopForInterceptorAddition());
138   URLRequestJobFactory::SetInterceptorForTesting(this);
139 }
140 
~URLRequestFilter()141 URLRequestFilter::~URLRequestFilter() {
142   DCHECK(OnMessageLoopForInterceptorRemoval());
143   URLRequestJobFactory::SetInterceptorForTesting(nullptr);
144 }
145 
146 }  // namespace net
147