1 // Copyright (c) 2010 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 "chrome/browser/net/url_request_mock_http_job.h"
6
7 #include "base/file_util.h"
8 #include "base/message_loop.h"
9 #include "base/string_util.h"
10 #include "base/threading/thread_restrictions.h"
11 #include "base/utf_string_conversions.h"
12 #include "chrome/common/url_constants.h"
13 #include "net/base/net_util.h"
14 #include "net/http/http_response_headers.h"
15 #include "net/url_request/url_request_filter.h"
16
17 static const char kMockHostname[] = "mock.http";
18 static const FilePath::CharType kMockHeaderFileSuffix[] =
19 FILE_PATH_LITERAL(".mock-http-headers");
20
21 FilePath URLRequestMockHTTPJob::base_path_;
22
23 // static
Factory(net::URLRequest * request,const std::string & scheme)24 net::URLRequestJob* URLRequestMockHTTPJob::Factory(net::URLRequest* request,
25 const std::string& scheme) {
26 return new URLRequestMockHTTPJob(request,
27 GetOnDiskPath(base_path_, request, scheme));
28 }
29
30 // static
AddUrlHandler(const FilePath & base_path)31 void URLRequestMockHTTPJob::AddUrlHandler(const FilePath& base_path) {
32 base_path_ = base_path;
33
34 // Add kMockHostname to net::URLRequestFilter.
35 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
36 filter->AddHostnameHandler("http", kMockHostname,
37 URLRequestMockHTTPJob::Factory);
38 }
39
40 /* static */
GetMockUrl(const FilePath & path)41 GURL URLRequestMockHTTPJob::GetMockUrl(const FilePath& path) {
42 std::string url = "http://";
43 url.append(kMockHostname);
44 url.append("/");
45 std::string path_str = path.MaybeAsASCII();
46 DCHECK(!path_str.empty()); // We only expect ASCII paths in tests.
47 url.append(path_str);
48 return GURL(url);
49 }
50
51 /* static */
GetMockViewSourceUrl(const FilePath & path)52 GURL URLRequestMockHTTPJob::GetMockViewSourceUrl(const FilePath& path) {
53 std::string url = chrome::kViewSourceScheme;
54 url.append(":");
55 url.append(GetMockUrl(path).spec());
56 return GURL(url);
57 }
58
59 /* static */
GetOnDiskPath(const FilePath & base_path,net::URLRequest * request,const std::string & scheme)60 FilePath URLRequestMockHTTPJob::GetOnDiskPath(const FilePath& base_path,
61 net::URLRequest* request,
62 const std::string& scheme) {
63 // Conceptually we just want to "return base_path + request->url().path()".
64 // But path in the request URL is in URL space (i.e. %-encoded spaces).
65 // So first we convert base FilePath to a URL, then append the URL
66 // path to that, and convert the final URL back to a FilePath.
67 GURL file_url(net::FilePathToFileURL(base_path));
68 std::string url = file_url.spec() + request->url().path();
69 FilePath file_path;
70 net::FileURLToFilePath(GURL(url), &file_path);
71 return file_path;
72 }
73
URLRequestMockHTTPJob(net::URLRequest * request,const FilePath & file_path)74 URLRequestMockHTTPJob::URLRequestMockHTTPJob(net::URLRequest* request,
75 const FilePath& file_path)
76 : net::URLRequestFileJob(request, file_path) { }
77
78 // Public virtual version.
GetResponseInfo(net::HttpResponseInfo * info)79 void URLRequestMockHTTPJob::GetResponseInfo(net::HttpResponseInfo* info) {
80 // Forward to private const version.
81 GetResponseInfoConst(info);
82 }
83
IsRedirectResponse(GURL * location,int * http_status_code)84 bool URLRequestMockHTTPJob::IsRedirectResponse(GURL* location,
85 int* http_status_code) {
86 // Override the net::URLRequestFileJob implementation to invoke the default
87 // one based on HttpResponseInfo.
88 return net::URLRequestJob::IsRedirectResponse(location, http_status_code);
89 }
90
91 // Private const version.
GetResponseInfoConst(net::HttpResponseInfo * info) const92 void URLRequestMockHTTPJob::GetResponseInfoConst(
93 net::HttpResponseInfo* info) const {
94 // We have to load our headers from disk, but we only use this class
95 // from tests, so allow these IO operations to happen on any thread.
96 base::ThreadRestrictions::ScopedAllowIO allow_io;
97
98 FilePath header_file = FilePath(file_path_.value() + kMockHeaderFileSuffix);
99 std::string raw_headers;
100 if (!file_util::ReadFileToString(header_file, &raw_headers))
101 return;
102
103 // ParseRawHeaders expects \0 to end each header line.
104 ReplaceSubstringsAfterOffset(&raw_headers, 0, "\n", std::string("\0", 1));
105 info->headers = new net::HttpResponseHeaders(raw_headers);
106 }
107
GetMimeType(std::string * mime_type) const108 bool URLRequestMockHTTPJob::GetMimeType(std::string* mime_type) const {
109 net::HttpResponseInfo info;
110 GetResponseInfoConst(&info);
111 return info.headers && info.headers->GetMimeType(mime_type);
112 }
113
GetCharset(std::string * charset)114 bool URLRequestMockHTTPJob::GetCharset(std::string* charset) {
115 net::HttpResponseInfo info;
116 GetResponseInfo(&info);
117 return info.headers && info.headers->GetCharset(charset);
118 }
119