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