url_request_filter.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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
12namespace net {
13
14namespace {
15
16class 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
37URLRequestFilter* URLRequestFilter::shared_instance_ = NULL;
38
39URLRequestFilter::~URLRequestFilter() {}
40
41// static
42URLRequestJob* 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
50URLRequestFilter* URLRequestFilter::GetInstance() {
51  if (!shared_instance_)
52    shared_instance_ = new URLRequestFilter;
53  return shared_instance_;
54}
55
56void 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
64void 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
89void 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 left no protocol factory for the scheme.
99  // URLRequestFilter::Factory will keep forwarding the requests to the
100  // URLRequestInetJob.
101}
102
103bool URLRequestFilter::AddUrlHandler(
104    const GURL& url,
105    URLRequest::ProtocolFactory* factory) {
106  return AddUrlProtocolHandler(
107      url,
108      scoped_ptr<URLRequestJobFactory::ProtocolHandler>(
109          new URLRequestFilterProtocolHandler(factory)));
110}
111
112
113bool URLRequestFilter::AddUrlProtocolHandler(
114    const GURL& url,
115    scoped_ptr<URLRequestJobFactory::ProtocolHandler> protocol_handler) {
116  if (!url.is_valid())
117    return false;
118  DCHECK_EQ(0u, url_handler_map_.count(url.spec()));
119  url_handler_map_[url.spec()] = protocol_handler.release();
120
121  // Register with the ProtocolFactory.
122  URLRequest::Deprecated::RegisterProtocolFactory(url.scheme(),
123                                                  &URLRequestFilter::Factory);
124  // Check to see if this URL is masked by a hostname handler.
125  DCHECK_EQ(0u, hostname_handler_map_.count(make_pair(url.scheme(),
126                                                      url.host())));
127
128  return true;
129}
130
131void URLRequestFilter::RemoveUrlHandler(const GURL& url) {
132  UrlHandlerMap::iterator iter = url_handler_map_.find(url.spec());
133  DCHECK(iter != url_handler_map_.end());
134
135  delete iter->second;
136  url_handler_map_.erase(iter);
137  // Note that we don't unregister from the URLRequest ProtocolFactory as
138  // this would left no protocol factory for the scheme.
139  // URLRequestFilter::Factory will keep forwarding the requests to the
140  // URLRequestInetJob.
141}
142
143void URLRequestFilter::ClearHandlers() {
144  // Unregister with the ProtocolFactory.
145  std::set<std::string> schemes;
146  for (UrlHandlerMap::const_iterator i = url_handler_map_.begin();
147       i != url_handler_map_.end(); ++i) {
148    schemes.insert(GURL(i->first).scheme());
149  }
150  for (HostnameHandlerMap::const_iterator i = hostname_handler_map_.begin();
151       i != hostname_handler_map_.end(); ++i) {
152    schemes.insert(i->first.first);
153  }
154  for (std::set<std::string>::const_iterator scheme = schemes.begin();
155       scheme != schemes.end(); ++scheme) {
156    URLRequest::Deprecated::RegisterProtocolFactory(*scheme, NULL);
157  }
158
159  STLDeleteValues(&url_handler_map_);
160  STLDeleteValues(&hostname_handler_map_);
161  hit_count_ = 0;
162}
163
164URLRequestFilter::URLRequestFilter() : hit_count_(0) { }
165
166URLRequestJob* URLRequestFilter::FindRequestHandler(
167    URLRequest* request,
168    NetworkDelegate* network_delegate,
169    const std::string& scheme) {
170  URLRequestJob* job = NULL;
171  if (request->url().is_valid()) {
172    // Check the hostname map first.
173    const std::string& hostname = request->url().host();
174
175    HostnameHandlerMap::iterator i =
176        hostname_handler_map_.find(make_pair(scheme, hostname));
177    if (i != hostname_handler_map_.end())
178      job = i->second->MaybeCreateJob(request, network_delegate);
179
180    if (!job) {
181      // Not in the hostname map, check the url map.
182      const std::string& url = request->url().spec();
183      UrlHandlerMap::iterator i = url_handler_map_.find(url);
184      if (i != url_handler_map_.end())
185        job = i->second->MaybeCreateJob(request, network_delegate);
186    }
187  }
188  if (job) {
189    DVLOG(1) << "URLRequestFilter hit for " << request->url().spec();
190    hit_count_++;
191  }
192  return job;
193}
194
195}  // namespace net
196