xref: /aosp_15_r20/external/cronet/net/test/embedded_test_server/default_handlers.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2015 The Chromium Authors
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/default_handlers.h"
6 
7 #include <ctime>
8 #include <map>
9 #include <memory>
10 #include <sstream>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include "base/base64.h"
16 #include "base/files/file_path.h"
17 #include "base/files/file_util.h"
18 #include "base/functional/bind.h"
19 #include "base/functional/callback_forward.h"
20 #include "base/functional/callback_helpers.h"
21 #include "base/hash/md5.h"
22 #include "base/logging.h"
23 #include "base/memory/weak_ptr.h"
24 #include "base/path_service.h"
25 #include "base/strings/escape.h"
26 #include "base/strings/string_number_conversions.h"
27 #include "base/strings/string_split.h"
28 #include "base/strings/string_util.h"
29 #include "base/strings/stringprintf.h"
30 #include "base/task/sequenced_task_runner.h"
31 #include "base/task/single_thread_task_runner.h"
32 #include "base/time/time.h"
33 #include "base/unguessable_token.h"
34 #include "net/base/host_port_pair.h"
35 #include "net/base/url_util.h"
36 #include "net/filter/filter_source_stream_test_util.h"
37 #include "net/test/embedded_test_server/http_request.h"
38 #include "net/test/embedded_test_server/http_response.h"
39 #include "net/test/embedded_test_server/request_handler_util.h"
40 
41 namespace net::test_server {
42 namespace {
43 
44 const char kDefaultRealm[] = "testrealm";
45 const char kDefaultPassword[] = "secret";
46 const char kEtag[] = "abc";
47 const char kLogoPath[] = "chrome/test/data/google/logo.gif";
48 
49 // method: CONNECT
50 // Responses with a BAD_REQUEST to any CONNECT requests.
HandleDefaultConnect(const HttpRequest & request)51 std::unique_ptr<HttpResponse> HandleDefaultConnect(const HttpRequest& request) {
52   if (request.method != METHOD_CONNECT)
53     return nullptr;
54 
55   auto http_response = std::make_unique<BasicHttpResponse>();
56   http_response->set_code(HTTP_BAD_REQUEST);
57   http_response->set_content(
58       "Your client has issued a malformed or illegal request.");
59   http_response->set_content_type("text/html");
60   return http_response;
61 }
62 
63 // /cachetime
64 // Returns a cacheable response.
HandleCacheTime(const HttpRequest & request)65 std::unique_ptr<HttpResponse> HandleCacheTime(const HttpRequest& request) {
66   auto http_response = std::make_unique<BasicHttpResponse>();
67   http_response->set_content("<!doctype html><title>Cache: max-age=60</title>");
68   http_response->set_content_type("text/html");
69   http_response->AddCustomHeader("Cache-Control", "max-age=60");
70   return http_response;
71 }
72 
73 // /echoheader?HEADERS | /echoheadercache?HEADERS
74 // Responds with the headers echoed in the message body.
75 // echoheader does not cache the results, while echoheadercache does.
HandleEchoHeader(const std::string & url,const std::string & cache_control,const HttpRequest & request)76 std::unique_ptr<HttpResponse> HandleEchoHeader(const std::string& url,
77                                                const std::string& cache_control,
78                                                const HttpRequest& request) {
79   if (!ShouldHandle(request, url))
80     return nullptr;
81 
82   auto http_response = std::make_unique<BasicHttpResponse>();
83 
84   GURL request_url = request.GetURL();
85   std::string vary;
86   std::string content;
87   RequestQuery headers = ParseQuery(request_url);
88   for (const auto& header : headers) {
89     std::string header_name = header.first;
90     std::string header_value = "None";
91     if (request.headers.find(header_name) != request.headers.end())
92       header_value = request.headers.at(header_name);
93     if (!vary.empty())
94       vary += ",";
95     vary += header_name;
96     if (!content.empty())
97       content += "\n";
98     content += header_value;
99   }
100 
101   http_response->AddCustomHeader("Vary", vary);
102   http_response->set_content(content);
103   http_response->set_content_type("text/plain");
104   http_response->AddCustomHeader("Access-Control-Allow-Origin", "*");
105   http_response->AddCustomHeader("Cache-Control", cache_control);
106   return http_response;
107 }
108 
109 // /echo-cookie-with-status?status=###
110 // Responds with the given status code and echos the cookies sent in the request
HandleEchoCookieWithStatus(const std::string & url,const HttpRequest & request)111 std::unique_ptr<HttpResponse> HandleEchoCookieWithStatus(
112     const std::string& url,
113     const HttpRequest& request) {
114   if (!ShouldHandle(request, url))
115     return nullptr;
116 
117   auto http_response = std::make_unique<BasicHttpResponse>();
118 
119   GURL request_url = request.GetURL();
120   RequestQuery query = ParseQuery(request_url);
121 
122   int status_code = 400;
123   const auto given_status = query.find("status");
124 
125   if (given_status != query.end() && !given_status->second.empty() &&
126       !base::StringToInt(given_status->second.front(), &status_code)) {
127     status_code = 400;
128   }
129 
130   http_response->set_code(static_cast<HttpStatusCode>(status_code));
131 
132   const auto given_cookie = request.headers.find("Cookie");
133   std::string content =
134       (given_cookie == request.headers.end()) ? "None" : given_cookie->second;
135   http_response->set_content(content);
136   http_response->set_content_type("text/plain");
137   return http_response;
138 }
139 
140 // TODO(https://crbug.com/1138913): Remove when request handlers are
141 // implementable in Android's embedded test server implementation
HandleEchoCriticalHeader(const HttpRequest & request)142 std::unique_ptr<HttpResponse> HandleEchoCriticalHeader(
143     const HttpRequest& request) {
144   auto http_response = std::make_unique<BasicHttpResponse>();
145 
146   http_response->set_content_type("text/plain");
147   http_response->AddCustomHeader("Access-Control-Allow-Origin", "*");
148 
149   http_response->AddCustomHeader("Accept-CH", "Sec-CH-UA-Platform");
150   http_response->AddCustomHeader("Critical-CH", "Sec-CH-UA-Platform");
151 
152   http_response->set_content(
153       request.headers.find("Sec-CH-UA-Mobile")->second +
154       request.headers.find("Sec-CH-UA-Platform")->second);
155 
156   return http_response;
157 }
158 
159 // /echo?status=STATUS
160 // Responds with the request body as the response body and
161 // a status code of STATUS.
HandleEcho(const HttpRequest & request)162 std::unique_ptr<HttpResponse> HandleEcho(const HttpRequest& request) {
163   auto http_response = std::make_unique<BasicHttpResponse>();
164 
165   GURL request_url = request.GetURL();
166   if (request_url.has_query()) {
167     RequestQuery query = ParseQuery(request_url);
168     if (query.find("status") != query.end())
169       http_response->set_code(static_cast<HttpStatusCode>(
170           std::atoi(query["status"].front().c_str())));
171   }
172 
173   http_response->set_content_type("text/html");
174   if (request.method != METHOD_POST && request.method != METHOD_PUT)
175     http_response->set_content("Echo");
176   else
177     http_response->set_content(request.content);
178   return http_response;
179 }
180 
181 // /echotitle
182 // Responds with the request body as the title.
HandleEchoTitle(const HttpRequest & request)183 std::unique_ptr<HttpResponse> HandleEchoTitle(const HttpRequest& request) {
184   auto http_response = std::make_unique<BasicHttpResponse>();
185   http_response->set_content_type("text/html");
186   http_response->set_content("<!doctype html><title>" + request.content +
187                              "</title>");
188   return http_response;
189 }
190 
191 // /echoall?QUERY
192 // Responds with the list of QUERY and the request headers.
193 //
194 // Alternative form:
195 // /echoall/nocache?QUERY prevents caching of the response.
HandleEchoAll(const HttpRequest & request)196 std::unique_ptr<HttpResponse> HandleEchoAll(const HttpRequest& request) {
197   auto http_response = std::make_unique<BasicHttpResponse>();
198 
199   std::string body =
200       "<!doctype html><title>EmbeddedTestServer - EchoAll</title><style>"
201       "pre { border: 1px solid black; margin: 5px; padding: 5px }"
202       "</style>"
203       "<div style=\"float: right\">"
204       "<a href=\"/echo\">back to referring page</a></div>"
205       "<h1>Request Body:</h1><pre>";
206 
207   if (request.has_content) {
208     std::vector<std::string> query_list = base::SplitString(
209         request.content, "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
210     for (const auto& query : query_list)
211       body += query + "\n";
212   }
213 
214   body +=
215       "</pre>"
216       "<h1>Request Headers:</h1><pre id='request-headers'>" +
217       request.all_headers + "</pre>" +
218       "<h1>Response nonce:</h1><pre id='response-nonce'>" +
219       base::UnguessableToken::Create().ToString() + "</pre>";
220 
221   http_response->set_content_type("text/html");
222   http_response->set_content(body);
223 
224   if (request.GetURL().path_piece().ends_with("/nocache")) {
225     http_response->AddCustomHeader("Cache-Control",
226                                    "no-cache, no-store, must-revalidate");
227   }
228 
229   return http_response;
230 }
231 
232 // /echo-raw
233 // Returns the query string as the raw response (no HTTP headers).
HandleEchoRaw(const HttpRequest & request)234 std::unique_ptr<HttpResponse> HandleEchoRaw(const HttpRequest& request) {
235   return std::make_unique<RawHttpResponse>("", request.GetURL().query());
236 }
237 
238 // /set-cookie?COOKIES
239 // Sets response cookies to be COOKIES.
HandleSetCookie(const HttpRequest & request)240 std::unique_ptr<HttpResponse> HandleSetCookie(const HttpRequest& request) {
241   auto http_response = std::make_unique<BasicHttpResponse>();
242   http_response->set_content_type("text/html");
243   std::string content;
244   GURL request_url = request.GetURL();
245   if (request_url.has_query()) {
246     std::vector<std::string> cookies = base::SplitString(
247         request_url.query(), "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
248     for (const auto& cookie : cookies) {
249       http_response->AddCustomHeader("Set-Cookie", cookie);
250       content += cookie;
251     }
252   }
253 
254   http_response->set_content(content);
255   return http_response;
256 }
257 
258 // /set-invalid-cookie
259 // Sets invalid response cookies "\x01" (chosen via fuzzer to not be a parsable
260 // cookie).
HandleSetInvalidCookie(const HttpRequest & request)261 std::unique_ptr<HttpResponse> HandleSetInvalidCookie(
262     const HttpRequest& request) {
263   auto http_response = std::make_unique<BasicHttpResponse>();
264   http_response->set_content_type("text/html");
265   std::string content;
266   GURL request_url = request.GetURL();
267 
268   http_response->AddCustomHeader("Set-Cookie", "\x01");
269 
270   http_response->set_content("TEST");
271   return http_response;
272 }
273 
274 // /expect-and-set-cookie?expect=EXPECTED&set=SET&data=DATA
275 // Verifies that the request cookies match EXPECTED and then returns cookies
276 // that match SET and a content that matches DATA.
HandleExpectAndSetCookie(const HttpRequest & request)277 std::unique_ptr<HttpResponse> HandleExpectAndSetCookie(
278     const HttpRequest& request) {
279   std::vector<std::string> received_cookies;
280   if (request.headers.find("Cookie") != request.headers.end()) {
281     received_cookies =
282         base::SplitString(request.headers.at("Cookie"), ";",
283                           base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
284   }
285 
286   bool got_all_expected = true;
287   GURL request_url = request.GetURL();
288   RequestQuery query_list = ParseQuery(request_url);
289   if (query_list.find("expect") != query_list.end()) {
290     for (const auto& expected_cookie : query_list.at("expect")) {
291       bool found = false;
292       for (const auto& received_cookie : received_cookies) {
293         if (expected_cookie == received_cookie)
294           found = true;
295       }
296       got_all_expected &= found;
297     }
298   }
299 
300   auto http_response = std::make_unique<BasicHttpResponse>();
301   http_response->set_content_type("text/html");
302   if (got_all_expected) {
303     for (const auto& cookie : query_list.at("set")) {
304       http_response->AddCustomHeader(
305           "Set-Cookie",
306           base::UnescapeBinaryURLComponent(
307               cookie, base::UnescapeRule::REPLACE_PLUS_WITH_SPACE));
308     }
309   }
310 
311   std::string content;
312   if (query_list.find("data") != query_list.end()) {
313     for (const auto& item : query_list.at("data"))
314       content += item;
315   }
316 
317   http_response->set_content(content);
318   return http_response;
319 }
320 
321 // An internal utility to extract HTTP Headers from a URL in the format of
322 // "/url&KEY1: VALUE&KEY2: VALUE2". Returns a header key to header value map.
ExtractHeadersFromQuery(const GURL & url)323 std::map<std::string, std::string> ExtractHeadersFromQuery(const GURL& url) {
324   std::map<std::string, std::string> key_to_value;
325   if (url.has_query()) {
326     RequestQuery headers = ParseQuery(url);
327     for (const auto& header : headers) {
328       size_t delimiter = header.first.find(": ");
329       if (delimiter == std::string::npos) {
330         continue;
331       }
332       std::string key = header.first.substr(0, delimiter);
333       std::string value = header.first.substr(delimiter + 2);
334       key_to_value.emplace(key, value);
335     }
336   }
337   return key_to_value;
338 }
339 
340 // /set-header?HEADERS
341 // Returns a response with HEADERS set as the response headers, and also set as
342 // the response content.
343 //
344 // Example:
345 //    /set-header?Content-Security-Policy: sandbox&Referer-Policy: origin
HandleSetHeader(const HttpRequest & request)346 std::unique_ptr<HttpResponse> HandleSetHeader(const HttpRequest& request) {
347   std::string content;
348 
349   GURL request_url = request.GetURL();
350 
351   auto http_response = std::make_unique<BasicHttpResponse>();
352   http_response->set_content_type("text/html");
353   auto headers = ExtractHeadersFromQuery(request_url);
354   for (const auto& [key, value] : headers) {
355     http_response->AddCustomHeader(key, value);
356     content += key + ": " + value;
357   }
358 
359   http_response->set_content(content);
360   return http_response;
361 }
362 
363 // /set-header-with-file/FILE_PATH?HEADERS
364 // Returns a response with context read from FILE_PATH as the response content,
365 // and HEADERS as the response header. Unlike /set-header?HEADERS, which only
366 // serves a response with HEADERS as response header and also HEADERS as its
367 // content.
368 //
369 // FILE_PATH points to the static test file. For example, a query like
370 // /set-header-with-file/content/test/data/title1.html will returns the content
371 // of the file at content/test/data/title1.html.
372 // HEADERS is composed of a list of "key: value" pairs. Note that unlike how a
373 // file is normally served by `HandleFileRequest()`, its static mock headers
374 // from the other file FILE_PATH.mock-http-headers will NOT be used here.
375 //
376 // Example:
377 //    /set-header-with-file/content/test/data/title1.html?Referer-Policy: origin
HandleSetHeaderWithFile(const std::string & prefix,const HttpRequest & request)378 std::unique_ptr<HttpResponse> HandleSetHeaderWithFile(
379     const std::string& prefix,
380     const HttpRequest& request) {
381   if (!ShouldHandle(request, prefix)) {
382     return nullptr;
383   }
384 
385   GURL request_url = request.GetURL();
386   auto http_response = std::make_unique<BasicHttpResponse>();
387 
388   base::FilePath server_root;
389   base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &server_root);
390   base::FilePath file_path =
391       server_root.AppendASCII(request_url.path().substr(prefix.size() + 1));
392   std::string file_content;
393   CHECK(base::ReadFileToString(file_path, &file_content));
394   http_response->set_content(file_content);
395   http_response->set_content_type(GetContentType(file_path));
396 
397   auto headers = ExtractHeadersFromQuery(request_url);
398   for (const auto& [key, value] : headers) {
399     http_response->AddCustomHeader(key, value);
400   }
401 
402   http_response->set_code(HTTP_OK);
403   return http_response;
404 }
405 
406 // /iframe?URL
407 // Returns a page that iframes the specified URL.
HandleIframe(const HttpRequest & request)408 std::unique_ptr<HttpResponse> HandleIframe(const HttpRequest& request) {
409   GURL request_url = request.GetURL();
410 
411   auto http_response = std::make_unique<BasicHttpResponse>();
412   http_response->set_content_type("text/html");
413 
414   GURL iframe_url("about:blank");
415   if (request_url.has_query()) {
416     iframe_url = GURL(base::UnescapeBinaryURLComponent(request_url.query()));
417   }
418 
419   http_response->set_content(base::StringPrintf(
420       "<!doctype html><iframe src=\"%s\">", iframe_url.spec().c_str()));
421   return http_response;
422 }
423 
424 // /nocontent
425 // Returns a NO_CONTENT response.
HandleNoContent(const HttpRequest & request)426 std::unique_ptr<HttpResponse> HandleNoContent(const HttpRequest& request) {
427   auto http_response = std::make_unique<BasicHttpResponse>();
428   http_response->set_code(HTTP_NO_CONTENT);
429   return http_response;
430 }
431 
432 // /close-socket
433 // Immediately closes the connection.
HandleCloseSocket(const HttpRequest & request)434 std::unique_ptr<HttpResponse> HandleCloseSocket(const HttpRequest& request) {
435   return std::make_unique<RawHttpResponse>("", "");
436 }
437 
438 // /auth-basic?password=PASS&realm=REALM
439 // Performs "Basic" HTTP authentication using expected password PASS and
440 // realm REALM.
HandleAuthBasic(const HttpRequest & request)441 std::unique_ptr<HttpResponse> HandleAuthBasic(const HttpRequest& request) {
442   GURL request_url = request.GetURL();
443   RequestQuery query = ParseQuery(request_url);
444 
445   std::string expected_password = kDefaultPassword;
446   if (query.find("password") != query.end())
447     expected_password = query.at("password").front();
448   std::string realm = kDefaultRealm;
449   if (query.find("realm") != query.end())
450     realm = query.at("realm").front();
451 
452   bool authed = false;
453   std::string error;
454   std::string auth;
455   std::string username;
456   std::string userpass;
457   std::string password;
458   std::string b64str;
459   if (request.headers.find("Authorization") == request.headers.end()) {
460     error = "Missing Authorization Header";
461   } else {
462     auth = request.headers.at("Authorization");
463     if (auth.find("Basic ") == std::string::npos) {
464       error = "Invalid Authorization Header";
465     } else {
466       b64str = auth.substr(std::string("Basic ").size());
467       base::Base64Decode(b64str, &userpass);
468       size_t delimiter = userpass.find(":");
469       if (delimiter != std::string::npos) {
470         username = userpass.substr(0, delimiter);
471         password = userpass.substr(delimiter + 1);
472         if (password == expected_password)
473           authed = true;
474         else
475           error = "Invalid Credentials";
476       } else {
477         error = "Invalid Credentials";
478       }
479     }
480   }
481 
482   auto http_response = std::make_unique<BasicHttpResponse>();
483   if (!authed) {
484     http_response->set_code(HTTP_UNAUTHORIZED);
485     http_response->set_content_type("text/html");
486     http_response->AddCustomHeader("WWW-Authenticate",
487                                    "Basic realm=\"" + realm + "\"");
488     if (query.find("set-cookie-if-challenged") != query.end())
489       http_response->AddCustomHeader("Set-Cookie", "got_challenged=true");
490     if (query.find("set-secure-cookie-if-challenged") != query.end())
491       http_response->AddCustomHeader("Set-Cookie",
492                                      "got_challenged=true;Secure");
493     http_response->set_content(base::StringPrintf(
494         "<!doctype html><title>Denied: %s</title>"
495         "<p>auth=%s<p>b64str=%s<p>username: %s<p>userpass: %s"
496         "<p>password: %s<p>You sent:<br>%s",
497         error.c_str(), auth.c_str(), b64str.c_str(), username.c_str(),
498         userpass.c_str(), password.c_str(), request.all_headers.c_str()));
499     return http_response;
500   }
501 
502   if (query.find("set-cookie-if-not-challenged") != query.end())
503     http_response->AddCustomHeader("Set-Cookie", "got_challenged=true");
504 
505   if (request.headers.find("If-None-Match") != request.headers.end() &&
506       request.headers.at("If-None-Match") == kEtag) {
507     http_response->set_code(HTTP_NOT_MODIFIED);
508     return http_response;
509   }
510 
511   base::FilePath file_path =
512       base::FilePath().AppendASCII(request.relative_url.substr(1));
513   if (file_path.FinalExtension() == FILE_PATH_LITERAL("gif")) {
514     base::FilePath server_root;
515     base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &server_root);
516     base::FilePath gif_path = server_root.AppendASCII(kLogoPath);
517     std::string gif_data;
518     base::ReadFileToString(gif_path, &gif_data);
519     http_response->set_content_type("image/gif");
520     http_response->set_content(gif_data);
521   } else {
522     http_response->set_content_type("text/html");
523     http_response->set_content(
524         base::StringPrintf("<!doctype html><title>%s/%s</title>"
525                            "<p>auth=%s<p>You sent:<br>%s",
526                            username.c_str(), password.c_str(), auth.c_str(),
527                            request.all_headers.c_str()));
528   }
529 
530   http_response->AddCustomHeader("Cache-Control", "max-age=60000");
531   http_response->AddCustomHeader("Etag", kEtag);
532   return http_response;
533 }
534 
535 // /auth-digest
536 // Performs "Digest" HTTP authentication.
HandleAuthDigest(const HttpRequest & request)537 std::unique_ptr<HttpResponse> HandleAuthDigest(const HttpRequest& request) {
538   std::string nonce = base::MD5String(
539       base::StringPrintf("privatekey%s", request.relative_url.c_str()));
540   std::string opaque = base::MD5String("opaque");
541   std::string password = kDefaultPassword;
542   std::string realm = kDefaultRealm;
543 
544   bool authed = false;
545   std::string error;
546   std::string auth;
547   std::string digest_str = "Digest";
548   std::string username;
549   if (request.headers.find("Authorization") == request.headers.end()) {
550     error = "no auth";
551   } else if (request.headers.at("Authorization").substr(0, digest_str.size()) !=
552              digest_str) {
553     error = "not digest";
554   } else {
555     auth = request.headers.at("Authorization").substr(digest_str.size() + 1);
556 
557     std::map<std::string, std::string> auth_pairs;
558     base::StringPairs auth_vector;
559     base::SplitStringIntoKeyValuePairs(auth, '=', ',', &auth_vector);
560     for (const auto& auth_pair : auth_vector) {
561       std::string key;
562       std::string value;
563       base::TrimWhitespaceASCII(auth_pair.first, base::TRIM_ALL, &key);
564       base::TrimWhitespaceASCII(auth_pair.second, base::TRIM_ALL, &value);
565       if (value.size() > 2 && value.at(0) == '"' &&
566           value.at(value.size() - 1) == '"') {
567         value = value.substr(1, value.size() - 2);
568       }
569       auth_pairs[key] = value;
570     }
571 
572     if (auth_pairs["nonce"] != nonce) {
573       error = "wrong nonce";
574     } else if (auth_pairs["opaque"] != opaque) {
575       error = "wrong opaque";
576     } else {
577       username = auth_pairs["username"];
578 
579       std::string hash1 = base::MD5String(
580           base::StringPrintf("%s:%s:%s", auth_pairs["username"].c_str(),
581                              realm.c_str(), password.c_str()));
582       std::string hash2 = base::MD5String(base::StringPrintf(
583           "%s:%s", request.method_string.c_str(), auth_pairs["uri"].c_str()));
584 
585       std::string response;
586       if (auth_pairs.find("qop") != auth_pairs.end() &&
587           auth_pairs.find("nc") != auth_pairs.end() &&
588           auth_pairs.find("cnonce") != auth_pairs.end()) {
589         response = base::MD5String(base::StringPrintf(
590             "%s:%s:%s:%s:%s:%s", hash1.c_str(), nonce.c_str(),
591             auth_pairs["nc"].c_str(), auth_pairs["cnonce"].c_str(),
592             auth_pairs["qop"].c_str(), hash2.c_str()));
593       } else {
594         response = base::MD5String(base::StringPrintf(
595             "%s:%s:%s", hash1.c_str(), nonce.c_str(), hash2.c_str()));
596       }
597 
598       if (auth_pairs["response"] == response)
599         authed = true;
600       else
601         error = "wrong password";
602     }
603   }
604 
605   auto http_response = std::make_unique<BasicHttpResponse>();
606   if (!authed) {
607     http_response->set_code(HTTP_UNAUTHORIZED);
608     http_response->set_content_type("text/html");
609     std::string auth_header = base::StringPrintf(
610         "Digest realm=\"%s\", "
611         "domain=\"/\", qop=\"auth\", algorithm=MD5, nonce=\"%s\", "
612         "opaque=\"%s\"",
613         realm.c_str(), nonce.c_str(), opaque.c_str());
614     http_response->AddCustomHeader("WWW-Authenticate", auth_header);
615     http_response->set_content(
616         base::StringPrintf("<!doctype html><title>Denied: %s</title>"
617                            "<p>auth=%s"
618                            "You sent:<br>%s<p>We are replying:<br>%s",
619                            error.c_str(), auth.c_str(),
620                            request.all_headers.c_str(), auth_header.c_str()));
621     return http_response;
622   }
623 
624   http_response->set_content_type("text/html");
625   http_response->set_content(
626       base::StringPrintf("<!doctype html><title>%s/%s</title>"
627                          "<p>auth=%s",
628                          username.c_str(), password.c_str(), auth.c_str()));
629 
630   return http_response;
631 }
632 
633 // 1. /server-redirect?URL or /server-redirect-xxx?URL
634 //    Returns a server redirect to URL.
635 // 2. /no-cors-server-redirect?URL or /no-cors-server-redirect-xxx?URL
636 //    Returns a server redirect to URL which does not allow CORS.
HandleServerRedirect(HttpStatusCode redirect_code,bool allow_cors,const HttpRequest & request)637 std::unique_ptr<HttpResponse> HandleServerRedirect(HttpStatusCode redirect_code,
638                                                    bool allow_cors,
639                                                    const HttpRequest& request) {
640   GURL request_url = request.GetURL();
641   std::string dest =
642       base::UnescapeBinaryURLComponent(request_url.query_piece());
643   RequestQuery query = ParseQuery(request_url);
644 
645   if (request.method == METHOD_OPTIONS) {
646     auto http_response = std::make_unique<BasicHttpResponse>();
647     http_response->set_code(HTTP_OK);
648     if (allow_cors) {
649       http_response->AddCustomHeader("Access-Control-Allow-Origin", "*");
650       http_response->AddCustomHeader("Access-Control-Allow-Methods", "*");
651       http_response->AddCustomHeader("Access-Control-Allow-Headers", "*");
652     }
653     return http_response;
654   }
655 
656   auto http_response = std::make_unique<BasicHttpResponse>();
657   http_response->set_code(redirect_code);
658   http_response->AddCustomHeader("Location", dest);
659   if (allow_cors) {
660     http_response->AddCustomHeader("Access-Control-Allow-Origin", "*");
661   }
662   http_response->set_content_type("text/html");
663   http_response->set_content(
664       base::StringPrintf("<!doctype html><p>Redirecting to %s", dest.c_str()));
665   return http_response;
666 }
667 // /server-redirect-with-cookie?URL
668 // Returns a server redirect to URL, and sets the cookie server-redirect=true.
HandleServerRedirectWithCookie(HttpStatusCode redirect_code,const HttpRequest & request)669 std::unique_ptr<HttpResponse> HandleServerRedirectWithCookie(
670     HttpStatusCode redirect_code,
671     const HttpRequest& request) {
672   GURL request_url = request.GetURL();
673   std::string dest =
674       base::UnescapeBinaryURLComponent(request_url.query_piece());
675   RequestQuery query = ParseQuery(request_url);
676 
677   auto http_response = std::make_unique<BasicHttpResponse>();
678   http_response->set_code(redirect_code);
679   http_response->AddCustomHeader("Location", dest);
680   http_response->AddCustomHeader("Set-Cookie", "server-redirect=true");
681   http_response->set_content_type("text/html");
682   http_response->set_content(
683       base::StringPrintf("<!doctype html><p>Redirecting to %s", dest.c_str()));
684   return http_response;
685 }
686 
687 // /server-redirect-with-secure-cookie?URL
688 // Returns a server redirect to URL, and sets the cookie
689 // server-redirect=true;Secure.
HandleServerRedirectWithSecureCookie(HttpStatusCode redirect_code,const HttpRequest & request)690 std::unique_ptr<HttpResponse> HandleServerRedirectWithSecureCookie(
691     HttpStatusCode redirect_code,
692     const HttpRequest& request) {
693   GURL request_url = request.GetURL();
694   std::string dest =
695       base::UnescapeBinaryURLComponent(request_url.query_piece());
696   RequestQuery query = ParseQuery(request_url);
697 
698   auto http_response = std::make_unique<BasicHttpResponse>();
699   http_response->set_code(redirect_code);
700   http_response->AddCustomHeader("Location", dest);
701   http_response->AddCustomHeader("Set-Cookie", "server-redirect=true;Secure");
702   http_response->set_content_type("text/html");
703   http_response->set_content(
704       base::StringPrintf("<!doctype html><p>Redirecting to %s", dest.c_str()));
705   return http_response;
706 }
707 
708 // /cross-site?URL (also /cross-site-with-cookie?URL)
709 // Returns a cross-site redirect to URL.
HandleCrossSiteRedirect(EmbeddedTestServer * server,const std::string & prefix,bool set_cookie,const HttpRequest & request)710 std::unique_ptr<HttpResponse> HandleCrossSiteRedirect(
711     EmbeddedTestServer* server,
712     const std::string& prefix,
713     bool set_cookie,
714     const HttpRequest& request) {
715   if (!ShouldHandle(request, prefix))
716     return nullptr;
717 
718   std::string dest_all = base::UnescapeBinaryURLComponent(
719       request.relative_url.substr(prefix.size() + 1));
720 
721   std::string dest;
722   size_t delimiter = dest_all.find("/");
723   if (delimiter != std::string::npos) {
724     dest = base::StringPrintf(
725         "//%s:%hu/%s", dest_all.substr(0, delimiter).c_str(), server->port(),
726         dest_all.substr(delimiter + 1).c_str());
727   }
728 
729   auto http_response = std::make_unique<BasicHttpResponse>();
730   http_response->set_code(HTTP_MOVED_PERMANENTLY);
731   http_response->AddCustomHeader("Location", dest);
732   if (set_cookie) {
733     http_response->AddCustomHeader("Set-Cookie", "server-redirect=true");
734   }
735   http_response->set_content_type("text/html");
736   http_response->set_content(
737       base::StringPrintf("<!doctype html><p>Redirecting to %s", dest.c_str()));
738   return http_response;
739 }
740 
741 // /client-redirect?URL
742 // Returns a meta redirect to URL.
HandleClientRedirect(const HttpRequest & request)743 std::unique_ptr<HttpResponse> HandleClientRedirect(const HttpRequest& request) {
744   GURL request_url = request.GetURL();
745   std::string dest =
746       base::UnescapeBinaryURLComponent(request_url.query_piece());
747 
748   auto http_response = std::make_unique<BasicHttpResponse>();
749   http_response->set_content_type("text/html");
750   http_response->set_content(base::StringPrintf(
751       "<!doctype html><meta http-equiv=\"refresh\" content=\"0;url=%s\">"
752       "<p>Redirecting to %s",
753       dest.c_str(), dest.c_str()));
754   return http_response;
755 }
756 
757 // /defaultresponse
758 // Returns a valid 200 response.
HandleDefaultResponse(const HttpRequest & request)759 std::unique_ptr<HttpResponse> HandleDefaultResponse(
760     const HttpRequest& request) {
761   auto http_response = std::make_unique<BasicHttpResponse>();
762   http_response->set_content_type("text/html");
763   http_response->set_content("Default response given for path: " +
764                              request.relative_url);
765   return http_response;
766 }
767 
768 // /slow?N
769 // Returns a response to the server delayed by N seconds.
HandleSlowServer(const HttpRequest & request)770 std::unique_ptr<HttpResponse> HandleSlowServer(const HttpRequest& request) {
771   double delay = 1.0f;
772 
773   GURL request_url = request.GetURL();
774   if (request_url.has_query())
775     delay = std::atof(request_url.query().c_str());
776 
777   auto http_response =
778       std::make_unique<DelayedHttpResponse>(base::Seconds(delay));
779   http_response->set_content_type("text/plain");
780   http_response->set_content(base::StringPrintf("waited %.1f seconds", delay));
781   return http_response;
782 }
783 
784 // /hung
785 // Never returns a response.
HandleHungResponse(const HttpRequest & request)786 std::unique_ptr<HttpResponse> HandleHungResponse(const HttpRequest& request) {
787   return std::make_unique<HungResponse>();
788 }
789 
790 // /hung-after-headers
791 // Never returns a response.
HandleHungAfterHeadersResponse(const HttpRequest & request)792 std::unique_ptr<HttpResponse> HandleHungAfterHeadersResponse(
793     const HttpRequest& request) {
794   return std::make_unique<HungAfterHeadersHttpResponse>();
795 }
796 
797 // /exabyte_response
798 // A HttpResponse that is almost never ending (with an Exabyte content-length).
799 class ExabyteResponse : public BasicHttpResponse {
800  public:
801   ExabyteResponse() = default;
802 
803   ExabyteResponse(const ExabyteResponse&) = delete;
804   ExabyteResponse& operator=(const ExabyteResponse&) = delete;
805 
SendResponse(base::WeakPtr<HttpResponseDelegate> delegate)806   void SendResponse(base::WeakPtr<HttpResponseDelegate> delegate) override {
807     // Use 10^18 bytes (exabyte) as the content length so that the client will
808     // be expecting data.
809     delegate->SendResponseHeaders(HTTP_OK, "OK",
810                                   {{"Content-Length", "1000000000000000000"}});
811     SendExabyte(delegate);
812   }
813 
814  private:
815   // Keeps sending the word "echo" over and over again. It can go further to
816   // limit the response to exactly an exabyte, but it shouldn't be necessary
817   // for the purpose of testing.
SendExabyte(base::WeakPtr<HttpResponseDelegate> delegate)818   void SendExabyte(base::WeakPtr<HttpResponseDelegate> delegate) {
819     delegate->SendContents(
820         "echo", base::BindOnce(&ExabyteResponse::PostSendExabyteTask,
821                                weak_factory_.GetWeakPtr(), delegate));
822   }
823 
PostSendExabyteTask(base::WeakPtr<HttpResponseDelegate> delegate)824   void PostSendExabyteTask(base::WeakPtr<HttpResponseDelegate> delegate) {
825     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
826         FROM_HERE, base::BindOnce(&ExabyteResponse::SendExabyte,
827                                   weak_factory_.GetWeakPtr(), delegate));
828   }
829 
830   base::WeakPtrFactory<ExabyteResponse> weak_factory_{this};
831 };
832 
833 // /exabyte_response
834 // Almost never ending response.
HandleExabyteResponse(const HttpRequest & request)835 std::unique_ptr<HttpResponse> HandleExabyteResponse(
836     const HttpRequest& request) {
837   return std::make_unique<ExabyteResponse>();
838 }
839 
840 // /gzip-body?<body>
841 // Returns a response with a gzipped body of "<body>". Attempts to allocate
842 // enough memory to contain the body, but DCHECKs if that fails.
HandleGzipBody(const HttpRequest & request)843 std::unique_ptr<HttpResponse> HandleGzipBody(const HttpRequest& request) {
844   std::string uncompressed_body = request.GetURL().query();
845   // Attempt to pick size that's large enough even in the worst case (deflate
846   // block headers should be shorter than 512 bytes, and deflating should never
847   // double size of data, modulo headers).
848   // TODO(mmenke): This is rather awkward. Worth improving CompressGzip?
849   std::vector<char> compressed_body(uncompressed_body.size() * 2 + 512);
850   size_t compressed_size = compressed_body.size();
851   CompressGzip(uncompressed_body.c_str(), uncompressed_body.size(),
852                compressed_body.data(), &compressed_size,
853                true /* gzip_framing */);
854   // CompressGzip should DCHECK itself if this fails, anyways.
855   DCHECK_GE(compressed_body.size(), compressed_size);
856 
857   auto http_response = std::make_unique<BasicHttpResponse>();
858   http_response->set_content(
859       std::string(compressed_body.data(), compressed_size));
860   http_response->AddCustomHeader("Content-Encoding", "gzip");
861   http_response->AddCustomHeader("Cache-Control", "max-age=60");
862   return http_response;
863 }
864 
865 // /self.pac
866 // Returns a response that is a PAC script making requests use the
867 // EmbeddedTestServer itself as a proxy.
HandleSelfPac(const HttpRequest & request)868 std::unique_ptr<HttpResponse> HandleSelfPac(const HttpRequest& request) {
869   std::unique_ptr<BasicHttpResponse> http_response =
870       std::make_unique<BasicHttpResponse>();
871   http_response->set_content(base::StringPrintf(
872       "function FindProxyForURL(url, host) {\n"
873       "return 'PROXY %s';\n"
874       "}",
875       net::HostPortPair::FromURL(request.base_url).ToString().c_str()));
876   return http_response;
877 }
878 
879 // A chunked HTTP response, with optional delays between chunks. See
880 // HandleChunks() for argument details.
881 class DelayedChunkedHttpResponse : public HttpResponse {
882  public:
DelayedChunkedHttpResponse(base::TimeDelta delay_before_headers,base::TimeDelta delay_between_chunks,int chunk_size,int num_chunks)883   DelayedChunkedHttpResponse(base::TimeDelta delay_before_headers,
884                              base::TimeDelta delay_between_chunks,
885                              int chunk_size,
886                              int num_chunks)
887       : delay_before_headers_(delay_before_headers),
888         delay_between_chunks_(delay_between_chunks),
889         chunk_size_(chunk_size),
890         remaining_chunks_(num_chunks) {}
891 
892   ~DelayedChunkedHttpResponse() override = default;
893 
894   DelayedChunkedHttpResponse(const DelayedChunkedHttpResponse&) = delete;
895   DelayedChunkedHttpResponse& operator=(const DelayedChunkedHttpResponse&) =
896       delete;
897 
SendResponse(base::WeakPtr<HttpResponseDelegate> delegate)898   void SendResponse(base::WeakPtr<HttpResponseDelegate> delegate) override {
899     delegate_ = delegate;
900 
901     base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
902         FROM_HERE,
903         base::BindOnce(&DelayedChunkedHttpResponse::SendHeaders,
904                        weak_ptr_factory_.GetWeakPtr()),
905         delay_before_headers_);
906   }
907 
908  private:
SendHeaders()909   void SendHeaders() {
910     base::StringPairs headers = {{"Content-Type", "text/plain"},
911                                  {"Connection", "close"},
912                                  {"Transfer-Encoding", "chunked"}};
913     delegate_->SendResponseHeaders(HTTP_OK, "OK", headers);
914     PrepareToSendNextChunk();
915   }
916 
PrepareToSendNextChunk()917   void PrepareToSendNextChunk() {
918     if (remaining_chunks_ == 0) {
919       delegate_->SendContentsAndFinish(CreateChunk(0 /* chunk_size */));
920       return;
921     }
922 
923     base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
924         FROM_HERE,
925         base::BindOnce(&DelayedChunkedHttpResponse::SendNextChunk,
926                        weak_ptr_factory_.GetWeakPtr()),
927         delay_between_chunks_);
928   }
929 
SendNextChunk()930   void SendNextChunk() {
931     DCHECK_GT(remaining_chunks_, 0);
932     remaining_chunks_--;
933 
934     delegate_->SendContents(
935         CreateChunk(chunk_size_),
936         base::BindOnce(&DelayedChunkedHttpResponse::PrepareToSendNextChunk,
937                        weak_ptr_factory_.GetWeakPtr()));
938   }
939 
CreateChunk(int chunk_size)940   static std::string CreateChunk(int chunk_size) {
941     return base::StringPrintf(
942         "%x\r\n"
943         "%s"
944         "\r\n",
945         chunk_size, std::string(chunk_size, '*').c_str());
946   }
947 
948   base::TimeDelta delay_before_headers_;
949   base::TimeDelta delay_between_chunks_;
950   int chunk_size_;
951   int remaining_chunks_;
952 
953   base::WeakPtr<HttpResponseDelegate> delegate_ = nullptr;
954 
955   base::WeakPtrFactory<DelayedChunkedHttpResponse> weak_ptr_factory_{this};
956 };
957 
958 // /chunked
959 // Returns a chunked response.
960 //
961 // Optional query parameters:
962 // * waitBeforeHeaders: Delays the specified number milliseconds before sending
963 // a response header. Defaults to 0.
964 // * waitBetweenChunks: Delays the specified number milliseconds before sending
965 // each chunk, except the last. Defaults to 0.
966 // * chunkSize: Size of each chunk, in bytes. Defaults to 5.
967 // * chunksNumber: Number of non-empty chunks. Defaults to 5.
HandleChunked(const HttpRequest & request)968 std::unique_ptr<HttpResponse> HandleChunked(const HttpRequest& request) {
969   GURL request_url = request.GetURL();
970 
971   base::TimeDelta delay_before_headers;
972   base::TimeDelta delay_between_chunks;
973   int chunk_size = 5;
974   int num_chunks = 5;
975 
976   for (QueryIterator query(request_url); !query.IsAtEnd(); query.Advance()) {
977     int value;
978     CHECK(base::StringToInt(query.GetValue(), &value));
979     CHECK_GE(value, 0);
980     if (query.GetKey() == "waitBeforeHeaders") {
981       delay_before_headers = base::Milliseconds(value);
982     } else if (query.GetKey() == "waitBetweenChunks") {
983       delay_between_chunks = base::Milliseconds(value);
984     } else if (query.GetKey() == "chunkSize") {
985       // A 0-size chunk indicates completion.
986       CHECK_LT(0, value);
987       chunk_size = value;
988     } else if (query.GetKey() == "chunksNumber") {
989       num_chunks = value;
990     } else {
991       NOTREACHED() << query.GetKey() << "Is not a valid argument of /chunked";
992     }
993   }
994 
995   return std::make_unique<DelayedChunkedHttpResponse>(
996       delay_before_headers, delay_between_chunks, chunk_size, num_chunks);
997 }
998 
PrefixHandler(const std::string & prefix,std::unique_ptr<HttpResponse> (* handler)(const HttpRequest & request))999 EmbeddedTestServer::HandleRequestCallback PrefixHandler(
1000     const std::string& prefix,
1001     std::unique_ptr<HttpResponse> (*handler)(const HttpRequest& request)) {
1002   return base::BindRepeating(&HandlePrefixedRequest, prefix,
1003                              base::BindRepeating(handler));
1004 }
1005 
ServerRedirectHandler(const std::string & prefix,std::unique_ptr<HttpResponse> (* handler)(HttpStatusCode redirect_code,bool allow_cors,const HttpRequest & request),HttpStatusCode redirect_code)1006 EmbeddedTestServer::HandleRequestCallback ServerRedirectHandler(
1007     const std::string& prefix,
1008     std::unique_ptr<HttpResponse> (*handler)(HttpStatusCode redirect_code,
1009                                              bool allow_cors,
1010                                              const HttpRequest& request),
1011     HttpStatusCode redirect_code) {
1012   return base::BindRepeating(
1013       &HandlePrefixedRequest, prefix,
1014       base::BindRepeating(handler, redirect_code, /*allow_cors=*/true));
1015 }
1016 
NoCorsServerRedirectHandler(const std::string & prefix,std::unique_ptr<HttpResponse> (* handler)(HttpStatusCode redirect_code,bool allow_cors,const HttpRequest & request),HttpStatusCode redirect_code)1017 EmbeddedTestServer::HandleRequestCallback NoCorsServerRedirectHandler(
1018     const std::string& prefix,
1019     std::unique_ptr<HttpResponse> (*handler)(HttpStatusCode redirect_code,
1020                                              bool allow_cors,
1021                                              const HttpRequest& request),
1022     HttpStatusCode redirect_code) {
1023   return base::BindRepeating(
1024       &HandlePrefixedRequest, prefix,
1025       base::BindRepeating(handler, redirect_code, /*allow_cors=*/false));
1026 }
1027 
ServerRedirectWithCookieHandler(const std::string & prefix,std::unique_ptr<HttpResponse> (* handler)(HttpStatusCode redirect_code,const HttpRequest & request),HttpStatusCode redirect_code)1028 EmbeddedTestServer::HandleRequestCallback ServerRedirectWithCookieHandler(
1029     const std::string& prefix,
1030     std::unique_ptr<HttpResponse> (*handler)(HttpStatusCode redirect_code,
1031                                              const HttpRequest& request),
1032     HttpStatusCode redirect_code) {
1033   return base::BindRepeating(&HandlePrefixedRequest, prefix,
1034                              base::BindRepeating(handler, redirect_code));
1035 }
1036 
1037 }  // anonymous namespace
1038 
RegisterDefaultHandlers(EmbeddedTestServer * server)1039 void RegisterDefaultHandlers(EmbeddedTestServer* server) {
1040   server->RegisterDefaultHandler(base::BindRepeating(&HandleDefaultConnect));
1041 
1042   server->RegisterDefaultHandler(PrefixHandler("/cachetime", &HandleCacheTime));
1043   server->RegisterDefaultHandler(
1044       base::BindRepeating(&HandleEchoHeader, "/echoheader", "no-cache"));
1045   server->RegisterDefaultHandler(base::BindRepeating(
1046       &HandleEchoCookieWithStatus, "/echo-cookie-with-status"));
1047   server->RegisterDefaultHandler(base::BindRepeating(
1048       &HandleEchoHeader, "/echoheadercache", "max-age=60000"));
1049   server->RegisterDefaultHandler(PrefixHandler("/echo", &HandleEcho));
1050   server->RegisterDefaultHandler(PrefixHandler("/echotitle", &HandleEchoTitle));
1051   server->RegisterDefaultHandler(PrefixHandler("/echoall", &HandleEchoAll));
1052   server->RegisterDefaultHandler(PrefixHandler("/echo-raw", &HandleEchoRaw));
1053   server->RegisterDefaultHandler(
1054       PrefixHandler("/echocriticalheader", &HandleEchoCriticalHeader));
1055   server->RegisterDefaultHandler(
1056       PrefixHandler("/set-cookie", &HandleSetCookie));
1057   server->RegisterDefaultHandler(
1058       PrefixHandler("/set-invalid-cookie", &HandleSetInvalidCookie));
1059   server->RegisterDefaultHandler(
1060       PrefixHandler("/expect-and-set-cookie", &HandleExpectAndSetCookie));
1061   server->RegisterDefaultHandler(
1062       PrefixHandler("/set-header", &HandleSetHeader));
1063   server->RegisterDefaultHandler(
1064       base::BindRepeating(&HandleSetHeaderWithFile, "/set-header-with-file"));
1065   server->RegisterDefaultHandler(PrefixHandler("/iframe", &HandleIframe));
1066   server->RegisterDefaultHandler(PrefixHandler("/nocontent", &HandleNoContent));
1067   server->RegisterDefaultHandler(
1068       PrefixHandler("/close-socket", &HandleCloseSocket));
1069   server->RegisterDefaultHandler(
1070       PrefixHandler("/auth-basic", &HandleAuthBasic));
1071   server->RegisterDefaultHandler(
1072       PrefixHandler("/auth-digest", &HandleAuthDigest));
1073 
1074   server->RegisterDefaultHandler(ServerRedirectHandler(
1075       "/server-redirect", &HandleServerRedirect, HTTP_MOVED_PERMANENTLY));
1076   server->RegisterDefaultHandler(ServerRedirectHandler(
1077       "/server-redirect-301", &HandleServerRedirect, HTTP_MOVED_PERMANENTLY));
1078   server->RegisterDefaultHandler(ServerRedirectHandler(
1079       "/server-redirect-302", &HandleServerRedirect, HTTP_FOUND));
1080   server->RegisterDefaultHandler(ServerRedirectHandler(
1081       "/server-redirect-303", &HandleServerRedirect, HTTP_SEE_OTHER));
1082   server->RegisterDefaultHandler(ServerRedirectHandler(
1083       "/server-redirect-307", &HandleServerRedirect, HTTP_TEMPORARY_REDIRECT));
1084   server->RegisterDefaultHandler(ServerRedirectHandler(
1085       "/server-redirect-308", &HandleServerRedirect, HTTP_PERMANENT_REDIRECT));
1086 
1087   server->RegisterDefaultHandler(NoCorsServerRedirectHandler(
1088       "/no-cors-server-redirect", &HandleServerRedirect,
1089       HTTP_MOVED_PERMANENTLY));
1090   server->RegisterDefaultHandler(NoCorsServerRedirectHandler(
1091       "/no-cors-server-redirect-301", &HandleServerRedirect,
1092       HTTP_MOVED_PERMANENTLY));
1093   server->RegisterDefaultHandler(NoCorsServerRedirectHandler(
1094       "/no-cors-server-redirect-302", &HandleServerRedirect, HTTP_FOUND));
1095   server->RegisterDefaultHandler(NoCorsServerRedirectHandler(
1096       "/no-cors-server-redirect-303", &HandleServerRedirect, HTTP_SEE_OTHER));
1097   server->RegisterDefaultHandler(NoCorsServerRedirectHandler(
1098       "/no-cors-server-redirect-307", &HandleServerRedirect,
1099       HTTP_TEMPORARY_REDIRECT));
1100   server->RegisterDefaultHandler(NoCorsServerRedirectHandler(
1101       "/no-cors-server-redirect-308", &HandleServerRedirect,
1102       HTTP_PERMANENT_REDIRECT));
1103 
1104   server->RegisterDefaultHandler(ServerRedirectWithCookieHandler(
1105       "/server-redirect-with-cookie", &HandleServerRedirectWithCookie,
1106       HTTP_MOVED_PERMANENTLY));
1107   server->RegisterDefaultHandler(ServerRedirectWithCookieHandler(
1108       "/server-redirect-with-secure-cookie",
1109       &HandleServerRedirectWithSecureCookie, HTTP_MOVED_PERMANENTLY));
1110 
1111   server->RegisterDefaultHandler(base::BindRepeating(&HandleCrossSiteRedirect,
1112                                                      server, "/cross-site",
1113                                                      /*set_cookie=*/false));
1114   server->RegisterDefaultHandler(
1115       base::BindRepeating(&HandleCrossSiteRedirect, server,
1116                           "/cross-site-with-cookie", /*set_cookie=*/true));
1117   server->RegisterDefaultHandler(
1118       PrefixHandler("/client-redirect", &HandleClientRedirect));
1119   server->RegisterDefaultHandler(
1120       PrefixHandler("/defaultresponse", &HandleDefaultResponse));
1121   server->RegisterDefaultHandler(PrefixHandler("/slow", &HandleSlowServer));
1122   server->RegisterDefaultHandler(PrefixHandler("/hung", &HandleHungResponse));
1123   server->RegisterDefaultHandler(
1124       PrefixHandler("/hung-after-headers", &HandleHungAfterHeadersResponse));
1125   server->RegisterDefaultHandler(
1126       PrefixHandler("/exabyte_response", &HandleExabyteResponse));
1127   server->RegisterDefaultHandler(PrefixHandler("/gzip-body", &HandleGzipBody));
1128   server->RegisterDefaultHandler(PrefixHandler("/self.pac", &HandleSelfPac));
1129   server->RegisterDefaultHandler(PrefixHandler("/chunked", &HandleChunked));
1130 
1131   // TODO(svaldez): HandleDownload
1132   // TODO(svaldez): HandleDownloadFinish
1133   // TODO(svaldez): HandleZipFile
1134   // TODO(svaldez): HandleSSLManySmallRecords
1135   // TODO(svaldez): HandleGetSSLSessionCache
1136   // TODO(svaldez): HandleGetChannelID
1137   // TODO(svaldez): HandleGetClientCert
1138   // TODO(svaldez): HandleClientCipherList
1139   // TODO(svaldez): HandleEchoMultipartPost
1140 }
1141 
1142 }  // namespace net::test_server
1143