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

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: Adding TODO to fix handlers post-Start. 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>
mmenke 2015/10/21 20:21:37 map, string should be in the header, per comment i
svaldez 2015/10/21 21:22:29 Done.
12
13 #include "base/base64.h"
14 #include "base/files/file_path.h"
mmenke 2015/10/21 20:21:37 Already in header
svaldez 2015/10/21 21:22:29 Done.
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 if (path.MatchesExtension(FILE_PATH_LITERAL(".exe")))
41 return "application/octet-stream";
42 if (path.MatchesExtension(FILE_PATH_LITERAL(".gif")))
43 return "image/gif";
44 if (path.MatchesExtension(FILE_PATH_LITERAL(".jpeg")) ||
45 path.MatchesExtension(FILE_PATH_LITERAL(".jpg"))) {
46 return "image/jpeg";
47 }
48 if (path.MatchesExtension(FILE_PATH_LITERAL(".js")))
49 return "application/javascript";
50 if (path.MatchesExtension(FILE_PATH_LITERAL(".json")))
51 return "application/json";
52 if (path.MatchesExtension(FILE_PATH_LITERAL(".pdf")))
53 return "application/pdf";
54 if (path.MatchesExtension(FILE_PATH_LITERAL(".txt")))
55 return "text/plain";
56 if (path.MatchesExtension(FILE_PATH_LITERAL(".wav")))
57 return "audio/wav";
58 if (path.MatchesExtension(FILE_PATH_LITERAL(".xml")))
59 return "text/xml";
60 if (path.MatchesExtension(FILE_PATH_LITERAL(".html")) ||
61 path.MatchesExtension(FILE_PATH_LITERAL(".htm"))) {
62 return "text/html";
63 }
64 return "";
65 }
66
67 } // namespace
68
69 CustomHttpResponse::CustomHttpResponse(const std::string& headers,
70 const std::string& contents)
71 : headers_(headers), contents_(contents) {}
72
73 void CustomHttpResponse::SendResponse(const SendBytesCallback& send,
74 const SendCompleteCallback& done) {
75 std::string response;
76 if (!headers_.empty() || !contents_.empty())
77 response = headers_ + "\r\n" + contents_;
mmenke 2015/10/21 20:21:37 This seems kinda weird, if headers_ is empty but c
svaldez 2015/10/21 21:22:29 Done.
78 send.Run(response, done);
79 }
80
81 bool ShouldHandle(const HttpRequest& request, const std::string& path_prefix) {
82 GURL url = request.ToURL();
83 return url.path() == path_prefix ||
84 base::StartsWith(url.path(), path_prefix + "/",
85 base::CompareCase::SENSITIVE);
86 }
87
88 scoped_ptr<HttpResponse> HandlePrefixedRequest(
89 const std::string& prefix,
90 const EmbeddedTestServer::HandleRequestCallback& handler,
91 const HttpRequest& request) {
92 if (ShouldHandle(request, prefix))
93 return handler.Run(request);
94 return nullptr;
95 }
96
97 RequestQuery ParseQuery(const GURL& url) {
98 RequestQuery queries;
99 for (QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
100 queries[net::UnescapeURLComponent(it.GetKey(), kUnescapeAll)].push_back(
101 it.GetUnescapedValue());
102 }
103 return queries;
104 }
105
106 void GetFilePathWithReplacements(const std::string& original_file_path,
107 const base::StringPairs& text_to_replace,
108 std::string* replacement_path) {
109 std::string new_file_path = original_file_path;
110 bool first_query_parameter = true;
111 for (auto replacement : text_to_replace) {
mmenke 2015/10/21 20:21:37 const auto& is preferred, I believe.
svaldez 2015/10/21 21:22:29 Done.
112 const std::string& old_text = replacement.first;
113 const std::string& new_text = replacement.second;
114 std::string base64_old;
115 std::string base64_new;
116 base::Base64Encode(old_text, &base64_old);
117 base::Base64Encode(new_text, &base64_new);
118 if (first_query_parameter) {
mmenke 2015/10/21 20:21:37 nit: Maybe get rid of this variable and use new_f
svaldez 2015/10/21 21:22:29 Done.
119 new_file_path += "?";
120 first_query_parameter = false;
121 } else {
122 new_file_path += "&";
123 }
124 new_file_path += "replace_text=";
125 new_file_path += base64_old;
126 new_file_path += ":";
127 new_file_path += base64_new;
128 }
129
130 *replacement_path = new_file_path;
131 }
132
133 // Handles |request| by serving a file from under |server_root|.
134 scoped_ptr<HttpResponse> HandleFileRequest(const base::FilePath& server_root,
135 const HttpRequest& request) {
136 // This is a test-only server. Ignore I/O thread restrictions.
137 // TODO(svaldez): Figure out why restriction is necessary.
mmenke 2015/10/21 20:21:37 Think "why restriction is necessary" -> "why threa
svaldez 2015/10/21 21:22:29 Done.
138 base::ThreadRestrictions::ScopedAllowIO allow_io;
139
140 std::string relative_path(request.relative_url);
mmenke 2015/10/21 20:21:37 Not needed - can you overwrite it unconditionally
svaldez 2015/10/21 21:22:29 Done.
141
142 // A proxy request will have an absolute path. Simulate the proxy by stripping
143 // the scheme, host, and port.
144 GURL request_url = request.ToURL();
145 relative_path = request_url.path();
146
147 std::string post_prefix("/post/");
148 if (base::StartsWith(relative_path, post_prefix,
149 base::CompareCase::SENSITIVE)) {
150 relative_path = relative_path.substr(post_prefix.size() - 1);
151 if (request.method != METHOD_POST)
152 return nullptr;
mmenke 2015/10/21 20:21:37 Suggest moving this above setting relative_path.
svaldez 2015/10/21 21:22:29 Done.
153 }
154
155 RequestQuery query = ParseQuery(request_url);
156
157 scoped_ptr<BasicHttpResponse> failed_response(new BasicHttpResponse);
158 failed_response->set_code(HTTP_NOT_FOUND);
159
160 if (query.find("expected_body") != query.end()) {
161 if (request.content.find(query["expected_body"].front()) ==
162 std::string::npos) {
163 return failed_response.Pass();
164 }
165 }
166
167 if (query.find("expected_headers") != query.end()) {
168 for (auto header : query["expected_headers"]) {
mmenke 2015/10/21 20:21:37 const auto&
svaldez 2015/10/21 21:22:29 Done.
169 if (header.find(":") == std::string::npos)
170 return failed_response.Pass();
171 std::string key = header.substr(0, header.find(":"));
172 std::string value = header.substr(header.find(":") + 1);
mmenke 2015/10/21 20:21:37 Hrm...Thought I commented on this. If header.find
svaldez 2015/10/21 21:22:29 But it won't be since we return a failure a few li
173 if (request.headers.find(key) == request.headers.end() ||
174 request.headers.at(key) != value) {
175 return failed_response.Pass();
176 }
177 }
178 }
179
180 // Trim the first byte ('/').
mmenke 2015/10/21 20:21:37 DCHECK that relative_path starts with "/"?
svaldez 2015/10/21 21:22:29 Done.
181 std::string request_path = relative_path.substr(1);
182 base::FilePath file_path(server_root.AppendASCII(request_path));
183 std::string file_contents;
184 if (!base::ReadFileToString(file_path, &file_contents)) {
185 file_path = file_path.AppendASCII("index.html");
186 if (!base::ReadFileToString(file_path, &file_contents))
187 return nullptr;
188 }
189
190 if (request.method == METHOD_HEAD)
191 file_contents = "";
192
193 if (query.find("replace_text") != query.end()) {
194 for (auto replacement : query["replace_text"]) {
mmenke 2015/10/21 20:21:37 const auto&
svaldez 2015/10/21 21:22:29 Done.
195 std::string find;
196 std::string with;
197 base::Base64Decode(replacement.substr(0, replacement.find(":")), &find);
198 base::Base64Decode(replacement.substr(replacement.find(":") + 1), &with);
199 base::ReplaceSubstringsAfterOffset(&file_contents, 0, find, with);
200 }
201 }
202
203 base::FilePath headers_path(
204 file_path.AddExtension(FILE_PATH_LITERAL("mock-http-headers")));
205
206 if (base::PathExists(headers_path)) {
207 std::string headers_contents;
208
209 if (!base::ReadFileToString(headers_path, &headers_contents))
210 return nullptr;
211
212 scoped_ptr<CustomHttpResponse> http_response(
213 new CustomHttpResponse(headers_contents, file_contents));
214 return http_response.Pass();
mmenke 2015/10/21 20:21:37 optional nit: Could just do: return make_scoped_
svaldez 2015/10/21 21:22:29 Done.
215 }
216
217 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
218 http_response->set_code(HTTP_OK);
219
220 if (request.headers.find("Range") != request.headers.end()) {
221 std::vector<HttpByteRange> ranges;
222 HttpUtil::ParseRangeHeader(request.headers.at("Range"), &ranges);
223 if (ranges.size() == 1) {
mmenke 2015/10/21 20:21:37 Can we fail if size() is not 1, or if ParseRangeHe
svaldez 2015/10/21 21:22:29 I think we should be ignoring Range we don't suppo
mmenke 2015/10/21 21:36:38 Good point - you should then include the result of
224 ranges[0].ComputeBounds(file_contents.size());
225 size_t start = ranges[0].first_byte_position();
226 size_t end = ranges[0].last_byte_position();
227
228 http_response->set_code(HTTP_PARTIAL_CONTENT);
229 http_response->AddCustomHeader(
230 "Content-Range",
231 base::StringPrintf("bytes %" PRIuS "-%" PRIuS "/%" PRIuS, start, end,
232 file_contents.size()));
233
234 file_contents = file_contents.substr(start, end - start + 1);
235 }
236 }
237
238 http_response->set_content_type(GetContentType(file_path));
239 http_response->AddCustomHeader("Accept-Ranges", "bytes");
240 http_response->AddCustomHeader("ETag", "'" + file_path.MaybeAsASCII() + "'");
241 http_response->set_content(file_contents);
242 return http_response.Pass();
243 }
244
245 } // namespace test_server
246 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698