1/*
2 * Copyright (C) 2017 Igalia S.L.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "CommandResult.h"
28
29namespace WebDriver {
30
31// These error codes are specified in JSON-RPC 2.0, Section 5.1.
32enum ProtocolErrorCode {
33 ParseError = -32700,
34 InvalidRequest = -32600,
35 MethodNotFound = -32601,
36 InvalidParams = -32602,
37 InternalError = -32603,
38 ServerError = -32000
39};
40
41CommandResult::CommandResult(RefPtr<JSON::Value>&& result, Optional<ErrorCode> errorCode)
42 : m_errorCode(errorCode)
43{
44 if (!m_errorCode) {
45 m_result = WTFMove(result);
46 return;
47 }
48
49 if (!result)
50 return;
51
52 RefPtr<JSON::Object> errorObject;
53 if (!result->asObject(errorObject))
54 return;
55
56 int error;
57 if (!errorObject->getInteger("code", error))
58 return;
59 String errorMessage;
60 if (!errorObject->getString("message", errorMessage))
61 return;
62
63 switch (error) {
64 case ProtocolErrorCode::ParseError:
65 case ProtocolErrorCode::InvalidRequest:
66 case ProtocolErrorCode::MethodNotFound:
67 case ProtocolErrorCode::InvalidParams:
68 case ProtocolErrorCode::InternalError:
69 m_errorCode = ErrorCode::UnknownError;
70 m_errorMessage = errorMessage;
71 break;
72 case ProtocolErrorCode::ServerError: {
73 String errorName;
74 auto position = errorMessage.find(';');
75 if (position != notFound) {
76 errorName = errorMessage.substring(0, position);
77 m_errorMessage = errorMessage.substring(position + 1);
78 } else
79 errorName = errorMessage;
80
81 if (errorName == "WindowNotFound")
82 m_errorCode = ErrorCode::NoSuchWindow;
83 else if (errorName == "FrameNotFound")
84 m_errorCode = ErrorCode::NoSuchFrame;
85 else if (errorName == "NotImplemented")
86 m_errorCode = ErrorCode::UnsupportedOperation;
87 else if (errorName == "ElementNotInteractable")
88 m_errorCode = ErrorCode::ElementNotInteractable;
89 else if (errorName == "JavaScriptError")
90 m_errorCode = ErrorCode::JavascriptError;
91 else if (errorName == "JavaScriptTimeout")
92 m_errorCode = ErrorCode::ScriptTimeout;
93 else if (errorName == "NodeNotFound")
94 m_errorCode = ErrorCode::StaleElementReference;
95 else if (errorName == "MissingParameter" || errorName == "InvalidParameter")
96 m_errorCode = ErrorCode::InvalidArgument;
97 else if (errorName == "InvalidElementState")
98 m_errorCode = ErrorCode::InvalidElementState;
99 else if (errorName == "InvalidSelector")
100 m_errorCode = ErrorCode::InvalidSelector;
101 else if (errorName == "Timeout")
102 m_errorCode = ErrorCode::Timeout;
103 else if (errorName == "NoJavaScriptDialog")
104 m_errorCode = ErrorCode::NoSuchAlert;
105 else if (errorName == "ElementNotSelectable")
106 m_errorCode = ErrorCode::ElementNotSelectable;
107 else if (errorName == "ScreenshotError")
108 m_errorCode = ErrorCode::UnableToCaptureScreen;
109 else if (errorName == "UnexpectedAlertOpen")
110 m_errorCode = ErrorCode::UnexpectedAlertOpen;
111 else if (errorName == "TargetOutOfBounds")
112 m_errorCode = ErrorCode::MoveTargetOutOfBounds;
113
114 break;
115 }
116 }
117}
118
119CommandResult::CommandResult(ErrorCode errorCode, Optional<String> errorMessage)
120 : m_errorCode(errorCode)
121 , m_errorMessage(errorMessage)
122{
123}
124
125unsigned CommandResult::httpStatusCode() const
126{
127 if (!m_errorCode)
128 return 200;
129
130 // ยง6.6 Handling Errors.
131 // https://www.w3.org/TR/webdriver/#handling-errors
132 switch (m_errorCode.value()) {
133 case ErrorCode::ElementClickIntercepted:
134 case ErrorCode::ElementNotSelectable:
135 case ErrorCode::ElementNotInteractable:
136 case ErrorCode::InvalidArgument:
137 case ErrorCode::InvalidElementState:
138 case ErrorCode::InvalidSelector:
139 return 400;
140 case ErrorCode::NoSuchAlert:
141 case ErrorCode::NoSuchCookie:
142 case ErrorCode::NoSuchElement:
143 case ErrorCode::NoSuchFrame:
144 case ErrorCode::NoSuchWindow:
145 case ErrorCode::StaleElementReference:
146 case ErrorCode::InvalidSessionID:
147 case ErrorCode::UnknownCommand:
148 return 404;
149 case ErrorCode::ScriptTimeout:
150 case ErrorCode::Timeout:
151 return 408;
152 case ErrorCode::JavascriptError:
153 case ErrorCode::MoveTargetOutOfBounds:
154 case ErrorCode::SessionNotCreated:
155 case ErrorCode::UnableToCaptureScreen:
156 case ErrorCode::UnexpectedAlertOpen:
157 case ErrorCode::UnknownError:
158 case ErrorCode::UnsupportedOperation:
159 return 500;
160 }
161
162 ASSERT_NOT_REACHED();
163 return 200;
164}
165
166String CommandResult::errorString() const
167{
168 ASSERT(isError());
169
170 switch (m_errorCode.value()) {
171 case ErrorCode::ElementClickIntercepted:
172 return "element click intercepted"_s;
173 case ErrorCode::ElementNotSelectable:
174 return "element not selectable"_s;
175 case ErrorCode::ElementNotInteractable:
176 return "element not interactable"_s;
177 case ErrorCode::InvalidArgument:
178 return "invalid argument"_s;
179 case ErrorCode::InvalidElementState:
180 return "invalid element state"_s;
181 case ErrorCode::InvalidSelector:
182 return "invalid selector"_s;
183 case ErrorCode::InvalidSessionID:
184 return "invalid session id"_s;
185 case ErrorCode::JavascriptError:
186 return "javascript error"_s;
187 case ErrorCode::NoSuchAlert:
188 return "no such alert"_s;
189 case ErrorCode::NoSuchCookie:
190 return "no such cookie"_s;
191 case ErrorCode::NoSuchElement:
192 return "no such element"_s;
193 case ErrorCode::NoSuchFrame:
194 return "no such frame"_s;
195 case ErrorCode::NoSuchWindow:
196 return "no such window"_s;
197 case ErrorCode::ScriptTimeout:
198 return "script timeout"_s;
199 case ErrorCode::SessionNotCreated:
200 return "session not created"_s;
201 case ErrorCode::StaleElementReference:
202 return "stale element reference"_s;
203 case ErrorCode::Timeout:
204 return "timeout"_s;
205 case ErrorCode::UnableToCaptureScreen:
206 return "unable to capture screen"_s;
207 case ErrorCode::MoveTargetOutOfBounds:
208 return "move target out of bounds"_s;
209 case ErrorCode::UnexpectedAlertOpen:
210 return "unexpected alert open"_s;
211 case ErrorCode::UnknownCommand:
212 return "unknown command"_s;
213 case ErrorCode::UnknownError:
214 return "unknown error"_s;
215 case ErrorCode::UnsupportedOperation:
216 return "unsupported operation"_s;
217 }
218
219 ASSERT_NOT_REACHED();
220 return emptyString();
221}
222
223} // namespace WebDriver
224