1 // Copyright (c) 2011 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 "net/url_request/url_request_filter.h"
6
7 #include <set>
8
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11
12 namespace net {
13
14 namespace {
15
16 class URLRequestFilterProtocolHandler
17 : public URLRequestJobFactory::ProtocolHandler {
18 public:
URLRequestFilterProtocolHandler(URLRequest::ProtocolFactory * factory)19 explicit URLRequestFilterProtocolHandler(URLRequest::ProtocolFactory* factory)
20 : factory_(factory) {}
~URLRequestFilterProtocolHandler()21 virtual ~URLRequestFilterProtocolHandler() {}
22
23 // URLRequestJobFactory::ProtocolHandler implementation
MaybeCreateJob(URLRequest * request,NetworkDelegate * network_delegate) const24 virtual URLRequestJob* MaybeCreateJob(
25 URLRequest* request, NetworkDelegate* network_delegate) const OVERRIDE {
26 return factory_(request, network_delegate, request->url().scheme());
27 }
28
29 private:
30 URLRequest::ProtocolFactory* factory_;
31
32 DISALLOW_COPY_AND_ASSIGN(URLRequestFilterProtocolHandler);
33 };
34
35 } // namespace
36
37 URLRequestFilter* URLRequestFilter::shared_instance_ = NULL;
38
~URLRequestFilter()39 URLRequestFilter::~URLRequestFilter() {}
40
41 // static
Factory(URLRequest * request,NetworkDelegate * network_delegate,const std::string & scheme)42 URLRequestJob* URLRequestFilter::Factory(URLRequest* request,
43 NetworkDelegate* network_delegate,
44 const std::string& scheme) {
45 // Returning null here just means that the built-in handler will be used.
46 return GetInstance()->FindRequestHandler(request, network_delegate, scheme);
47 }
48
49 // static
GetInstance()50 URLRequestFilter* URLRequestFilter::GetInstance() {
51 if (!shared_instance_)
52 shared_instance_ = new URLRequestFilter;
53 return shared_instance_;
54 }
55
AddHostnameHandler(const std::string & scheme,const std::string & hostname,URLRequest::ProtocolFactory * factory)56 void URLRequestFilter::AddHostnameHandler(const std::string& scheme,
57 const std::string& hostname, URLRequest::ProtocolFactory* factory) {
58 AddHostnameProtocolHandler(
59 scheme, hostname,
60 scoped_ptr<URLRequestJobFactory::ProtocolHandler>(
61 new URLRequestFilterProtocolHandler(factory)));
62 }
63
AddHostnameProtocolHandler(const std::string & scheme,const std::string & hostname,scoped_ptr<URLRequestJobFactory::ProtocolHandler> protocol_handler)64 void URLRequestFilter::AddHostnameProtocolHandler(
65 const std::string& scheme,
66 const std::string& hostname,
67 scoped_ptr<URLRequestJobFactory::ProtocolHandler> protocol_handler) {
68 DCHECK_EQ(0u, hostname_handler_map_.count(make_pair(scheme, hostname)));
69 hostname_handler_map_[make_pair(scheme, hostname)] =
70 protocol_handler.release();
71
72 // Register with the ProtocolFactory.
73 URLRequest::Deprecated::RegisterProtocolFactory(
74 scheme, &URLRequestFilter::Factory);
75
76 #ifndef NDEBUG
77 // Check to see if we're masking URLs in the url_handler_map_.
78 for (UrlHandlerMap::const_iterator i = url_handler_map_.begin();
79 i != url_handler_map_.end(); ++i) {
80 const GURL& url = GURL(i->first);
81 HostnameHandlerMap::iterator host_it =
82 hostname_handler_map_.find(make_pair(url.scheme(), url.host()));
83 if (host_it != hostname_handler_map_.end())
84 NOTREACHED();
85 }
86 #endif // !NDEBUG
87 }
88
RemoveHostnameHandler(const std::string & scheme,const std::string & hostname)89 void URLRequestFilter::RemoveHostnameHandler(const std::string& scheme,
90 const std::string& hostname) {
91 HostnameHandlerMap::iterator iter =
92 hostname_handler_map_.find(make_pair(scheme, hostname));
93 DCHECK(iter != hostname_handler_map_.end());
94
95 delete iter->second;
96 hostname_handler_map_.erase(iter);
97 // Note that we don't unregister from the URLRequest ProtocolFactory as
98 // this would leave no protocol factory for the remaining hostname and URL
99 // handlers.
100 }
101
AddUrlHandler(const GURL & url,URLRequest::ProtocolFactory * factory)102 bool URLRequestFilter::AddUrlHandler(
103 const GURL& url,
104 URLRequest::ProtocolFactory* factory) {
105 return AddUrlProtocolHandler(
106 url,
107 scoped_ptr<URLRequestJobFactory::ProtocolHandler>(
108 new URLRequestFilterProtocolHandler(factory)));
109 }
110
111
AddUrlProtocolHandler(const GURL & url,scoped_ptr<URLRequestJobFactory::ProtocolHandler> protocol_handler)112 bool URLRequestFilter::AddUrlProtocolHandler(
113 const GURL& url,
114 scoped_ptr<URLRequestJobFactory::ProtocolHandler> protocol_handler) {
115 if (!url.is_valid())
116 return false;
117 DCHECK_EQ(0u, url_handler_map_.count(url.spec()));
118 url_handler_map_[url.spec()] = protocol_handler.release();
119
120 // Register with the ProtocolFactory.
121 URLRequest::Deprecated::RegisterProtocolFactory(url.scheme(),
122 &URLRequestFilter::Factory);
123 // Check to see if this URL is masked by a hostname handler.
124 DCHECK_EQ(0u, hostname_handler_map_.count(make_pair(url.scheme(),
125 url.host())));
126
127 return true;
128 }
129
RemoveUrlHandler(const GURL & url)130 void URLRequestFilter::RemoveUrlHandler(const GURL& url) {
131 UrlHandlerMap::iterator iter = url_handler_map_.find(url.spec());
132 DCHECK(iter != url_handler_map_.end());
133
134 delete iter->second;
135 url_handler_map_.erase(iter);
136 // Note that we don't unregister from the URLRequest ProtocolFactory as
137 // this would leave no protocol factory for the remaining hostname and URL
138 // handlers.
139 }
140
ClearHandlers()141 void URLRequestFilter::ClearHandlers() {
142 // Unregister with the ProtocolFactory.
143 std::set<std::string> schemes;
144 for (UrlHandlerMap::const_iterator i = url_handler_map_.begin();
145 i != url_handler_map_.end(); ++i) {
146 schemes.insert(GURL(i->first).scheme());
147 }
148 for (HostnameHandlerMap::const_iterator i = hostname_handler_map_.begin();
149 i != hostname_handler_map_.end(); ++i) {
150 schemes.insert(i->first.first);
151 }
152 for (std::set<std::string>::const_iterator scheme = schemes.begin();
153 scheme != schemes.end(); ++scheme) {
154 URLRequest::Deprecated::RegisterProtocolFactory(*scheme, NULL);
155 }
156
157 STLDeleteValues(&url_handler_map_);
158 STLDeleteValues(&hostname_handler_map_);
159 hit_count_ = 0;
160 }
161
URLRequestFilter()162 URLRequestFilter::URLRequestFilter() : hit_count_(0) { }
163
FindRequestHandler(URLRequest * request,NetworkDelegate * network_delegate,const std::string & scheme)164 URLRequestJob* URLRequestFilter::FindRequestHandler(
165 URLRequest* request,
166 NetworkDelegate* network_delegate,
167 const std::string& scheme) {
168 URLRequestJob* job = NULL;
169 if (request->url().is_valid()) {
170 // Check the hostname map first.
171 const std::string& hostname = request->url().host();
172
173 HostnameHandlerMap::iterator i =
174 hostname_handler_map_.find(make_pair(scheme, hostname));
175 if (i != hostname_handler_map_.end())
176 job = i->second->MaybeCreateJob(request, network_delegate);
177
178 if (!job) {
179 // Not in the hostname map, check the url map.
180 const std::string& url = request->url().spec();
181 UrlHandlerMap::iterator i = url_handler_map_.find(url);
182 if (i != url_handler_map_.end())
183 job = i->second->MaybeCreateJob(request, network_delegate);
184 }
185 }
186 if (job) {
187 DVLOG(1) << "URLRequestFilter hit for " << request->url().spec();
188 hit_count_++;
189 }
190 return job;
191 }
192
193 } // namespace net
194