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

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

Powered by Google App Engine
This is Rietveld 408576698