Suppression for crbug/241044.
[chromium-blink-merge.git] / chrome / test / chromedriver / server / http_handler.cc
blob0cfe67637029dd5b52a20f0d71519fbe6cbced31
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/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/string_util.h"
11 #include "base/strings/string_split.h"
12 #include "base/values.h"
13 #include "chrome/test/chromedriver/chrome/status.h"
14 #include "chrome/test/chromedriver/command_executor.h"
15 #include "chrome/test/chromedriver/command_names.h"
16 #include "chrome/test/chromedriver/server/http_response.h"
17 #include "chrome/test/chromedriver/util.h"
19 namespace {
21 const char kShutdownPath[] = "shutdown";
23 } // namespace
25 HttpRequest::HttpRequest(HttpMethod method,
26 const std::string& path,
27 const std::string& body)
28 : method(method), path(path), body(body) {}
30 HttpRequest::~HttpRequest() {}
32 CommandMapping::CommandMapping(HttpMethod method,
33 const std::string& path_pattern,
34 const std::string& name)
35 : method(method), path_pattern(path_pattern), name(name) {}
37 CommandMapping::~CommandMapping() {}
39 // static
40 scoped_ptr<HttpHandler::CommandMap> HttpHandler::CreateCommandMap() {
41 CommandMapping commands[] = {
42 CommandMapping(kPost, "session", CommandNames::kNewSession),
43 CommandMapping(kGet, "session/:sessionId",
44 CommandNames::kGetSessionCapabilities),
45 CommandMapping(kDelete, "session/:sessionId", CommandNames::kQuit),
46 CommandMapping(kGet, "session/:sessionId/window_handle",
47 CommandNames::kGetCurrentWindowHandle),
48 CommandMapping(kGet, "session/:sessionId/window_handles",
49 CommandNames::kGetWindowHandles),
50 CommandMapping(kPost, "session/:sessionId/url", CommandNames::kGet),
51 CommandMapping(kGet, "session/:sessionId/alert", CommandNames::kGetAlert),
52 CommandMapping(kPost, "session/:sessionId/dismiss_alert",
53 CommandNames::kDismissAlert),
54 CommandMapping(kPost, "session/:sessionId/accept_alert",
55 CommandNames::kAcceptAlert),
56 CommandMapping(kGet, "session/:sessionId/alert_text",
57 CommandNames::kGetAlertText),
58 CommandMapping(kPost, "session/:sessionId/alert_text",
59 CommandNames::kSetAlertValue),
60 CommandMapping(kPost, "session/:sessionId/forward",
61 CommandNames::kGoForward),
62 CommandMapping(kPost, "session/:sessionId/back", CommandNames::kGoBack),
63 CommandMapping(kPost, "session/:sessionId/refresh",
64 CommandNames::kRefresh),
65 CommandMapping(kPost, "session/:sessionId/execute",
66 CommandNames::kExecuteScript),
67 CommandMapping(kPost, "session/:sessionId/execute_async",
68 CommandNames::kExecuteAsyncScript),
69 CommandMapping(kGet, "session/:sessionId/url",
70 CommandNames::kGetCurrentUrl),
71 CommandMapping(kGet, "session/:sessionId/title", CommandNames::kGetTitle),
72 CommandMapping(kGet, "session/:sessionId/source",
73 CommandNames::kGetPageSource),
74 CommandMapping(kGet, "session/:sessionId/screenshot",
75 CommandNames::kScreenshot),
76 CommandMapping(kPost, "session/:sessionId/visible",
77 CommandNames::kSetBrowserVisible),
78 CommandMapping(kGet, "session/:sessionId/visible",
79 CommandNames::kIsBrowserVisible),
80 CommandMapping(kPost, "session/:sessionId/element",
81 CommandNames::kFindElement),
82 CommandMapping(kPost, "session/:sessionId/elements",
83 CommandNames::kFindElements),
84 CommandMapping(kPost, "session/:sessionId/element/active",
85 CommandNames::kGetActiveElement),
86 CommandMapping(kPost, "session/:sessionId/element/:id/element",
87 CommandNames::kFindChildElement),
88 CommandMapping(kPost, "session/:sessionId/element/:id/elements",
89 CommandNames::kFindChildElements),
90 CommandMapping(kPost, "session/:sessionId/element/:id/click",
91 CommandNames::kClickElement),
92 CommandMapping(kPost, "session/:sessionId/element/:id/clear",
93 CommandNames::kClearElement),
94 CommandMapping(kPost, "session/:sessionId/element/:id/submit",
95 CommandNames::kSubmitElement),
96 CommandMapping(kGet, "session/:sessionId/element/:id/text",
97 CommandNames::kGetElementText),
98 CommandMapping(kPost, "session/:sessionId/element/:id/value",
99 CommandNames::kSendKeysToElement),
100 CommandMapping(kPost, "session/:sessionId/file",
101 CommandNames::kUploadFile),
102 CommandMapping(kGet, "session/:sessionId/element/:id/value",
103 CommandNames::kGetElementValue),
104 CommandMapping(kGet, "session/:sessionId/element/:id/name",
105 CommandNames::kGetElementTagName),
106 CommandMapping(kGet, "session/:sessionId/element/:id/selected",
107 CommandNames::kIsElementSelected),
108 CommandMapping(kGet, "session/:sessionId/element/:id/enabled",
109 CommandNames::kIsElementEnabled),
110 CommandMapping(kGet, "session/:sessionId/element/:id/displayed",
111 CommandNames::kIsElementDisplayed),
112 CommandMapping(kPost, "session/:sessionId/element/:id/hover",
113 CommandNames::kHoverOverElement),
114 CommandMapping(kGet, "session/:sessionId/element/:id/location",
115 CommandNames::kGetElementLocation),
116 CommandMapping(kGet, "session/:sessionId/element/:id/location_in_view",
117 CommandNames::kGetElementLocationOnceScrolledIntoView),
118 CommandMapping(kGet, "session/:sessionId/element/:id/size",
119 CommandNames::kGetElementSize),
120 CommandMapping(kGet, "session/:sessionId/element/:id/attribute/:name",
121 CommandNames::kGetElementAttribute),
122 CommandMapping(kGet, "session/:sessionId/element/:id/equals/:other",
123 CommandNames::kElementEquals),
124 CommandMapping(kGet, "session/:sessionId/cookie",
125 CommandNames::kGetCookies),
126 CommandMapping(kPost, "session/:sessionId/cookie",
127 CommandNames::kAddCookie),
128 CommandMapping(kDelete, "session/:sessionId/cookie",
129 CommandNames::kDeleteAllCookies),
130 CommandMapping(kDelete, "session/:sessionId/cookie/:name",
131 CommandNames::kDeleteCookie),
132 CommandMapping(kPost, "session/:sessionId/frame",
133 CommandNames::kSwitchToFrame),
134 CommandMapping(kPost, "session/:sessionId/window",
135 CommandNames::kSwitchToWindow),
136 CommandMapping(kGet, "session/:sessionId/window/:windowHandle/size",
137 CommandNames::kGetWindowSize),
138 CommandMapping(kGet, "session/:sessionId/window/:windowHandle/position",
139 CommandNames::kGetWindowPosition),
140 CommandMapping(kPost, "session/:sessionId/window/:windowHandle/size",
141 CommandNames::kSetWindowSize),
142 CommandMapping(kPost, "session/:sessionId/window/:windowHandle/position",
143 CommandNames::kSetWindowPosition),
144 CommandMapping(kPost, "session/:sessionId/window/:windowHandle/maximize",
145 CommandNames::kMaximizeWindow),
146 CommandMapping(kDelete, "session/:sessionId/window",
147 CommandNames::kClose),
148 CommandMapping(kPost, "session/:sessionId/element/:id/drag",
149 CommandNames::kDragElement),
150 CommandMapping(kGet, "session/:sessionId/element/:id/css/:propertyName",
151 CommandNames::kGetElementValueOfCssProperty),
152 CommandMapping(kPost, "session/:sessionId/timeouts/implicit_wait",
153 CommandNames::kImplicitlyWait),
154 CommandMapping(kPost, "session/:sessionId/timeouts/async_script",
155 CommandNames::kSetScriptTimeout),
156 CommandMapping(kPost, "session/:sessionId/timeouts",
157 CommandNames::kSetTimeout),
158 CommandMapping(kPost, "session/:sessionId/execute_sql",
159 CommandNames::kExecuteSQL),
160 CommandMapping(kGet, "session/:sessionId/location",
161 CommandNames::kGetLocation),
162 CommandMapping(kPost, "session/:sessionId/location",
163 CommandNames::kSetLocation),
164 CommandMapping(kGet, "session/:sessionId/application_cache/status",
165 CommandNames::kGetStatus),
166 CommandMapping(kGet, "session/:sessionId/browser_connection",
167 CommandNames::kIsBrowserOnline),
168 CommandMapping(kPost, "session/:sessionId/browser_connection",
169 CommandNames::kSetBrowserOnline),
170 CommandMapping(kGet, "session/:sessionId/local_storage/key/:key",
171 CommandNames::kGetLocalStorageItem),
172 CommandMapping(kDelete, "session/:sessionId/local_storage/key/:key",
173 CommandNames::kRemoveLocalStorageItem),
174 CommandMapping(kGet, "session/:sessionId/local_storage",
175 CommandNames::kGetLocalStorageKeys),
176 CommandMapping(kPost, "session/:sessionId/local_storage",
177 CommandNames::kSetLocalStorageItem),
178 CommandMapping(kDelete, "session/:sessionId/local_storage",
179 CommandNames::kClearLocalStorage),
180 CommandMapping(kGet, "session/:sessionId/local_storage/size",
181 CommandNames::kGetLocalStorageSize),
182 CommandMapping(kGet, "session/:sessionId/session_storage/key/:key",
183 CommandNames::kGetSessionStorageItem),
184 CommandMapping(kDelete, "session/:sessionId/session_storage/key/:key",
185 CommandNames::kRemoveSessionStorageItem),
186 CommandMapping(kGet, "session/:sessionId/session_storage",
187 CommandNames::kGetSessionStorageKey),
188 CommandMapping(kPost, "session/:sessionId/session_storage",
189 CommandNames::kSetSessionStorageItem),
190 CommandMapping(kDelete, "session/:sessionId/session_storage",
191 CommandNames::kClearSessionStorage),
192 CommandMapping(kGet, "session/:sessionId/session_storage/size",
193 CommandNames::kGetSessionStorageSize),
194 CommandMapping(kGet, "session/:sessionId/orientation",
195 CommandNames::kGetScreenOrientation),
196 CommandMapping(kPost, "session/:sessionId/orientation",
197 CommandNames::kSetScreenOrientation),
198 CommandMapping(kPost, "session/:sessionId/click",
199 CommandNames::kMouseClick),
200 CommandMapping(kPost, "session/:sessionId/doubleclick",
201 CommandNames::kMouseDoubleClick),
202 CommandMapping(kPost, "session/:sessionId/buttondown",
203 CommandNames::kMouseButtonDown),
204 CommandMapping(kPost, "session/:sessionId/buttonup",
205 CommandNames::kMouseButtonUp),
206 CommandMapping(kPost, "session/:sessionId/moveto",
207 CommandNames::kMouseMoveTo),
208 CommandMapping(kPost, "session/:sessionId/keys",
209 CommandNames::kSendKeysToActiveElement),
210 CommandMapping(kGet, "session/:sessionId/ime/available_engines",
211 CommandNames::kImeGetAvailableEngines),
212 CommandMapping(kGet, "session/:sessionId/ime/active_engine",
213 CommandNames::kImeGetActiveEngine),
214 CommandMapping(kGet, "session/:sessionId/ime/activated",
215 CommandNames::kImeIsActivated),
216 CommandMapping(kPost, "session/:sessionId/ime/deactivate",
217 CommandNames::kImeDeactivate),
218 CommandMapping(kPost, "session/:sessionId/ime/activate",
219 CommandNames::kImeActivateEngine),
220 CommandMapping(kPost, "session/:sessionId/touch/click",
221 CommandNames::kTouchSingleTap),
222 CommandMapping(kPost, "session/:sessionId/touch/down",
223 CommandNames::kTouchDown),
224 CommandMapping(kPost, "session/:sessionId/touch/up",
225 CommandNames::kTouchUp),
226 CommandMapping(kPost, "session/:sessionId/touch/move",
227 CommandNames::kTouchMove),
228 CommandMapping(kPost, "session/:sessionId/touch/scroll",
229 CommandNames::kTouchScroll),
230 CommandMapping(kPost, "session/:sessionId/touch/doubleclick",
231 CommandNames::kTouchDoubleTap),
232 CommandMapping(kPost, "session/:sessionId/touch/longclick",
233 CommandNames::kTouchLongPress),
234 CommandMapping(kPost, "session/:sessionId/touch/flick",
235 CommandNames::kTouchFlick),
236 CommandMapping(kPost, "session/:sessionId/log", CommandNames::kGetLog),
237 CommandMapping(kGet, "session/:sessionId/log/types",
238 CommandNames::kGetAvailableLogTypes),
239 CommandMapping(kPost, "logs", CommandNames::kGetSessionLogs),
240 CommandMapping(kGet, "status", CommandNames::kStatus),
242 // Custom Chrome commands:
243 // Allow quit all to be called with GET or POST.
244 CommandMapping(kGet, kShutdownPath, CommandNames::kQuitAll),
245 CommandMapping(kPost, kShutdownPath, CommandNames::kQuitAll),
247 return scoped_ptr<CommandMap>(
248 new CommandMap(commands, commands + arraysize(commands)));
251 HttpHandler::HttpHandler(scoped_ptr<CommandExecutor> executor,
252 scoped_ptr<CommandMap> command_map,
253 const std::string& url_base)
254 : executor_(executor.Pass()),
255 command_map_(command_map.Pass()),
256 url_base_(url_base) {
257 executor_->Init();
260 HttpHandler::~HttpHandler() {}
262 void HttpHandler::Handle(const HttpRequest& request,
263 HttpResponse* response) {
264 std::string path = request.path;
265 if (!StartsWithASCII(path, url_base_, true)) {
266 *response = HttpResponse(HttpResponse::kBadRequest);
267 response->set_body("unhandled request");
268 return;
271 path.erase(0, url_base_.length());
273 if (!HandleWebDriverCommand(request, path, response)) {
274 *response = HttpResponse(HttpResponse::kNotFound);
275 response->set_body("unknown command: " + path);
276 return;
280 bool HttpHandler::ShouldShutdown(const HttpRequest& request) {
281 return request.path == url_base_ + kShutdownPath;
284 bool HttpHandler::HandleWebDriverCommand(
285 const HttpRequest& request,
286 const std::string& trimmed_path,
287 HttpResponse* response) {
288 base::DictionaryValue params;
289 std::string session_id;
290 CommandMap::const_iterator iter = command_map_->begin();
291 while (true) {
292 if (iter == command_map_->end()) {
293 return false;
295 if (internal::MatchesCommand(
296 request.method, trimmed_path, *iter, &session_id, &params)) {
297 break;
299 ++iter;
302 if (request.method == kPost && request.body.length()) {
303 base::DictionaryValue* body_params;
304 scoped_ptr<base::Value> parsed_body(base::JSONReader::Read(request.body));
305 if (!parsed_body || !parsed_body->GetAsDictionary(&body_params)) {
306 *response = HttpResponse(HttpResponse::kBadRequest);
307 response->set_body("missing command parameters");
308 return true;
310 params.MergeDictionary(body_params);
313 StatusCode status = kOk;
314 scoped_ptr<base::Value> value;
315 std::string out_session_id;
316 executor_->ExecuteCommand(
317 iter->name, params, session_id, &status, &value, &out_session_id);
319 if (status == kUnknownCommand) {
320 *response = HttpResponse(HttpResponse::kNotImplemented);
321 response->set_body("unimplemented command: " + iter->name);
322 return true;
325 if (iter->name == CommandNames::kNewSession && status == kOk) {
326 // Creating a session involves a HTTP request to /session, which is
327 // supposed to redirect to /session/:sessionId, which returns the
328 // session info.
329 *response = HttpResponse(HttpResponse::kSeeOther);
330 response->AddHeader("Location", url_base_ + "session/" + out_session_id);
331 return true;
334 base::DictionaryValue body_params;
335 body_params.SetInteger("status", status);
336 body_params.Set("value", value.release());
337 body_params.SetString("sessionId", out_session_id);
338 std::string body;
339 base::JSONWriter::WriteWithOptions(
340 &body_params, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
341 &body);
342 *response = HttpResponse(HttpResponse::kOk);
343 response->SetMimeType("application/json; charset=utf-8");
344 response->set_body(body);
345 return true;
348 namespace internal {
350 bool MatchesCommand(HttpMethod method,
351 const std::string& path,
352 const CommandMapping& command,
353 std::string* session_id,
354 base::DictionaryValue* out_params) {
355 if (method != command.method)
356 return false;
358 std::vector<std::string> path_parts;
359 base::SplitString(path, '/', &path_parts);
360 std::vector<std::string> command_path_parts;
361 base::SplitString(command.path_pattern, '/', &command_path_parts);
362 if (path_parts.size() != command_path_parts.size())
363 return false;
365 base::DictionaryValue params;
366 for (size_t i = 0; i < path_parts.size(); ++i) {
367 CHECK(command_path_parts[i].length());
368 if (command_path_parts[i][0] == ':') {
369 std::string name = command_path_parts[i];
370 name.erase(0, 1);
371 CHECK(name.length());
372 if (name == "sessionId")
373 *session_id = path_parts[i];
374 else
375 params.SetString(name, path_parts[i]);
376 } else if (command_path_parts[i] != path_parts[i]) {
377 return false;
380 out_params->MergeDictionary(&params);
381 return true;
384 } // namespace