633b8995bbaba202c7f5a372fa6f78c08a94300b
[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 == "JavaScriptError")
92             m_errorCode = ErrorCode::JavascriptError;
93         else if (errorName == "JavaScriptTimeout")
94             m_errorCode = ErrorCode::ScriptTimeout;
95         else if (errorName == "NodeNotFound")
96             m_errorCode = ErrorCode::StaleElementReference;
97         else if (errorName == "MissingParameter" || errorName == "InvalidParameter")
98             m_errorCode = ErrorCode::InvalidArgument;
99         else if (errorName == "InvalidElementState")
100             m_errorCode = ErrorCode::InvalidElementState;
101         else if (errorName == "InvalidSelector")
102             m_errorCode = ErrorCode::InvalidSelector;
103         else if (errorName == "Timeout")
104             m_errorCode = ErrorCode::Timeout;
105
106         break;
107     }
108     }
109 }
110
111 CommandResult::CommandResult(ErrorCode errorCode, std::optional<String> errorMessage)
112     : m_errorCode(errorCode)
113     , m_errorMessage(errorMessage)
114 {
115 }
116
117 unsigned CommandResult::httpStatusCode() const
118 {
119     if (!m_errorCode)
120         return 200;
121
122     // ยง6.6 Handling Errors.
123     // https://www.w3.org/TR/webdriver/#handling-errors
124     switch (m_errorCode.value()) {
125     case ErrorCode::ElementClickIntercepted:
126     case ErrorCode::ElementNotInteractable:
127     case ErrorCode::InvalidArgument:
128     case ErrorCode::InvalidElementState:
129     case ErrorCode::InvalidSelector:
130     case ErrorCode::NoSuchElement:
131     case ErrorCode::NoSuchFrame:
132     case ErrorCode::NoSuchWindow:
133     case ErrorCode::StaleElementReference:
134         return 400;
135     case ErrorCode::InvalidSessionID:
136     case ErrorCode::UnknownCommand:
137         return 404;
138     case ErrorCode::ScriptTimeout:
139     case ErrorCode::Timeout:
140         return 408;
141     case ErrorCode::JavascriptError:
142     case ErrorCode::SessionNotCreated:
143     case ErrorCode::UnknownError:
144     case ErrorCode::UnsupportedOperation:
145         return 500;
146     }
147
148     ASSERT_NOT_REACHED();
149     return 200;
150 }
151
152 String CommandResult::errorString() const
153 {
154     ASSERT(isError());
155
156     switch (m_errorCode.value()) {
157     case ErrorCode::ElementClickIntercepted:
158         return ASCIILiteral("element click intercepted");
159     case ErrorCode::ElementNotInteractable:
160         return ASCIILiteral("element not interactable");
161     case ErrorCode::InvalidArgument:
162         return ASCIILiteral("invalid argument");
163     case ErrorCode::InvalidElementState:
164         return ASCIILiteral("invalid element state");
165     case ErrorCode::InvalidSelector:
166         return ASCIILiteral("invalid selector");
167     case ErrorCode::InvalidSessionID:
168         return ASCIILiteral("invalid session id");
169     case ErrorCode::JavascriptError:
170         return ASCIILiteral("javascript error");
171     case ErrorCode::NoSuchElement:
172         return ASCIILiteral("no such element");
173     case ErrorCode::NoSuchFrame:
174         return ASCIILiteral("no such frame");
175     case ErrorCode::NoSuchWindow:
176         return ASCIILiteral("no such window");
177     case ErrorCode::ScriptTimeout:
178         return ASCIILiteral("script timeout");
179     case ErrorCode::SessionNotCreated:
180         return ASCIILiteral("session not created");
181     case ErrorCode::StaleElementReference:
182         return ASCIILiteral("stale element reference");
183     case ErrorCode::Timeout:
184         return ASCIILiteral("timeout");
185     case ErrorCode::UnknownCommand:
186         return ASCIILiteral("unknown command");
187     case ErrorCode::UnknownError:
188         return ASCIILiteral("unknown error");
189     case ErrorCode::UnsupportedOperation:
190         return ASCIILiteral("unsupported operation");
191     }
192
193     ASSERT_NOT_REACHED();
194     return emptyString();
195 }
196
197 } // namespace WebDriver