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