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 |