Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / test / url_request / url_request_mock_http_job.cc
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 "net/test/url_request/url_request_mock_http_job.h"
6
7 #include "base/files/file_util.h"
8 #include "base/macros.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/task_runner_util.h"
14 #include "base/threading/sequenced_worker_pool.h"
15 #include "base/threading/thread_restrictions.h"
16 #include "net/base/filename_util.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/url_util.h"
19 #include "net/http/http_response_headers.h"
20 #include "net/url_request/url_request_filter.h"
21 #include "net/url_request/url_request_interceptor.h"
22
23 namespace net {
24
25 namespace {
26
27 const char kMockHostname[] = "mock.http";
28 const base::FilePath::CharType kMockHeaderFileSuffix[] =
29     FILE_PATH_LITERAL(".mock-http-headers");
30
31 // String names of failure phases matching FailurePhase enum.
32 const char* kFailurePhase[] {
33   "start",      // START
34   "readasync",  // READ_ASYNC
35   "readsync",   // READ_SYNC
36 };
37
38 class MockJobInterceptor : public net::URLRequestInterceptor {
39  public:
40   // When |map_all_requests_to_base_path| is true, all request should return the
41   // contents of the file at |base_path|. When |map_all_requests_to_base_path|
42   // is false, |base_path| is the file path leading to the root of the directory
43   // to use as the root of the HTTP server.
44   MockJobInterceptor(
45       const base::FilePath& base_path,
46       bool map_all_requests_to_base_path,
47       const scoped_refptr<base::SequencedWorkerPool>& worker_pool)
48       : base_path_(base_path),
49         map_all_requests_to_base_path_(map_all_requests_to_base_path),
50         worker_pool_(worker_pool) {}
51   ~MockJobInterceptor() override {}
52
53   // net::URLRequestJobFactory::ProtocolHandler implementation
54   net::URLRequestJob* MaybeInterceptRequest(
55       net::URLRequest* request,
56       net::NetworkDelegate* network_delegate) const override {
57     return new URLRequestMockHTTPJob(
58         request,
59         network_delegate,
60         map_all_requests_to_base_path_ ? base_path_ : GetOnDiskPath(request),
61         worker_pool_->GetTaskRunnerWithShutdownBehavior(
62             base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
63   }
64
65  private:
66   base::FilePath GetOnDiskPath(net::URLRequest* request) const {
67     // Conceptually we just want to "return base_path_ + request->url().path()".
68     // But path in the request URL is in URL space (i.e. %-encoded spaces).
69     // So first we convert base FilePath to a URL, then append the URL
70     // path to that, and convert the final URL back to a FilePath.
71     GURL file_url(net::FilePathToFileURL(base_path_));
72     std::string url = file_url.spec() + request->url().path();
73     base::FilePath file_path;
74     net::FileURLToFilePath(GURL(url), &file_path);
75     return file_path;
76   }
77
78   const base::FilePath base_path_;
79   const bool map_all_requests_to_base_path_;
80   const scoped_refptr<base::SequencedWorkerPool> worker_pool_;
81
82   DISALLOW_COPY_AND_ASSIGN(MockJobInterceptor);
83 };
84
85 std::string DoFileIO(const base::FilePath& file_path) {
86   base::FilePath header_file =
87       base::FilePath(file_path.value() + kMockHeaderFileSuffix);
88
89   if (!base::PathExists(header_file)) {
90     // If there is no mock-http-headers file, fake a 200 OK.
91     return "HTTP/1.0 200 OK\n";
92   }
93
94   std::string raw_headers;
95   base::ReadFileToString(header_file, &raw_headers);
96   return raw_headers;
97 }
98
99 }  // namespace
100
101 // static
102 void URLRequestMockHTTPJob::AddUrlHandler(
103     const base::FilePath& base_path,
104     const scoped_refptr<base::SequencedWorkerPool>& worker_pool) {
105   // Add kMockHostname to net::URLRequestFilter.
106   net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
107   filter->AddHostnameInterceptor(
108       "http", kMockHostname, CreateInterceptor(base_path, worker_pool));
109 }
110
111 // static
112 void URLRequestMockHTTPJob::AddHostnameToFileHandler(
113     const std::string& hostname,
114     const base::FilePath& file,
115     const scoped_refptr<base::SequencedWorkerPool>& worker_pool) {
116   net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
117   filter->AddHostnameInterceptor(
118       "http", hostname, CreateInterceptorForSingleFile(file, worker_pool));
119 }
120
121 // static
122 GURL URLRequestMockHTTPJob::GetMockUrl(const base::FilePath& path) {
123   std::string url = "http://";
124   url.append(kMockHostname);
125   url.append("/");
126   std::string path_str = path.MaybeAsASCII();
127   DCHECK(!path_str.empty());  // We only expect ASCII paths in tests.
128   url.append(path_str);
129   return GURL(url);
130 }
131
132 // static
133 GURL URLRequestMockHTTPJob::GetMockUrlWithFailure(const base::FilePath& path,
134                                                   FailurePhase phase,
135                                                   int net_error) {
136   COMPILE_ASSERT(arraysize(kFailurePhase) == MAX_FAILURE_PHASE,
137                  kFailurePhase_must_match_FailurePhase_enum);
138   DCHECK_GE(phase, START);
139   DCHECK_LE(phase, READ_SYNC);
140   std::string url(GetMockUrl(path).spec());
141   url.append("?");
142   url.append(kFailurePhase[phase]);
143   url.append("=");
144   url.append(base::IntToString(net_error));
145   return GURL(url);
146 }
147
148 // static
149 scoped_ptr<net::URLRequestInterceptor> URLRequestMockHTTPJob::CreateInterceptor(
150     const base::FilePath& base_path,
151     const scoped_refptr<base::SequencedWorkerPool>& worker_pool) {
152   return scoped_ptr<net::URLRequestInterceptor>(
153       new MockJobInterceptor(base_path, false, worker_pool));
154 }
155
156 // static
157 scoped_ptr<net::URLRequestInterceptor>
158 URLRequestMockHTTPJob::CreateInterceptorForSingleFile(
159     const base::FilePath& file,
160     const scoped_refptr<base::SequencedWorkerPool>& worker_pool) {
161   return scoped_ptr<net::URLRequestInterceptor>(
162       new MockJobInterceptor(file, true, worker_pool));
163 }
164
165 URLRequestMockHTTPJob::URLRequestMockHTTPJob(
166     net::URLRequest* request,
167     net::NetworkDelegate* network_delegate,
168     const base::FilePath& file_path,
169     const scoped_refptr<base::TaskRunner>& task_runner)
170     : net::URLRequestFileJob(request, network_delegate, file_path, task_runner),
171       task_runner_(task_runner),
172       weak_ptr_factory_(this) {
173 }
174
175 URLRequestMockHTTPJob::~URLRequestMockHTTPJob() {
176 }
177
178 // Public virtual version.
179 void URLRequestMockHTTPJob::GetResponseInfo(net::HttpResponseInfo* info) {
180   // Forward to private const version.
181   GetResponseInfoConst(info);
182 }
183
184 bool URLRequestMockHTTPJob::IsRedirectResponse(GURL* location,
185                                                int* http_status_code) {
186   // Override the net::URLRequestFileJob implementation to invoke the default
187   // one based on HttpResponseInfo.
188   return net::URLRequestJob::IsRedirectResponse(location, http_status_code);
189 }
190
191 // Public virtual version.
192 void URLRequestMockHTTPJob::Start() {
193   if (MaybeReportErrorOnPhase(START))
194     return;
195   base::PostTaskAndReplyWithResult(
196       task_runner_.get(),
197       FROM_HERE,
198       base::Bind(&DoFileIO, file_path_),
199       base::Bind(&URLRequestMockHTTPJob::SetHeadersAndStart,
200                  weak_ptr_factory_.GetWeakPtr()));
201 }
202
203 // Public virtual version.
204 bool URLRequestMockHTTPJob::ReadRawData(IOBuffer* buf,
205                                         int buf_size,
206                                         int* bytes_read) {
207   if (MaybeReportErrorOnPhase(READ_SYNC))
208     return false;
209   if (MaybeReportErrorOnPhase(READ_ASYNC))
210     return false;
211   return URLRequestFileJob::ReadRawData(buf, buf_size, bytes_read);
212 }
213
214 void URLRequestMockHTTPJob::SetHeadersAndStart(const std::string& raw_headers) {
215   if (MaybeReportErrorOnPhase(START))
216     return;
217   raw_headers_ = raw_headers;
218   // Handle CRLF line-endings.
219   ReplaceSubstringsAfterOffset(&raw_headers_, 0, "\r\n", "\n");
220   // ParseRawHeaders expects \0 to end each header line.
221   ReplaceSubstringsAfterOffset(&raw_headers_, 0, "\n", std::string("\0", 1));
222   URLRequestFileJob::Start();
223 }
224
225 bool URLRequestMockHTTPJob::MaybeReportErrorOnPhase(
226     FailurePhase current_phase) {
227   DCHECK_GE(current_phase, START);
228   DCHECK_LE(current_phase, READ_SYNC);
229   std::string phase_key(kFailurePhase[current_phase]);
230   std::string phase_error_string;
231   if (!GetValueForKeyInQuery(request_->url(), phase_key, &phase_error_string))
232     return false;
233
234   int net_error;
235   if (!base::StringToInt(phase_error_string, &net_error))
236     return false;
237
238   if (net_error != net::ERR_IO_PENDING &&
239       (current_phase == START || current_phase == READ_SYNC)) {
240     NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, net_error));
241     return true;
242   }
243
244   SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
245
246   if (current_phase != READ_ASYNC)
247     return true;
248
249   base::MessageLoopProxy::current()->PostTask(
250       FROM_HERE,
251       base::Bind(
252           &URLRequestMockHTTPJob::NotifyDone,
253           weak_ptr_factory_.GetWeakPtr(),
254           net::URLRequestStatus(net::URLRequestStatus::FAILED, net_error)));
255
256   return true;
257 }
258
259 // Private const version.
260 void URLRequestMockHTTPJob::GetResponseInfoConst(
261     net::HttpResponseInfo* info) const {
262   info->headers = new net::HttpResponseHeaders(raw_headers_);
263 }
264
265 bool URLRequestMockHTTPJob::GetMimeType(std::string* mime_type) const {
266   net::HttpResponseInfo info;
267   GetResponseInfoConst(&info);
268   return info.headers.get() && info.headers->GetMimeType(mime_type);
269 }
270
271 int URLRequestMockHTTPJob::GetResponseCode() const {
272   net::HttpResponseInfo info;
273   GetResponseInfoConst(&info);
274   // If we have headers, get the response code from them.
275   if (info.headers.get())
276     return info.headers->response_code();
277   return net::URLRequestJob::GetResponseCode();
278 }
279
280 bool URLRequestMockHTTPJob::GetCharset(std::string* charset) {
281   net::HttpResponseInfo info;
282   GetResponseInfo(&info);
283   return info.headers.get() && info.headers->GetCharset(charset);
284 }
285
286 }  // namespace net