blob: 842a54f07215918efa6f4a1db31ed27dc75446e0 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000010#include "base/stl_util.h"
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +010011#include "net/url_request/url_request_job_factory_impl.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000012
13namespace net {
14
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000015namespace {
16
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010017class URLRequestFilterInterceptor : public URLRequestInterceptor {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000018 public:
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010019 explicit URLRequestFilterInterceptor(URLRequest::ProtocolFactory* factory)
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000020 : factory_(factory) {}
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010021 virtual ~URLRequestFilterInterceptor() {}
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000022
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010023 // URLRequestInterceptor implementation.
24 virtual URLRequestJob* MaybeInterceptRequest(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000025 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
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010032 DISALLOW_COPY_AND_ASSIGN(URLRequestFilterInterceptor);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000033};
34
35} // namespace
36
Torne (Richard Coles)58218062012-11-14 11:43:16 +000037URLRequestFilter* URLRequestFilter::shared_instance_ = NULL;
38
Torne (Richard Coles)58218062012-11-14 11:43:16 +000039// static
40URLRequestFilter* URLRequestFilter::GetInstance() {
41 if (!shared_instance_)
42 shared_instance_ = new URLRequestFilter;
43 return shared_instance_;
44}
45
46void URLRequestFilter::AddHostnameHandler(const std::string& scheme,
47 const std::string& hostname, URLRequest::ProtocolFactory* factory) {
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010048 AddHostnameInterceptor(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000049 scheme, hostname,
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010050 scoped_ptr<URLRequestInterceptor>(
51 new URLRequestFilterInterceptor(factory)));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000052}
53
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010054void URLRequestFilter::AddHostnameInterceptor(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000055 const std::string& scheme,
56 const std::string& hostname,
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010057 scoped_ptr<URLRequestInterceptor> interceptor) {
58 DCHECK_EQ(0u, hostname_interceptor_map_.count(make_pair(scheme, hostname)));
59 hostname_interceptor_map_[make_pair(scheme, hostname)] =
60 interceptor.release();
Torne (Richard Coles)58218062012-11-14 11:43:16 +000061
Torne (Richard Coles)58218062012-11-14 11:43:16 +000062#ifndef NDEBUG
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010063 // Check to see if we're masking URLs in the url_interceptor_map_.
64 for (URLInterceptorMap::const_iterator it = url_interceptor_map_.begin();
65 it != url_interceptor_map_.end(); ++it) {
66 const GURL& url = GURL(it->first);
67 HostnameInterceptorMap::const_iterator host_it =
68 hostname_interceptor_map_.find(make_pair(url.scheme(), url.host()));
69 if (host_it != hostname_interceptor_map_.end())
Torne (Richard Coles)58218062012-11-14 11:43:16 +000070 NOTREACHED();
71 }
72#endif // !NDEBUG
73}
74
75void URLRequestFilter::RemoveHostnameHandler(const std::string& scheme,
76 const std::string& hostname) {
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010077 HostnameInterceptorMap::iterator it =
78 hostname_interceptor_map_.find(make_pair(scheme, hostname));
79 DCHECK(it != hostname_interceptor_map_.end());
Torne (Richard Coles)58218062012-11-14 11:43:16 +000080
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010081 delete it->second;
82 hostname_interceptor_map_.erase(it);
Torne (Richard Coles)58218062012-11-14 11:43:16 +000083 // Note that we don't unregister from the URLRequest ProtocolFactory as
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +000084 // this would leave no protocol factory for the remaining hostname and URL
85 // handlers.
Torne (Richard Coles)58218062012-11-14 11:43:16 +000086}
87
88bool URLRequestFilter::AddUrlHandler(
89 const GURL& url,
90 URLRequest::ProtocolFactory* factory) {
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010091 return AddUrlInterceptor(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000092 url,
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010093 scoped_ptr<URLRequestInterceptor>(
94 new URLRequestFilterInterceptor(factory)));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000095}
96
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010097bool URLRequestFilter::AddUrlInterceptor(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000098 const GURL& url,
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010099 scoped_ptr<URLRequestInterceptor> interceptor) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000100 if (!url.is_valid())
101 return false;
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100102 DCHECK_EQ(0u, url_interceptor_map_.count(url.spec()));
103 url_interceptor_map_[url.spec()] = interceptor.release();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000104
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000105 // Check to see if this URL is masked by a hostname handler.
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100106 DCHECK_EQ(0u, hostname_interceptor_map_.count(make_pair(url.scheme(),
107 url.host())));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000108
109 return true;
110}
111
112void URLRequestFilter::RemoveUrlHandler(const GURL& url) {
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100113 URLInterceptorMap::iterator it = url_interceptor_map_.find(url.spec());
114 DCHECK(it != url_interceptor_map_.end());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000115
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100116 delete it->second;
117 url_interceptor_map_.erase(it);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000118 // Note that we don't unregister from the URLRequest ProtocolFactory as
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000119 // this would leave no protocol factory for the remaining hostname and URL
120 // handlers.
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000121}
122
123void URLRequestFilter::ClearHandlers() {
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100124 STLDeleteValues(&url_interceptor_map_);
125 STLDeleteValues(&hostname_interceptor_map_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000126 hit_count_ = 0;
127}
128
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100129URLRequestJob* URLRequestFilter::MaybeInterceptRequest(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000130 URLRequest* request,
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100131 NetworkDelegate* network_delegate) const {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000132 URLRequestJob* job = NULL;
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100133 if (!request->url().is_valid())
134 return NULL;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000135
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100136 // Check the hostname map first.
137 const std::string hostname = request->url().host();
138 const std::string scheme = request->url().scheme();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000139
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100140 HostnameInterceptorMap::const_iterator it =
141 hostname_interceptor_map_.find(make_pair(scheme, hostname));
142 if (it != hostname_interceptor_map_.end())
143 job = it->second->MaybeInterceptRequest(request, network_delegate);
144
145 if (!job) {
146 // Not in the hostname map, check the url map.
147 const std::string& url = request->url().spec();
148 URLInterceptorMap::const_iterator it = url_interceptor_map_.find(url);
149 if (it != url_interceptor_map_.end())
150 job = it->second->MaybeInterceptRequest(request, network_delegate);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000151 }
152 if (job) {
153 DVLOG(1) << "URLRequestFilter hit for " << request->url().spec();
154 hit_count_++;
155 }
156 return job;
157}
158
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100159URLRequestFilter::URLRequestFilter() : hit_count_(0) {
160 URLRequestJobFactoryImpl::SetInterceptorForTesting(this);
161}
162
163URLRequestFilter::~URLRequestFilter() {
164 URLRequestJobFactoryImpl::SetInterceptorForTesting(NULL);
165}
166
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000167} // namespace net