15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_filter.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h"
11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "net/url_request/url_request_job_factory_impl.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)class URLRequestFilterInterceptor : public URLRequestInterceptor {
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  explicit URLRequestFilterInterceptor(URLRequest::ProtocolFactory* factory)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : factory_(factory) {}
2146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual ~URLRequestFilterInterceptor() {}
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // URLRequestInterceptor implementation.
2446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual URLRequestJob* MaybeInterceptRequest(
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      URLRequest* request, NetworkDelegate* network_delegate) const OVERRIDE {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return factory_(request, network_delegate, request->url().scheme());
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  URLRequest::ProtocolFactory* factory_;
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(URLRequestFilterInterceptor);
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLRequestFilter* URLRequestFilter::shared_instance_ = NULL;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLRequestFilter* URLRequestFilter::GetInstance() {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!shared_instance_)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shared_instance_ = new URLRequestFilter;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return shared_instance_;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestFilter::AddHostnameHandler(const std::string& scheme,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& hostname, URLRequest::ProtocolFactory* factory) {
4846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  AddHostnameInterceptor(
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scheme, hostname,
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      scoped_ptr<URLRequestInterceptor>(
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          new URLRequestFilterInterceptor(factory)));
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void URLRequestFilter::AddHostnameInterceptor(
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& scheme,
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& hostname,
5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    scoped_ptr<URLRequestInterceptor> interceptor) {
5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK_EQ(0u, hostname_interceptor_map_.count(make_pair(scheme, hostname)));
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  hostname_interceptor_map_[make_pair(scheme, hostname)] =
6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      interceptor.release();
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Check to see if we're masking URLs in the url_interceptor_map_.
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (URLInterceptorMap::const_iterator it = url_interceptor_map_.begin();
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       it != url_interceptor_map_.end(); ++it) {
6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const GURL& url = GURL(it->first);
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    HostnameInterceptorMap::const_iterator host_it =
6846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        hostname_interceptor_map_.find(make_pair(url.scheme(), url.host()));
6946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (host_it != hostname_interceptor_map_.end())
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // !NDEBUG
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestFilter::RemoveHostnameHandler(const std::string& scheme,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const std::string& hostname) {
7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  HostnameInterceptorMap::iterator it =
7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      hostname_interceptor_map_.find(make_pair(scheme, hostname));
7946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(it != hostname_interceptor_map_.end());
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  delete it->second;
8246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  hostname_interceptor_map_.erase(it);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that we don't unregister from the URLRequest ProtocolFactory as
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // this would leave no protocol factory for the remaining hostname and URL
85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // handlers.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLRequestFilter::AddUrlHandler(
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRequest::ProtocolFactory* factory) {
9146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return AddUrlInterceptor(
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      url,
9346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      scoped_ptr<URLRequestInterceptor>(
9446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          new URLRequestFilterInterceptor(factory)));
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool URLRequestFilter::AddUrlInterceptor(
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& url,
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    scoped_ptr<URLRequestInterceptor> interceptor) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!url.is_valid())
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK_EQ(0u, url_interceptor_map_.count(url.spec()));
10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  url_interceptor_map_[url.spec()] = interceptor.release();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check to see if this URL is masked by a hostname handler.
10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK_EQ(0u, hostname_interceptor_map_.count(make_pair(url.scheme(),
10746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                                          url.host())));
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestFilter::RemoveUrlHandler(const GURL& url) {
11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  URLInterceptorMap::iterator it = url_interceptor_map_.find(url.spec());
11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(it != url_interceptor_map_.end());
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  delete it->second;
11746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  url_interceptor_map_.erase(it);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that we don't unregister from the URLRequest ProtocolFactory as
119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // this would leave no protocol factory for the remaining hostname and URL
120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // handlers.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestFilter::ClearHandlers() {
12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  STLDeleteValues(&url_interceptor_map_);
12546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  STLDeleteValues(&hostname_interceptor_map_);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hit_count_ = 0;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)URLRequestJob* URLRequestFilter::MaybeInterceptRequest(
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRequest* request,
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    NetworkDelegate* network_delegate) const {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRequestJob* job = NULL;
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!request->url().is_valid())
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return NULL;
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Check the hostname map first.
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const std::string hostname = request->url().host();
138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const std::string scheme = request->url().scheme();
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  HostnameInterceptorMap::const_iterator it =
141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      hostname_interceptor_map_.find(make_pair(scheme, hostname));
142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (it != hostname_interceptor_map_.end())
143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    job = it->second->MaybeInterceptRequest(request, network_delegate);
144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!job) {
146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Not in the hostname map, check the url map.
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& url = request->url().spec();
148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    URLInterceptorMap::const_iterator it = url_interceptor_map_.find(url);
149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (it != url_interceptor_map_.end())
150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      job = it->second->MaybeInterceptRequest(request, network_delegate);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (job) {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "URLRequestFilter hit for " << request->url().spec();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hit_count_++;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return job;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)URLRequestFilter::URLRequestFilter() : hit_count_(0) {
160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  URLRequestJobFactoryImpl::SetInterceptorForTesting(this);
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)URLRequestFilter::~URLRequestFilter() {
164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  URLRequestJobFactoryImpl::SetInterceptorForTesting(NULL);
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
168