Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Side by Side Diff: net/test/embedded_test_server/request_helpers.cc

Issue 1376593007: SSL in EmbeddedTestServer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Removing unused macros. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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/embedded_test_server/request_helpers.h"
6
7 #include <stdlib.h>
8 #include <ctime>
9 #include <map>
10 #include <sstream>
11 #include <string>
12
13 #include "base/base64.h"
14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h"
16 #include "base/format_macros.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/threading/thread_restrictions.h"
20 #include "net/base/escape.h"
21 #include "net/base/url_util.h"
22 #include "net/http/http_byte_range.h"
23 #include "net/http/http_util.h"
24 #include "net/test/embedded_test_server/embedded_test_server.h"
25 #include "net/test/embedded_test_server/http_request.h"
26 #include "net/test/embedded_test_server/http_response.h"
27
28 namespace net {
29 namespace test_server {
30 namespace {
31
32 const UnescapeRule::Type kUnescapeAll =
33 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS |
34 UnescapeRule::SPOOFING_AND_CONTROL_CHARS |
35 UnescapeRule::REPLACE_PLUS_WITH_SPACE;
36
37 std::string GetContentType(const base::FilePath& path) {
38 if (path.MatchesExtension(FILE_PATH_LITERAL(".crx")))
39 return "application/x-chrome-extension";
40 else if (path.MatchesExtension(FILE_PATH_LITERAL(".exe")))
mmenke 2015/10/19 18:07:41 Don't need all these else's, since earlier branche
svaldez 2015/10/19 21:56:15 Done.
41 return "application/octet-stream";
42 else if (path.MatchesExtension(FILE_PATH_LITERAL(".gif")))
43 return "image/gif";
44 else if (path.MatchesExtension(FILE_PATH_LITERAL(".jpeg")) ||
45 path.MatchesExtension(FILE_PATH_LITERAL(".jpg")))
46 return "image/jpeg";
mmenke 2015/10/19 18:07:41 nit: Use braces when condition takes more than on
svaldez 2015/10/19 21:56:15 Done.
47 else if (path.MatchesExtension(FILE_PATH_LITERAL(".js")))
48 return "application/javascript";
49 else if (path.MatchesExtension(FILE_PATH_LITERAL(".json")))
50 return "application/json";
51 else if (path.MatchesExtension(FILE_PATH_LITERAL(".pdf")))
52 return "application/pdf";
53 else if (path.MatchesExtension(FILE_PATH_LITERAL(".txt")))
54 return "text/plain";
55 else if (path.MatchesExtension(FILE_PATH_LITERAL(".wav")))
56 return "audio/wav";
57 else if (path.MatchesExtension(FILE_PATH_LITERAL(".xml")))
58 return "text/xml";
59 else if (path.MatchesExtension(FILE_PATH_LITERAL(".html")) ||
60 path.MatchesExtension(FILE_PATH_LITERAL(".htm")))
61 return "text/html";
mmenke 2015/10/19 18:07:41 nit: braces
svaldez 2015/10/19 21:56:15 Done.
62 return "";
63 }
64
65 }
mmenke 2015/10/19 18:07:41 } // namespace
svaldez 2015/10/19 21:56:15 Done.
66
67 void CustomHttpResponse::SendResponse(SendBytesCallback send,
68 SendCompleteCallback done) {
69 std::string response;
70 if (headers_.size() != 0 || contents_.size() != 0)
mmenke 2015/10/19 18:07:41 prefer !headers_.empty() (It may be faster / small
svaldez 2015/10/19 21:56:15 Done.
71 response = headers_ + "\r\n" + contents_;
72 send.Run(response, done);
73 }
74
75 bool ShouldHandle(const HttpRequest& request, std::string path_prefix) {
mmenke 2015/10/19 18:07:41 std::string -> const std::string&
svaldez 2015/10/19 21:56:15 Done.
76 GURL url = request.ToURL();
77 return url.path() == path_prefix ||
78 base::StartsWith(url.path(), path_prefix + "/",
79 base::CompareCase::SENSITIVE);
80 }
81
82 scoped_ptr<HttpResponse> HandlePrefixedRequest(
83 std::string prefix,
84 EmbeddedTestServer::HandleRequestCallback handler,
85 const HttpRequest& request) {
86 if (ShouldHandle(request, prefix))
87 return handler.Run(request);
88 return nullptr;
89 }
90
91 RequestQuery ParseQuery(const GURL& url) {
92 RequestQuery queries;
93 for (QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
94 queries[net::UnescapeURLComponent(it.GetKey(), kUnescapeAll)].push_back(
95 it.GetUnescapedValue());
96 }
97 return queries;
98 }
99
100 void GetFilePathWithReplacements(const std::string& original_file_path,
101 const base::StringPairs& text_to_replace,
102 std::string* replacement_path) {
103 std::string new_file_path = original_file_path;
104 bool first_query_parameter = true;
105 for (auto replacement : text_to_replace) {
106 const std::string& old_text = replacement.first;
107 const std::string& new_text = replacement.second;
108 std::string base64_old;
109 std::string base64_new;
110 base::Base64Encode(old_text, &base64_old);
111 base::Base64Encode(new_text, &base64_new);
112 if (first_query_parameter) {
113 new_file_path += "?";
114 first_query_parameter = false;
115 } else {
116 new_file_path += "&";
117 }
118 new_file_path += "replace_text=";
119 new_file_path += base64_old;
120 new_file_path += ":";
121 new_file_path += base64_new;
122 }
123
124 *replacement_path = new_file_path;
125 }
126
127 // Handles |request| by serving a file from under |server_root|.
128 scoped_ptr<HttpResponse> HandleFileRequest(const base::FilePath& server_root,
129 const HttpRequest& request) {
130 // This is a test-only server. Ignore I/O thread restrictions.
mmenke 2015/10/19 18:07:41 Could you add a TODO about figuring out why this i
svaldez 2015/10/19 21:56:15 Done.
131 base::ThreadRestrictions::ScopedAllowIO allow_io;
132
133 std::string relative_url(request.relative_url);
134
135 // A proxy request will have an absolute path. Simulate the proxy by stripping
136 // the scheme, host, and port.
137 GURL request_gurl = request.ToURL();
mmenke 2015/10/19 18:07:41 nit: request_url
svaldez 2015/10/19 21:56:15 Done.
138 relative_url = request_gurl.path();
mmenke 2015/10/19 18:07:41 Suggest calling this relative_path (Since this is
svaldez 2015/10/19 21:56:15 Done.
139
140 std::string post_prefix("/post/");
141 if (base::StartsWith(relative_url, post_prefix,
142 base::CompareCase::SENSITIVE)) {
143 relative_url = relative_url.substr(post_prefix.size() - 1);
144 if (request.method != METHOD_POST)
145 return nullptr;
146 }
147
148 RequestQuery query = ParseQuery(request_gurl);
149
150 scoped_ptr<BasicHttpResponse> failed_response(new BasicHttpResponse);
151 failed_response->set_code(HTTP_NOT_FOUND);
152
153 if (query.find("expected_body") != query.end()) {
154 if (request.content.find(query["expected_body"].front()) ==
155 std::string::npos) {
156 return failed_response.Pass();
157 }
158 }
159
160 if (query.find("expected_headers") != query.end()) {
161 for (auto header : query["expected_headers"]) {
162 if (header.find(":") == std::string::npos)
163 return failed_response.Pass();
164 std::string key = header.substr(0, header.find(":"));
165 std::string value = header.substr(header.find(":") + 1);
166 if (request.headers.find(key) == request.headers.end() ||
167 request.headers.at(key) != value) {
168 return failed_response.Pass();
169 }
170 }
171 }
172
173 // Trim the first byte ('/').
174 std::string request_path = relative_url.substr(1);
175 base::FilePath file_path(server_root.AppendASCII(request_path));
176 std::string file_contents;
177 if (!base::ReadFileToString(file_path, &file_contents)) {
178 file_path = file_path.AppendASCII("index.html");
179 if (!base::ReadFileToString(file_path, &file_contents))
180 return nullptr;
181 }
182
183 if (request.method == METHOD_HEAD)
184 file_contents = "";
185
186 if (query.find("replace_text") != query.end()) {
187 for (auto replacement : query["replace_text"]) {
188 std::string find;
189 std::string with;
190 base::Base64Decode(replacement.substr(0, replacement.find(":")), &find);
191 base::Base64Decode(replacement.substr(replacement.find(":") + 1), &with);
192 base::ReplaceSubstringsAfterOffset(&file_contents, 0, find, with);
193 }
194 }
195
196 base::FilePath headers_path(
197 file_path.AddExtension(FILE_PATH_LITERAL("mock-http-headers")));
198
199 if (base::PathExists(headers_path)) {
200 std::string headers_contents;
201
202 if (!base::ReadFileToString(headers_path, &headers_contents))
203 return nullptr;
204
205 scoped_ptr<CustomHttpResponse> http_response(
206 new CustomHttpResponse(headers_contents, file_contents));
207 return http_response.Pass();
208 }
209
210 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
211 http_response->set_code(HTTP_OK);
212
213 if (request.headers.find("Range") != request.headers.end()) {
214 std::vector<HttpByteRange> ranges;
215 HttpUtil::ParseRangeHeader(request.headers.at("Range"), &ranges);
216 if (ranges.size() == 1) {
217 ranges[0].ComputeBounds(file_contents.size());
218 size_t start = ranges[0].first_byte_position();
219 size_t end = ranges[0].last_byte_position();
220
221 http_response->set_code(HTTP_PARTIAL_CONTENT);
222 http_response->AddCustomHeader(
223 "Content-Range",
224 base::StringPrintf("bytes %" PRIuS "-%" PRIuS "/%" PRIuS, start, end,
225 file_contents.size()));
226
227 file_contents = file_contents.substr(start, end - start + 1);
228 }
229 }
230
231 http_response->set_content_type(GetContentType(file_path));
232 http_response->AddCustomHeader("Accept-Ranges", "bytes");
233 http_response->AddCustomHeader("ETag", "'" + file_path.MaybeAsASCII() + "'");
234 http_response->set_content(file_contents);
235 return http_response.Pass();
236 }
237
238 } // namespace test_server
239 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698