Chromium Code Reviews| OLD | NEW |
|---|---|
| (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/default_handlers.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/time/time.h" | |
| 24 #include "net/base/escape.h" | |
| 25 #include "net/base/url_util.h" | |
| 26 #include "net/test/embedded_test_server/http_request.h" | |
| 27 #include "net/test/embedded_test_server/http_response.h" | |
| 28 #include "net/test/embedded_test_server/request_handler_util.h" | |
| 29 | |
| 30 namespace net { | |
| 31 namespace test_server { | |
| 32 namespace { | |
| 33 | |
| 34 const UnescapeRule::Type kUnescapeAll = | |
| 35 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS | | |
| 36 UnescapeRule::SPOOFING_AND_CONTROL_CHARS | | |
| 37 UnescapeRule::REPLACE_PLUS_WITH_SPACE; | |
| 38 | |
| 39 const char kDefaultRealm[] = "testrealm"; | |
| 40 const char kDefaultPassword[] = "secret"; | |
| 41 | |
| 42 scoped_ptr<HttpResponse> HandleDefaultConnect(const HttpRequest& request) { | |
| 43 if (request.method != METHOD_CONNECT) | |
| 44 return nullptr; | |
| 45 | |
| 46 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 47 http_response->set_code(HTTP_BAD_REQUEST); | |
| 48 http_response->set_content( | |
| 49 "Your client has issued a malformed or illegal request."); | |
| 50 http_response->set_content_type("text/html"); | |
| 51 return http_response.Pass(); | |
| 52 } | |
| 53 | |
| 54 scoped_ptr<HttpResponse> HandleCacheTime(const HttpRequest& request) { | |
| 55 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 56 http_response->set_content( | |
| 57 "<html><head><title>Cache: max-age=60</title></head></html>"); | |
| 58 http_response->set_content_type("text/html"); | |
| 59 http_response->AddCustomHeader("Cache-Control", "max-age=60"); | |
| 60 return http_response.Pass(); | |
| 61 } | |
| 62 | |
| 63 scoped_ptr<HttpResponse> HandleEchoHeader(std::string url, | |
| 64 std::string cache_control, | |
|
mmenke
2015/10/29 20:20:29
const std::string& (x2)
svaldez
2015/10/29 21:27:37
Done.
| |
| 65 const HttpRequest& request) { | |
| 66 if (!ShouldHandle(request, url)) | |
| 67 return nullptr; | |
| 68 | |
| 69 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 70 | |
| 71 GURL request_gurl = request.GetURL(); | |
|
mmenke
2015/10/29 20:20:28
Suggest using request_url everywhere in this file
svaldez
2015/10/29 21:27:37
Done.
| |
| 72 if (request_gurl.has_query()) { | |
| 73 std::string header_name = request_gurl.query(); | |
| 74 http_response->AddCustomHeader("Vary", header_name); | |
| 75 if (request.headers.find(header_name) != request.headers.end()) | |
| 76 http_response->set_content(request.headers.at(header_name)); | |
| 77 else | |
| 78 http_response->set_content("None"); | |
| 79 } | |
| 80 | |
| 81 http_response->set_content_type("text/plain"); | |
| 82 http_response->AddCustomHeader("Cache-Control", cache_control); | |
| 83 return http_response.Pass(); | |
| 84 } | |
| 85 | |
| 86 scoped_ptr<HttpResponse> HandleEcho(const HttpRequest& request) { | |
| 87 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 88 | |
| 89 GURL request_gurl = request.GetURL(); | |
| 90 if (request_gurl.has_query()) { | |
| 91 RequestQuery query = ParseQuery(request_gurl); | |
| 92 if (query.find("status") != query.end()) | |
| 93 http_response->set_code(static_cast<HttpStatusCode>( | |
| 94 std::atoi(query["status"].front().c_str()))); | |
| 95 } | |
| 96 | |
| 97 http_response->set_content_type("text/html"); | |
| 98 if (request.method != METHOD_POST && request.method != METHOD_PUT) | |
| 99 http_response->set_content("Echo"); | |
|
mmenke
2015/10/29 20:20:29
The old handler just sent an empty body in this ca
svaldez
2015/10/29 21:27:37
The other server had the behavior that it would al
| |
| 100 else | |
| 101 http_response->set_content(request.content); | |
| 102 return http_response.Pass(); | |
| 103 } | |
| 104 | |
| 105 scoped_ptr<HttpResponse> HandleEchoTitle(const HttpRequest& request) { | |
| 106 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 107 http_response->set_content_type("text/html"); | |
| 108 http_response->set_content("<html><head><title>" + request.content + | |
| 109 "</title></head></html>"); | |
| 110 return http_response.Pass(); | |
| 111 } | |
| 112 | |
| 113 scoped_ptr<HttpResponse> HandleEchoAll(const HttpRequest& request) { | |
| 114 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 115 | |
| 116 std::string body = | |
| 117 "<html><head><style>" | |
| 118 "pre { border: 1px solid black; margin: 5px; padding: 5px }" | |
| 119 "</style></head><body>" | |
| 120 "<div style=\"float: right\">" | |
| 121 "<a href=\"/echo\">back to referring page</a></div>" | |
| 122 "<h1>Request Body:</h1><pre>"; | |
| 123 | |
| 124 if (request.has_content) { | |
| 125 std::vector<std::string> qs = base::SplitString( | |
|
mmenke
2015/10/29 20:20:29
Avoid uncommon abbreviations in variable names. S
svaldez
2015/10/29 21:27:37
Done.
| |
| 126 request.content, "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); | |
| 127 for (size_t i = 0; i < qs.size(); ++i) { | |
| 128 body += qs[i] + "\n"; | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 body += | |
| 133 "</pre>" | |
| 134 "<h1>Request Headers:</h1><pre>" + | |
| 135 request.all_headers + | |
| 136 "</pre>" | |
| 137 "</body></html>"; | |
| 138 | |
| 139 http_response->set_content_type("text/html"); | |
| 140 http_response->set_content(body); | |
| 141 return http_response.Pass(); | |
| 142 } | |
| 143 | |
| 144 scoped_ptr<HttpResponse> HandleSetCookie(const HttpRequest& request) { | |
| 145 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 146 http_response->set_content_type("text/html"); | |
| 147 std::string content; | |
| 148 GURL request_gurl = request.GetURL(); | |
| 149 if (request_gurl.has_query()) { | |
| 150 std::vector<std::string> cookies = base::SplitString( | |
| 151 request_gurl.query(), "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); | |
| 152 for (size_t i = 0; i < cookies.size(); ++i) { | |
|
mmenke
2015/10/29 20:20:29
nit: Range loop.
svaldez
2015/10/29 21:27:37
Done.
| |
| 153 http_response->AddCustomHeader("Set-Cookie", cookies[i]); | |
| 154 content += cookies[i]; | |
| 155 } | |
| 156 } | |
| 157 | |
| 158 http_response->set_content(content); | |
| 159 return http_response.Pass(); | |
| 160 } | |
| 161 | |
| 162 scoped_ptr<HttpResponse> HandleSetManyCookies(const HttpRequest& request) { | |
| 163 std::string content; | |
| 164 | |
| 165 GURL request_gurl = request.GetURL(); | |
| 166 size_t num = 0; | |
| 167 if (request_gurl.has_query()) { | |
| 168 num = std::atoi(request_gurl.query().c_str()); | |
| 169 } | |
|
mmenke
2015/10/29 20:20:29
nit: Remove braces.
svaldez
2015/10/29 21:27:38
Done.
| |
| 170 | |
| 171 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 172 http_response->set_content_type("text/html"); | |
| 173 for (size_t i = 0; i < num; ++i) { | |
| 174 http_response->AddCustomHeader("Set-Cookie", "a="); | |
| 175 } | |
| 176 | |
| 177 http_response->set_content( | |
| 178 base::StringPrintf("%" PRIuS " cookies were sent", num)); | |
| 179 return http_response.Pass(); | |
| 180 } | |
| 181 | |
| 182 scoped_ptr<HttpResponse> HandleExpectAndSetCookie(const HttpRequest& request) { | |
| 183 std::vector<std::string> sentCookies; | |
|
mmenke
2015/10/29 20:20:29
sent_cookies - maybe received_cookies would be cle
svaldez
2015/10/29 21:27:37
Done.
| |
| 184 if (request.headers.find("Cookie") != request.headers.end()) { | |
| 185 std::vector<std::string> cookies = | |
| 186 base::SplitString(request.headers.at("Cookie"), ";", | |
| 187 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); | |
| 188 for (size_t i = 0; i < cookies.size(); ++i) { | |
| 189 sentCookies.push_back(cookies[i]); | |
|
mmenke
2015/10/29 20:20:29
You're copying everything in one vector of std::st
svaldez
2015/10/29 21:27:37
Done.
| |
| 190 } | |
| 191 } | |
| 192 bool got_expected = true; | |
|
mmenke
2015/10/29 20:20:28
nit: got_all_expected? Think it's a little clear
svaldez
2015/10/29 21:27:37
Done.
| |
| 193 | |
| 194 GURL request_gurl = request.GetURL(); | |
| 195 RequestQuery qs = ParseQuery(request_gurl); | |
|
mmenke
2015/10/29 20:20:28
Avoid uncommon abbreviations in variable names.
svaldez
2015/10/29 21:27:37
Done.
| |
| 196 if (qs.find("expect") != qs.end()) { | |
| 197 std::vector<std::string> expected = qs.at("expect"); | |
|
mmenke
2015/10/29 20:20:29
expected_cookies?
svaldez
2015/10/29 21:27:37
Done.
| |
| 198 for (size_t i = 0; i < expected.size(); ++i) { | |
|
mmenke
2015/10/29 20:20:29
Suggest range loops (x4). Perf doesn't really mat
svaldez
2015/10/29 21:27:38
Done.
| |
| 199 bool found = false; | |
| 200 for (size_t j = 0; j < sentCookies.size(); ++j) { | |
|
mmenke
2015/10/29 20:20:28
Could just use std::find, though suppose it doesn'
svaldez
2015/10/29 21:27:37
Acknowledged.
| |
| 201 if (expected[i] == sentCookies[j]) | |
| 202 found = true; | |
| 203 } | |
| 204 got_expected &= found; | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 209 http_response->set_content_type("text/html"); | |
| 210 if (got_expected) { | |
| 211 std::vector<std::string> setCookies = qs.at("set"); | |
|
mmenke
2015/10/29 20:20:28
set_cookies
svaldez
2015/10/29 21:27:37
Done.
| |
| 212 for (size_t i = 0; i < setCookies.size(); ++i) { | |
| 213 http_response->AddCustomHeader( | |
| 214 "Set-Cookie", net::UnescapeURLComponent(setCookies[i], kUnescapeAll)); | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 std::string content; | |
| 219 if (qs.find("data") != qs.end()) { | |
| 220 std::vector<std::string> data = qs.at("data"); | |
| 221 for (size_t i = 0; i < data.size(); ++i) { | |
| 222 content += data[i]; | |
| 223 } | |
| 224 } | |
| 225 | |
| 226 http_response->set_content(content); | |
| 227 return http_response.Pass(); | |
| 228 } | |
| 229 | |
| 230 scoped_ptr<HttpResponse> HandleSetHeader(const HttpRequest& request) { | |
| 231 std::string content; | |
| 232 | |
| 233 GURL request_gurl = request.GetURL(); | |
| 234 | |
| 235 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 236 http_response->set_content_type("text/html"); | |
| 237 if (request_gurl.has_query()) { | |
| 238 RequestQuery headers = ParseQuery(request_gurl); | |
| 239 for (auto header : headers) { | |
|
mmenke
2015/10/29 20:20:29
const auto&
svaldez
2015/10/29 21:27:37
Done.
| |
| 240 std::string key = header.first.substr(0, header.first.find(": ")); | |
| 241 std::string value = header.first.substr(header.first.find(": ") + 2); | |
|
mmenke
2015/10/29 20:20:29
Should be careful about find returning npos.
svaldez
2015/10/29 21:27:38
Done.
| |
| 242 http_response->AddCustomHeader(key, value); | |
| 243 content += header.first; | |
| 244 } | |
| 245 } | |
| 246 | |
| 247 http_response->set_content(content); | |
| 248 return http_response.Pass(); | |
| 249 } | |
| 250 | |
| 251 scoped_ptr<HttpResponse> HandleNoContent(const HttpRequest& request) { | |
| 252 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 253 http_response->set_code(HTTP_NO_CONTENT); | |
| 254 return http_response.Pass(); | |
| 255 } | |
| 256 | |
| 257 scoped_ptr<HttpResponse> HandleCloseSocket(const HttpRequest& request) { | |
| 258 scoped_ptr<RawHttpResponse> http_response(new RawHttpResponse("", "")); | |
| 259 return http_response.Pass(); | |
| 260 } | |
| 261 | |
| 262 scoped_ptr<HttpResponse> HandleAuthBasic(const HttpRequest& request) { | |
| 263 GURL request_gurl = request.GetURL(); | |
| 264 RequestQuery query = ParseQuery(request_gurl); | |
| 265 | |
| 266 std::string expected_password = kDefaultPassword; | |
| 267 if (query.find("password") != query.end()) | |
| 268 expected_password = query.at("password").front(); | |
| 269 std::string realm = kDefaultRealm; | |
| 270 if (query.find("realm") != query.end()) | |
| 271 realm = query.at("realm").front(); | |
| 272 | |
| 273 bool authed = false; | |
| 274 std::string error; | |
| 275 std::string auth; | |
| 276 std::string username; | |
| 277 std::string userpass; | |
| 278 std::string password; | |
| 279 std::string b64str; | |
| 280 if (request.headers.find("Authorization") == request.headers.end()) { | |
| 281 error = "Missing Authorization Header"; | |
| 282 } else { | |
| 283 auth = request.headers.at("Authorization"); | |
| 284 if (auth.find("Basic ") == std::string::npos) { | |
| 285 error = "Invalid Authorization Header"; | |
| 286 } else { | |
| 287 b64str = auth.substr(std::string("Basic ").size()); | |
| 288 base::Base64Decode(b64str, &userpass); | |
| 289 if (userpass.find(":") != std::string::npos) { | |
| 290 username = userpass.substr(0, userpass.find(":")); | |
| 291 password = userpass.substr(userpass.find(":") + 1); | |
| 292 if (password == expected_password) | |
| 293 authed = true; | |
| 294 else | |
| 295 error = "Invalid Credentials"; | |
| 296 } else | |
| 297 error = "Invalid Credentials"; | |
|
mmenke
2015/10/29 20:20:29
Use braces. (Both parts of an if/else should eith
svaldez
2015/10/29 21:27:37
Done.
| |
| 298 } | |
| 299 } | |
| 300 | |
| 301 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 302 if (!authed) { | |
| 303 http_response->set_code(HTTP_UNAUTHORIZED); | |
| 304 http_response->set_content_type("text/html"); | |
| 305 http_response->AddCustomHeader("WWW-Authenticate", | |
| 306 "Basic realm=\"" + realm + "\""); | |
| 307 if (query.find("set-cookie-if-challenged") != query.end()) | |
| 308 http_response->AddCustomHeader("Set-Cookie", "got_challenged=true"); | |
| 309 http_response->set_content(base::StringPrintf( | |
| 310 "<html><head><title>Denied: %s</title></head>" | |
| 311 "<body>auth=%s<p>b64str=%s<p>username: %s<p>userpass: %s<p>" | |
| 312 "password: %s<p>You sent:<br>%s<p></body></html>", | |
| 313 error.c_str(), auth.c_str(), b64str.c_str(), username.c_str(), | |
| 314 userpass.c_str(), password.c_str(), request.all_headers.c_str())); | |
| 315 return http_response.Pass(); | |
| 316 } | |
| 317 | |
| 318 if (request.headers.find("If-None-Match") != request.headers.end() && | |
| 319 request.headers.at("If-None-Match") == "abc") { | |
|
mmenke
2015/10/29 20:20:29
"abc" should probably be a local constant. kEtag o
svaldez
2015/10/29 21:27:37
Done.
| |
| 320 http_response->set_code(HTTP_NOT_MODIFIED); | |
| 321 return http_response.Pass(); | |
| 322 } | |
| 323 | |
| 324 base::FilePath file_path = | |
| 325 base::FilePath().AppendASCII(request.relative_url.substr(1)); | |
|
mmenke
2015/10/29 20:20:28
Hrm... This seems kind of silly, but I guess Gene
svaldez
2015/10/29 21:27:38
Acknowledged.
| |
| 326 if (file_path.FinalExtension() == FILE_PATH_LITERAL("gif")) { | |
| 327 base::FilePath server_root; | |
| 328 PathService::Get(base::DIR_SOURCE_ROOT, &server_root); | |
| 329 base::FilePath gif_path = | |
| 330 server_root.AppendASCII("chrome/test/data/google/logo.gif"); | |
|
mmenke
2015/10/29 20:20:29
Suggest making this path a const char[] at the top
svaldez
2015/10/29 21:27:37
Done.
| |
| 331 std::string gif_data; | |
| 332 base::ReadFileToString(gif_path, &gif_data); | |
| 333 http_response->set_content_type("image/gif"); | |
| 334 http_response->set_content(gif_data); | |
| 335 } else { | |
| 336 http_response->set_content_type("text/html"); | |
| 337 http_response->set_content( | |
| 338 base::StringPrintf("<html><head><title>%s/%s</title></head>" | |
| 339 "<body>auth=%s<p>You sent:<br>%s<p></body></html>", | |
| 340 username.c_str(), password.c_str(), auth.c_str(), | |
| 341 request.all_headers.c_str())); | |
| 342 } | |
| 343 | |
| 344 http_response->AddCustomHeader("Cache-Control", "max-age=60000"); | |
| 345 http_response->AddCustomHeader("Etag", "abc"); | |
| 346 return http_response.Pass(); | |
| 347 } | |
| 348 | |
| 349 scoped_ptr<HttpResponse> HandleAuthDigest(const HttpRequest& request) { | |
| 350 std::string nonce = base::MD5String( | |
| 351 base::StringPrintf("privatekey%s", request.relative_url.c_str())); | |
| 352 std::string opaque = base::MD5String("opaque"); | |
| 353 std::string password = kDefaultPassword; | |
| 354 std::string realm = kDefaultRealm; | |
| 355 | |
| 356 bool authed = false; | |
| 357 std::string error; | |
| 358 std::string auth; | |
| 359 std::string digest_str = "Digest"; | |
| 360 std::string username; | |
| 361 if (request.headers.find("Authorization") == request.headers.end()) { | |
| 362 error = "no auth"; | |
| 363 } else if (request.headers.at("Authorization").substr(0, digest_str.size()) != | |
| 364 digest_str) { | |
| 365 error = "not digest"; | |
| 366 } else { | |
| 367 auth = request.headers.at("Authorization"); | |
| 368 | |
| 369 std::map<std::string, std::string> auth_pairs; | |
| 370 std::vector<std::string> authVector = base::SplitString( | |
| 371 auth, ", ", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); | |
|
mmenke
2015/10/29 20:20:29
May be a little cleaner to use SplitStringIntoKeyV
svaldez
2015/10/29 21:27:37
Done.
| |
| 372 for (auto authPair : authVector) { | |
|
mmenke
2015/10/29 20:20:29
const auto&
svaldez
2015/10/29 21:27:37
Done.
| |
| 373 std::string key = authPair.substr(0, authPair.find("=")); | |
| 374 std::string value = authPair.substr(authPair.find("=") + 1); | |
|
mmenke
2015/10/29 20:20:28
Should handle the case authPair.find("=") is npos.
svaldez
2015/10/29 21:27:37
Acknowledged.
| |
| 375 if (value.substr(0, 1) == "\"" && value.substr(value.size() - 1) == "\"") | |
| 376 value = value.substr(1, value.size() - 2); | |
| 377 auth_pairs[key] = value; | |
| 378 } | |
| 379 | |
| 380 if (auth_pairs["nonce"] != nonce) { | |
| 381 error = "wrong nonce"; | |
| 382 } else if (auth_pairs["opaque"] != opaque) { | |
| 383 error = "wrong opaque"; | |
| 384 } else { | |
| 385 username = auth_pairs["username"]; | |
| 386 | |
| 387 std::string hash1 = base::MD5String( | |
| 388 base::StringPrintf("%s:%s:%s", auth_pairs["username"].c_str(), | |
| 389 realm.c_str(), password.c_str())); | |
| 390 std::string hash2 = base::MD5String(base::StringPrintf( | |
| 391 "%s:%s", request.method_string.c_str(), auth_pairs["uri"].c_str())); | |
| 392 | |
| 393 std::string response; | |
| 394 if (auth_pairs.find("qop") != auth_pairs.end() && | |
| 395 auth_pairs.find("nc") != auth_pairs.end() && | |
| 396 auth_pairs.find("cnonce") != auth_pairs.end()) { | |
| 397 response = base::MD5String(base::StringPrintf( | |
| 398 "%s:%s:%s:%s:%s:%s", hash1.c_str(), nonce.c_str(), | |
| 399 auth_pairs["nc"].c_str(), auth_pairs["cnonce"].c_str(), | |
| 400 auth_pairs["qop"].c_str(), hash2.c_str())); | |
| 401 } else { | |
| 402 response = base::MD5String(base::StringPrintf( | |
| 403 "%s:%s:%s", hash1.c_str(), nonce.c_str(), hash2.c_str())); | |
| 404 } | |
| 405 | |
| 406 if (auth_pairs["response"] == response) | |
| 407 authed = true; | |
| 408 else | |
| 409 error = "wrong password"; | |
| 410 } | |
| 411 } | |
| 412 | |
| 413 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 414 if (!authed) { | |
| 415 http_response->set_code(HTTP_UNAUTHORIZED); | |
| 416 http_response->set_content_type("text/html"); | |
| 417 std::string authHeader = base::StringPrintf( | |
|
mmenke
2015/10/29 20:20:29
auth_header
svaldez
2015/10/29 21:27:38
Done.
| |
| 418 "Digest realm=\"%s\", " | |
| 419 "domain=\"/\", qop=\"auth\", algorithm=MD5, nonce=\"%s\", " | |
| 420 "opaque=\"%s\"", | |
| 421 realm.c_str(), nonce.c_str(), opaque.c_str()); | |
| 422 http_response->AddCustomHeader("WWW-Authenticate", authHeader); | |
| 423 http_response->set_content(base::StringPrintf( | |
| 424 "<html><head><title>Denied: %s</title></head>" | |
| 425 "<body>auth=%s<p>" | |
| 426 "You sent:<br>%s<p>We are replying:<br>%s<p></body></html>", | |
| 427 error.c_str(), auth.c_str(), request.all_headers.c_str(), | |
| 428 authHeader.c_str())); | |
| 429 return http_response.Pass(); | |
| 430 } | |
| 431 | |
| 432 http_response->set_content_type("text/html"); | |
| 433 http_response->set_content( | |
| 434 base::StringPrintf("<html><head><title>%s/%s</title></head>" | |
| 435 "<body>auth=%s<p></body></html>", | |
| 436 username.c_str(), password.c_str(), auth.c_str())); | |
| 437 | |
| 438 return http_response.Pass(); | |
| 439 } | |
| 440 | |
| 441 scoped_ptr<HttpResponse> HandleServerRedirect(const HttpRequest& request) { | |
| 442 GURL request_gurl = request.GetURL(); | |
| 443 std::string dest = | |
| 444 net::UnescapeURLComponent(request_gurl.query(), kUnescapeAll); | |
| 445 | |
| 446 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 447 http_response->set_code(HTTP_MOVED_PERMANENTLY); | |
| 448 http_response->AddCustomHeader("Location", dest); | |
| 449 http_response->set_content_type("text/html"); | |
| 450 http_response->set_content(base::StringPrintf( | |
| 451 "<html><head></head><body>Redirecting to %s</body></html>", | |
| 452 dest.c_str())); | |
| 453 return http_response.Pass(); | |
| 454 } | |
| 455 | |
| 456 scoped_ptr<HttpResponse> HandleCrossSiteRedirect(EmbeddedTestServer* server, | |
| 457 const HttpRequest& request) { | |
| 458 if (!ShouldHandle(request, "/cross-site")) | |
| 459 return nullptr; | |
| 460 | |
| 461 std::string dest_all = net::UnescapeURLComponent( | |
| 462 request.relative_url.substr(std::string("/cross-site").size() + 1), | |
| 463 kUnescapeAll); | |
| 464 | |
| 465 std::string dest = base::StringPrintf( | |
| 466 "//%s:%hu/%s", dest_all.substr(0, dest_all.find("/")).c_str(), | |
| 467 server->port(), dest_all.substr(dest_all.find("/") + 1).c_str()); | |
| 468 | |
| 469 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 470 http_response->set_code(HTTP_MOVED_PERMANENTLY); | |
| 471 http_response->AddCustomHeader("Location", dest); | |
| 472 http_response->set_content_type("text/html"); | |
| 473 http_response->set_content(base::StringPrintf( | |
| 474 "<html><head></head><body>Redirecting to %s</body></html>", | |
| 475 dest.c_str())); | |
| 476 return http_response.Pass(); | |
| 477 } | |
| 478 | |
| 479 scoped_ptr<HttpResponse> HandleClientRedirect(const HttpRequest& request) { | |
| 480 GURL request_gurl = request.GetURL(); | |
| 481 std::string dest = | |
| 482 net::UnescapeURLComponent(request_gurl.query(), kUnescapeAll); | |
| 483 | |
| 484 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 485 http_response->set_content_type("text/html"); | |
| 486 http_response->set_content(base::StringPrintf( | |
| 487 "<html><head><meta http-equiv=\"refresh\" content=\"0;url=%s\"></head>" | |
| 488 "<body>Redirecting to %s</body></html>", | |
| 489 dest.c_str(), dest.c_str())); | |
| 490 return http_response.Pass(); | |
| 491 } | |
| 492 | |
| 493 scoped_ptr<HttpResponse> HandleDefaultResponse(const HttpRequest& request) { | |
| 494 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
| 495 http_response->set_content_type("text/html"); | |
| 496 http_response->set_content("Default response given for path: " + | |
| 497 request.relative_url); | |
| 498 return http_response.Pass(); | |
| 499 } | |
| 500 | |
| 501 class DelayedHttpResponse : public BasicHttpResponse { | |
| 502 public: | |
| 503 DelayedHttpResponse(double delay) : delay_(delay) {} | |
| 504 | |
| 505 void SendResponse(const SendBytesCallback& send, | |
| 506 const SendCompleteCallback& done) override { | |
| 507 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 508 FROM_HERE, base::Bind(send, ToResponseString(), done), | |
| 509 base::TimeDelta::FromSecondsD(delay_)); | |
| 510 } | |
| 511 | |
| 512 private: | |
| 513 double delay_; | |
| 514 }; | |
| 515 | |
| 516 scoped_ptr<HttpResponse> HandleSlowServer(const HttpRequest& request) { | |
| 517 double delay = 1.0f; | |
| 518 | |
| 519 GURL request_gurl = request.GetURL(); | |
| 520 if (request_gurl.has_query()) { | |
| 521 delay = std::atof(request_gurl.query().c_str()); | |
| 522 } | |
| 523 | |
| 524 scoped_ptr<BasicHttpResponse> http_response(new DelayedHttpResponse(delay)); | |
| 525 http_response->set_content_type("text/plain"); | |
| 526 http_response->set_content(base::StringPrintf("waited %.1f seconds", delay)); | |
| 527 return http_response.Pass(); | |
| 528 } | |
| 529 | |
| 530 } // namespace anonymous | |
| 531 | |
| 532 #define PREFIXED_HANDLER(prefix, handler) \ | |
| 533 base::Bind(&HandlePrefixedRequest, prefix, base::Bind(handler)) | |
| 534 | |
| 535 void RegisterDefaultHandlers(EmbeddedTestServer* server) { | |
| 536 server->RegisterDefaultHandler(base::Bind(&HandleDefaultConnect)); | |
| 537 | |
| 538 server->RegisterDefaultHandler( | |
| 539 PREFIXED_HANDLER("/cachetime", &HandleCacheTime)); | |
| 540 server->RegisterDefaultHandler( | |
| 541 base::Bind(&HandleEchoHeader, "/echoheader", "no-cache")); | |
| 542 server->RegisterDefaultHandler( | |
| 543 base::Bind(&HandleEchoHeader, "/echoheadercache", "max-age=60000")); | |
| 544 server->RegisterDefaultHandler(PREFIXED_HANDLER("/echo", &HandleEcho)); | |
| 545 server->RegisterDefaultHandler( | |
| 546 PREFIXED_HANDLER("/echotitle", &HandleEchoTitle)); | |
| 547 server->RegisterDefaultHandler(PREFIXED_HANDLER("/echoall", &HandleEchoAll)); | |
| 548 server->RegisterDefaultHandler( | |
| 549 PREFIXED_HANDLER("/set-cookie", &HandleSetCookie)); | |
| 550 server->RegisterDefaultHandler( | |
| 551 PREFIXED_HANDLER("/set-many-cookies", &HandleSetManyCookies)); | |
| 552 server->RegisterDefaultHandler( | |
| 553 PREFIXED_HANDLER("/expect-and-set-cookie", &HandleExpectAndSetCookie)); | |
| 554 server->RegisterDefaultHandler( | |
| 555 PREFIXED_HANDLER("/set-header", &HandleSetHeader)); | |
| 556 server->RegisterDefaultHandler( | |
| 557 PREFIXED_HANDLER("/nocontent", &HandleNoContent)); | |
| 558 server->RegisterDefaultHandler( | |
| 559 PREFIXED_HANDLER("/close-socket", &HandleCloseSocket)); | |
| 560 server->RegisterDefaultHandler( | |
| 561 PREFIXED_HANDLER("/auth-basic", &HandleAuthBasic)); | |
| 562 server->RegisterDefaultHandler( | |
| 563 PREFIXED_HANDLER("/auth-digest", &HandleAuthDigest)); | |
| 564 server->RegisterDefaultHandler( | |
| 565 PREFIXED_HANDLER("/server-redirect", &HandleServerRedirect)); | |
| 566 server->RegisterDefaultHandler(base::Bind(&HandleCrossSiteRedirect, server)); | |
| 567 server->RegisterDefaultHandler( | |
| 568 PREFIXED_HANDLER("/client-redirect", &HandleClientRedirect)); | |
| 569 server->RegisterDefaultHandler( | |
| 570 PREFIXED_HANDLER("/defaultresponse", &HandleDefaultResponse)); | |
| 571 server->RegisterDefaultHandler(PREFIXED_HANDLER("/slow", &HandleSlowServer)); | |
| 572 | |
| 573 // TODO(svaldez): HandleDownload | |
| 574 // TODO(svaldez): HandleDownloadFinish | |
| 575 // TODO(svaldez): HandleZipFile | |
| 576 // TODO(svaldez): HandleRangeReset | |
| 577 // TODO(svaldez): HandleSSLManySmallRecords | |
| 578 // TODO(svaldez): HandleChunkedServer | |
| 579 // TODO(svaldez): HandleGetSSLSessionCache | |
| 580 // TODO(svaldez): HandleGetChannelID | |
| 581 // TODO(svaldez): HandleGetClientCert | |
| 582 // TODO(svaldez): HandleClientCipherList | |
| 583 // TODO(svaldez): HandleEchoMultipartPost | |
| 584 } | |
| 585 | |
| 586 #undef PREFIXED_HANDLER | |
| 587 | |
| 588 } // namespace test_server | |
| 589 } // namespace net | |
| OLD | NEW |