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

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: Rebase. 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/md5.h"
18 #include "base/path_service.h"
19 #include "base/strings/string_split.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/thread_task_runner_handle.h"
23 #include "base/threading/thread_restrictions.h"
24 #include "base/time/time.h"
25 #include "net/base/escape.h"
26 #include "net/base/url_util.h"
27 #include "net/test/embedded_test_server/embedded_test_server.h"
28 #include "net/test/embedded_test_server/http_request.h"
29 #include "net/test/embedded_test_server/http_response.h"
30
31 #define NOT_HANDLED scoped_ptr<HttpResponse>()
davidben 2015/10/13 19:43:48 Just return nullptr. nullptr has a distinct type (
mmenke 2015/10/13 19:55:50 I'm not sure all of these really belong in this CL
svaldez 2015/10/13 20:54:44 Even if we don't land request_helpers in this CL,
svaldez 2015/10/13 20:54:44 Done.
mmenke 2015/10/13 21:08:02 Just because the trybots pass does not mean this w
32
33 net::UnescapeRule::Type UNESCAPE_ALL =
34 net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS |
35 net::UnescapeRule::SPOOFING_AND_CONTROL_CHARS |
36 net::UnescapeRule::REPLACE_PLUS_WITH_SPACE;
37
38 namespace net {
39 namespace test_server {
40
41 void CustomHttpResponse::SendResponse(SendCallback send,
42 SendDoneCallback done) {
43 std::string response;
44 if (headers_.size() != 0 || contents_.size() != 0)
45 response = headers_ + "\r\n" + contents_;
46 send.Run(response, done);
47 }
48
49 bool ShouldHandle(const HttpRequest& request, std::string url) {
50 if (request.relative_url.compare(0, url.size(), url) == 0) {
51 if (request.relative_url.size() == url.size())
52 return true;
53 std::string endings("/?;#");
54 if (endings.find(request.relative_url.at(url.size())) != std::string::npos)
55 return true;
56 }
57 return false;
58 }
59
60 GURL ToGURL(const HttpRequest& request) {
61 return GURL("http://localhost" + request.relative_url);
62 }
63
64 RequestQuery ParseQuery(GURL url) {
65 RequestQuery queries;
66
67 for (QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
68 queries[net::UnescapeURLComponent(it.GetKey(), UNESCAPE_ALL)].push_back(
69 it.GetUnescapedValue());
70 }
71 return queries;
72 }
73
74 // Handles |request| by serving a file from under |server_root|.
75 scoped_ptr<HttpResponse> HandleFileRequest(const base::FilePath& server_root,
76 const HttpRequest& request) {
77 // This is a test-only server. Ignore I/O thread restrictions.
78 base::ThreadRestrictions::ScopedAllowIO allow_io;
79
80 std::string relative_url(request.relative_url);
81
82 // A proxy request will have an absolute path. Simulate the proxy by stripping
83 // the scheme, host, and port.
84 GURL request_gurl = ToGURL(request);
85 relative_url = request_gurl.path();
86
87 std::string files_prefix("/files/");
88 if (relative_url.compare(0, files_prefix.size(), files_prefix) == 0) {
89 LOG(ERROR) << "Using old-style /files/ for: " << relative_url;
90 relative_url = relative_url.substr(files_prefix.size() - 1);
91 }
92
93 std::string post_prefix("/post/");
94 if (relative_url.compare(0, post_prefix.size(), post_prefix) == 0) {
95 relative_url = relative_url.substr(post_prefix.size() - 1);
96 if (request.method != METHOD_POST)
97 return NOT_HANDLED;
98 }
99
100 RequestQuery query = ParseQuery(request_gurl);
101
102 if (query.find("expected_body") != query.end()) {
103 if (request.content.find(query["expected_body"].front()) ==
104 std::string::npos) {
105 scoped_ptr<BasicHttpResponse> not_found_response(new BasicHttpResponse);
106 not_found_response->set_code(HTTP_NOT_FOUND);
107 return not_found_response.Pass();
108 }
109 }
110
111 if (query.find("expected_headers") != query.end()) {
112 std::vector<std::string> headers = query["expected_headers"];
113 for (size_t i = 0; i < headers.size(); ++i) {
114 std::string key = headers[i].substr(0, headers[i].find(":"));
115 std::string value = headers[i].substr(headers[i].find(":") + 1);
116 if (request.headers.find(key) == request.headers.end() ||
117 request.headers.at(key) != value) {
118 scoped_ptr<BasicHttpResponse> not_found_response(new BasicHttpResponse);
119 not_found_response->set_code(HTTP_NOT_FOUND);
120 return not_found_response.Pass();
121 }
122 }
123 }
124
125 // Trim the first byte ('/').
126 std::string request_path = relative_url.substr(1);
127 base::FilePath file_path(server_root.AppendASCII(request_path));
128 std::string file_contents;
129 if (!base::ReadFileToString(file_path, &file_contents)) {
130 file_path = file_path.AppendASCII("index.html");
131 if (!base::ReadFileToString(file_path, &file_contents))
132 return NOT_HANDLED;
133 }
134
135 if (query.find("replace_text") != query.end()) {
136 std::vector<std::string> replacements = query["replace_text"];
137 for (size_t i = 0; i < replacements.size(); ++i) {
138 std::string find, with;
139 base::Base64Decode(replacements[i].substr(0, replacements[i].find(":")),
140 &find);
141 base::Base64Decode(replacements[i].substr(replacements[i].find(":") + 1),
142 &with);
143 base::ReplaceSubstringsAfterOffset(&file_contents, 0, find, with);
144 }
145 }
146
147 base::FilePath headers_path(
148 file_path.AddExtension(FILE_PATH_LITERAL("mock-http-headers")));
149
150 if (base::PathExists(headers_path)) {
151 std::string headers_contents;
152
153 if (!base::ReadFileToString(headers_path, &headers_contents))
154 return NOT_HANDLED;
155
156 if (request.method == METHOD_HEAD)
157 file_contents = "";
158
159 scoped_ptr<CustomHttpResponse> http_response(
160 new CustomHttpResponse(headers_contents, file_contents));
161 return http_response.Pass();
162 }
163
164 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
165 http_response->set_code(HTTP_OK);
166
167 if (request.headers.find("Range") != request.headers.end()) {
168 std::string range_header = request.headers.at("Range");
169 if (range_header.compare(0, 6, "bytes=") == 0) {
170 range_header = range_header.substr(6);
171
172 size_t start = 0;
173 size_t end = file_contents.size();
174 size_t delim = range_header.find("-");
175
176 if (delim == std::string::npos) {
177 start = std::atoi(range_header.c_str());
178 } else if (delim == range_header.size() - 1) {
179 start = std::atoi(range_header.substr(0, delim).c_str());
180 } else if (delim == 0) {
181 start = end - std::atoi(range_header.substr(1).c_str());
182 } else {
183 start = std::atoi(range_header.substr(0, delim).c_str());
184 end = std::atoi(range_header.substr(delim + 1).c_str());
185 }
186
187 http_response->set_code(HTTP_PARTIAL_CONTENT);
188 http_response->AddCustomHeader(
189 "Content-Range",
190 base::StringPrintf("bytes %" PRIuS "-%" PRIuS "/%" PRIuS, start,
191 end - 1, file_contents.size()));
192
193 file_contents = file_contents.substr(start, end - start);
194 }
195 }
196
197 base::FilePath::StringType ext = file_path.FinalExtension();
198 if (ext == FILE_PATH_LITERAL(".crx"))
199 http_response->set_content_type("application/x-chrome-extension");
200 else if (ext == FILE_PATH_LITERAL(".exe"))
201 http_response->set_content_type("application/octet-stream");
202 else if (ext == FILE_PATH_LITERAL(".gif"))
203 http_response->set_content_type("image/gif");
204 else if (ext == FILE_PATH_LITERAL(".jpeg") ||
205 ext == FILE_PATH_LITERAL(".jpg"))
206 http_response->set_content_type("image/jpeg");
207 else if (ext == FILE_PATH_LITERAL(".js"))
208 http_response->set_content_type("application/javascript");
209 else if (ext == FILE_PATH_LITERAL(".json"))
210 http_response->set_content_type("application/json");
211 else if (ext == FILE_PATH_LITERAL(".pdf"))
212 http_response->set_content_type("application/pdf");
213 else if (ext == FILE_PATH_LITERAL(".txt"))
214 http_response->set_content_type("text/plain");
215 else if (ext == FILE_PATH_LITERAL(".wav"))
216 http_response->set_content_type("audio/wav");
217 else if (ext == FILE_PATH_LITERAL(".xml"))
218 http_response->set_content_type("text/xml");
219 else if (ext == FILE_PATH_LITERAL(".html") ||
220 ext == FILE_PATH_LITERAL(".htm"))
221 http_response->set_content_type("text/html");
222
223 http_response->AddCustomHeader("Accept-Ranges", "bytes");
224 http_response->AddCustomHeader("ETag", "'" + file_path.MaybeAsASCII() + "'");
225 http_response->set_content(file_contents);
226 return http_response.Pass();
227 }
228
229 scoped_ptr<HttpResponse> HandleRedirectConnect(const HttpRequest& request) {
230 if (request.headers.find("Host") == request.headers.end() ||
231 request.headers.at("Host") != "www.redirect.com" ||
232 request.method != METHOD_CONNECT)
233 return NOT_HANDLED;
234
235 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
236 http_response->set_code(HTTP_FOUND);
237 http_response->AddCustomHeader("Location",
238 "http://www.destination.com/foo.js");
239 return http_response.Pass();
240 }
241
242 scoped_ptr<HttpResponse> HandleServerAuthConnect(const HttpRequest& request) {
243 if (request.headers.find("Host") == request.headers.end() ||
244 request.headers.at("Host") != "www.server-auth.com" ||
245 request.method != METHOD_CONNECT)
246 return NOT_HANDLED;
247
248 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
249 http_response->set_code(HTTP_UNAUTHORIZED);
250 http_response->AddCustomHeader("WWW-Authenticate",
251 "Basic realm=\"WallyWorld\"");
252 return http_response.Pass();
253 }
254
255 scoped_ptr<HttpResponse> HandleDefaultConnect(const HttpRequest& request) {
256 if (request.method != METHOD_CONNECT)
257 return NOT_HANDLED;
258
259 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
260 http_response->set_code(HTTP_BAD_REQUEST);
261 http_response->set_content(
262 "Your client has issued a malformed or illegal request.");
263 http_response->set_content_type("text/html");
264 return http_response.Pass();
265 }
266
267 scoped_ptr<HttpResponse> HandleCacheControl(std::string url,
268 std::string value,
269 const HttpRequest& request) {
270 if (!ShouldHandle(request, url))
271 return NOT_HANDLED;
272
273 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
274 http_response->set_code(HTTP_OK);
275 std::stringstream time;
276 time << std::time(0);
277 http_response->set_content("<html><head><title>" + time.str() +
278 "</title></head></html>");
279 http_response->set_content_type("text/html");
280 http_response->AddCustomHeader("Cache-Control", value);
281 return http_response.Pass();
282 }
283
284 scoped_ptr<HttpResponse> HandleCacheExpires(const HttpRequest& request) {
285 if (!ShouldHandle(request, "/cache/expires"))
286 return NOT_HANDLED;
287
288 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
289 http_response->set_code(HTTP_OK);
290 std::stringstream time;
291 time << std::time(0);
292 http_response->set_content("<html><head><title>" + time.str() +
293 "</title></head></html>");
294 http_response->set_content_type("text/html");
295 http_response->AddCustomHeader("Expires", "Thu, 1 Jan 2099 00:00:00 GMT");
296 return http_response.Pass();
297 }
298
299 scoped_ptr<HttpResponse> HandleEchoHeader(std::string url,
300 std::string value,
301 const HttpRequest& request) {
302 if (!ShouldHandle(request, url))
303 return NOT_HANDLED;
304
305 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
306 http_response->set_code(HTTP_OK);
307
308 GURL request_gurl = ToGURL(request);
309 if (request_gurl.has_query()) {
310 std::string header_name = request_gurl.query();
311 http_response->AddCustomHeader("Vary", header_name);
312 if (request.headers.find(header_name) != request.headers.end())
313 http_response->set_content(request.headers.at(header_name));
314 else
315 http_response->set_content("None");
316 }
317
318 http_response->set_content_type("text/plain");
319 http_response->AddCustomHeader("Cache-Control", value);
320 return http_response.Pass();
321 }
322
323 scoped_ptr<HttpResponse> HandleEcho(const HttpRequest& request) {
324 if (!ShouldHandle(request, "/echo"))
325 return NOT_HANDLED;
326
327 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
328 http_response->set_code(HTTP_OK);
329
330 GURL request_gurl = ToGURL(request);
331 if (request_gurl.has_query()) {
332 RequestQuery query = ParseQuery(request_gurl);
333 if (query.find("status") != query.end())
334 http_response->set_code(static_cast<HttpStatusCode>(
335 std::atoi(query["status"].front().c_str())));
336 }
337
338 http_response->set_content_type("text/html");
339 if (request.method != METHOD_POST && request.method != METHOD_PUT)
340 http_response->set_content("Echo");
341 else
342 http_response->set_content(request.content);
343 return http_response.Pass();
344 }
345
346 scoped_ptr<HttpResponse> HandleEchoTitle(const HttpRequest& request) {
347 if (!ShouldHandle(request, "/echotitle"))
348 return NOT_HANDLED;
349
350 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
351 http_response->set_code(HTTP_OK);
352 http_response->set_content_type("text/html");
353 http_response->set_content("<html><head><title>" + request.content +
354 "</title></head></html>");
355 return http_response.Pass();
356 }
357
358 scoped_ptr<HttpResponse> HandleEchoAll(const HttpRequest& request) {
359 if (!ShouldHandle(request, "/echoall"))
360 return NOT_HANDLED;
361
362 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
363 http_response->set_code(HTTP_OK);
364
365 std::string body;
366 body +=
367 "<html><head><style>"
368 "pre { border: 1px solid black; margin: 5px; padding: 5px }"
369 "</style></head><body>"
370 "<div style=\"float: right\">"
371 "<a href=\"/echo\">back to referring page</a></div>"
372 "<h1>Request Body:</h1><pre>";
373
374 if (request.has_content) {
375 std::vector<std::string> qs = base::SplitString(
376 request.content, "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
377 for (size_t i = 0; i < qs.size(); ++i) {
378 body += qs[i] + "\n";
379 }
380 }
381
382 body +=
383 "</pre>"
384 "<h1>Request Headers:</h1><pre>" +
385 request.all_headers +
386 "</pre>"
387 "</body></html>";
388
389 http_response->set_content_type("text/html");
390 http_response->set_content(body);
391 return http_response.Pass();
392 }
393
394 scoped_ptr<HttpResponse> HandleSetCookie(const HttpRequest& request) {
395 if (!ShouldHandle(request, "/set-cookie"))
396 return NOT_HANDLED;
397
398 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
399 http_response->set_code(HTTP_OK);
400 http_response->set_content_type("text/html");
401 std::string content;
402 GURL request_gurl = ToGURL(request);
403 if (request_gurl.has_query()) {
404 std::vector<std::string> cookies = base::SplitString(
405 request_gurl.query(), "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
406 for (size_t i = 0; i < cookies.size(); ++i) {
407 http_response->AddCustomHeader("Set-Cookie", cookies[i]);
408 content += cookies[i];
409 }
410 }
411
412 http_response->set_content(content);
413 return http_response.Pass();
414 }
415
416 scoped_ptr<HttpResponse> HandleSetManyCookies(const HttpRequest& request) {
417 if (!ShouldHandle(request, "/set-many-cookies"))
418 return NOT_HANDLED;
419
420 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
421 http_response->set_code(HTTP_OK);
422 http_response->set_content_type("text/html");
423 std::string content;
424
425 GURL request_gurl = ToGURL(request);
426 size_t num = 0;
427 if (request_gurl.has_query()) {
428 num = std::atoi(request_gurl.query().c_str());
429 }
430
431 for (size_t i = 0; i < num; ++i) {
432 http_response->AddCustomHeader("Set-Cookie", "a=");
433 }
434
435 http_response->set_content(
436 base::StringPrintf("%" PRIuS " cookies were sent", num));
437 return http_response.Pass();
438 }
439
440 scoped_ptr<HttpResponse> HandleExpectAndSetCookie(const HttpRequest& request) {
441 if (!ShouldHandle(request, "/expect-and-set-cookie"))
442 return NOT_HANDLED;
443
444 std::vector<std::string> sentCookies;
445 if (request.headers.find("Cookie") != request.headers.end()) {
446 std::vector<std::string> cookies =
447 base::SplitString(request.headers.at("Cookie"), ";",
448 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
449 for (size_t i = 0; i < cookies.size(); ++i) {
450 sentCookies.push_back(cookies[i]);
451 }
452 }
453 bool gotExpected = true;
454
455 GURL request_gurl = ToGURL(request);
456 RequestQuery qs = ParseQuery(request_gurl);
457 if (qs.find("expect") != qs.end()) {
458 std::vector<std::string> expected = qs.at("expect");
459 for (size_t i = 0; i < expected.size(); ++i) {
460 bool found = false;
461 for (size_t j = 0; j < sentCookies.size(); ++j) {
462 if (expected[i] == sentCookies[j])
463 found = true;
464 }
465 gotExpected &= found;
466 }
467 }
468
469 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
470 http_response->set_code(HTTP_OK);
471 http_response->set_content_type("text/html");
472 if (gotExpected) {
473 std::vector<std::string> setCookies = qs.at("set");
474 for (size_t i = 0; i < setCookies.size(); ++i) {
475 http_response->AddCustomHeader(
476 "Set-Cookie", net::UnescapeURLComponent(setCookies[i], UNESCAPE_ALL));
477 }
478 }
479
480 std::string content;
481 if (qs.find("data") != qs.end()) {
482 std::vector<std::string> data = qs.at("data");
483 for (size_t i = 0; i < data.size(); ++i) {
484 content += data[i];
485 }
486 }
487
488 http_response->set_content(content);
489 return http_response.Pass();
490 }
491
492 scoped_ptr<HttpResponse> HandleSetHeader(const HttpRequest& request) {
493 if (!ShouldHandle(request, "/set-header"))
494 return NOT_HANDLED;
495
496 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
497 http_response->set_code(HTTP_OK);
498 http_response->set_content_type("text/html");
499
500 std::string content;
501
502 GURL request_gurl = ToGURL(request);
503 if (request_gurl.has_query()) {
504 RequestQuery headers = ParseQuery(request_gurl);
505 for (RequestQuery::iterator it = headers.begin(); it != headers.end();
506 ++it) {
507 std::string header = it->first;
508 std::string key = header.substr(0, header.find(": "));
509 std::string value = header.substr(header.find(": ") + 2);
510 http_response->AddCustomHeader(key, value);
511 content += header;
512 }
513 }
514
515 http_response->set_content(content);
516 return http_response.Pass();
517 }
518
519 scoped_ptr<HttpResponse> HandleNoContent(const HttpRequest& request) {
520 if (!ShouldHandle(request, "/nocontent"))
521 return NOT_HANDLED;
522
523 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
524 http_response->set_code(HTTP_NO_CONTENT);
525 return http_response.Pass();
526 }
527
528 scoped_ptr<HttpResponse> HandleCloseSocket(const HttpRequest& request) {
529 if (!ShouldHandle(request, "/close-socket"))
530 return NOT_HANDLED;
531
532 scoped_ptr<CustomHttpResponse> http_response(new CustomHttpResponse("", ""));
533 return http_response.Pass();
534 }
535
536 scoped_ptr<HttpResponse> HandleAuthBasic(const HttpRequest& request) {
537 if (!ShouldHandle(request, "/auth-basic"))
538 return NOT_HANDLED;
539
540 std::string username, userpass, password, b64str;
541 std::string expectedPassword = "secret";
542 std::string realm = "testrealm";
543 bool setCookie = false;
544
545 GURL request_gurl = ToGURL(request);
546 RequestQuery query = ParseQuery(request_gurl);
547
548 if (query.find("set-cookie-if-challenged") != query.end())
549 setCookie = true;
550 if (query.find("password") != query.end())
551 expectedPassword = query.at("password").front();
552 if (query.find("realm") != query.end())
553 realm = query.at("realm").front();
554
555 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
556 bool authed = false;
557 std::string error;
558 std::string auth;
559 if (request.headers.find("Authorization") == request.headers.end()) {
560 error = "Missing Authorization Header";
561 } else {
562 auth = request.headers.at("Authorization");
563 b64str = auth.substr(std::string("Basic ").size());
564 base::Base64Decode(b64str, &userpass);
565 username = userpass.substr(0, userpass.find(":"));
566 password = userpass.substr(userpass.find(":") + 1);
567 if (password == expectedPassword)
568 authed = true;
569 else
570 error = "Invalid Credentials";
571 }
572
573 if (!authed) {
574 http_response->set_code(HTTP_UNAUTHORIZED);
575 http_response->set_content_type("text/html");
576 http_response->AddCustomHeader("WWW-Authenticate",
577 "Basic realm=\"" + realm + "\"");
578 if (setCookie)
579 http_response->AddCustomHeader("Set-Cookie", "got_challenged=true");
580 http_response->set_content(base::StringPrintf(
581 "<html><head><title>Denied: %s</title></head>"
582 "<body>auth=%s<p>b64str=%s<p>username: %s<p>userpass: %s<p>"
583 "password: %s<p>You sent:<br>%s<p></body></html>",
584 error.c_str(), auth.c_str(), b64str.c_str(), username.c_str(),
585 userpass.c_str(), password.c_str(), request.all_headers.c_str()));
586 return http_response.Pass();
587 }
588
589 if (request.headers.find("If-None-Match") != request.headers.end() &&
590 request.headers.at("If-None-Match") == "abc") {
591 http_response->set_code(HTTP_NOT_MODIFIED);
592 return http_response.Pass();
593 }
594
595 base::FilePath file_path =
596 base::FilePath().AppendASCII(request.relative_url.substr(1));
597 if (file_path.FinalExtension() == FILE_PATH_LITERAL("gif")) {
598 base::FilePath server_root;
599 PathService::Get(base::DIR_SOURCE_ROOT, &server_root);
600 base::FilePath gif_path =
601 server_root.AppendASCII("chrome/test/data/google/logo.gif");
602 std::string gif_data;
603 base::ReadFileToString(gif_path, &gif_data);
604 http_response->set_content_type("image/gif");
605 http_response->set_content(gif_data);
606 } else {
607 http_response->set_content_type("text/html");
608 http_response->set_content(
609 base::StringPrintf("<html><head><title>%s/%s</title></head>"
610 "<body>auth=%s<p>You sent:<br>%s<p></body></html>",
611 username.c_str(), password.c_str(), auth.c_str(),
612 request.all_headers.c_str()));
613 }
614
615 http_response->set_code(HTTP_OK);
616 http_response->AddCustomHeader("Cache-Control", "max-age=60000");
617 http_response->AddCustomHeader("Etag", "abc");
618 return http_response.Pass();
619 }
620
621 scoped_ptr<HttpResponse> HandleAuthDigest(const HttpRequest& request) {
622 if (!ShouldHandle(request, "/auth-digest"))
623 return NOT_HANDLED;
624
625 std::string nonce = base::MD5String(
626 base::StringPrintf("privatekey%s", request.relative_url.c_str()));
627 std::string opaque = base::MD5String("opaque");
628 std::string password = "secret";
629 std::string realm = "testrealm";
630
631 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
632 bool authed = false;
633 std::string error;
634 std::string auth;
635 std::string digestStr = "Digest";
636 std::string username;
637 if (request.headers.find("Authorization") == request.headers.end()) {
638 error = "no auth";
639 } else if (request.headers.at("Authorization").substr(0, digestStr.size()) !=
640 digestStr) {
641 error = "not digest";
642 } else {
643 auth = request.headers.at("Authorization");
644
645 std::map<std::string, std::string> authPairs;
646 std::vector<std::string> authVector = base::SplitString(
647 auth, ", ", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
648 for (size_t i = 0; i < authVector.size(); ++i) {
649 std::string key = authVector[i].substr(0, authVector[i].find("="));
650 std::string value = authVector[i].substr(authVector[i].find("=") + 1);
651 if (value.substr(0, 1) == "\"" && value.substr(value.size() - 1) == "\"")
652 value = value.substr(1, value.size() - 2);
653 authPairs[key] = value;
654 }
655
656 if (authPairs["nonce"] != nonce) {
657 error = "wrong nonce";
658 } else if (authPairs["opaque"] != opaque) {
659 error = "wrong opaque";
660 } else {
661 username = authPairs["username"];
662
663 std::string hA1 = base::MD5String(
664 base::StringPrintf("%s:%s:%s", authPairs["username"].c_str(),
665 realm.c_str(), password.c_str()));
666 std::string hA2 = base::MD5String(base::StringPrintf(
667 "%s:%s", request.method_string.c_str(), authPairs["uri"].c_str()));
668
669 std::string response;
670 if (authPairs.find("qop") != authPairs.end() &&
671 authPairs.find("nc") != authPairs.end() &&
672 authPairs.find("cnonce") != authPairs.end()) {
673 response = base::MD5String(base::StringPrintf(
674 "%s:%s:%s:%s:%s:%s", hA1.c_str(), nonce.c_str(),
675 authPairs["nc"].c_str(), authPairs["cnonce"].c_str(),
676 authPairs["qop"].c_str(), hA2.c_str()));
677 } else {
678 response = base::MD5String(base::StringPrintf(
679 "%s:%s:%s", hA1.c_str(), nonce.c_str(), hA2.c_str()));
680 }
681
682 if (authPairs["response"] == response)
683 authed = true;
684 else
685 error = "wrong password";
686 }
687 }
688
689 if (!authed) {
690 http_response->set_code(HTTP_UNAUTHORIZED);
691 http_response->set_content_type("text/html");
692 std::string authHeader = base::StringPrintf(
693 "Digest realm=\"%s\", "
694 "domain=\"/\", qop=\"auth\", algorithm=MD5, nonce=\"%s\", "
695 "opaque=\"%s\"",
696 realm.c_str(), nonce.c_str(), opaque.c_str());
697 http_response->AddCustomHeader("WWW-Authenticate", authHeader);
698 http_response->set_content(base::StringPrintf(
699 "<html><head><title>Denied: %s</title></head>"
700 "<body>auth=%s<p>"
701 "You sent:<br>%s<p>We are replying:<br>%s<p></body></html>",
702 error.c_str(), auth.c_str(), request.all_headers.c_str(),
703 authHeader.c_str()));
704 return http_response.Pass();
705 }
706
707 http_response->set_content_type("text/html");
708 http_response->set_content(
709 base::StringPrintf("<html><head><title>%s/%s</title></head>"
710 "<body>auth=%s<p></body></html>",
711 username.c_str(), password.c_str(), auth.c_str()));
712
713 return http_response.Pass();
714 }
715
716 scoped_ptr<HttpResponse> HandleServerRedirect(const HttpRequest& request) {
717 if (!ShouldHandle(request, "/server-redirect"))
718 return NOT_HANDLED;
719
720 GURL request_gurl = ToGURL(request);
721 std::string dest =
722 net::UnescapeURLComponent(request_gurl.query(), UNESCAPE_ALL);
723
724 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
725 http_response->set_code(HTTP_MOVED_PERMANENTLY);
726 http_response->AddCustomHeader("Location", dest);
727 http_response->set_content_type("text/html");
728 http_response->set_content(base::StringPrintf(
729 "<html><head></head><body>Redirecting to %s</body></html>",
730 dest.c_str()));
731 return http_response.Pass();
732 }
733
734 scoped_ptr<HttpResponse> HandleCrossSiteRedirect(EmbeddedTestServer* server,
735 const HttpRequest& request) {
736 if (!ShouldHandle(request, "/cross-site"))
737 return NOT_HANDLED;
738
739 std::string destAll = net::UnescapeURLComponent(
740 request.relative_url.substr(std::string("/cross-site").size() + 1),
741 UNESCAPE_ALL);
742
743 std::string dest = base::StringPrintf(
744 "//%s:%hu/%s", destAll.substr(0, destAll.find("/")).c_str(),
745 server->port(), destAll.substr(destAll.find("/") + 1).c_str());
746
747 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
748 http_response->set_code(HTTP_MOVED_PERMANENTLY);
749 http_response->AddCustomHeader("Location", dest);
750 http_response->set_content_type("text/html");
751 http_response->set_content(base::StringPrintf(
752 "<html><head></head><body>Redirecting to %s</body></html>",
753 dest.c_str()));
754 return http_response.Pass();
755 }
756
757 scoped_ptr<HttpResponse> HandleClientRedirect(const HttpRequest& request) {
758 if (!ShouldHandle(request, "/client-redirect"))
759 return NOT_HANDLED;
760
761 GURL request_gurl = ToGURL(request);
762 std::string dest =
763 net::UnescapeURLComponent(request_gurl.query(), UNESCAPE_ALL);
764
765 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
766 http_response->set_code(HTTP_OK);
767 http_response->set_content_type("text/html");
768 http_response->set_content(base::StringPrintf(
769 "<html><head><meta http-equiv=\"refresh\" content=\"0;url=%s\"></head>"
770 "<body>Redirecting to %s</body></html>",
771 dest.c_str(), dest.c_str()));
772 return http_response.Pass();
773 }
774
775 scoped_ptr<HttpResponse> HandleDefaultResponse(const HttpRequest& request) {
776 if (!ShouldHandle(request, "/defaultresponse"))
777 return NOT_HANDLED;
778
779 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
780 http_response->set_code(HTTP_OK);
781 http_response->set_content_type("text/html");
782 http_response->set_content("Default response given for path: " +
783 request.relative_url);
784 return http_response.Pass();
785 }
786
787 class DelayedHttpResponse : public BasicHttpResponse {
788 public:
789 DelayedHttpResponse(double delay) : delay_(delay) {}
790
791 void SendResponse(SendCallback send, SendDoneCallback done) override {
792 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
793 FROM_HERE, base::Bind(send, ToResponseString(), done),
794 base::TimeDelta::FromSecondsD(delay_));
795 }
796
797 private:
798 double delay_;
799 };
800
801 scoped_ptr<HttpResponse> HandleSlowServer(const HttpRequest& request) {
802 if (!ShouldHandle(request, "/slow"))
803 return NOT_HANDLED;
804
805 double delay = 1.0f;
806
807 GURL request_gurl = ToGURL(request);
808 if (request_gurl.has_query()) {
809 delay = std::atof(request_gurl.query().c_str());
810 }
811
812 scoped_ptr<BasicHttpResponse> http_response(new DelayedHttpResponse(delay));
813 http_response->set_code(HTTP_OK);
814 http_response->set_content_type("text/plain");
815 http_response->set_content(base::StringPrintf("waited %.1f seconds", delay));
816 return http_response.Pass();
817 }
818
819 void RegisterDefaultHandlers(EmbeddedTestServer* server) {
820 server->RegisterDefaultHandler(base::Bind(&HandleRedirectConnect));
821 server->RegisterDefaultHandler(base::Bind(&HandleServerAuthConnect));
822 server->RegisterDefaultHandler(base::Bind(&HandleDefaultConnect));
823
824 server->RegisterDefaultHandler(
825 base::Bind(&HandleCacheControl, "/nocachetime/maxage", "max-age=0"));
826 server->RegisterDefaultHandler(
827 base::Bind(&HandleCacheControl, "/nocachetime", "no-cache"));
828 server->RegisterDefaultHandler(
829 base::Bind(&HandleCacheControl, "/cachetime", "max-age=60"));
830 server->RegisterDefaultHandler(base::Bind(&HandleCacheExpires));
831 server->RegisterDefaultHandler(base::Bind(&HandleCacheControl,
832 "/cache/proxy-revalidate",
833 "max-age=60, proxy-revalidate"));
834 server->RegisterDefaultHandler(
835 base::Bind(&HandleCacheControl, "/cache/private", "max-age=3, private"));
836 server->RegisterDefaultHandler(
837 base::Bind(&HandleCacheControl, "/cache/public", "max-age=3, public"));
838 server->RegisterDefaultHandler(base::Bind(&HandleCacheControl,
839 "/cache/s-maxage",
840 "public, s-maxage=60, max-age=0"));
841 server->RegisterDefaultHandler(base::Bind(
842 &HandleCacheControl, "/cache/must-revalidate", "must-revalidate"));
843 server->RegisterDefaultHandler(base::Bind(&HandleCacheControl,
844 "/cache/must-revalidate/max-age",
845 "max-age=60, must-revalidate"));
846 server->RegisterDefaultHandler(
847 base::Bind(&HandleCacheControl, "/cache/no-store", "no-store"));
848 server->RegisterDefaultHandler(base::Bind(
849 &HandleCacheControl, "/cache/no-store/max-age", "max-age=60, no-store"));
850 server->RegisterDefaultHandler(
851 base::Bind(&HandleCacheControl, "/cache/no-transform", "no-transform"));
852
853 server->RegisterDefaultHandler(
854 base::Bind(&HandleEchoHeader, "/echoheader", "no-cache"));
855 server->RegisterDefaultHandler(
856 base::Bind(&HandleEchoHeader, "/echoheadercache", "max-age=60000"));
857 server->RegisterDefaultHandler(base::Bind(&HandleEcho));
858 server->RegisterDefaultHandler(base::Bind(&HandleEchoTitle));
859 server->RegisterDefaultHandler(base::Bind(&HandleEchoAll));
860
861 server->RegisterDefaultHandler(base::Bind(&HandleSetCookie));
862 server->RegisterDefaultHandler(base::Bind(&HandleSetManyCookies));
863 server->RegisterDefaultHandler(base::Bind(&HandleExpectAndSetCookie));
864 server->RegisterDefaultHandler(base::Bind(&HandleSetHeader));
865 server->RegisterDefaultHandler(base::Bind(&HandleNoContent));
866 server->RegisterDefaultHandler(base::Bind(&HandleCloseSocket));
867 server->RegisterDefaultHandler(base::Bind(&HandleAuthBasic));
868 server->RegisterDefaultHandler(base::Bind(&HandleAuthDigest));
869 server->RegisterDefaultHandler(base::Bind(&HandleServerRedirect));
870 server->RegisterDefaultHandler(base::Bind(&HandleCrossSiteRedirect, server));
871 server->RegisterDefaultHandler(base::Bind(&HandleClientRedirect));
872 server->RegisterDefaultHandler(base::Bind(&HandleDefaultResponse));
873 server->RegisterDefaultHandler(base::Bind(&HandleSlowServer));
874
875 // TODO(svaldez): HandleDownload
876 // TODO(svaldez): HandleDownloadFinish
877 // TODO(svaldez): HandleZipFile
878 // TODO(svaldez): HandleRangeReset
879 // TODO(svaldez): HandleSSLManySmallRecords
880 // TODO(svaldez): HandleChunkedServer
881 // TODO(svaldez): HandleGetSSLSessionCache
882 // TODO(svaldez): HandleGetChannelID
883 // TODO(svaldez): HandleGetClientCert
884 // TODO(svaldez): HandleClientCipherList
885 // TODO(svaldez): HandleEchoMultipartPost
886 }
887
888 void GetFilePathWithReplacements(const std::string& original_file_path,
889 const base::StringPairs& text_to_replace,
890 std::string* replacement_path) {
891 std::string new_file_path = original_file_path;
892 bool first_query_parameter = true;
893 const base::StringPairs::const_iterator end = text_to_replace.end();
894 for (base::StringPairs::const_iterator it = text_to_replace.begin();
895 it != end; ++it) {
896 const std::string& old_text = it->first;
897 const std::string& new_text = it->second;
898 std::string base64_old;
899 std::string base64_new;
900 base::Base64Encode(old_text, &base64_old);
901 base::Base64Encode(new_text, &base64_new);
902 if (first_query_parameter) {
903 new_file_path += "?";
904 first_query_parameter = false;
905 } else {
906 new_file_path += "&";
907 }
908 new_file_path += "replace_text=";
909 new_file_path += base64_old;
910 new_file_path += ":";
911 new_file_path += base64_new;
912 }
913
914 *replacement_path = new_file_path;
915 }
916
917 } // namespace test_server
918 } // namespace net
OLDNEW
« no previous file with comments | « net/test/embedded_test_server/request_helpers.h ('k') | remoting/protocol/ssl_hmac_channel_authenticator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698