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
11namespace net {
12
13URLRequestFilter* URLRequestFilter::shared_instance_ = NULL;
14
15URLRequestFilter::~URLRequestFilter() {}
16
17// static
18URLRequestJob* URLRequestFilter::Factory(URLRequest* request,
19                                         const std::string& scheme) {
20  // Returning null here just means that the built-in handler will be used.
21  return GetInstance()->FindRequestHandler(request, scheme);
22}
23
24// static
25URLRequestFilter* URLRequestFilter::GetInstance() {
26  if (!shared_instance_)
27    shared_instance_ = new URLRequestFilter;
28  return shared_instance_;
29}
30
31void URLRequestFilter::AddHostnameHandler(const std::string& scheme,
32    const std::string& hostname, URLRequest::ProtocolFactory* factory) {
33  hostname_handler_map_[make_pair(scheme, hostname)] = factory;
34
35  // Register with the ProtocolFactory.
36  URLRequest::RegisterProtocolFactory(scheme, &URLRequestFilter::Factory);
37
38#ifndef NDEBUG
39  // Check to see if we're masking URLs in the url_handler_map_.
40  for (UrlHandlerMap::const_iterator i = url_handler_map_.begin();
41       i != url_handler_map_.end(); ++i) {
42    const GURL& url = GURL(i->first);
43    HostnameHandlerMap::iterator host_it =
44        hostname_handler_map_.find(make_pair(url.scheme(), url.host()));
45    if (host_it != hostname_handler_map_.end())
46      NOTREACHED();
47  }
48#endif  // !NDEBUG
49}
50
51void URLRequestFilter::RemoveHostnameHandler(const std::string& scheme,
52                                             const std::string& hostname) {
53  HostnameHandlerMap::iterator iter =
54      hostname_handler_map_.find(make_pair(scheme, hostname));
55  DCHECK(iter != hostname_handler_map_.end());
56
57  hostname_handler_map_.erase(iter);
58  // Note that we don't unregister from the URLRequest ProtocolFactory as
59  // this would left no protocol factory for the scheme.
60  // URLRequestFilter::Factory will keep forwarding the requests to the
61  // URLRequestInetJob.
62}
63
64bool URLRequestFilter::AddUrlHandler(
65    const GURL& url,
66    URLRequest::ProtocolFactory* factory) {
67  if (!url.is_valid())
68    return false;
69  url_handler_map_[url.spec()] = factory;
70
71  // Register with the ProtocolFactory.
72  URLRequest::RegisterProtocolFactory(url.scheme(),
73                                           &URLRequestFilter::Factory);
74#ifndef NDEBUG
75  // Check to see if this URL is masked by a hostname handler.
76  HostnameHandlerMap::iterator host_it =
77      hostname_handler_map_.find(make_pair(url.scheme(), url.host()));
78  if (host_it != hostname_handler_map_.end())
79    NOTREACHED();
80#endif  // !NDEBUG
81
82  return true;
83}
84
85void URLRequestFilter::RemoveUrlHandler(const GURL& url) {
86  UrlHandlerMap::iterator iter = url_handler_map_.find(url.spec());
87  DCHECK(iter != url_handler_map_.end());
88
89  url_handler_map_.erase(iter);
90  // Note that we don't unregister from the URLRequest ProtocolFactory as
91  // this would left no protocol factory for the scheme.
92  // URLRequestFilter::Factory will keep forwarding the requests to the
93  // URLRequestInetJob.
94}
95
96void URLRequestFilter::ClearHandlers() {
97  // Unregister with the ProtocolFactory.
98  std::set<std::string> schemes;
99  for (UrlHandlerMap::const_iterator i = url_handler_map_.begin();
100       i != url_handler_map_.end(); ++i) {
101    schemes.insert(GURL(i->first).scheme());
102  }
103  for (HostnameHandlerMap::const_iterator i = hostname_handler_map_.begin();
104       i != hostname_handler_map_.end(); ++i) {
105    schemes.insert(i->first.first);
106  }
107  for (std::set<std::string>::const_iterator scheme = schemes.begin();
108       scheme != schemes.end(); ++scheme) {
109    URLRequest::RegisterProtocolFactory(*scheme, NULL);
110  }
111
112  url_handler_map_.clear();
113  hostname_handler_map_.clear();
114  hit_count_ = 0;
115}
116
117URLRequestFilter::URLRequestFilter() : hit_count_(0) { }
118
119URLRequestJob* URLRequestFilter::FindRequestHandler(
120    URLRequest* request,
121    const std::string& scheme) {
122  URLRequestJob* job = NULL;
123  if (request->url().is_valid()) {
124    // Check the hostname map first.
125    const std::string& hostname = request->url().host();
126
127    HostnameHandlerMap::iterator i =
128        hostname_handler_map_.find(make_pair(scheme, hostname));
129    if (i != hostname_handler_map_.end())
130      job = i->second(request, scheme);
131
132    if (!job) {
133      // Not in the hostname map, check the url map.
134      const std::string& url = request->url().spec();
135      UrlHandlerMap::iterator i = url_handler_map_.find(url);
136      if (i != url_handler_map_.end())
137        job = i->second(request, scheme);
138    }
139  }
140  if (job) {
141    DVLOG(1) << "URLRequestFilter hit for " << request->url().spec();
142    hit_count_++;
143  }
144  return job;
145}
146
147}  // namespace net
148