be8c8176a66bd740ecd574d2ec214c03ab55ff10
[WebKit-https.git] / Source / WebDriver / CommandResult.cpp
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 #include <inspector/InspectorValues.h>
30
31 using namespace Inspector;
32
33 namespace WebDriver {
34
35 // These error codes are specified in JSON-RPC 2.0, Section 5.1.
36 enum ProtocolErrorCode {
37     ParseError = -32700,
38     InvalidRequest = -32600,
39     MethodNotFound = -32601,
40     InvalidParams = -32602,
41     InternalError = -32603,
42     ServerError = -32000
43 };
44
45 CommandResult::CommandResult(RefPtr<InspectorValue>&& result, std::optional<ErrorCode> errorCode)
46     : m_errorCode(errorCode)
47 {
48     if (!m_errorCode) {
49         m_result = WTFMove(result);
50         return;
51     }
52
53     if (!result)
54         return;
55
56     RefPtr<InspectorObject> errorObject;
57     if (!result->asObject(errorObject))
58         return;
59
60     int error;
61     if (!errorObject->getInteger("code", error))
62         return;
63     String errorMessage;
64     if (!errorObject->getString("message", errorMessage))
65         return;
66
67     switch (error) {
68     case ProtocolErrorCode::ParseError:
69     case ProtocolErrorCode::InvalidRequest:
70     case ProtocolErrorCode::MethodNotFound:
71     case ProtocolErrorCode::InvalidParams:
72     case ProtocolErrorCode::InternalError:
73         m_errorCode = ErrorCode::UnknownError;
74         m_errorMessage = errorMessage;
75         break;
76     case ProtocolErrorCode::ServerError: {
77         String errorName;
78         auto position = errorMessage.find(';');
79         if (position != notFound) {
80             errorName = errorMessage.substring(0, position);
81             m_errorMessage = errorMessage.substring(position + 1);
82         } else
83             errorName = errorMessage;
84
85         if (errorName == "WindowNotFound")
86             m_errorCode = ErrorCode::NoSuchWindow;
87         else if (errorName == "FrameNotFound")
88             m_errorCode = ErrorCode::NoSuchFrame;
89         else if (errorName == "NotImplemented")
90             m_errorCode = ErrorCode::UnsupportedOperation;
91         else if (errorName == "ElementNotInteractable")
92             m_errorCode = ErrorCode::ElementNotInteractable;
93         else if (errorName == "JavaScriptError")
94             m_errorCode = ErrorCode::JavascriptError;
95         else if (errorName == "JavaScriptTimeout")
96             m_errorCode = ErrorCode::ScriptTimeout;
97         else if (errorName == "NodeNotFound")
98             m_errorCode = ErrorCode::StaleElementReference;
99         else if (errorName == "MissingParameter" || errorName == "InvalidParameter")
100             m_errorCode = ErrorCode::InvalidArgument;
101         else if (errorName == "InvalidElementState")
102             m_errorCode = ErrorCode::InvalidElementState;
103         else if (errorName == "InvalidSelector")
104             m_errorCode = ErrorCode::InvalidSelector;
105         else if (errorName == "Timeout")
106             m_errorCode = ErrorCode::Timeout;
107         else if (errorName == "NoJavaScriptDialog")
108             m_errorCode = ErrorCode::NoSuchAlert;
109
110         break;
111     }
112     }
113 }
114
115 CommandResult::CommandResult(ErrorCode errorCode, std::optional<String> errorMessage)
116     : m_errorCode(errorCode)
117     , m_errorMessage(errorMessage)
118 {
119 }
120
121 unsigned CommandResult::httpStatusCode() const
122 {
123     if (!m_errorCode)
124         return 200;
125
126     // ยง6.6 Handling Errors.
127     // https://www.w3.org/TR/webdriver/#handling-errors
128     switch (m_errorCode.value()) {
129     case ErrorCode::ElementClickIntercepted:
130     case ErrorCode::ElementNotInteractable:
131     case ErrorCode::InvalidArgument:
132     case ErrorCode::InvalidElementState:
133     case ErrorCode::InvalidSelector:
134     case ErrorCode::NoSuchAlert:
135     case ErrorCode::NoSuchElement:
136     case ErrorCode::NoSuchFrame:
137     case ErrorCode::NoSuchWindow:
138     case ErrorCode::StaleElementReference:
139         return 400;
140     case ErrorCode::InvalidSessionID:
141     case ErrorCode::UnknownCommand:
142         return 404;
143     case ErrorCode::ScriptTimeout:
144     case ErrorCode::Timeout:
145         return 408;
146     case ErrorCode::JavascriptError:
147     case ErrorCode::SessionNotCreated:
148     case ErrorCode::UnexpectedAlertOpen:
149     case ErrorCode::UnknownError:
150     case ErrorCode::UnsupportedOperation:
151         return 500;
152     }
153
154     ASSERT_NOT_REACHED();
155     return 200;
156 }
157
158 String CommandResult::errorString() const
159 {
160     ASSERT(isError());
161
162     switch (m_errorCode.value()) {
163     case ErrorCode::ElementClickIntercepted:
164         return ASCIILiteral("element click intercepted");
165     case ErrorCode::ElementNotInteractable:
166         return ASCIILiteral("element not interactable");
167     case ErrorCode::InvalidArgument:
168         return ASCIILiteral("invalid argument");
169     case ErrorCode::InvalidElementState:
170         return ASCIILiteral("invalid element state");
171     case ErrorCode::InvalidSelector:
172         return ASCIILiteral("invalid selector");
173     case ErrorCode::InvalidSessionID:
174         return ASCIILiteral("invalid session id");
175     case ErrorCode::JavascriptError:
176         return ASCIILiteral("javascript error");
177     case ErrorCode::NoSuchAlert:
178         return ASCIILiteral("no such alert");
179     case ErrorCode::NoSuchElement:
180         return ASCIILiteral("no such element");
181     case ErrorCode::NoSuchFrame:
182         return ASCIILiteral("no such frame");
183     case ErrorCode::NoSuchWindow:
184         return ASCIILiteral("no such window");
185     case ErrorCode::ScriptTimeout:
186         return ASCIILiteral("script timeout");
187     case ErrorCode::SessionNotCreated:
188         return ASCIILiteral("session not created");
189     case ErrorCode::StaleElementReference:
190         return ASCIILiteral("stale element reference");
191     case ErrorCode::Timeout:
192         return ASCIILiteral("timeout");
193     case ErrorCode::UnexpectedAlertOpen:
194         return ASCIILiteral("unexpected alert open");
195     case ErrorCode::UnknownCommand:
196         return ASCIILiteral("unknown command");
197     case ErrorCode::UnknownError:
198         return ASCIILiteral("unknown error");
199     case ErrorCode::UnsupportedOperation:
200         return ASCIILiteral("unsupported operation");
201     }
202
203     ASSERT_NOT_REACHED();
204     return emptyString();
205 }
206
207 } // namespace WebDriver