Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chrome / test / chromedriver / server / http_handler.cc
blobc3941b0ee2597336fc233516091c1cda6c5b9026
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/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/sys_info.h"
18 #include "base/thread_task_runner_handle.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 "sessions",
101 base::Bind(&ExecuteGetSessions,
102 WrapToCommand("GetSessions",
103 base::Bind(&ExecuteGetSessionCapabilities)),
104 &session_thread_map_)),
105 CommandMapping(kGet,
106 "session/:sessionId",
107 WrapToCommand("GetSessionCapabilities",
108 base::Bind(&ExecuteGetSessionCapabilities))),
109 CommandMapping(kDelete,
110 "session/:sessionId",
111 base::Bind(&ExecuteSessionCommand,
112 &session_thread_map_,
113 "Quit",
114 base::Bind(&ExecuteQuit, false),
115 true)),
116 CommandMapping(kGet,
117 "session/:sessionId/window_handle",
118 WrapToCommand("GetWindow",
119 base::Bind(&ExecuteGetCurrentWindowHandle))),
120 CommandMapping(
121 kGet,
122 "session/:sessionId/window_handles",
123 WrapToCommand("GetWindows", base::Bind(&ExecuteGetWindowHandles))),
124 CommandMapping(kPost,
125 "session/:sessionId/url",
126 WrapToCommand("Navigate", base::Bind(&ExecuteGet))),
127 CommandMapping(kPost,
128 "session/:sessionId/chromium/launch_app",
129 WrapToCommand("LaunchApp", base::Bind(&ExecuteLaunchApp))),
130 CommandMapping(kGet,
131 "session/:sessionId/alert",
132 WrapToCommand("IsAlertOpen",
133 base::Bind(&ExecuteAlertCommand,
134 base::Bind(&ExecuteGetAlert)))),
135 CommandMapping(
136 kPost,
137 "session/:sessionId/dismiss_alert",
138 WrapToCommand("DismissAlert",
139 base::Bind(&ExecuteAlertCommand,
140 base::Bind(&ExecuteDismissAlert)))),
141 CommandMapping(
142 kPost,
143 "session/:sessionId/accept_alert",
144 WrapToCommand("AcceptAlert",
145 base::Bind(&ExecuteAlertCommand,
146 base::Bind(&ExecuteAcceptAlert)))),
147 CommandMapping(
148 kGet,
149 "session/:sessionId/alert_text",
150 WrapToCommand("GetAlertMessage",
151 base::Bind(&ExecuteAlertCommand,
152 base::Bind(&ExecuteGetAlertText)))),
153 CommandMapping(
154 kPost,
155 "session/:sessionId/alert_text",
156 WrapToCommand("SetAlertPrompt",
157 base::Bind(&ExecuteAlertCommand,
158 base::Bind(&ExecuteSetAlertValue)))),
159 CommandMapping(kPost,
160 "session/:sessionId/forward",
161 WrapToCommand("GoForward", base::Bind(&ExecuteGoForward))),
162 CommandMapping(kPost,
163 "session/:sessionId/back",
164 WrapToCommand("GoBack", base::Bind(&ExecuteGoBack))),
165 CommandMapping(kPost,
166 "session/:sessionId/refresh",
167 WrapToCommand("Refresh", base::Bind(&ExecuteRefresh))),
168 CommandMapping(
169 kPost,
170 "session/:sessionId/execute",
171 WrapToCommand("ExecuteScript", base::Bind(&ExecuteExecuteScript))),
172 CommandMapping(kPost,
173 "session/:sessionId/execute_async",
174 WrapToCommand("ExecuteAsyncScript",
175 base::Bind(&ExecuteExecuteAsyncScript))),
176 CommandMapping(
177 kGet,
178 "session/:sessionId/url",
179 WrapToCommand("GetUrl", base::Bind(&ExecuteGetCurrentUrl))),
180 CommandMapping(kGet,
181 "session/:sessionId/title",
182 WrapToCommand("GetTitle", base::Bind(&ExecuteGetTitle))),
183 CommandMapping(
184 kGet,
185 "session/:sessionId/source",
186 WrapToCommand("GetSource", base::Bind(&ExecuteGetPageSource))),
187 CommandMapping(
188 kGet,
189 "session/:sessionId/screenshot",
190 WrapToCommand("Screenshot", base::Bind(&ExecuteScreenshot))),
191 CommandMapping(
192 kGet,
193 "session/:sessionId/chromium/heap_snapshot",
194 WrapToCommand("HeapSnapshot", base::Bind(&ExecuteTakeHeapSnapshot))),
195 CommandMapping(kPost,
196 "session/:sessionId/visible",
197 base::Bind(&UnimplementedCommand)),
198 CommandMapping(kGet,
199 "session/:sessionId/visible",
200 base::Bind(&UnimplementedCommand)),
201 CommandMapping(
202 kPost,
203 "session/:sessionId/element",
204 WrapToCommand("FindElement", base::Bind(&ExecuteFindElement, 50))),
205 CommandMapping(
206 kPost,
207 "session/:sessionId/elements",
208 WrapToCommand("FindElements", base::Bind(&ExecuteFindElements, 50))),
209 CommandMapping(kPost,
210 "session/:sessionId/element/active",
211 WrapToCommand("GetActiveElement",
212 base::Bind(&ExecuteGetActiveElement))),
213 CommandMapping(kPost,
214 "session/:sessionId/element/:id/element",
215 WrapToCommand("FindChildElement",
216 base::Bind(&ExecuteFindChildElement, 50))),
217 CommandMapping(kPost,
218 "session/:sessionId/element/:id/elements",
219 WrapToCommand("FindChildElements",
220 base::Bind(&ExecuteFindChildElements, 50))),
221 CommandMapping(
222 kPost,
223 "session/:sessionId/element/:id/click",
224 WrapToCommand("ClickElement", base::Bind(&ExecuteClickElement))),
225 CommandMapping(
226 kPost,
227 "session/:sessionId/element/:id/clear",
228 WrapToCommand("ClearElement", base::Bind(&ExecuteClearElement))),
229 CommandMapping(
230 kPost,
231 "session/:sessionId/element/:id/submit",
232 WrapToCommand("SubmitElement", base::Bind(&ExecuteSubmitElement))),
233 CommandMapping(
234 kGet,
235 "session/:sessionId/element/:id/text",
236 WrapToCommand("GetElementText", base::Bind(&ExecuteGetElementText))),
237 CommandMapping(
238 kPost,
239 "session/:sessionId/element/:id/value",
240 WrapToCommand("TypeElement", base::Bind(&ExecuteSendKeysToElement))),
241 CommandMapping(
242 kPost,
243 "session/:sessionId/file",
244 WrapToCommand("UploadFile", base::Bind(&ExecuteUploadFile))),
245 CommandMapping(kGet,
246 "session/:sessionId/element/:id/value",
247 WrapToCommand("GetElementValue",
248 base::Bind(&ExecuteGetElementValue))),
249 CommandMapping(kGet,
250 "session/:sessionId/element/:id/name",
251 WrapToCommand("GetElementTagName",
252 base::Bind(&ExecuteGetElementTagName))),
253 CommandMapping(kGet,
254 "session/:sessionId/element/:id/selected",
255 WrapToCommand("IsElementSelected",
256 base::Bind(&ExecuteIsElementSelected))),
257 CommandMapping(kGet,
258 "session/:sessionId/element/:id/enabled",
259 WrapToCommand("IsElementEnabled",
260 base::Bind(&ExecuteIsElementEnabled))),
261 CommandMapping(kGet,
262 "session/:sessionId/element/:id/displayed",
263 WrapToCommand("IsElementDisplayed",
264 base::Bind(&ExecuteIsElementDisplayed))),
265 CommandMapping(
266 kPost,
267 "session/:sessionId/element/:id/hover",
268 WrapToCommand("HoverElement", base::Bind(&ExecuteHoverOverElement))),
269 CommandMapping(kGet,
270 "session/:sessionId/element/:id/location",
271 WrapToCommand("GetElementLocation",
272 base::Bind(&ExecuteGetElementLocation))),
273 CommandMapping(
274 kGet,
275 "session/:sessionId/element/:id/location_in_view",
276 WrapToCommand(
277 "GetElementLocationInView",
278 base::Bind(&ExecuteGetElementLocationOnceScrolledIntoView))),
279 CommandMapping(
280 kGet,
281 "session/:sessionId/element/:id/size",
282 WrapToCommand("GetElementSize", base::Bind(&ExecuteGetElementSize))),
283 CommandMapping(kGet,
284 "session/:sessionId/element/:id/attribute/:name",
285 WrapToCommand("GetElementAttribute",
286 base::Bind(&ExecuteGetElementAttribute))),
287 CommandMapping(
288 kGet,
289 "session/:sessionId/element/:id/equals/:other",
290 WrapToCommand("IsElementEqual", base::Bind(&ExecuteElementEquals))),
291 CommandMapping(
292 kGet,
293 "session/:sessionId/cookie",
294 WrapToCommand("GetCookies", base::Bind(&ExecuteGetCookies))),
295 CommandMapping(kPost,
296 "session/:sessionId/cookie",
297 WrapToCommand("AddCookie", base::Bind(&ExecuteAddCookie))),
298 CommandMapping(kDelete,
299 "session/:sessionId/cookie",
300 WrapToCommand("DeleteAllCookies",
301 base::Bind(&ExecuteDeleteAllCookies))),
302 CommandMapping(
303 kDelete,
304 "session/:sessionId/cookie/:name",
305 WrapToCommand("DeleteCookie", base::Bind(&ExecuteDeleteCookie))),
306 CommandMapping(
307 kPost,
308 "session/:sessionId/frame",
309 WrapToCommand("SwitchToFrame", base::Bind(&ExecuteSwitchToFrame))),
310 CommandMapping(
311 kPost,
312 "session/:sessionId/frame/parent",
313 WrapToCommand("SwitchToParentFrame",
314 base::Bind(&ExecuteSwitchToParentFrame))),
315 CommandMapping(
316 kPost,
317 "session/:sessionId/window",
318 WrapToCommand("SwitchToWindow", base::Bind(&ExecuteSwitchToWindow))),
319 CommandMapping(
320 kGet,
321 "session/:sessionId/window/:windowHandle/size",
322 WrapToCommand("GetWindowSize", base::Bind(&ExecuteGetWindowSize))),
323 CommandMapping(kGet,
324 "session/:sessionId/window/:windowHandle/position",
325 WrapToCommand("GetWindowPosition",
326 base::Bind(&ExecuteGetWindowPosition))),
327 CommandMapping(
328 kPost,
329 "session/:sessionId/window/:windowHandle/size",
330 WrapToCommand("SetWindowSize", base::Bind(&ExecuteSetWindowSize))),
331 CommandMapping(kPost,
332 "session/:sessionId/window/:windowHandle/position",
333 WrapToCommand("SetWindowPosition",
334 base::Bind(&ExecuteSetWindowPosition))),
335 CommandMapping(
336 kPost,
337 "session/:sessionId/window/:windowHandle/maximize",
338 WrapToCommand("MaximizeWindow", base::Bind(&ExecuteMaximizeWindow))),
339 CommandMapping(kDelete,
340 "session/:sessionId/window",
341 WrapToCommand("CloseWindow", base::Bind(&ExecuteClose))),
342 CommandMapping(kPost,
343 "session/:sessionId/element/:id/drag",
344 base::Bind(&UnimplementedCommand)),
345 CommandMapping(
346 kGet,
347 "session/:sessionId/element/:id/css/:propertyName",
348 WrapToCommand("GetElementCSSProperty",
349 base::Bind(&ExecuteGetElementValueOfCSSProperty))),
350 CommandMapping(
351 kPost,
352 "session/:sessionId/timeouts/implicit_wait",
353 WrapToCommand("SetImplicitWait", base::Bind(&ExecuteImplicitlyWait))),
354 CommandMapping(kPost,
355 "session/:sessionId/timeouts/async_script",
356 WrapToCommand("SetScriptTimeout",
357 base::Bind(&ExecuteSetScriptTimeout))),
358 CommandMapping(
359 kPost,
360 "session/:sessionId/timeouts",
361 WrapToCommand("SetTimeout", base::Bind(&ExecuteSetTimeout))),
362 CommandMapping(kPost,
363 "session/:sessionId/execute_sql",
364 base::Bind(&UnimplementedCommand)),
365 CommandMapping(
366 kGet,
367 "session/:sessionId/location",
368 WrapToCommand("GetGeolocation", base::Bind(&ExecuteGetLocation))),
369 CommandMapping(
370 kPost,
371 "session/:sessionId/location",
372 WrapToCommand("SetGeolocation", base::Bind(&ExecuteSetLocation))),
373 CommandMapping(
374 kGet,
375 "session/:sessionId/chromium/network_conditions",
376 WrapToCommand("GetNetworkConditions",
377 base::Bind(&ExecuteGetNetworkConditions))),
378 CommandMapping(
379 kPost,
380 "session/:sessionId/chromium/network_conditions",
381 WrapToCommand("SetNetworkConditions",
382 base::Bind(&ExecuteSetNetworkConditions))),
383 CommandMapping(
384 kDelete,
385 "session/:sessionId/chromium/network_conditions",
386 WrapToCommand("DeleteNetworkConditions",
387 base::Bind(&ExecuteDeleteNetworkConditions))),
388 CommandMapping(kGet,
389 "session/:sessionId/application_cache/status",
390 base::Bind(&ExecuteGetStatus)),
391 CommandMapping(kGet,
392 "session/:sessionId/browser_connection",
393 base::Bind(&UnimplementedCommand)),
394 CommandMapping(kPost,
395 "session/:sessionId/browser_connection",
396 base::Bind(&UnimplementedCommand)),
397 CommandMapping(
398 kGet,
399 "session/:sessionId/local_storage/key/:key",
400 WrapToCommand("GetLocalStorageItem",
401 base::Bind(&ExecuteGetStorageItem, kLocalStorage))),
402 CommandMapping(
403 kDelete,
404 "session/:sessionId/local_storage/key/:key",
405 WrapToCommand("RemoveLocalStorageItem",
406 base::Bind(&ExecuteRemoveStorageItem, kLocalStorage))),
407 CommandMapping(
408 kGet,
409 "session/:sessionId/local_storage",
410 WrapToCommand("GetLocalStorageKeys",
411 base::Bind(&ExecuteGetStorageKeys, kLocalStorage))),
412 CommandMapping(
413 kPost,
414 "session/:sessionId/local_storage",
415 WrapToCommand("SetLocalStorageKeys",
416 base::Bind(&ExecuteSetStorageItem, kLocalStorage))),
417 CommandMapping(
418 kDelete,
419 "session/:sessionId/local_storage",
420 WrapToCommand("ClearLocalStorage",
421 base::Bind(&ExecuteClearStorage, kLocalStorage))),
422 CommandMapping(
423 kGet,
424 "session/:sessionId/local_storage/size",
425 WrapToCommand("GetLocalStorageSize",
426 base::Bind(&ExecuteGetStorageSize, kLocalStorage))),
427 CommandMapping(
428 kGet,
429 "session/:sessionId/session_storage/key/:key",
430 WrapToCommand("GetSessionStorageItem",
431 base::Bind(&ExecuteGetStorageItem, kSessionStorage))),
432 CommandMapping(kDelete,
433 "session/:sessionId/session_storage/key/:key",
434 WrapToCommand("RemoveSessionStorageItem",
435 base::Bind(&ExecuteRemoveStorageItem,
436 kSessionStorage))),
437 CommandMapping(
438 kGet,
439 "session/:sessionId/session_storage",
440 WrapToCommand("GetSessionStorageKeys",
441 base::Bind(&ExecuteGetStorageKeys, kSessionStorage))),
442 CommandMapping(
443 kPost,
444 "session/:sessionId/session_storage",
445 WrapToCommand("SetSessionStorageItem",
446 base::Bind(&ExecuteSetStorageItem, kSessionStorage))),
447 CommandMapping(
448 kDelete,
449 "session/:sessionId/session_storage",
450 WrapToCommand("ClearSessionStorage",
451 base::Bind(&ExecuteClearStorage, kSessionStorage))),
452 CommandMapping(
453 kGet,
454 "session/:sessionId/session_storage/size",
455 WrapToCommand("GetSessionStorageSize",
456 base::Bind(&ExecuteGetStorageSize, kSessionStorage))),
457 CommandMapping(kGet,
458 "session/:sessionId/orientation",
459 base::Bind(&UnimplementedCommand)),
460 CommandMapping(kPost,
461 "session/:sessionId/orientation",
462 base::Bind(&UnimplementedCommand)),
463 CommandMapping(kPost,
464 "session/:sessionId/click",
465 WrapToCommand("Click", base::Bind(&ExecuteMouseClick))),
466 CommandMapping(
467 kPost,
468 "session/:sessionId/doubleclick",
469 WrapToCommand("DoubleClick", base::Bind(&ExecuteMouseDoubleClick))),
470 CommandMapping(
471 kPost,
472 "session/:sessionId/buttondown",
473 WrapToCommand("MouseDown", base::Bind(&ExecuteMouseButtonDown))),
474 CommandMapping(
475 kPost,
476 "session/:sessionId/buttonup",
477 WrapToCommand("MouseUp", base::Bind(&ExecuteMouseButtonUp))),
478 CommandMapping(
479 kPost,
480 "session/:sessionId/moveto",
481 WrapToCommand("MouseMove", base::Bind(&ExecuteMouseMoveTo))),
482 CommandMapping(
483 kPost,
484 "session/:sessionId/keys",
485 WrapToCommand("Type", base::Bind(&ExecuteSendKeysToActiveElement))),
486 CommandMapping(kGet,
487 "session/:sessionId/ime/available_engines",
488 base::Bind(&UnimplementedCommand)),
489 CommandMapping(kGet,
490 "session/:sessionId/ime/active_engine",
491 base::Bind(&UnimplementedCommand)),
492 CommandMapping(kGet,
493 "session/:sessionId/ime/activated",
494 base::Bind(&UnimplementedCommand)),
495 CommandMapping(kPost,
496 "session/:sessionId/ime/deactivate",
497 base::Bind(&UnimplementedCommand)),
498 CommandMapping(kPost,
499 "session/:sessionId/ime/activate",
500 base::Bind(&UnimplementedCommand)),
501 CommandMapping(kPost,
502 "session/:sessionId/touch/click",
503 WrapToCommand("Tap", base::Bind(&ExecuteTouchSingleTap))),
504 CommandMapping(kPost,
505 "session/:sessionId/touch/down",
506 WrapToCommand("TouchDown", base::Bind(&ExecuteTouchDown))),
507 CommandMapping(kPost,
508 "session/:sessionId/touch/up",
509 WrapToCommand("TouchUp", base::Bind(&ExecuteTouchUp))),
510 CommandMapping(kPost,
511 "session/:sessionId/touch/move",
512 WrapToCommand("TouchMove", base::Bind(&ExecuteTouchMove))),
513 CommandMapping(kPost,
514 "session/:sessionId/touch/scroll",
515 WrapToCommand("TouchScroll",
516 base::Bind(&ExecuteTouchScroll))),
517 CommandMapping(kPost,
518 "session/:sessionId/touch/doubleclick",
519 WrapToCommand("TouchDoubleTap",
520 base::Bind(&ExecuteTouchDoubleTap))),
521 CommandMapping(kPost,
522 "session/:sessionId/touch/longclick",
523 WrapToCommand("TouchLongPress",
524 base::Bind(&ExecuteTouchLongPress))),
525 CommandMapping(kPost,
526 "session/:sessionId/touch/flick",
527 WrapToCommand("TouchFlick", base::Bind(&ExecuteFlick))),
528 CommandMapping(kPost,
529 "session/:sessionId/log",
530 WrapToCommand("GetLog", base::Bind(&ExecuteGetLog))),
531 CommandMapping(kGet,
532 "session/:sessionId/log/types",
533 WrapToCommand("GetLogTypes",
534 base::Bind(&ExecuteGetAvailableLogTypes))),
535 CommandMapping(kPost, "logs", base::Bind(&UnimplementedCommand)),
536 CommandMapping(kGet, "status", base::Bind(&ExecuteGetStatus)),
538 // Custom Chrome commands:
539 // Allow quit all to be called with GET or POST.
540 CommandMapping(
541 kGet,
542 kShutdownPath,
543 base::Bind(&ExecuteQuitAll,
544 WrapToCommand("QuitAll", base::Bind(&ExecuteQuit, true)),
545 &session_thread_map_)),
546 CommandMapping(
547 kPost,
548 kShutdownPath,
549 base::Bind(&ExecuteQuitAll,
550 WrapToCommand("QuitAll", base::Bind(&ExecuteQuit, true)),
551 &session_thread_map_)),
552 CommandMapping(kGet,
553 "session/:sessionId/is_loading",
554 WrapToCommand("IsLoading", base::Bind(&ExecuteIsLoading))),
555 CommandMapping(kGet,
556 "session/:sessionId/autoreport",
557 WrapToCommand("IsAutoReporting",
558 base::Bind(&ExecuteIsAutoReporting))),
559 CommandMapping(kPost,
560 "session/:sessionId/autoreport",
561 WrapToCommand(
562 "SetAutoReporting",
563 base::Bind(&ExecuteSetAutoReporting))),
564 CommandMapping(kPost,
565 "session/:sessionId/touch/pinch",
566 WrapToCommand("TouchPinch",
567 base::Bind(&ExecuteTouchPinch))),
569 command_map_.reset(
570 new CommandMap(commands, commands + arraysize(commands)));
573 HttpHandler::~HttpHandler() {}
575 void HttpHandler::Handle(const net::HttpServerRequestInfo& request,
576 const HttpResponseSenderFunc& send_response_func) {
577 CHECK(thread_checker_.CalledOnValidThread());
579 if (received_shutdown_)
580 return;
582 std::string path = request.path;
583 if (!base::StartsWith(path, url_base_, base::CompareCase::SENSITIVE)) {
584 scoped_ptr<net::HttpServerResponseInfo> response(
585 new net::HttpServerResponseInfo(net::HTTP_BAD_REQUEST));
586 response->SetBody("unhandled request", "text/plain");
587 send_response_func.Run(response.Pass());
588 return;
591 path.erase(0, url_base_.length());
593 HandleCommand(request, path, send_response_func);
595 if (path == kShutdownPath)
596 received_shutdown_ = true;
599 Command HttpHandler::WrapToCommand(
600 const char* name,
601 const SessionCommand& session_command) {
602 return base::Bind(&ExecuteSessionCommand,
603 &session_thread_map_,
604 name,
605 session_command,
606 false);
609 Command HttpHandler::WrapToCommand(
610 const char* name,
611 const WindowCommand& window_command) {
612 return WrapToCommand(name, base::Bind(&ExecuteWindowCommand, window_command));
615 Command HttpHandler::WrapToCommand(
616 const char* name,
617 const ElementCommand& element_command) {
618 return WrapToCommand(name,
619 base::Bind(&ExecuteElementCommand, element_command));
622 void HttpHandler::HandleCommand(
623 const net::HttpServerRequestInfo& request,
624 const std::string& trimmed_path,
625 const HttpResponseSenderFunc& send_response_func) {
626 base::DictionaryValue params;
627 std::string session_id;
628 CommandMap::const_iterator iter = command_map_->begin();
629 while (true) {
630 if (iter == command_map_->end()) {
631 scoped_ptr<net::HttpServerResponseInfo> response(
632 new net::HttpServerResponseInfo(net::HTTP_NOT_FOUND));
633 response->SetBody("unknown command: " + trimmed_path, "text/plain");
634 send_response_func.Run(response.Pass());
635 return;
637 if (internal::MatchesCommand(
638 request.method, trimmed_path, *iter, &session_id, &params)) {
639 break;
641 ++iter;
644 if (request.data.length()) {
645 base::DictionaryValue* body_params;
646 scoped_ptr<base::Value> parsed_body = base::JSONReader::Read(request.data);
647 if (!parsed_body || !parsed_body->GetAsDictionary(&body_params)) {
648 scoped_ptr<net::HttpServerResponseInfo> response(
649 new net::HttpServerResponseInfo(net::HTTP_BAD_REQUEST));
650 response->SetBody("missing command parameters", "text/plain");
651 send_response_func.Run(response.Pass());
652 return;
654 params.MergeDictionary(body_params);
657 iter->command.Run(params,
658 session_id,
659 base::Bind(&HttpHandler::PrepareResponse,
660 weak_ptr_factory_.GetWeakPtr(),
661 trimmed_path,
662 send_response_func));
665 void HttpHandler::PrepareResponse(
666 const std::string& trimmed_path,
667 const HttpResponseSenderFunc& send_response_func,
668 const Status& status,
669 scoped_ptr<base::Value> value,
670 const std::string& session_id) {
671 CHECK(thread_checker_.CalledOnValidThread());
672 scoped_ptr<net::HttpServerResponseInfo> response =
673 PrepareResponseHelper(trimmed_path, status, value.Pass(), session_id);
674 send_response_func.Run(response.Pass());
675 if (trimmed_path == kShutdownPath)
676 quit_func_.Run();
679 scoped_ptr<net::HttpServerResponseInfo> HttpHandler::PrepareResponseHelper(
680 const std::string& trimmed_path,
681 const Status& status,
682 scoped_ptr<base::Value> value,
683 const std::string& session_id) {
684 if (status.code() == kUnknownCommand) {
685 scoped_ptr<net::HttpServerResponseInfo> response(
686 new net::HttpServerResponseInfo(net::HTTP_NOT_IMPLEMENTED));
687 response->SetBody("unimplemented command: " + trimmed_path, "text/plain");
688 return response.Pass();
691 if (status.IsError()) {
692 Status full_status(status);
693 full_status.AddDetails(base::StringPrintf(
694 "Driver info: chromedriver=%s,platform=%s %s %s",
695 kChromeDriverVersion,
696 base::SysInfo::OperatingSystemName().c_str(),
697 base::SysInfo::OperatingSystemVersion().c_str(),
698 base::SysInfo::OperatingSystemArchitecture().c_str()));
699 scoped_ptr<base::DictionaryValue> error(new base::DictionaryValue());
700 error->SetString("message", full_status.message());
701 value.reset(error.release());
703 if (!value)
704 value = base::Value::CreateNullValue();
706 base::DictionaryValue body_params;
707 body_params.SetInteger("status", status.code());
708 body_params.Set("value", value.release());
709 body_params.SetString("sessionId", session_id);
710 std::string body;
711 base::JSONWriter::WriteWithOptions(
712 body_params, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
713 &body);
714 scoped_ptr<net::HttpServerResponseInfo> response(
715 new net::HttpServerResponseInfo(net::HTTP_OK));
716 response->SetBody(body, "application/json; charset=utf-8");
717 return response.Pass();
720 namespace internal {
722 const char kNewSessionPathPattern[] = "session";
724 bool MatchesMethod(HttpMethod command_method, const std::string& method) {
725 std::string lower_method = base::ToLowerASCII(method);
726 switch (command_method) {
727 case kGet:
728 return lower_method == "get";
729 case kPost:
730 return lower_method == "post" || lower_method == "put";
731 case kDelete:
732 return lower_method == "delete";
734 return false;
737 bool MatchesCommand(const std::string& method,
738 const std::string& path,
739 const CommandMapping& command,
740 std::string* session_id,
741 base::DictionaryValue* out_params) {
742 if (!MatchesMethod(command.method, method))
743 return false;
745 std::vector<std::string> path_parts = base::SplitString(
746 path, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
747 std::vector<std::string> command_path_parts = base::SplitString(
748 command.path_pattern, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
749 if (path_parts.size() != command_path_parts.size())
750 return false;
752 base::DictionaryValue params;
753 for (size_t i = 0; i < path_parts.size(); ++i) {
754 CHECK(command_path_parts[i].length());
755 if (command_path_parts[i][0] == ':') {
756 std::string name = command_path_parts[i];
757 name.erase(0, 1);
758 CHECK(name.length());
759 if (name == "sessionId")
760 *session_id = path_parts[i];
761 else
762 params.SetString(name, path_parts[i]);
763 } else if (command_path_parts[i] != path_parts[i]) {
764 return false;
767 out_params->MergeDictionary(&params);
768 return true;
771 } // namespace internal