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"
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"
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
);
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
,
70 scoped_ptr
<PortServer
> port_server
)
71 : quit_func_(quit_func
),
73 received_shutdown_(false),
74 weak_ptr_factory_(this) {
75 #if defined(OS_MACOSX)
76 base::mac::ScopedNSAutoreleasePool autorelease_pool
;
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
[] = {
88 internal::kNewSessionPathPattern
,
89 base::Bind(&ExecuteCreateSession
,
93 base::Bind(&ExecuteInitSession
,
94 InitSessionParams(context_getter_
,
96 device_manager_
.get(),
98 port_manager_
.get()))))),
101 base::Bind(&ExecuteGetSessions
,
102 WrapToCommand("GetSessions",
103 base::Bind(&ExecuteGetSessionCapabilities
)),
104 &session_thread_map_
)),
106 "session/:sessionId",
107 WrapToCommand("GetSessionCapabilities",
108 base::Bind(&ExecuteGetSessionCapabilities
))),
109 CommandMapping(kDelete
,
110 "session/:sessionId",
111 base::Bind(&ExecuteSessionCommand
,
112 &session_thread_map_
,
114 base::Bind(&ExecuteQuit
, false),
117 "session/:sessionId/window_handle",
118 WrapToCommand("GetWindow",
119 base::Bind(&ExecuteGetCurrentWindowHandle
))),
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
))),
131 "session/:sessionId/alert",
132 WrapToCommand("IsAlertOpen",
133 base::Bind(&ExecuteAlertCommand
,
134 base::Bind(&ExecuteGetAlert
)))),
137 "session/:sessionId/dismiss_alert",
138 WrapToCommand("DismissAlert",
139 base::Bind(&ExecuteAlertCommand
,
140 base::Bind(&ExecuteDismissAlert
)))),
143 "session/:sessionId/accept_alert",
144 WrapToCommand("AcceptAlert",
145 base::Bind(&ExecuteAlertCommand
,
146 base::Bind(&ExecuteAcceptAlert
)))),
149 "session/:sessionId/alert_text",
150 WrapToCommand("GetAlertMessage",
151 base::Bind(&ExecuteAlertCommand
,
152 base::Bind(&ExecuteGetAlertText
)))),
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
))),
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
))),
178 "session/:sessionId/url",
179 WrapToCommand("GetUrl", base::Bind(&ExecuteGetCurrentUrl
))),
181 "session/:sessionId/title",
182 WrapToCommand("GetTitle", base::Bind(&ExecuteGetTitle
))),
185 "session/:sessionId/source",
186 WrapToCommand("GetSource", base::Bind(&ExecuteGetPageSource
))),
189 "session/:sessionId/screenshot",
190 WrapToCommand("Screenshot", base::Bind(&ExecuteScreenshot
))),
193 "session/:sessionId/chromium/heap_snapshot",
194 WrapToCommand("HeapSnapshot", base::Bind(&ExecuteTakeHeapSnapshot
))),
195 CommandMapping(kPost
,
196 "session/:sessionId/visible",
197 base::Bind(&UnimplementedCommand
)),
199 "session/:sessionId/visible",
200 base::Bind(&UnimplementedCommand
)),
203 "session/:sessionId/element",
204 WrapToCommand("FindElement", base::Bind(&ExecuteFindElement
, 50))),
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))),
223 "session/:sessionId/element/:id/click",
224 WrapToCommand("ClickElement", base::Bind(&ExecuteClickElement
))),
227 "session/:sessionId/element/:id/clear",
228 WrapToCommand("ClearElement", base::Bind(&ExecuteClearElement
))),
231 "session/:sessionId/element/:id/submit",
232 WrapToCommand("SubmitElement", base::Bind(&ExecuteSubmitElement
))),
235 "session/:sessionId/element/:id/text",
236 WrapToCommand("GetElementText", base::Bind(&ExecuteGetElementText
))),
239 "session/:sessionId/element/:id/value",
240 WrapToCommand("TypeElement", base::Bind(&ExecuteSendKeysToElement
))),
243 "session/:sessionId/file",
244 WrapToCommand("UploadFile", base::Bind(&ExecuteUploadFile
))),
246 "session/:sessionId/element/:id/value",
247 WrapToCommand("GetElementValue",
248 base::Bind(&ExecuteGetElementValue
))),
250 "session/:sessionId/element/:id/name",
251 WrapToCommand("GetElementTagName",
252 base::Bind(&ExecuteGetElementTagName
))),
254 "session/:sessionId/element/:id/selected",
255 WrapToCommand("IsElementSelected",
256 base::Bind(&ExecuteIsElementSelected
))),
258 "session/:sessionId/element/:id/enabled",
259 WrapToCommand("IsElementEnabled",
260 base::Bind(&ExecuteIsElementEnabled
))),
262 "session/:sessionId/element/:id/displayed",
263 WrapToCommand("IsElementDisplayed",
264 base::Bind(&ExecuteIsElementDisplayed
))),
267 "session/:sessionId/element/:id/hover",
268 WrapToCommand("HoverElement", base::Bind(&ExecuteHoverOverElement
))),
270 "session/:sessionId/element/:id/location",
271 WrapToCommand("GetElementLocation",
272 base::Bind(&ExecuteGetElementLocation
))),
275 "session/:sessionId/element/:id/location_in_view",
277 "GetElementLocationInView",
278 base::Bind(&ExecuteGetElementLocationOnceScrolledIntoView
))),
281 "session/:sessionId/element/:id/size",
282 WrapToCommand("GetElementSize", base::Bind(&ExecuteGetElementSize
))),
284 "session/:sessionId/element/:id/attribute/:name",
285 WrapToCommand("GetElementAttribute",
286 base::Bind(&ExecuteGetElementAttribute
))),
289 "session/:sessionId/element/:id/equals/:other",
290 WrapToCommand("IsElementEqual", base::Bind(&ExecuteElementEquals
))),
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
))),
304 "session/:sessionId/cookie/:name",
305 WrapToCommand("DeleteCookie", base::Bind(&ExecuteDeleteCookie
))),
308 "session/:sessionId/frame",
309 WrapToCommand("SwitchToFrame", base::Bind(&ExecuteSwitchToFrame
))),
312 "session/:sessionId/frame/parent",
313 WrapToCommand("SwitchToParentFrame",
314 base::Bind(&ExecuteSwitchToParentFrame
))),
317 "session/:sessionId/window",
318 WrapToCommand("SwitchToWindow", base::Bind(&ExecuteSwitchToWindow
))),
321 "session/:sessionId/window/:windowHandle/size",
322 WrapToCommand("GetWindowSize", base::Bind(&ExecuteGetWindowSize
))),
324 "session/:sessionId/window/:windowHandle/position",
325 WrapToCommand("GetWindowPosition",
326 base::Bind(&ExecuteGetWindowPosition
))),
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
))),
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
)),
347 "session/:sessionId/element/:id/css/:propertyName",
348 WrapToCommand("GetElementCSSProperty",
349 base::Bind(&ExecuteGetElementValueOfCSSProperty
))),
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
))),
360 "session/:sessionId/timeouts",
361 WrapToCommand("SetTimeout", base::Bind(&ExecuteSetTimeout
))),
362 CommandMapping(kPost
,
363 "session/:sessionId/execute_sql",
364 base::Bind(&UnimplementedCommand
)),
367 "session/:sessionId/location",
368 WrapToCommand("GetGeolocation", base::Bind(&ExecuteGetLocation
))),
371 "session/:sessionId/location",
372 WrapToCommand("SetGeolocation", base::Bind(&ExecuteSetLocation
))),
375 "session/:sessionId/chromium/network_conditions",
376 WrapToCommand("GetNetworkConditions",
377 base::Bind(&ExecuteGetNetworkConditions
))),
380 "session/:sessionId/chromium/network_conditions",
381 WrapToCommand("SetNetworkConditions",
382 base::Bind(&ExecuteSetNetworkConditions
))),
385 "session/:sessionId/chromium/network_conditions",
386 WrapToCommand("DeleteNetworkConditions",
387 base::Bind(&ExecuteDeleteNetworkConditions
))),
389 "session/:sessionId/application_cache/status",
390 base::Bind(&ExecuteGetStatus
)),
392 "session/:sessionId/browser_connection",
393 base::Bind(&UnimplementedCommand
)),
394 CommandMapping(kPost
,
395 "session/:sessionId/browser_connection",
396 base::Bind(&UnimplementedCommand
)),
399 "session/:sessionId/local_storage/key/:key",
400 WrapToCommand("GetLocalStorageItem",
401 base::Bind(&ExecuteGetStorageItem
, kLocalStorage
))),
404 "session/:sessionId/local_storage/key/:key",
405 WrapToCommand("RemoveLocalStorageItem",
406 base::Bind(&ExecuteRemoveStorageItem
, kLocalStorage
))),
409 "session/:sessionId/local_storage",
410 WrapToCommand("GetLocalStorageKeys",
411 base::Bind(&ExecuteGetStorageKeys
, kLocalStorage
))),
414 "session/:sessionId/local_storage",
415 WrapToCommand("SetLocalStorageKeys",
416 base::Bind(&ExecuteSetStorageItem
, kLocalStorage
))),
419 "session/:sessionId/local_storage",
420 WrapToCommand("ClearLocalStorage",
421 base::Bind(&ExecuteClearStorage
, kLocalStorage
))),
424 "session/:sessionId/local_storage/size",
425 WrapToCommand("GetLocalStorageSize",
426 base::Bind(&ExecuteGetStorageSize
, kLocalStorage
))),
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
,
439 "session/:sessionId/session_storage",
440 WrapToCommand("GetSessionStorageKeys",
441 base::Bind(&ExecuteGetStorageKeys
, kSessionStorage
))),
444 "session/:sessionId/session_storage",
445 WrapToCommand("SetSessionStorageItem",
446 base::Bind(&ExecuteSetStorageItem
, kSessionStorage
))),
449 "session/:sessionId/session_storage",
450 WrapToCommand("ClearSessionStorage",
451 base::Bind(&ExecuteClearStorage
, kSessionStorage
))),
454 "session/:sessionId/session_storage/size",
455 WrapToCommand("GetSessionStorageSize",
456 base::Bind(&ExecuteGetStorageSize
, kSessionStorage
))),
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
))),
468 "session/:sessionId/doubleclick",
469 WrapToCommand("DoubleClick", base::Bind(&ExecuteMouseDoubleClick
))),
472 "session/:sessionId/buttondown",
473 WrapToCommand("MouseDown", base::Bind(&ExecuteMouseButtonDown
))),
476 "session/:sessionId/buttonup",
477 WrapToCommand("MouseUp", base::Bind(&ExecuteMouseButtonUp
))),
480 "session/:sessionId/moveto",
481 WrapToCommand("MouseMove", base::Bind(&ExecuteMouseMoveTo
))),
484 "session/:sessionId/keys",
485 WrapToCommand("Type", base::Bind(&ExecuteSendKeysToActiveElement
))),
487 "session/:sessionId/ime/available_engines",
488 base::Bind(&UnimplementedCommand
)),
490 "session/:sessionId/ime/active_engine",
491 base::Bind(&UnimplementedCommand
)),
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
))),
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.
543 base::Bind(&ExecuteQuitAll
,
544 WrapToCommand("QuitAll", base::Bind(&ExecuteQuit
, true)),
545 &session_thread_map_
)),
549 base::Bind(&ExecuteQuitAll
,
550 WrapToCommand("QuitAll", base::Bind(&ExecuteQuit
, true)),
551 &session_thread_map_
)),
553 "session/:sessionId/is_loading",
554 WrapToCommand("IsLoading", base::Bind(&ExecuteIsLoading
))),
556 "session/:sessionId/autoreport",
557 WrapToCommand("IsAutoReporting",
558 base::Bind(&ExecuteIsAutoReporting
))),
559 CommandMapping(kPost
,
560 "session/:sessionId/autoreport",
563 base::Bind(&ExecuteSetAutoReporting
))),
564 CommandMapping(kPost
,
565 "session/:sessionId/touch/pinch",
566 WrapToCommand("TouchPinch",
567 base::Bind(&ExecuteTouchPinch
))),
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_
)
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());
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(
601 const SessionCommand
& session_command
) {
602 return base::Bind(&ExecuteSessionCommand
,
603 &session_thread_map_
,
609 Command
HttpHandler::WrapToCommand(
611 const WindowCommand
& window_command
) {
612 return WrapToCommand(name
, base::Bind(&ExecuteWindowCommand
, window_command
));
615 Command
HttpHandler::WrapToCommand(
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();
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());
637 if (internal::MatchesCommand(
638 request
.method
, trimmed_path
, *iter
, &session_id
, ¶ms
)) {
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());
654 params
.MergeDictionary(body_params
);
657 iter
->command
.Run(params
,
659 base::Bind(&HttpHandler::PrepareResponse
,
660 weak_ptr_factory_
.GetWeakPtr(),
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
)
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());
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
);
711 base::JSONWriter::WriteWithOptions(
712 body_params
, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION
,
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();
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
) {
728 return lower_method
== "get";
730 return lower_method
== "post" || lower_method
== "put";
732 return lower_method
== "delete";
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
))
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())
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
];
758 CHECK(name
.length());
759 if (name
== "sessionId")
760 *session_id
= path_parts
[i
];
762 params
.SetString(name
, path_parts
[i
]);
763 } else if (command_path_parts
[i
] != path_parts
[i
]) {
767 out_params
->MergeDictionary(¶ms
);
771 } // namespace internal