• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "content/test/net/url_request_mock_http_job.h"
6 
7 #include "base/file_util.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/threading/sequenced_worker_pool.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/common/url_constants.h"
15 #include "net/base/net_util.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/url_request/url_request_filter.h"
18 
19 const char kMockHostname[] = "mock.http";
20 const base::FilePath::CharType kMockHeaderFileSuffix[] =
21     FILE_PATH_LITERAL(".mock-http-headers");
22 
23 namespace content {
24 
25 namespace {
26 
27 class ProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
28  public:
29   // When |map_all_requests_to_base_path| is true, all request should return the
30   // contents of the file at |base_path|. When |map_all_requests_to_base_path|
31   // is false, |base_path| is the file path leading to the root of the directory
32   // to use as the root of the HTTP server.
ProtocolHandler(const base::FilePath & base_path,bool map_all_requests_to_base_path)33   explicit ProtocolHandler(const base::FilePath& base_path,
34                            bool map_all_requests_to_base_path)
35       : base_path_(base_path),
36         map_all_requests_to_base_path_(map_all_requests_to_base_path) {}
~ProtocolHandler()37   virtual ~ProtocolHandler() {}
38 
39   // net::URLRequestJobFactory::ProtocolHandler implementation
MaybeCreateJob(net::URLRequest * request,net::NetworkDelegate * network_delegate) const40   virtual net::URLRequestJob* MaybeCreateJob(
41       net::URLRequest* request,
42       net::NetworkDelegate* network_delegate) const OVERRIDE {
43     return new URLRequestMockHTTPJob(request, network_delegate,
44         map_all_requests_to_base_path_ ? base_path_ : GetOnDiskPath(request));
45   }
46 
47  private:
GetOnDiskPath(net::URLRequest * request) const48   base::FilePath GetOnDiskPath(net::URLRequest* request) const {
49     // Conceptually we just want to "return base_path_ + request->url().path()".
50     // But path in the request URL is in URL space (i.e. %-encoded spaces).
51     // So first we convert base FilePath to a URL, then append the URL
52     // path to that, and convert the final URL back to a FilePath.
53     GURL file_url(net::FilePathToFileURL(base_path_));
54     std::string url = file_url.spec() + request->url().path();
55     base::FilePath file_path;
56     net::FileURLToFilePath(GURL(url), &file_path);
57     return file_path;
58   }
59 
60   const base::FilePath base_path_;
61   const bool map_all_requests_to_base_path_;
62 
63   DISALLOW_COPY_AND_ASSIGN(ProtocolHandler);
64 };
65 
66 }  // namespace
67 
68 // static
AddUrlHandler(const base::FilePath & base_path)69 void URLRequestMockHTTPJob::AddUrlHandler(const base::FilePath& base_path) {
70   // Add kMockHostname to net::URLRequestFilter.
71   net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
72   filter->AddHostnameProtocolHandler("http", kMockHostname,
73       CreateProtocolHandler(base_path));
74 }
75 
76 // static
AddHostnameToFileHandler(const std::string & hostname,const base::FilePath & file)77 void URLRequestMockHTTPJob::AddHostnameToFileHandler(
78     const std::string& hostname,
79     const base::FilePath& file) {
80   net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
81   filter->AddHostnameProtocolHandler(
82       "http", hostname, CreateProtocolHandlerForSingleFile(file));
83 }
84 
85 // static
GetMockUrl(const base::FilePath & path)86 GURL URLRequestMockHTTPJob::GetMockUrl(const base::FilePath& path) {
87   std::string url = "http://";
88   url.append(kMockHostname);
89   url.append("/");
90   std::string path_str = path.MaybeAsASCII();
91   DCHECK(!path_str.empty());  // We only expect ASCII paths in tests.
92   url.append(path_str);
93   return GURL(url);
94 }
95 
96 // static
GetMockViewSourceUrl(const base::FilePath & path)97 GURL URLRequestMockHTTPJob::GetMockViewSourceUrl(const base::FilePath& path) {
98   std::string url = kViewSourceScheme;
99   url.append(":");
100   url.append(GetMockUrl(path).spec());
101   return GURL(url);
102 }
103 
104 // static
105 scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
CreateProtocolHandler(const base::FilePath & base_path)106 URLRequestMockHTTPJob::CreateProtocolHandler(const base::FilePath& base_path) {
107   return scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(
108       new ProtocolHandler(base_path, false));
109 }
110 
111 // static
112 scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
CreateProtocolHandlerForSingleFile(const base::FilePath & file)113 URLRequestMockHTTPJob::CreateProtocolHandlerForSingleFile(
114     const base::FilePath& file) {
115   return scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(
116       new ProtocolHandler(file, true));
117 }
118 
URLRequestMockHTTPJob(net::URLRequest * request,net::NetworkDelegate * network_delegate,const base::FilePath & file_path)119 URLRequestMockHTTPJob::URLRequestMockHTTPJob(
120     net::URLRequest* request, net::NetworkDelegate* network_delegate,
121     const base::FilePath& file_path)
122     : net::URLRequestFileJob(
123           request, network_delegate, file_path,
124           content::BrowserThread::GetBlockingPool()->
125               GetTaskRunnerWithShutdownBehavior(
126                   base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)) {}
127 
~URLRequestMockHTTPJob()128 URLRequestMockHTTPJob::~URLRequestMockHTTPJob() { }
129 
130 // Public virtual version.
GetResponseInfo(net::HttpResponseInfo * info)131 void URLRequestMockHTTPJob::GetResponseInfo(net::HttpResponseInfo* info) {
132   // Forward to private const version.
133   GetResponseInfoConst(info);
134 }
135 
IsRedirectResponse(GURL * location,int * http_status_code)136 bool URLRequestMockHTTPJob::IsRedirectResponse(GURL* location,
137                                                int* http_status_code) {
138   // Override the net::URLRequestFileJob implementation to invoke the default
139   // one based on HttpResponseInfo.
140   return net::URLRequestJob::IsRedirectResponse(location, http_status_code);
141 }
142 
143 // Private const version.
GetResponseInfoConst(net::HttpResponseInfo * info) const144 void URLRequestMockHTTPJob::GetResponseInfoConst(
145     net::HttpResponseInfo* info) const {
146   // We have to load our headers from disk, but we only use this class
147   // from tests, so allow these IO operations to happen on any thread.
148   base::ThreadRestrictions::ScopedAllowIO allow_io;
149 
150   base::FilePath header_file =
151       base::FilePath(file_path_.value() + kMockHeaderFileSuffix);
152   std::string raw_headers;
153   if (!base::ReadFileToString(header_file, &raw_headers))
154     return;
155 
156   // Handle CRLF line-endings.
157   ReplaceSubstringsAfterOffset(&raw_headers, 0, "\r\n", "\n");
158   // ParseRawHeaders expects \0 to end each header line.
159   ReplaceSubstringsAfterOffset(&raw_headers, 0, "\n", std::string("\0", 1));
160   info->headers = new net::HttpResponseHeaders(raw_headers);
161 }
162 
GetMimeType(std::string * mime_type) const163 bool URLRequestMockHTTPJob::GetMimeType(std::string* mime_type) const {
164   net::HttpResponseInfo info;
165   GetResponseInfoConst(&info);
166   return info.headers.get() && info.headers->GetMimeType(mime_type);
167 }
168 
GetResponseCode() const169 int URLRequestMockHTTPJob::GetResponseCode() const {
170   net::HttpResponseInfo info;
171   GetResponseInfoConst(&info);
172   // If we have headers, get the response code from them.
173   if (info.headers.get())
174     return info.headers->response_code();
175   return net::URLRequestJob::GetResponseCode();
176 }
177 
GetCharset(std::string * charset)178 bool URLRequestMockHTTPJob::GetCharset(std::string* charset) {
179   net::HttpResponseInfo info;
180   GetResponseInfo(&info);
181   return info.headers.get() && info.headers->GetCharset(charset);
182 }
183 
184 }  // namespace content
185