Security update for permissions_by_term
[yaffs-website] / vendor / instaclick / php-webdriver / lib / WebDriver / AbstractWebDriver.php
1 <?php
2 /**
3  * Copyright 2004-2017 Facebook. All Rights Reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * @package WebDriver
18  *
19  * @author Justin Bishop <jubishop@gmail.com>
20  * @author Anthon Pang <apang@softwaredevelopment.ca>
21  * @author Fabrizio Branca <mail@fabrizio-branca.de>
22  * @author Tsz Ming Wong <tszming@gmail.com>
23  */
24
25 namespace WebDriver;
26
27 use WebDriver\Exception as WebDriverException;
28
29 /**
30  * Abstract WebDriver\AbstractWebDriver class
31  *
32  * @package WebDriver
33  */
34 abstract class AbstractWebDriver
35 {
36     /**
37      * URL
38      *
39      * @var string
40      */
41     protected $url;
42
43     /**
44      * Return array of supported method names and corresponding HTTP request methods
45      *
46      * @return array
47      */
48     abstract protected function methods();
49
50     /**
51      * Return array of obsolete method names and corresponding HTTP request methods
52      *
53      * @return array
54      */
55     protected function obsoleteMethods()
56     {
57         return array();
58     }
59
60     /**
61      * Constructor
62      *
63      * @param string $url URL to Selenium server
64      */
65     public function __construct($url = 'http://localhost:4444/wd/hub')
66     {
67         $this->url = $url;
68     }
69
70     /**
71      * Magic method which returns URL to Selenium server
72      *
73      * @return string
74      */
75     public function __toString()
76     {
77         return $this->url;
78     }
79
80     /**
81      * Returns URL to Selenium server
82      *
83      * @return string
84      */
85     public function getURL()
86     {
87         return $this->url;
88     }
89
90     /**
91      * Curl request to webdriver server.
92      *
93      * @param string $requestMethod HTTP request method, e.g., 'GET', 'POST', or 'DELETE'
94      * @param string $command       If not defined in methods() this function will throw.
95      * @param array  $parameters    If an array(), they will be posted as JSON parameters
96      *                              If a number or string, "/$params" is appended to url
97      * @param array  $extraOptions  key=>value pairs of curl options to pass to curl_setopt()
98      *
99      * @return array array('value' => ..., 'info' => ...)
100      *
101      * @throws \WebDriver\Exception if error
102      */
103     protected function curl($requestMethod, $command, $parameters = null, $extraOptions = array())
104     {
105         if ($parameters && is_array($parameters) && $requestMethod !== 'POST') {
106             throw WebDriverException::factory(
107                 WebDriverException::NO_PARAMETERS_EXPECTED,
108                 sprintf(
109                     'The http request method called for %s is %s but it has to be POST if you want to pass the JSON parameters %s',
110                     $command,
111                     $requestMethod,
112                     json_encode($parameters)
113                 )
114             );
115         }
116
117         $url = sprintf('%s%s', $this->url, $command);
118
119         if ($parameters && (is_int($parameters) || is_string($parameters))) {
120             $url .= '/' . $parameters;
121         }
122
123         list($rawResult, $info) = ServiceFactory::getInstance()->getService('service.curl')->execute($requestMethod, $url, $parameters, $extraOptions);
124
125         $httpCode = $info['http_code'];
126
127         // According to https://w3c.github.io/webdriver/webdriver-spec.html all 4xx responses are to be considered
128         // an error and return plaintext, while 5xx responses are json encoded
129         if ($httpCode >= 400 && $httpCode <= 499) {
130             throw WebDriverException::factory(
131                 WebDriverException::CURL_EXEC,
132                 'Webdriver http error: ' . $httpCode . ', payload :' . substr($rawResult, 0, 1000)
133             );
134         }
135
136         $result = json_decode($rawResult, true);
137
138         if (!empty($rawResult) && $result === null && json_last_error() != JSON_ERROR_NONE) {
139             throw WebDriverException::factory(
140                 WebDriverException::CURL_EXEC,
141                 'Payload received from webdriver is not valid json: ' . substr($rawResult, 0, 1000)
142             );
143         }
144
145         if (is_array($result) && !array_key_exists('status', $result)) {
146             throw WebDriverException::factory(
147                 WebDriverException::CURL_EXEC,
148                 'Payload received from webdriver is valid but unexpected json: ' . substr($rawResult, 0, 1000)
149             );
150         }
151
152         $value   = (is_array($result) && array_key_exists('value', $result)) ? $result['value'] : null;
153         $message = (is_array($value) && array_key_exists('message', $value)) ? $value['message'] : null;
154
155         // if not success, throw exception
156         if ((int) $result['status'] !== 0) {
157             throw WebDriverException::factory($result['status'], $message);
158         }
159
160         $sessionId = isset($result['sessionId'])
161            ? $result['sessionId']
162            : (isset($value['webdriver.remote.sessionid'])
163                ? $value['webdriver.remote.sessionid']
164                : null
165            );
166
167         return array(
168             'value'      => $value,
169             'info'       => $info,
170             'sessionId'  => $sessionId,
171             'sessionUrl' => $sessionId ? $this->url . '/session/' . $sessionId : $info['url'],
172         );
173     }
174
175     /**
176      * Magic method that maps calls to class methods to execute WebDriver commands
177      *
178      * @param string $name      Method name
179      * @param array  $arguments Arguments
180      *
181      * @return mixed
182      *
183      * @throws \WebDriver\Exception if invalid WebDriver command
184      */
185     public function __call($name, $arguments)
186     {
187         if (count($arguments) > 1) {
188             throw WebDriverException::factory(
189                 WebDriverException::JSON_PARAMETERS_EXPECTED,
190                 'Commands should have at most only one parameter, which should be the JSON Parameter object'
191             );
192         }
193
194         if (preg_match('/^(get|post|delete)/', $name, $matches)) {
195             $requestMethod = strtoupper($matches[0]);
196             $webdriverCommand = strtolower(substr($name, strlen($requestMethod)));
197         } else {
198             $webdriverCommand = $name;
199             $requestMethod = $this->getRequestMethod($webdriverCommand);
200         }
201
202         $methods = $this->methods();
203
204         if (!in_array($requestMethod, (array) $methods[$webdriverCommand])) {
205             throw WebDriverException::factory(
206                 WebDriverException::INVALID_REQUEST,
207                 sprintf(
208                     '%s is not an available http request method for the command %s.',
209                     $requestMethod,
210                     $webdriverCommand
211                 )
212             );
213         }
214
215         $result = $this->curl(
216             $requestMethod,
217             '/' . $webdriverCommand,
218             array_shift($arguments)
219         );
220
221         return $result['value'];
222     }
223
224     /**
225      * Get default HTTP request method for a given WebDriver command
226      *
227      * @param string $webdriverCommand
228      *
229      * @return string
230      *
231      * @throws \WebDriver\Exception if invalid WebDriver command
232      */
233     private function getRequestMethod($webdriverCommand)
234     {
235         if (!array_key_exists($webdriverCommand, $this->methods())) {
236             throw WebDriverException::factory(
237                 array_key_exists($webdriverCommand, $this->obsoleteMethods())
238                 ? WebDriverException::OBSOLETE_COMMAND : WebDriverException::UNKNOWN_COMMAND,
239                 sprintf('%s is not a valid WebDriver command.', $webdriverCommand)
240             );
241         }
242
243         $methods = $this->methods();
244         $requestMethods = (array) $methods[$webdriverCommand];
245
246         return array_shift($requestMethods);
247     }
248 }