1// Copyright 2013 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/weburl_loader_mock_factory.h"
6
7#include "base/files/file_util.h"
8#include "base/logging.h"
9#include "base/run_loop.h"
10#include "content/test/weburl_loader_mock.h"
11#include "third_party/WebKit/public/platform/WebString.h"
12#include "third_party/WebKit/public/platform/WebURLError.h"
13#include "third_party/WebKit/public/platform/WebURLRequest.h"
14#include "third_party/WebKit/public/platform/WebURLResponse.h"
15#include "third_party/WebKit/public/web/WebCache.h"
16
17using blink::WebCache;
18using blink::WebData;
19using blink::WebString;
20using blink::WebURL;
21using blink::WebURLError;
22using blink::WebURLLoader;
23using blink::WebURLRequest;
24using blink::WebURLResponse;
25
26WebURLLoaderMockFactory::WebURLLoaderMockFactory() {}
27
28WebURLLoaderMockFactory::~WebURLLoaderMockFactory() {}
29
30void WebURLLoaderMockFactory::RegisterURL(const WebURL& url,
31                                          const WebURLResponse& response,
32                                          const WebString& file_path) {
33  ResponseInfo response_info;
34  response_info.response = response;
35  if (!file_path.isNull() && !file_path.isEmpty()) {
36#if defined(OS_POSIX)
37    // TODO(jcivelli): On Linux, UTF8 might not be correct.
38    response_info.file_path =
39        base::FilePath(static_cast<std::string>(file_path.utf8()));
40#elif defined(OS_WIN)
41    base::string16 file_path_16 = file_path;
42    response_info.file_path = base::FilePath(std::wstring(
43        file_path_16.data(), file_path_16.length()));
44#endif
45    DCHECK(base::PathExists(response_info.file_path))
46        << response_info.file_path.MaybeAsASCII() << " does not exist.";
47  }
48
49  DCHECK(url_to_reponse_info_.find(url) == url_to_reponse_info_.end());
50  url_to_reponse_info_[url] = response_info;
51}
52
53
54void WebURLLoaderMockFactory::RegisterErrorURL(const WebURL& url,
55                                               const WebURLResponse& response,
56                                               const WebURLError& error) {
57  DCHECK(url_to_reponse_info_.find(url) == url_to_reponse_info_.end());
58  RegisterURL(url, response, WebString());
59  url_to_error_info_[url] = error;
60}
61
62void WebURLLoaderMockFactory::UnregisterURL(const blink::WebURL& url) {
63  URLToResponseMap::iterator iter = url_to_reponse_info_.find(url);
64  DCHECK(iter != url_to_reponse_info_.end());
65  url_to_reponse_info_.erase(iter);
66
67  URLToErrorMap::iterator error_iter = url_to_error_info_.find(url);
68  if (error_iter != url_to_error_info_.end())
69    url_to_error_info_.erase(error_iter);
70}
71
72void WebURLLoaderMockFactory::UnregisterAllURLs() {
73  url_to_reponse_info_.clear();
74  url_to_error_info_.clear();
75  WebCache::clear();
76}
77
78void WebURLLoaderMockFactory::ServeAsynchronousRequests() {
79  last_handled_asynchronous_request_.reset();
80  // Serving a request might trigger more requests, so we cannot iterate on
81  // pending_loaders_ as it might get modified.
82  while (!pending_loaders_.empty()) {
83    LoaderToRequestMap::iterator iter = pending_loaders_.begin();
84    WebURLLoaderMock* loader = iter->first;
85    const WebURLRequest& request = iter->second;
86    WebURLResponse response;
87    WebURLError error;
88    WebData data;
89    last_handled_asynchronous_request_ = request;
90    LoadRequest(request, &response, &error, &data);
91    // Follow any redirects while the loader is still active.
92    while (response.httpStatusCode() >= 300 &&
93           response.httpStatusCode() < 400) {
94      WebURLRequest newRequest = loader->ServeRedirect(response);
95      if (!IsPending(loader) || loader->isDeferred())
96        break;
97      last_handled_asynchronous_request_ = newRequest;
98      LoadRequest(newRequest, &response, &error, &data);
99    }
100    // Serve the request if the loader is still active.
101    if (IsPending(loader) && !loader->isDeferred())
102      loader->ServeAsynchronousRequest(response, data, error);
103    // The loader might have already been removed.
104    pending_loaders_.erase(loader);
105  }
106  base::RunLoop().RunUntilIdle();
107}
108
109blink::WebURLRequest
110WebURLLoaderMockFactory::GetLastHandledAsynchronousRequest() {
111  return last_handled_asynchronous_request_;
112}
113
114bool WebURLLoaderMockFactory::IsMockedURL(const blink::WebURL& url) {
115  return url_to_reponse_info_.find(url) != url_to_reponse_info_.end();
116}
117
118void WebURLLoaderMockFactory::CancelLoad(WebURLLoaderMock* loader) {
119  LoaderToRequestMap::iterator iter = pending_loaders_.find(loader);
120  DCHECK(iter != pending_loaders_.end());
121  pending_loaders_.erase(iter);
122}
123
124WebURLLoader* WebURLLoaderMockFactory::CreateURLLoader(
125    WebURLLoader* default_loader) {
126  DCHECK(default_loader);
127  return new WebURLLoaderMock(this, default_loader);
128}
129
130void WebURLLoaderMockFactory::LoadSynchronously(const WebURLRequest& request,
131                                                WebURLResponse* response,
132                                                WebURLError* error,
133                                                WebData* data) {
134  LoadRequest(request, response, error, data);
135}
136
137void WebURLLoaderMockFactory::LoadAsynchronouly(const WebURLRequest& request,
138                                                WebURLLoaderMock* loader) {
139  LoaderToRequestMap::iterator iter = pending_loaders_.find(loader);
140  DCHECK(iter == pending_loaders_.end());
141  pending_loaders_[loader] = request;
142}
143
144void WebURLLoaderMockFactory::LoadRequest(const WebURLRequest& request,
145                                          WebURLResponse* response,
146                                          WebURLError* error,
147                                          WebData* data) {
148  URLToErrorMap::const_iterator error_iter =
149      url_to_error_info_.find(request.url());
150  if (error_iter != url_to_error_info_.end())
151    *error = error_iter->second;
152
153  URLToResponseMap::const_iterator iter =
154      url_to_reponse_info_.find(request.url());
155  if (iter == url_to_reponse_info_.end()) {
156    // Non mocked URLs should not have been passed to the default URLLoader.
157    NOTREACHED();
158    return;
159  }
160
161  if (!error->reason && !ReadFile(iter->second.file_path, data)) {
162    NOTREACHED();
163    return;
164  }
165
166  *response = iter->second.response;
167}
168
169bool WebURLLoaderMockFactory::IsPending(WebURLLoaderMock* loader) {
170  LoaderToRequestMap::iterator iter = pending_loaders_.find(loader);
171  return iter != pending_loaders_.end();
172}
173
174// static
175bool WebURLLoaderMockFactory::ReadFile(const base::FilePath& file_path,
176                                       WebData* data) {
177  int64 file_size = 0;
178  if (!base::GetFileSize(file_path, &file_size))
179    return false;
180
181  int size = static_cast<int>(file_size);
182  scoped_ptr<char[]> buffer(new char[size]);
183  data->reset();
184  int read_count = base::ReadFile(file_path, buffer.get(), size);
185  if (read_count == -1)
186    return false;
187  DCHECK(read_count == size);
188  data->assign(buffer.get(), size);
189
190  return true;
191}
192