| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/test/webdriver/dispatch.h" | 5 #include "chrome/test/webdriver/dispatch.h" |
| 6 | 6 |
| 7 #include <sstream> | 7 #include <sstream> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/format_macros.h" | 11 #include "base/format_macros.h" |
| 12 #include "base/json/json_reader.h" | |
| 13 #include "base/logging.h" | 12 #include "base/logging.h" |
| 14 #include "base/memory/scoped_ptr.h" | |
| 15 #include "base/message_loop_proxy.h" | 13 #include "base/message_loop_proxy.h" |
| 16 #include "base/string_split.h" | 14 #include "base/string_split.h" |
| 17 #include "base/string_util.h" | 15 #include "base/string_util.h" |
| 18 #include "base/stringprintf.h" | 16 #include "base/stringprintf.h" |
| 19 #include "base/synchronization/waitable_event.h" | 17 #include "base/synchronization/waitable_event.h" |
| 20 #include "base/threading/thread.h" | 18 #include "base/threading/thread.h" |
| 21 #include "chrome/test/webdriver/http_response.h" | 19 #include "chrome/test/webdriver/http_response.h" |
| 22 #include "chrome/test/webdriver/commands/command.h" | 20 #include "chrome/test/webdriver/commands/command.h" |
| 23 #include "chrome/test/webdriver/session_manager.h" | 21 #include "chrome/test/webdriver/session_manager.h" |
| 24 #include "chrome/test/webdriver/utility_functions.h" | 22 #include "chrome/test/webdriver/utility_functions.h" |
| 25 #include "chrome/test/webdriver/webdriver_logging.h" | |
| 26 | 23 |
| 27 namespace webdriver { | 24 namespace webdriver { |
| 28 | 25 |
| 29 namespace { | 26 namespace { |
| 30 | 27 |
| 31 // Maximum safe size of HTTP response message. Any larger than this, | |
| 32 // the message may not be transferred at all. | |
| 33 const int kMaxHttpMessageSize = 1024 * 1024 * 16; // 16MB | |
| 34 | |
| 35 bool ForbidsMessageBody(const std::string& request_method, | 28 bool ForbidsMessageBody(const std::string& request_method, |
| 36 const HttpResponse& response) { | 29 const HttpResponse& response) { |
| 37 return request_method == "HEAD" || | 30 return request_method == "HEAD" || |
| 38 response.status() == HttpResponse::kNoContent || | 31 response.status() == HttpResponse::kNoContent || |
| 39 response.status() == HttpResponse::kNotModified || | 32 response.status() == HttpResponse::kNotModified || |
| 40 (response.status() >= 100 && response.status() < 200); | 33 (response.status() >= 100 && response.status() < 200); |
| 41 } | 34 } |
| 42 | 35 |
| 43 void DispatchCommand(Command* const command, | 36 void DispatchCommand(Command* const command, |
| 44 const std::string& method, | 37 const std::string& method, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 59 | 52 |
| 60 void Shutdown(struct mg_connection* connection, | 53 void Shutdown(struct mg_connection* connection, |
| 61 const struct mg_request_info* request_info, | 54 const struct mg_request_info* request_info, |
| 62 void* user_data) { | 55 void* user_data) { |
| 63 base::WaitableEvent* shutdown_event = | 56 base::WaitableEvent* shutdown_event = |
| 64 reinterpret_cast<base::WaitableEvent*>(user_data); | 57 reinterpret_cast<base::WaitableEvent*>(user_data); |
| 65 mg_printf(connection, "HTTP/1.1 200 OK\r\n\r\n"); | 58 mg_printf(connection, "HTTP/1.1 200 OK\r\n\r\n"); |
| 66 shutdown_event->Signal(); | 59 shutdown_event->Signal(); |
| 67 } | 60 } |
| 68 | 61 |
| 69 void SendOkWithBody(struct mg_connection* connection, | 62 void SendStatus(struct mg_connection* connection, |
| 70 const std::string& content) { | 63 const struct mg_request_info* request_info, |
| 71 const char* response_fmt = "HTTP/1.1 200 OK\r\n" | 64 void* user_data) { |
| 72 "Content-Length:%d\r\n\r\n" | 65 std::string response = "HTTP/1.1 200 OK\r\n" |
| 73 "%s"; | 66 "Content-Length:2\r\n\r\n" |
| 74 std::string response = base::StringPrintf( | 67 "ok"; |
| 75 response_fmt, content.length(), content.c_str()); | |
| 76 mg_write(connection, response.data(), response.length()); | 68 mg_write(connection, response.data(), response.length()); |
| 77 } | 69 } |
| 78 | 70 |
| 79 void SendHealthz(struct mg_connection* connection, | |
| 80 const struct mg_request_info* request_info, | |
| 81 void* user_data) { | |
| 82 SendOkWithBody(connection, "ok"); | |
| 83 } | |
| 84 | |
| 85 void SendLog(struct mg_connection* connection, | |
| 86 const struct mg_request_info* request_info, | |
| 87 void* user_data) { | |
| 88 std::string content, log; | |
| 89 if (GetLogContents(&log)) { | |
| 90 content = "START ChromeDriver log"; | |
| 91 const int kMaxSizeWithoutHeaders = kMaxHttpMessageSize - 10000; | |
| 92 if (log.size() > kMaxSizeWithoutHeaders) { | |
| 93 log = log.substr(log.size() - kMaxSizeWithoutHeaders); | |
| 94 content += " (only last several MB)"; | |
| 95 } | |
| 96 content += ":\n" + log + "END ChromeDriver log"; | |
| 97 } else { | |
| 98 content = "No ChromeDriver log found"; | |
| 99 } | |
| 100 SendOkWithBody(connection, content); | |
| 101 } | |
| 102 | |
| 103 void SendNoContentResponse(struct mg_connection* connection, | 71 void SendNoContentResponse(struct mg_connection* connection, |
| 104 const struct mg_request_info* request_info, | 72 const struct mg_request_info* request_info, |
| 105 void* user_data) { | 73 void* user_data) { |
| 106 std::string response = "HTTP/1.1 204 No Content\r\n" | 74 std::string response = "HTTP/1.1 204 No Content\r\n" |
| 107 "Content-Length:0\r\n" | 75 "Content-Length:0\r\n" |
| 108 "\r\n"; | 76 "\r\n"; |
| 109 mg_write(connection, response.data(), response.length()); | 77 mg_write(connection, response.data(), response.length()); |
| 110 } | 78 } |
| 111 | 79 |
| 112 void SendForbidden(struct mg_connection* connection, | 80 void SendForbidden(struct mg_connection* connection, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 124 "{\"status\":%d,\"value\":{\"message\":" | 92 "{\"status\":%d,\"value\":{\"message\":" |
| 125 "\"Command has not been implemented yet: %s %s\"}}", | 93 "\"Command has not been implemented yet: %s %s\"}}", |
| 126 kUnknownCommand, request_info->request_method, request_info->uri); | 94 kUnknownCommand, request_info->request_method, request_info->uri); |
| 127 | 95 |
| 128 std::string header = base::StringPrintf( | 96 std::string header = base::StringPrintf( |
| 129 "HTTP/1.1 501 Not Implemented\r\n" | 97 "HTTP/1.1 501 Not Implemented\r\n" |
| 130 "Content-Type:application/json\r\n" | 98 "Content-Type:application/json\r\n" |
| 131 "Content-Length:%" PRIuS "\r\n" | 99 "Content-Length:%" PRIuS "\r\n" |
| 132 "\r\n", body.length()); | 100 "\r\n", body.length()); |
| 133 | 101 |
| 102 LOG(ERROR) << header << body; |
| 134 mg_write(connection, header.data(), header.length()); | 103 mg_write(connection, header.data(), header.length()); |
| 135 mg_write(connection, body.data(), body.length()); | 104 mg_write(connection, body.data(), body.length()); |
| 136 } | 105 } |
| 137 | 106 |
| 138 } // namespace | 107 } // namespace |
| 139 | 108 |
| 140 namespace internal { | 109 namespace internal { |
| 141 | 110 |
| 142 void PrepareHttpResponse(const Response& command_response, | 111 void PrepareHttpResponse(const Response& command_response, |
| 143 HttpResponse* const http_response) { | 112 HttpResponse* const http_response) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 else if (*method == "PUT") | 218 else if (*method == "PUT") |
| 250 *method = "POST"; | 219 *method = "POST"; |
| 251 | 220 |
| 252 std::string uri(request_info->uri); | 221 std::string uri(request_info->uri); |
| 253 SessionManager* manager = SessionManager::GetInstance(); | 222 SessionManager* manager = SessionManager::GetInstance(); |
| 254 uri = uri.substr(manager->url_base().length()); | 223 uri = uri.substr(manager->url_base().length()); |
| 255 | 224 |
| 256 base::SplitString(uri, '/', path_segments); | 225 base::SplitString(uri, '/', path_segments); |
| 257 | 226 |
| 258 if (*method == "POST" && request_info->post_data_len > 0) { | 227 if (*method == "POST" && request_info->post_data_len > 0) { |
| 228 VLOG(1) << "...parsing request body"; |
| 259 std::string json(request_info->post_data, request_info->post_data_len); | 229 std::string json(request_info->post_data, request_info->post_data_len); |
| 260 std::string error_msg; | 230 std::string error; |
| 261 scoped_ptr<Value> params(base::JSONReader::ReadAndReturnError( | 231 if (!ParseJSONDictionary(json, parameters, &error)) { |
| 262 json, true, NULL, &error_msg)); | |
| 263 if (!params.get()) { | |
| 264 response->SetError(new Error( | 232 response->SetError(new Error( |
| 265 kBadRequest, | 233 kBadRequest, |
| 266 "Failed to parse command data: " + error_msg + "\n Data: " + json)); | 234 "Failed to parse command data: " + error + "\n Data: " + json)); |
| 267 return false; | 235 return false; |
| 268 } | 236 } |
| 269 if (!params->IsType(Value::TYPE_DICTIONARY)) { | |
| 270 response->SetError(new Error( | |
| 271 kBadRequest, | |
| 272 "Data passed in URL must be a dictionary. Data: " + json)); | |
| 273 return false; | |
| 274 } | |
| 275 *parameters = static_cast<DictionaryValue*>(params.release()); | |
| 276 } | 237 } |
| 238 VLOG(1) << "Parsed " << method << " " << uri |
| 239 << std::string(request_info->post_data, request_info->post_data_len); |
| 277 return true; | 240 return true; |
| 278 } | 241 } |
| 279 | 242 |
| 280 void DispatchHelper(Command* command_ptr, | 243 void DispatchHelper(Command* command_ptr, |
| 281 const std::string& method, | 244 const std::string& method, |
| 282 Response* response) { | 245 Response* response) { |
| 283 CHECK(method == "GET" || method == "POST" || method == "DELETE"); | 246 CHECK(method == "GET" || method == "POST" || method == "DELETE"); |
| 284 scoped_ptr<Command> command(command_ptr); | 247 scoped_ptr<Command> command(command_ptr); |
| 285 | 248 |
| 286 if ((method == "GET" && !command->DoesGet()) || | 249 if ((method == "GET" && !command->DoesGet()) || |
| (...skipping 26 matching lines...) Expand all Loading... |
| 313 } | 276 } |
| 314 | 277 |
| 315 Dispatcher::~Dispatcher() {} | 278 Dispatcher::~Dispatcher() {} |
| 316 | 279 |
| 317 void Dispatcher::AddShutdown(const std::string& pattern, | 280 void Dispatcher::AddShutdown(const std::string& pattern, |
| 318 base::WaitableEvent* shutdown_event) { | 281 base::WaitableEvent* shutdown_event) { |
| 319 mg_set_uri_callback(context_, (root_ + pattern).c_str(), &Shutdown, | 282 mg_set_uri_callback(context_, (root_ + pattern).c_str(), &Shutdown, |
| 320 shutdown_event); | 283 shutdown_event); |
| 321 } | 284 } |
| 322 | 285 |
| 323 void Dispatcher::AddHealthz(const std::string& pattern) { | 286 void Dispatcher::AddStatus(const std::string& pattern) { |
| 324 mg_set_uri_callback(context_, (root_ + pattern).c_str(), &SendHealthz, NULL); | 287 mg_set_uri_callback(context_, (root_ + pattern).c_str(), &SendStatus, NULL); |
| 325 } | |
| 326 | |
| 327 void Dispatcher::AddLog(const std::string& pattern) { | |
| 328 mg_set_uri_callback(context_, (root_ + pattern).c_str(), &SendLog, NULL); | |
| 329 } | 288 } |
| 330 | 289 |
| 331 void Dispatcher::SetNotImplemented(const std::string& pattern) { | 290 void Dispatcher::SetNotImplemented(const std::string& pattern) { |
| 332 mg_set_uri_callback(context_, (root_ + pattern).c_str(), | 291 mg_set_uri_callback(context_, (root_ + pattern).c_str(), |
| 333 &SendNotImplementedError, NULL); | 292 &SendNotImplementedError, NULL); |
| 334 } | 293 } |
| 335 | 294 |
| 336 void Dispatcher::ForbidAllOtherRequests() { | 295 void Dispatcher::ForbidAllOtherRequests() { |
| 337 mg_set_uri_callback(context_, "*", &SendForbidden, NULL); | 296 mg_set_uri_callback(context_, "*", &SendForbidden, NULL); |
| 338 } | 297 } |
| 339 | 298 |
| 340 } // namespace webdriver | 299 } // namespace webdriver |
| OLD | NEW |