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 | |
29 | namespace WebDriver { |
30 | |
31 | // These error codes are specified in JSON-RPC 2.0, Section 5.1. |
32 | enum ProtocolErrorCode { |
33 | ParseError = -32700, |
34 | InvalidRequest = -32600, |
35 | MethodNotFound = -32601, |
36 | InvalidParams = -32602, |
37 | InternalError = -32603, |
38 | ServerError = -32000 |
39 | }; |
40 | |
41 | CommandResult::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 | |
119 | CommandResult::CommandResult(ErrorCode errorCode, Optional<String> errorMessage) |
120 | : m_errorCode(errorCode) |
121 | , m_errorMessage(errorMessage) |
122 | { |
123 | } |
124 | |
125 | unsigned 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 | |
166 | String 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 | |