Roll src/third_party/WebKit bf18a82:a9cee16 (svn 185297:185304)
[chromium-blink-merge.git] / chrome / test / chromedriver / server / http_handler.cc
blobe7150557baf853380ab56f3aec8bf12eaaddd0fd
1 // Copyright (c) 2013 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.
5 #include "chrome/test/chromedriver/server/http_handler.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/json/json_reader.h"
10 #include "base/json/json_writer.h"
11 #include "base/logging.h" // For CHECK macros.
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/message_loop/message_loop_proxy.h"
15 #include "base/strings/string_split.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/sys_info.h"
19 #include "base/values.h"
20 #include "chrome/test/chromedriver/alert_commands.h"
21 #include "chrome/test/chromedriver/chrome/adb_impl.h"
22 #include "chrome/test/chromedriver/chrome/device_manager.h"
23 #include "chrome/test/chromedriver/chrome/status.h"
24 #include "chrome/test/chromedriver/net/port_server.h"
25 #include "chrome/test/chromedriver/net/url_request_context_getter.h"
26 #include "chrome/test/chromedriver/session.h"
27 #include "chrome/test/chromedriver/session_thread_map.h"
28 #include "chrome/test/chromedriver/util.h"
29 #include "chrome/test/chromedriver/version.h"
30 #include "net/server/http_server_request_info.h"
31 #include "net/server/http_server_response_info.h"
33 #if defined(OS_MACOSX)
34 #include "base/mac/scoped_nsautorelease_pool.h"
35 #endif
37 namespace {
39 const char kLocalStorage[] = "localStorage";
40 const char kSessionStorage[] = "sessionStorage";
41 const char kShutdownPath[] = "shutdown";
43 void UnimplementedCommand(
44 const base::DictionaryValue& params,
45 const std::string& session_id,
46 const CommandCallback& callback) {
47 callback.Run(Status(kUnknownCommand), scoped_ptr<base::Value>(), session_id);
50 } // namespace
52 CommandMapping::CommandMapping(HttpMethod method,
53 const std::string& path_pattern,
54 const Command& command)
55 : method(method), path_pattern(path_pattern), command(command) {}
57 CommandMapping::~CommandMapping() {}
59 HttpHandler::HttpHandler(const std::string& url_base)
60 : url_base_(url_base),
61 received_shutdown_(false),
62 command_map_(new CommandMap()),
63 weak_ptr_factory_(this) {}
65 HttpHandler::HttpHandler(
66 const base::Closure& quit_func,
67 const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
68 const std::string& url_base,
69 int adb_port,
70 scoped_ptr<PortServer> port_server)
71 : quit_func_(quit_func),
72 url_base_(url_base),
73 received_shutdown_(false),
74 weak_ptr_factory_(this) {
75 #if defined(OS_MACOSX)
76 base::mac::ScopedNSAutoreleasePool autorelease_pool;
77 #endif
78 context_getter_ = new URLRequestContextGetter(io_task_runner);
79 socket_factory_ = CreateSyncWebSocketFactory(context_getter_.get());
80 adb_.reset(new AdbImpl(io_task_runner, adb_port));
81 device_manager_.reset(new DeviceManager(adb_.get()));
82 port_server_ = port_server.Pass();
83 port_manager_.reset(new PortManager(12000, 13000));
85 CommandMapping commands[] = {
86 CommandMapping(
87 kPost,
88 internal::kNewSessionPathPattern,
89 base::Bind(&ExecuteCreateSession,
90 &session_thread_map_,
91 WrapToCommand(
92 "InitSession",
93 base::Bind(&ExecuteInitSession,
94 InitSessionParams(context_getter_,
95 socket_factory_,
96 device_manager_.get(),
97 port_server_.get(),
98 port_manager_.get()))))),
99 CommandMapping(kGet,
100 "session/:sessionId",
101 WrapToCommand("GetSessionCapabilities",
102 base::Bind(&ExecuteGetSessionCapabilities))),
103 CommandMapping(kDelete,
104 "session/:sessionId",
105 base::Bind(&ExecuteSessionCommand,
106 &session_thread_map_,
107 "Quit",
108 base::Bind(&ExecuteQuit, false),
109 true)),
110 CommandMapping(kGet,
111 "session/:sessionId/window_handle",
112 WrapToCommand("GetWindow",
113 base::Bind(&ExecuteGetCurrentWindowHandle))),
114 CommandMapping(
115 kGet,
116 "session/:sessionId/window_handles",
117 WrapToCommand("GetWindows", base::Bind(&ExecuteGetWindowHandles))),
118 CommandMapping(kPost,
119 "session/:sessionId/url",
120 WrapToCommand("Navigate", base::Bind(&ExecuteGet))),
121 CommandMapping(kPost,
122 "session/:sessionId/chromium/launch_app",
123 WrapToCommand("LaunchApp", base::Bind(&ExecuteLaunchApp))),
124 CommandMapping(kGet,
125 "session/:sessionId/alert",
126 WrapToCommand("IsAlertOpen",
127 base::Bind(&ExecuteAlertCommand,
128 base::Bind(&ExecuteGetAlert)))),
129 CommandMapping(
130 kPost,
131 "session/:sessionId/dismiss_alert",
132 WrapToCommand("DismissAlert",
133 base::Bind(&ExecuteAlertCommand,
134 base::Bind(&ExecuteDismissAlert)))),
135 CommandMapping(
136 kPost,
137 "session/:sessionId/accept_alert",
138 WrapToCommand("AcceptAlert",
139 base::Bind(&ExecuteAlertCommand,
140 base::Bind(&ExecuteAcceptAlert)))),
141 CommandMapping(
142 kGet,
143 "session/:sessionId/alert_text",
144 WrapToCommand("GetAlertMessage",
145 base::Bind(&ExecuteAlertCommand,
146 base::Bind(&ExecuteGetAlertText)))),
147 CommandMapping(
148 kPost,
149 "session/:sessionId/alert_text",
150 WrapToCommand("SetAlertPrompt",
151 base::Bind(&ExecuteAlertCommand,
152 base::Bind(&ExecuteSetAlertValue)))),
153 CommandMapping(kPost,
154 "session/:sessionId/forward",
155 WrapToCommand("GoForward", base::Bind(&ExecuteGoForward))),
156 CommandMapping(kPost,
157 "session/:sessionId/back",
158 WrapToCommand("GoBack", base::Bind(&ExecuteGoBack))),
159 CommandMapping(kPost,
160 "session/:sessionId/refresh",
161 WrapToCommand("Refresh", base::Bind(&ExecuteRefresh))),
162 CommandMapping(
163 kPost,
164 "session/:sessionId/execute",
165 WrapToCommand("ExecuteScript", base::Bind(&ExecuteExecuteScript))),
166 CommandMapping(kPost,
167 "session/:sessionId/execute_async",
168 WrapToCommand("ExecuteAsyncScript",
169 base::Bind(&ExecuteExecuteAsyncScript))),
170 CommandMapping(
171 kGet,
172 "session/:sessionId/url",
173 WrapToCommand("GetUrl", base::Bind(&ExecuteGetCurrentUrl))),
174 CommandMapping(kGet,
175 "session/:sessionId/title",
176 WrapToCommand("GetTitle", base::Bind(&ExecuteGetTitle))),
177 CommandMapping(
178 kGet,
179 "session/:sessionId/source",
180 WrapToCommand("GetSource", base::Bind(&ExecuteGetPageSource))),
181 CommandMapping(
182 kGet,
183 "session/:sessionId/screenshot",
184 WrapToCommand("Screenshot", base::Bind(&ExecuteScreenshot))),
185 CommandMapping(
186 kGet,
187 "session/:sessionId/chromium/heap_snapshot",
188 WrapToCommand("HeapSnapshot", base::Bind(&ExecuteTakeHeapSnapshot))),
189 CommandMapping(kPost,
190 "session/:sessionId/visible",
191 base::Bind(&UnimplementedCommand)),
192 CommandMapping(kGet,
193 "session/:sessionId/visible",
194 base::Bind(&UnimplementedCommand)),
195 CommandMapping(
196 kPost,
197 "session/:sessionId/element",
198 WrapToCommand("FindElement", base::Bind(&ExecuteFindElement, 50))),
199 CommandMapping(
200 kPost,
201 "session/:sessionId/elements",
202 WrapToCommand("FindElements", base::Bind(&ExecuteFindElements, 50))),
203 CommandMapping(kPost,
204 "session/:sessionId/element/active",
205 WrapToCommand("GetActiveElement",
206 base::Bind(&ExecuteGetActiveElement))),
207 CommandMapping(kPost,
208 "session/:sessionId/element/:id/element",
209 WrapToCommand("FindChildElement",
210 base::Bind(&ExecuteFindChildElement, 50))),
211 CommandMapping(kPost,
212 "session/:sessionId/element/:id/elements",
213 WrapToCommand("FindChildElements",
214 base::Bind(&ExecuteFindChildElements, 50))),
215 CommandMapping(
216 kPost,
217 "session/:sessionId/element/:id/click",
218 WrapToCommand("ClickElement", base::Bind(&ExecuteClickElement))),
219 CommandMapping(
220 kPost,
221 "session/:sessionId/element/:id/clear",
222 WrapToCommand("ClearElement", base::Bind(&ExecuteClearElement))),
223 CommandMapping(
224 kPost,
225 "session/:sessionId/element/:id/submit",
226 WrapToCommand("SubmitElement", base::Bind(&ExecuteSubmitElement))),
227 CommandMapping(
228 kGet,
229 "session/:sessionId/element/:id/text",
230 WrapToCommand("GetElementText", base::Bind(&ExecuteGetElementText))),
231 CommandMapping(
232 kPost,
233 "session/:sessionId/element/:id/value",
234 WrapToCommand("TypeElement", base::Bind(&ExecuteSendKeysToElement))),
235 CommandMapping(
236 kPost,
237 "session/:sessionId/file",
238 WrapToCommand("UploadFile", base::Bind(&ExecuteUploadFile))),
239 CommandMapping(kGet,
240 "session/:sessionId/element/:id/value",
241 WrapToCommand("GetElementValue",
242 base::Bind(&ExecuteGetElementValue))),
243 CommandMapping(kGet,
244 "session/:sessionId/element/:id/name",
245 WrapToCommand("GetElementTagName",
246 base::Bind(&ExecuteGetElementTagName))),
247 CommandMapping(kGet,
248 "session/:sessionId/element/:id/selected",
249 WrapToCommand("IsElementSelected",
250 base::Bind(&ExecuteIsElementSelected))),
251 CommandMapping(kGet,
252 "session/:sessionId/element/:id/enabled",
253 WrapToCommand("IsElementEnabled",
254 base::Bind(&ExecuteIsElementEnabled))),
255 CommandMapping(kGet,
256 "session/:sessionId/element/:id/displayed",
257 WrapToCommand("IsElementDisplayed",
258 base::Bind(&ExecuteIsElementDisplayed))),
259 CommandMapping(
260 kPost,
261 "session/:sessionId/element/:id/hover",
262 WrapToCommand("HoverElement", base::Bind(&ExecuteHoverOverElement))),
263 CommandMapping(kGet,
264 "session/:sessionId/element/:id/location",
265 WrapToCommand("GetElementLocation",
266 base::Bind(&ExecuteGetElementLocation))),
267 CommandMapping(
268 kGet,
269 "session/:sessionId/element/:id/location_in_view",
270 WrapToCommand(
271 "GetElementLocationInView",
272 base::Bind(&ExecuteGetElementLocationOnceScrolledIntoView))),
273 CommandMapping(
274 kGet,
275 "session/:sessionId/element/:id/size",
276 WrapToCommand("GetElementSize", base::Bind(&ExecuteGetElementSize))),
277 CommandMapping(kGet,
278 "session/:sessionId/element/:id/attribute/:name",
279 WrapToCommand("GetElementAttribute",
280 base::Bind(&ExecuteGetElementAttribute))),
281 CommandMapping(
282 kGet,
283 "session/:sessionId/element/:id/equals/:other",
284 WrapToCommand("IsElementEqual", base::Bind(&ExecuteElementEquals))),
285 CommandMapping(
286 kGet,
287 "session/:sessionId/cookie",
288 WrapToCommand("GetCookies", base::Bind(&ExecuteGetCookies))),
289 CommandMapping(kPost,
290 "session/:sessionId/cookie",
291 WrapToCommand("AddCookie", base::Bind(&ExecuteAddCookie))),
292 CommandMapping(kDelete,
293 "session/:sessionId/cookie",
294 WrapToCommand("DeleteAllCookies",
295 base::Bind(&ExecuteDeleteAllCookies))),
296 CommandMapping(
297 kDelete,
298 "session/:sessionId/cookie/:name",
299 WrapToCommand("DeleteCookie", base::Bind(&ExecuteDeleteCookie))),
300 CommandMapping(
301 kPost,
302 "session/:sessionId/frame",
303 WrapToCommand("SwitchToFrame", base::Bind(&ExecuteSwitchToFrame))),
304 CommandMapping(
305 kPost,
306 "session/:sessionId/frame/parent",
307 WrapToCommand("SwitchToParentFrame",
308 base::Bind(&ExecuteSwitchToParentFrame))),
309 CommandMapping(
310 kPost,
311 "session/:sessionId/window",
312 WrapToCommand("SwitchToWindow", base::Bind(&ExecuteSwitchToWindow))),
313 CommandMapping(
314 kGet,
315 "session/:sessionId/window/:windowHandle/size",
316 WrapToCommand("GetWindowSize", base::Bind(&ExecuteGetWindowSize))),
317 CommandMapping(kGet,
318 "session/:sessionId/window/:windowHandle/position",
319 WrapToCommand("GetWindowPosition",
320 base::Bind(&ExecuteGetWindowPosition))),
321 CommandMapping(
322 kPost,
323 "session/:sessionId/window/:windowHandle/size",
324 WrapToCommand("SetWindowSize", base::Bind(&ExecuteSetWindowSize))),
325 CommandMapping(kPost,
326 "session/:sessionId/window/:windowHandle/position",
327 WrapToCommand("SetWindowPosition",
328 base::Bind(&ExecuteSetWindowPosition))),
329 CommandMapping(
330 kPost,
331 "session/:sessionId/window/:windowHandle/maximize",
332 WrapToCommand("MaximizeWindow", base::Bind(&ExecuteMaximizeWindow))),
333 CommandMapping(kDelete,
334 "session/:sessionId/window",
335 WrapToCommand("CloseWindow", base::Bind(&ExecuteClose))),
336 CommandMapping(kPost,
337 "session/:sessionId/element/:id/drag",
338 base::Bind(&UnimplementedCommand)),
339 CommandMapping(
340 kGet,
341 "session/:sessionId/element/:id/css/:propertyName",
342 WrapToCommand("GetElementCSSProperty",
343 base::Bind(&ExecuteGetElementValueOfCSSProperty))),
344 CommandMapping(
345 kPost,
346 "session/:sessionId/timeouts/implicit_wait",
347 WrapToCommand("SetImplicitWait", base::Bind(&ExecuteImplicitlyWait))),
348 CommandMapping(kPost,
349 "session/:sessionId/timeouts/async_script",
350 WrapToCommand("SetScriptTimeout",
351 base::Bind(&ExecuteSetScriptTimeout))),
352 CommandMapping(
353 kPost,
354 "session/:sessionId/timeouts",
355 WrapToCommand("SetTimeout", base::Bind(&ExecuteSetTimeout))),
356 CommandMapping(kPost,
357 "session/:sessionId/execute_sql",
358 base::Bind(&UnimplementedCommand)),
359 CommandMapping(
360 kGet,
361 "session/:sessionId/location",
362 WrapToCommand("GetGeolocation", base::Bind(&ExecuteGetLocation))),
363 CommandMapping(
364 kPost,
365 "session/:sessionId/location",
366 WrapToCommand("SetGeolocation", base::Bind(&ExecuteSetLocation))),
367 CommandMapping(kGet,
368 "session/:sessionId/application_cache/status",
369 base::Bind(&ExecuteGetStatus)),
370 CommandMapping(kGet,
371 "session/:sessionId/browser_connection",
372 base::Bind(&UnimplementedCommand)),
373 CommandMapping(kPost,
374 "session/:sessionId/browser_connection",
375 base::Bind(&UnimplementedCommand)),
376 CommandMapping(
377 kGet,
378 "session/:sessionId/local_storage/key/:key",
379 WrapToCommand("GetLocalStorageItem",
380 base::Bind(&ExecuteGetStorageItem, kLocalStorage))),
381 CommandMapping(
382 kDelete,
383 "session/:sessionId/local_storage/key/:key",
384 WrapToCommand("RemoveLocalStorageItem",
385 base::Bind(&ExecuteRemoveStorageItem, kLocalStorage))),
386 CommandMapping(
387 kGet,
388 "session/:sessionId/local_storage",
389 WrapToCommand("GetLocalStorageKeys",
390 base::Bind(&ExecuteGetStorageKeys, kLocalStorage))),
391 CommandMapping(
392 kPost,
393 "session/:sessionId/local_storage",
394 WrapToCommand("SetLocalStorageKeys",
395 base::Bind(&ExecuteSetStorageItem, kLocalStorage))),
396 CommandMapping(
397 kDelete,
398 "session/:sessionId/local_storage",
399 WrapToCommand("ClearLocalStorage",
400 base::Bind(&ExecuteClearStorage, kLocalStorage))),
401 CommandMapping(
402 kGet,
403 "session/:sessionId/local_storage/size",
404 WrapToCommand("GetLocalStorageSize",
405 base::Bind(&ExecuteGetStorageSize, kLocalStorage))),
406 CommandMapping(
407 kGet,
408 "session/:sessionId/session_storage/key/:key",
409 WrapToCommand("GetSessionStorageItem",
410 base::Bind(&ExecuteGetStorageItem, kSessionStorage))),
411 CommandMapping(kDelete,
412 "session/:sessionId/session_storage/key/:key",
413 WrapToCommand("RemoveSessionStorageItem",
414 base::Bind(&ExecuteRemoveStorageItem,
415 kSessionStorage))),
416 CommandMapping(
417 kGet,
418 "session/:sessionId/session_storage",
419 WrapToCommand("GetSessionStorageKeys",
420 base::Bind(&ExecuteGetStorageKeys, kSessionStorage))),
421 CommandMapping(
422 kPost,
423 "session/:sessionId/session_storage",
424 WrapToCommand("SetSessionStorageItem",
425 base::Bind(&ExecuteSetStorageItem, kSessionStorage))),
426 CommandMapping(
427 kDelete,
428 "session/:sessionId/session_storage",
429 WrapToCommand("ClearSessionStorage",
430 base::Bind(&ExecuteClearStorage, kSessionStorage))),
431 CommandMapping(
432 kGet,
433 "session/:sessionId/session_storage/size",
434 WrapToCommand("GetSessionStorageSize",
435 base::Bind(&ExecuteGetStorageSize, kSessionStorage))),
436 CommandMapping(kGet,
437 "session/:sessionId/orientation",
438 base::Bind(&UnimplementedCommand)),
439 CommandMapping(kPost,
440 "session/:sessionId/orientation",
441 base::Bind(&UnimplementedCommand)),
442 CommandMapping(kPost,
443 "session/:sessionId/click",
444 WrapToCommand("Click", base::Bind(&ExecuteMouseClick))),
445 CommandMapping(
446 kPost,
447 "session/:sessionId/doubleclick",
448 WrapToCommand("DoubleClick", base::Bind(&ExecuteMouseDoubleClick))),
449 CommandMapping(
450 kPost,
451 "session/:sessionId/buttondown",
452 WrapToCommand("MouseDown", base::Bind(&ExecuteMouseButtonDown))),
453 CommandMapping(
454 kPost,
455 "session/:sessionId/buttonup",
456 WrapToCommand("MouseUp", base::Bind(&ExecuteMouseButtonUp))),
457 CommandMapping(
458 kPost,
459 "session/:sessionId/moveto",
460 WrapToCommand("MouseMove", base::Bind(&ExecuteMouseMoveTo))),
461 CommandMapping(
462 kPost,
463 "session/:sessionId/keys",
464 WrapToCommand("Type", base::Bind(&ExecuteSendKeysToActiveElement))),
465 CommandMapping(kGet,
466 "session/:sessionId/ime/available_engines",
467 base::Bind(&UnimplementedCommand)),
468 CommandMapping(kGet,
469 "session/:sessionId/ime/active_engine",
470 base::Bind(&UnimplementedCommand)),
471 CommandMapping(kGet,
472 "session/:sessionId/ime/activated",
473 base::Bind(&UnimplementedCommand)),
474 CommandMapping(kPost,
475 "session/:sessionId/ime/deactivate",
476 base::Bind(&UnimplementedCommand)),
477 CommandMapping(kPost,
478 "session/:sessionId/ime/activate",
479 base::Bind(&UnimplementedCommand)),
480 CommandMapping(kPost,
481 "session/:sessionId/touch/click",
482 WrapToCommand("Tap", base::Bind(&ExecuteTouchSingleTap))),
483 CommandMapping(kPost,
484 "session/:sessionId/touch/down",
485 WrapToCommand("TouchDown", base::Bind(&ExecuteTouchDown))),
486 CommandMapping(kPost,
487 "session/:sessionId/touch/up",
488 WrapToCommand("TouchUp", base::Bind(&ExecuteTouchUp))),
489 CommandMapping(kPost,
490 "session/:sessionId/touch/move",
491 WrapToCommand("TouchMove", base::Bind(&ExecuteTouchMove))),
492 CommandMapping(kPost,
493 "session/:sessionId/touch/scroll",
494 base::Bind(&UnimplementedCommand)),
495 CommandMapping(kPost,
496 "session/:sessionId/touch/doubleclick",
497 base::Bind(&UnimplementedCommand)),
498 CommandMapping(kPost,
499 "session/:sessionId/touch/longclick",
500 base::Bind(&UnimplementedCommand)),
501 CommandMapping(kPost,
502 "session/:sessionId/touch/flick",
503 WrapToCommand("TouchFlick", base::Bind(&ExecuteFlick))),
504 CommandMapping(kPost,
505 "session/:sessionId/log",
506 WrapToCommand("GetLog", base::Bind(&ExecuteGetLog))),
507 CommandMapping(kGet,
508 "session/:sessionId/log/types",
509 WrapToCommand("GetLogTypes",
510 base::Bind(&ExecuteGetAvailableLogTypes))),
511 CommandMapping(kPost, "logs", base::Bind(&UnimplementedCommand)),
512 CommandMapping(kGet, "status", base::Bind(&ExecuteGetStatus)),
514 // Custom Chrome commands:
515 // Allow quit all to be called with GET or POST.
516 CommandMapping(
517 kGet,
518 kShutdownPath,
519 base::Bind(&ExecuteQuitAll,
520 WrapToCommand("QuitAll", base::Bind(&ExecuteQuit, true)),
521 &session_thread_map_)),
522 CommandMapping(
523 kPost,
524 kShutdownPath,
525 base::Bind(&ExecuteQuitAll,
526 WrapToCommand("QuitAll", base::Bind(&ExecuteQuit, true)),
527 &session_thread_map_)),
528 CommandMapping(kGet,
529 "session/:sessionId/is_loading",
530 WrapToCommand("IsLoading", base::Bind(&ExecuteIsLoading))),
531 CommandMapping(kGet,
532 "session/:sessionId/autoreport",
533 WrapToCommand("IsAutoReporting",
534 base::Bind(&ExecuteIsAutoReporting))),
535 CommandMapping(kPost,
536 "session/:sessionId/autoreport",
537 WrapToCommand(
538 "SetAutoReporting",
539 base::Bind(&ExecuteSetAutoReporting))),
541 command_map_.reset(
542 new CommandMap(commands, commands + arraysize(commands)));
545 HttpHandler::~HttpHandler() {}
547 void HttpHandler::Handle(const net::HttpServerRequestInfo& request,
548 const HttpResponseSenderFunc& send_response_func) {
549 CHECK(thread_checker_.CalledOnValidThread());
551 if (received_shutdown_)
552 return;
554 std::string path = request.path;
555 if (!StartsWithASCII(path, url_base_, true)) {
556 scoped_ptr<net::HttpServerResponseInfo> response(
557 new net::HttpServerResponseInfo(net::HTTP_BAD_REQUEST));
558 response->SetBody("unhandled request", "text/plain");
559 send_response_func.Run(response.Pass());
560 return;
563 path.erase(0, url_base_.length());
565 HandleCommand(request, path, send_response_func);
567 if (path == kShutdownPath)
568 received_shutdown_ = true;
571 Command HttpHandler::WrapToCommand(
572 const char* name,
573 const SessionCommand& session_command) {
574 return base::Bind(&ExecuteSessionCommand,
575 &session_thread_map_,
576 name,
577 session_command,
578 false);
581 Command HttpHandler::WrapToCommand(
582 const char* name,
583 const WindowCommand& window_command) {
584 return WrapToCommand(name, base::Bind(&ExecuteWindowCommand, window_command));
587 Command HttpHandler::WrapToCommand(
588 const char* name,
589 const ElementCommand& element_command) {
590 return WrapToCommand(name,
591 base::Bind(&ExecuteElementCommand, element_command));
594 void HttpHandler::HandleCommand(
595 const net::HttpServerRequestInfo& request,
596 const std::string& trimmed_path,
597 const HttpResponseSenderFunc& send_response_func) {
598 base::DictionaryValue params;
599 std::string session_id;
600 CommandMap::const_iterator iter = command_map_->begin();
601 while (true) {
602 if (iter == command_map_->end()) {
603 scoped_ptr<net::HttpServerResponseInfo> response(
604 new net::HttpServerResponseInfo(net::HTTP_NOT_FOUND));
605 response->SetBody("unknown command: " + trimmed_path, "text/plain");
606 send_response_func.Run(response.Pass());
607 return;
609 if (internal::MatchesCommand(
610 request.method, trimmed_path, *iter, &session_id, &params)) {
611 break;
613 ++iter;
616 if (request.data.length()) {
617 base::DictionaryValue* body_params;
618 scoped_ptr<base::Value> parsed_body(base::JSONReader::Read(request.data));
619 if (!parsed_body || !parsed_body->GetAsDictionary(&body_params)) {
620 scoped_ptr<net::HttpServerResponseInfo> response(
621 new net::HttpServerResponseInfo(net::HTTP_BAD_REQUEST));
622 response->SetBody("missing command parameters", "text/plain");
623 send_response_func.Run(response.Pass());
624 return;
626 params.MergeDictionary(body_params);
629 iter->command.Run(params,
630 session_id,
631 base::Bind(&HttpHandler::PrepareResponse,
632 weak_ptr_factory_.GetWeakPtr(),
633 trimmed_path,
634 send_response_func));
637 void HttpHandler::PrepareResponse(
638 const std::string& trimmed_path,
639 const HttpResponseSenderFunc& send_response_func,
640 const Status& status,
641 scoped_ptr<base::Value> value,
642 const std::string& session_id) {
643 CHECK(thread_checker_.CalledOnValidThread());
644 scoped_ptr<net::HttpServerResponseInfo> response =
645 PrepareResponseHelper(trimmed_path, status, value.Pass(), session_id);
646 send_response_func.Run(response.Pass());
647 if (trimmed_path == kShutdownPath)
648 quit_func_.Run();
651 scoped_ptr<net::HttpServerResponseInfo> HttpHandler::PrepareResponseHelper(
652 const std::string& trimmed_path,
653 const Status& status,
654 scoped_ptr<base::Value> value,
655 const std::string& session_id) {
656 if (status.code() == kUnknownCommand) {
657 scoped_ptr<net::HttpServerResponseInfo> response(
658 new net::HttpServerResponseInfo(net::HTTP_NOT_IMPLEMENTED));
659 response->SetBody("unimplemented command: " + trimmed_path, "text/plain");
660 return response.Pass();
663 if (status.IsError()) {
664 Status full_status(status);
665 full_status.AddDetails(base::StringPrintf(
666 "Driver info: chromedriver=%s,platform=%s %s %s",
667 kChromeDriverVersion,
668 base::SysInfo::OperatingSystemName().c_str(),
669 base::SysInfo::OperatingSystemVersion().c_str(),
670 base::SysInfo::OperatingSystemArchitecture().c_str()));
671 scoped_ptr<base::DictionaryValue> error(new base::DictionaryValue());
672 error->SetString("message", full_status.message());
673 value.reset(error.release());
675 if (!value)
676 value.reset(base::Value::CreateNullValue());
678 base::DictionaryValue body_params;
679 body_params.SetInteger("status", status.code());
680 body_params.Set("value", value.release());
681 body_params.SetString("sessionId", session_id);
682 std::string body;
683 base::JSONWriter::WriteWithOptions(
684 &body_params, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
685 &body);
686 scoped_ptr<net::HttpServerResponseInfo> response(
687 new net::HttpServerResponseInfo(net::HTTP_OK));
688 response->SetBody(body, "application/json; charset=utf-8");
689 return response.Pass();
692 namespace internal {
694 const char kNewSessionPathPattern[] = "session";
696 bool MatchesMethod(HttpMethod command_method, const std::string& method) {
697 std::string lower_method = base::StringToLowerASCII(method);
698 switch (command_method) {
699 case kGet:
700 return lower_method == "get";
701 case kPost:
702 return lower_method == "post" || lower_method == "put";
703 case kDelete:
704 return lower_method == "delete";
706 return false;
709 bool MatchesCommand(const std::string& method,
710 const std::string& path,
711 const CommandMapping& command,
712 std::string* session_id,
713 base::DictionaryValue* out_params) {
714 if (!MatchesMethod(command.method, method))
715 return false;
717 std::vector<std::string> path_parts;
718 base::SplitString(path, '/', &path_parts);
719 std::vector<std::string> command_path_parts;
720 base::SplitString(command.path_pattern, '/', &command_path_parts);
721 if (path_parts.size() != command_path_parts.size())
722 return false;
724 base::DictionaryValue params;
725 for (size_t i = 0; i < path_parts.size(); ++i) {
726 CHECK(command_path_parts[i].length());
727 if (command_path_parts[i][0] == ':') {
728 std::string name = command_path_parts[i];
729 name.erase(0, 1);
730 CHECK(name.length());
731 if (name == "sessionId")
732 *session_id = path_parts[i];
733 else
734 params.SetString(name, path_parts[i]);
735 } else if (command_path_parts[i] != path_parts[i]) {
736 return false;
739 out_params->MergeDictionary(&params);
740 return true;
743 } // namespace internal