Unregister from GCM when the only GCM app is removed
[chromium-blink-merge.git] / chrome / test / chromedriver / server / http_handler.cc
blob6e452fe8795f80769cc8f73d869319de6aa6e5af
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 "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(kGet,
374 "session/:sessionId/application_cache/status",
375 base::Bind(&ExecuteGetStatus)),
376 CommandMapping(kGet,
377 "session/:sessionId/browser_connection",
378 base::Bind(&UnimplementedCommand)),
379 CommandMapping(kPost,
380 "session/:sessionId/browser_connection",
381 base::Bind(&UnimplementedCommand)),
382 CommandMapping(
383 kGet,
384 "session/:sessionId/local_storage/key/:key",
385 WrapToCommand("GetLocalStorageItem",
386 base::Bind(&ExecuteGetStorageItem, kLocalStorage))),
387 CommandMapping(
388 kDelete,
389 "session/:sessionId/local_storage/key/:key",
390 WrapToCommand("RemoveLocalStorageItem",
391 base::Bind(&ExecuteRemoveStorageItem, kLocalStorage))),
392 CommandMapping(
393 kGet,
394 "session/:sessionId/local_storage",
395 WrapToCommand("GetLocalStorageKeys",
396 base::Bind(&ExecuteGetStorageKeys, kLocalStorage))),
397 CommandMapping(
398 kPost,
399 "session/:sessionId/local_storage",
400 WrapToCommand("SetLocalStorageKeys",
401 base::Bind(&ExecuteSetStorageItem, kLocalStorage))),
402 CommandMapping(
403 kDelete,
404 "session/:sessionId/local_storage",
405 WrapToCommand("ClearLocalStorage",
406 base::Bind(&ExecuteClearStorage, kLocalStorage))),
407 CommandMapping(
408 kGet,
409 "session/:sessionId/local_storage/size",
410 WrapToCommand("GetLocalStorageSize",
411 base::Bind(&ExecuteGetStorageSize, kLocalStorage))),
412 CommandMapping(
413 kGet,
414 "session/:sessionId/session_storage/key/:key",
415 WrapToCommand("GetSessionStorageItem",
416 base::Bind(&ExecuteGetStorageItem, kSessionStorage))),
417 CommandMapping(kDelete,
418 "session/:sessionId/session_storage/key/:key",
419 WrapToCommand("RemoveSessionStorageItem",
420 base::Bind(&ExecuteRemoveStorageItem,
421 kSessionStorage))),
422 CommandMapping(
423 kGet,
424 "session/:sessionId/session_storage",
425 WrapToCommand("GetSessionStorageKeys",
426 base::Bind(&ExecuteGetStorageKeys, kSessionStorage))),
427 CommandMapping(
428 kPost,
429 "session/:sessionId/session_storage",
430 WrapToCommand("SetSessionStorageItem",
431 base::Bind(&ExecuteSetStorageItem, kSessionStorage))),
432 CommandMapping(
433 kDelete,
434 "session/:sessionId/session_storage",
435 WrapToCommand("ClearSessionStorage",
436 base::Bind(&ExecuteClearStorage, kSessionStorage))),
437 CommandMapping(
438 kGet,
439 "session/:sessionId/session_storage/size",
440 WrapToCommand("GetSessionStorageSize",
441 base::Bind(&ExecuteGetStorageSize, kSessionStorage))),
442 CommandMapping(kGet,
443 "session/:sessionId/orientation",
444 base::Bind(&UnimplementedCommand)),
445 CommandMapping(kPost,
446 "session/:sessionId/orientation",
447 base::Bind(&UnimplementedCommand)),
448 CommandMapping(kPost,
449 "session/:sessionId/click",
450 WrapToCommand("Click", base::Bind(&ExecuteMouseClick))),
451 CommandMapping(
452 kPost,
453 "session/:sessionId/doubleclick",
454 WrapToCommand("DoubleClick", base::Bind(&ExecuteMouseDoubleClick))),
455 CommandMapping(
456 kPost,
457 "session/:sessionId/buttondown",
458 WrapToCommand("MouseDown", base::Bind(&ExecuteMouseButtonDown))),
459 CommandMapping(
460 kPost,
461 "session/:sessionId/buttonup",
462 WrapToCommand("MouseUp", base::Bind(&ExecuteMouseButtonUp))),
463 CommandMapping(
464 kPost,
465 "session/:sessionId/moveto",
466 WrapToCommand("MouseMove", base::Bind(&ExecuteMouseMoveTo))),
467 CommandMapping(
468 kPost,
469 "session/:sessionId/keys",
470 WrapToCommand("Type", base::Bind(&ExecuteSendKeysToActiveElement))),
471 CommandMapping(kGet,
472 "session/:sessionId/ime/available_engines",
473 base::Bind(&UnimplementedCommand)),
474 CommandMapping(kGet,
475 "session/:sessionId/ime/active_engine",
476 base::Bind(&UnimplementedCommand)),
477 CommandMapping(kGet,
478 "session/:sessionId/ime/activated",
479 base::Bind(&UnimplementedCommand)),
480 CommandMapping(kPost,
481 "session/:sessionId/ime/deactivate",
482 base::Bind(&UnimplementedCommand)),
483 CommandMapping(kPost,
484 "session/:sessionId/ime/activate",
485 base::Bind(&UnimplementedCommand)),
486 CommandMapping(kPost,
487 "session/:sessionId/touch/click",
488 WrapToCommand("Tap", base::Bind(&ExecuteTouchSingleTap))),
489 CommandMapping(kPost,
490 "session/:sessionId/touch/down",
491 WrapToCommand("TouchDown", base::Bind(&ExecuteTouchDown))),
492 CommandMapping(kPost,
493 "session/:sessionId/touch/up",
494 WrapToCommand("TouchUp", base::Bind(&ExecuteTouchUp))),
495 CommandMapping(kPost,
496 "session/:sessionId/touch/move",
497 WrapToCommand("TouchMove", base::Bind(&ExecuteTouchMove))),
498 CommandMapping(kPost,
499 "session/:sessionId/touch/scroll",
500 base::Bind(&UnimplementedCommand)),
501 CommandMapping(kPost,
502 "session/:sessionId/touch/doubleclick",
503 base::Bind(&UnimplementedCommand)),
504 CommandMapping(kPost,
505 "session/:sessionId/touch/longclick",
506 base::Bind(&UnimplementedCommand)),
507 CommandMapping(kPost,
508 "session/:sessionId/touch/flick",
509 WrapToCommand("TouchFlick", base::Bind(&ExecuteFlick))),
510 CommandMapping(kPost,
511 "session/:sessionId/log",
512 WrapToCommand("GetLog", base::Bind(&ExecuteGetLog))),
513 CommandMapping(kGet,
514 "session/:sessionId/log/types",
515 WrapToCommand("GetLogTypes",
516 base::Bind(&ExecuteGetAvailableLogTypes))),
517 CommandMapping(kPost, "logs", base::Bind(&UnimplementedCommand)),
518 CommandMapping(kGet, "status", base::Bind(&ExecuteGetStatus)),
520 // Custom Chrome commands:
521 // Allow quit all to be called with GET or POST.
522 CommandMapping(
523 kGet,
524 kShutdownPath,
525 base::Bind(&ExecuteQuitAll,
526 WrapToCommand("QuitAll", base::Bind(&ExecuteQuit, true)),
527 &session_thread_map_)),
528 CommandMapping(
529 kPost,
530 kShutdownPath,
531 base::Bind(&ExecuteQuitAll,
532 WrapToCommand("QuitAll", base::Bind(&ExecuteQuit, true)),
533 &session_thread_map_)),
534 CommandMapping(kGet,
535 "session/:sessionId/is_loading",
536 WrapToCommand("IsLoading", base::Bind(&ExecuteIsLoading))),
537 CommandMapping(kGet,
538 "session/:sessionId/autoreport",
539 WrapToCommand("IsAutoReporting",
540 base::Bind(&ExecuteIsAutoReporting))),
541 CommandMapping(kPost,
542 "session/:sessionId/autoreport",
543 WrapToCommand(
544 "SetAutoReporting",
545 base::Bind(&ExecuteSetAutoReporting))),
547 command_map_.reset(
548 new CommandMap(commands, commands + arraysize(commands)));
551 HttpHandler::~HttpHandler() {}
553 void HttpHandler::Handle(const net::HttpServerRequestInfo& request,
554 const HttpResponseSenderFunc& send_response_func) {
555 CHECK(thread_checker_.CalledOnValidThread());
557 if (received_shutdown_)
558 return;
560 std::string path = request.path;
561 if (!StartsWithASCII(path, url_base_, true)) {
562 scoped_ptr<net::HttpServerResponseInfo> response(
563 new net::HttpServerResponseInfo(net::HTTP_BAD_REQUEST));
564 response->SetBody("unhandled request", "text/plain");
565 send_response_func.Run(response.Pass());
566 return;
569 path.erase(0, url_base_.length());
571 HandleCommand(request, path, send_response_func);
573 if (path == kShutdownPath)
574 received_shutdown_ = true;
577 Command HttpHandler::WrapToCommand(
578 const char* name,
579 const SessionCommand& session_command) {
580 return base::Bind(&ExecuteSessionCommand,
581 &session_thread_map_,
582 name,
583 session_command,
584 false);
587 Command HttpHandler::WrapToCommand(
588 const char* name,
589 const WindowCommand& window_command) {
590 return WrapToCommand(name, base::Bind(&ExecuteWindowCommand, window_command));
593 Command HttpHandler::WrapToCommand(
594 const char* name,
595 const ElementCommand& element_command) {
596 return WrapToCommand(name,
597 base::Bind(&ExecuteElementCommand, element_command));
600 void HttpHandler::HandleCommand(
601 const net::HttpServerRequestInfo& request,
602 const std::string& trimmed_path,
603 const HttpResponseSenderFunc& send_response_func) {
604 base::DictionaryValue params;
605 std::string session_id;
606 CommandMap::const_iterator iter = command_map_->begin();
607 while (true) {
608 if (iter == command_map_->end()) {
609 scoped_ptr<net::HttpServerResponseInfo> response(
610 new net::HttpServerResponseInfo(net::HTTP_NOT_FOUND));
611 response->SetBody("unknown command: " + trimmed_path, "text/plain");
612 send_response_func.Run(response.Pass());
613 return;
615 if (internal::MatchesCommand(
616 request.method, trimmed_path, *iter, &session_id, &params)) {
617 break;
619 ++iter;
622 if (request.data.length()) {
623 base::DictionaryValue* body_params;
624 scoped_ptr<base::Value> parsed_body(base::JSONReader::Read(request.data));
625 if (!parsed_body || !parsed_body->GetAsDictionary(&body_params)) {
626 scoped_ptr<net::HttpServerResponseInfo> response(
627 new net::HttpServerResponseInfo(net::HTTP_BAD_REQUEST));
628 response->SetBody("missing command parameters", "text/plain");
629 send_response_func.Run(response.Pass());
630 return;
632 params.MergeDictionary(body_params);
635 iter->command.Run(params,
636 session_id,
637 base::Bind(&HttpHandler::PrepareResponse,
638 weak_ptr_factory_.GetWeakPtr(),
639 trimmed_path,
640 send_response_func));
643 void HttpHandler::PrepareResponse(
644 const std::string& trimmed_path,
645 const HttpResponseSenderFunc& send_response_func,
646 const Status& status,
647 scoped_ptr<base::Value> value,
648 const std::string& session_id) {
649 CHECK(thread_checker_.CalledOnValidThread());
650 scoped_ptr<net::HttpServerResponseInfo> response =
651 PrepareResponseHelper(trimmed_path, status, value.Pass(), session_id);
652 send_response_func.Run(response.Pass());
653 if (trimmed_path == kShutdownPath)
654 quit_func_.Run();
657 scoped_ptr<net::HttpServerResponseInfo> HttpHandler::PrepareResponseHelper(
658 const std::string& trimmed_path,
659 const Status& status,
660 scoped_ptr<base::Value> value,
661 const std::string& session_id) {
662 if (status.code() == kUnknownCommand) {
663 scoped_ptr<net::HttpServerResponseInfo> response(
664 new net::HttpServerResponseInfo(net::HTTP_NOT_IMPLEMENTED));
665 response->SetBody("unimplemented command: " + trimmed_path, "text/plain");
666 return response.Pass();
669 if (status.IsError()) {
670 Status full_status(status);
671 full_status.AddDetails(base::StringPrintf(
672 "Driver info: chromedriver=%s,platform=%s %s %s",
673 kChromeDriverVersion,
674 base::SysInfo::OperatingSystemName().c_str(),
675 base::SysInfo::OperatingSystemVersion().c_str(),
676 base::SysInfo::OperatingSystemArchitecture().c_str()));
677 scoped_ptr<base::DictionaryValue> error(new base::DictionaryValue());
678 error->SetString("message", full_status.message());
679 value.reset(error.release());
681 if (!value)
682 value.reset(base::Value::CreateNullValue());
684 base::DictionaryValue body_params;
685 body_params.SetInteger("status", status.code());
686 body_params.Set("value", value.release());
687 body_params.SetString("sessionId", session_id);
688 std::string body;
689 base::JSONWriter::WriteWithOptions(
690 &body_params, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
691 &body);
692 scoped_ptr<net::HttpServerResponseInfo> response(
693 new net::HttpServerResponseInfo(net::HTTP_OK));
694 response->SetBody(body, "application/json; charset=utf-8");
695 return response.Pass();
698 namespace internal {
700 const char kNewSessionPathPattern[] = "session";
702 bool MatchesMethod(HttpMethod command_method, const std::string& method) {
703 std::string lower_method = base::StringToLowerASCII(method);
704 switch (command_method) {
705 case kGet:
706 return lower_method == "get";
707 case kPost:
708 return lower_method == "post" || lower_method == "put";
709 case kDelete:
710 return lower_method == "delete";
712 return false;
715 bool MatchesCommand(const std::string& method,
716 const std::string& path,
717 const CommandMapping& command,
718 std::string* session_id,
719 base::DictionaryValue* out_params) {
720 if (!MatchesMethod(command.method, method))
721 return false;
723 std::vector<std::string> path_parts;
724 base::SplitString(path, '/', &path_parts);
725 std::vector<std::string> command_path_parts;
726 base::SplitString(command.path_pattern, '/', &command_path_parts);
727 if (path_parts.size() != command_path_parts.size())
728 return false;
730 base::DictionaryValue params;
731 for (size_t i = 0; i < path_parts.size(); ++i) {
732 CHECK(command_path_parts[i].length());
733 if (command_path_parts[i][0] == ':') {
734 std::string name = command_path_parts[i];
735 name.erase(0, 1);
736 CHECK(name.length());
737 if (name == "sessionId")
738 *session_id = path_parts[i];
739 else
740 params.SetString(name, path_parts[i]);
741 } else if (command_path_parts[i] != path_parts[i]) {
742 return false;
745 out_params->MergeDictionary(&params);
746 return true;
749 } // namespace internal