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: 19 explicit URLRequestFilterProtocolHandler(URLRequest::ProtocolFactory* factory) 20 : factory_(factory) {} 21 virtual ~URLRequestFilterProtocolHandler() {} 22 23 // URLRequestJobFactory::ProtocolHandler implementation 24 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 39 URLRequestFilter::~URLRequestFilter() {} 40 41 // static 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 50 URLRequestFilter* URLRequestFilter::GetInstance() { 51 if (!shared_instance_) 52 shared_instance_ = new URLRequestFilter; 53 return shared_instance_; 54 } 55 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 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 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 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 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 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 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 162 URLRequestFilter::URLRequestFilter() : hit_count_(0) { } 163 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