1*04fd306cSNickeau<?php 2*04fd306cSNickeau 3*04fd306cSNickeaunamespace Facebook\WebDriver\Remote; 4*04fd306cSNickeau 5*04fd306cSNickeauuse BadMethodCallException; 6*04fd306cSNickeauuse Facebook\WebDriver\Exception\WebDriverCurlException; 7*04fd306cSNickeauuse Facebook\WebDriver\Exception\WebDriverException; 8*04fd306cSNickeauuse Facebook\WebDriver\WebDriverCommandExecutor; 9*04fd306cSNickeauuse InvalidArgumentException; 10*04fd306cSNickeau 11*04fd306cSNickeau/** 12*04fd306cSNickeau * Command executor talking to the standalone server via HTTP. 13*04fd306cSNickeau */ 14*04fd306cSNickeauclass HttpCommandExecutor implements WebDriverCommandExecutor 15*04fd306cSNickeau{ 16*04fd306cSNickeau const DEFAULT_HTTP_HEADERS = [ 17*04fd306cSNickeau 'Content-Type: application/json;charset=UTF-8', 18*04fd306cSNickeau 'Accept: application/json', 19*04fd306cSNickeau ]; 20*04fd306cSNickeau 21*04fd306cSNickeau /** 22*04fd306cSNickeau * @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#command-reference 23*04fd306cSNickeau */ 24*04fd306cSNickeau protected static $commands = [ 25*04fd306cSNickeau DriverCommand::ACCEPT_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/accept_alert'], 26*04fd306cSNickeau DriverCommand::ADD_COOKIE => ['method' => 'POST', 'url' => '/session/:sessionId/cookie'], 27*04fd306cSNickeau DriverCommand::CLEAR_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/clear'], 28*04fd306cSNickeau DriverCommand::CLICK_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/click'], 29*04fd306cSNickeau DriverCommand::CLOSE => ['method' => 'DELETE', 'url' => '/session/:sessionId/window'], 30*04fd306cSNickeau DriverCommand::DELETE_ALL_COOKIES => ['method' => 'DELETE', 'url' => '/session/:sessionId/cookie'], 31*04fd306cSNickeau DriverCommand::DELETE_COOKIE => ['method' => 'DELETE', 'url' => '/session/:sessionId/cookie/:name'], 32*04fd306cSNickeau DriverCommand::DISMISS_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/dismiss_alert'], 33*04fd306cSNickeau DriverCommand::ELEMENT_EQUALS => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/equals/:other'], 34*04fd306cSNickeau DriverCommand::FIND_CHILD_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/element'], 35*04fd306cSNickeau DriverCommand::FIND_CHILD_ELEMENTS => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/elements'], 36*04fd306cSNickeau DriverCommand::EXECUTE_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute'], 37*04fd306cSNickeau DriverCommand::EXECUTE_ASYNC_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute_async'], 38*04fd306cSNickeau DriverCommand::FIND_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element'], 39*04fd306cSNickeau DriverCommand::FIND_ELEMENTS => ['method' => 'POST', 'url' => '/session/:sessionId/elements'], 40*04fd306cSNickeau DriverCommand::SWITCH_TO_FRAME => ['method' => 'POST', 'url' => '/session/:sessionId/frame'], 41*04fd306cSNickeau DriverCommand::SWITCH_TO_PARENT_FRAME => ['method' => 'POST', 'url' => '/session/:sessionId/frame/parent'], 42*04fd306cSNickeau DriverCommand::SWITCH_TO_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window'], 43*04fd306cSNickeau DriverCommand::GET => ['method' => 'POST', 'url' => '/session/:sessionId/url'], 44*04fd306cSNickeau DriverCommand::GET_ACTIVE_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/active'], 45*04fd306cSNickeau DriverCommand::GET_ALERT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/alert_text'], 46*04fd306cSNickeau DriverCommand::GET_ALL_COOKIES => ['method' => 'GET', 'url' => '/session/:sessionId/cookie'], 47*04fd306cSNickeau DriverCommand::GET_NAMED_COOKIE => ['method' => 'GET', 'url' => '/session/:sessionId/cookie/:name'], 48*04fd306cSNickeau DriverCommand::GET_ALL_SESSIONS => ['method' => 'GET', 'url' => '/sessions'], 49*04fd306cSNickeau DriverCommand::GET_AVAILABLE_LOG_TYPES => ['method' => 'GET', 'url' => '/session/:sessionId/log/types'], 50*04fd306cSNickeau DriverCommand::GET_CURRENT_URL => ['method' => 'GET', 'url' => '/session/:sessionId/url'], 51*04fd306cSNickeau DriverCommand::GET_CURRENT_WINDOW_HANDLE => ['method' => 'GET', 'url' => '/session/:sessionId/window_handle'], 52*04fd306cSNickeau DriverCommand::GET_ELEMENT_ATTRIBUTE => [ 53*04fd306cSNickeau 'method' => 'GET', 54*04fd306cSNickeau 'url' => '/session/:sessionId/element/:id/attribute/:name', 55*04fd306cSNickeau ], 56*04fd306cSNickeau DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY => [ 57*04fd306cSNickeau 'method' => 'GET', 58*04fd306cSNickeau 'url' => '/session/:sessionId/element/:id/css/:propertyName', 59*04fd306cSNickeau ], 60*04fd306cSNickeau DriverCommand::GET_ELEMENT_LOCATION => [ 61*04fd306cSNickeau 'method' => 'GET', 62*04fd306cSNickeau 'url' => '/session/:sessionId/element/:id/location', 63*04fd306cSNickeau ], 64*04fd306cSNickeau DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW => [ 65*04fd306cSNickeau 'method' => 'GET', 66*04fd306cSNickeau 'url' => '/session/:sessionId/element/:id/location_in_view', 67*04fd306cSNickeau ], 68*04fd306cSNickeau DriverCommand::GET_ELEMENT_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/size'], 69*04fd306cSNickeau DriverCommand::GET_ELEMENT_TAG_NAME => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/name'], 70*04fd306cSNickeau DriverCommand::GET_ELEMENT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/text'], 71*04fd306cSNickeau DriverCommand::GET_LOG => ['method' => 'POST', 'url' => '/session/:sessionId/log'], 72*04fd306cSNickeau DriverCommand::GET_PAGE_SOURCE => ['method' => 'GET', 'url' => '/session/:sessionId/source'], 73*04fd306cSNickeau DriverCommand::GET_SCREEN_ORIENTATION => ['method' => 'GET', 'url' => '/session/:sessionId/orientation'], 74*04fd306cSNickeau DriverCommand::GET_CAPABILITIES => ['method' => 'GET', 'url' => '/session/:sessionId'], 75*04fd306cSNickeau DriverCommand::GET_TITLE => ['method' => 'GET', 'url' => '/session/:sessionId/title'], 76*04fd306cSNickeau DriverCommand::GET_WINDOW_HANDLES => ['method' => 'GET', 'url' => '/session/:sessionId/window_handles'], 77*04fd306cSNickeau DriverCommand::GET_WINDOW_POSITION => [ 78*04fd306cSNickeau 'method' => 'GET', 79*04fd306cSNickeau 'url' => '/session/:sessionId/window/:windowHandle/position', 80*04fd306cSNickeau ], 81*04fd306cSNickeau DriverCommand::GET_WINDOW_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/window/:windowHandle/size'], 82*04fd306cSNickeau DriverCommand::GO_BACK => ['method' => 'POST', 'url' => '/session/:sessionId/back'], 83*04fd306cSNickeau DriverCommand::GO_FORWARD => ['method' => 'POST', 'url' => '/session/:sessionId/forward'], 84*04fd306cSNickeau DriverCommand::IS_ELEMENT_DISPLAYED => [ 85*04fd306cSNickeau 'method' => 'GET', 86*04fd306cSNickeau 'url' => '/session/:sessionId/element/:id/displayed', 87*04fd306cSNickeau ], 88*04fd306cSNickeau DriverCommand::IS_ELEMENT_ENABLED => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/enabled'], 89*04fd306cSNickeau DriverCommand::IS_ELEMENT_SELECTED => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/selected'], 90*04fd306cSNickeau DriverCommand::MAXIMIZE_WINDOW => [ 91*04fd306cSNickeau 'method' => 'POST', 92*04fd306cSNickeau 'url' => '/session/:sessionId/window/:windowHandle/maximize', 93*04fd306cSNickeau ], 94*04fd306cSNickeau DriverCommand::MOUSE_DOWN => ['method' => 'POST', 'url' => '/session/:sessionId/buttondown'], 95*04fd306cSNickeau DriverCommand::MOUSE_UP => ['method' => 'POST', 'url' => '/session/:sessionId/buttonup'], 96*04fd306cSNickeau DriverCommand::CLICK => ['method' => 'POST', 'url' => '/session/:sessionId/click'], 97*04fd306cSNickeau DriverCommand::DOUBLE_CLICK => ['method' => 'POST', 'url' => '/session/:sessionId/doubleclick'], 98*04fd306cSNickeau DriverCommand::MOVE_TO => ['method' => 'POST', 'url' => '/session/:sessionId/moveto'], 99*04fd306cSNickeau DriverCommand::NEW_SESSION => ['method' => 'POST', 'url' => '/session'], 100*04fd306cSNickeau DriverCommand::QUIT => ['method' => 'DELETE', 'url' => '/session/:sessionId'], 101*04fd306cSNickeau DriverCommand::REFRESH => ['method' => 'POST', 'url' => '/session/:sessionId/refresh'], 102*04fd306cSNickeau DriverCommand::UPLOAD_FILE => ['method' => 'POST', 'url' => '/session/:sessionId/file'], // undocumented 103*04fd306cSNickeau DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/keys'], 104*04fd306cSNickeau DriverCommand::SET_ALERT_VALUE => ['method' => 'POST', 'url' => '/session/:sessionId/alert_text'], 105*04fd306cSNickeau DriverCommand::SEND_KEYS_TO_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/value'], 106*04fd306cSNickeau DriverCommand::IMPLICITLY_WAIT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts/implicit_wait'], 107*04fd306cSNickeau DriverCommand::SET_SCREEN_ORIENTATION => ['method' => 'POST', 'url' => '/session/:sessionId/orientation'], 108*04fd306cSNickeau DriverCommand::SET_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'], 109*04fd306cSNickeau DriverCommand::SET_SCRIPT_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts/async_script'], 110*04fd306cSNickeau DriverCommand::SET_WINDOW_POSITION => [ 111*04fd306cSNickeau 'method' => 'POST', 112*04fd306cSNickeau 'url' => '/session/:sessionId/window/:windowHandle/position', 113*04fd306cSNickeau ], 114*04fd306cSNickeau DriverCommand::SET_WINDOW_SIZE => [ 115*04fd306cSNickeau 'method' => 'POST', 116*04fd306cSNickeau 'url' => '/session/:sessionId/window/:windowHandle/size', 117*04fd306cSNickeau ], 118*04fd306cSNickeau DriverCommand::STATUS => ['method' => 'GET', 'url' => '/status'], 119*04fd306cSNickeau DriverCommand::SUBMIT_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/submit'], 120*04fd306cSNickeau DriverCommand::SCREENSHOT => ['method' => 'GET', 'url' => '/session/:sessionId/screenshot'], 121*04fd306cSNickeau DriverCommand::TAKE_ELEMENT_SCREENSHOT => [ 122*04fd306cSNickeau 'method' => 'GET', 123*04fd306cSNickeau 'url' => '/session/:sessionId/element/:id/screenshot', 124*04fd306cSNickeau ], 125*04fd306cSNickeau DriverCommand::TOUCH_SINGLE_TAP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/click'], 126*04fd306cSNickeau DriverCommand::TOUCH_DOWN => ['method' => 'POST', 'url' => '/session/:sessionId/touch/down'], 127*04fd306cSNickeau DriverCommand::TOUCH_DOUBLE_TAP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/doubleclick'], 128*04fd306cSNickeau DriverCommand::TOUCH_FLICK => ['method' => 'POST', 'url' => '/session/:sessionId/touch/flick'], 129*04fd306cSNickeau DriverCommand::TOUCH_LONG_PRESS => ['method' => 'POST', 'url' => '/session/:sessionId/touch/longclick'], 130*04fd306cSNickeau DriverCommand::TOUCH_MOVE => ['method' => 'POST', 'url' => '/session/:sessionId/touch/move'], 131*04fd306cSNickeau DriverCommand::TOUCH_SCROLL => ['method' => 'POST', 'url' => '/session/:sessionId/touch/scroll'], 132*04fd306cSNickeau DriverCommand::TOUCH_UP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/up'], 133*04fd306cSNickeau DriverCommand::CUSTOM_COMMAND => [], 134*04fd306cSNickeau ]; 135*04fd306cSNickeau /** 136*04fd306cSNickeau * @var array Will be merged with $commands 137*04fd306cSNickeau */ 138*04fd306cSNickeau protected static $w3cCompliantCommands = [ 139*04fd306cSNickeau DriverCommand::ACCEPT_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/alert/accept'], 140*04fd306cSNickeau DriverCommand::ACTIONS => ['method' => 'POST', 'url' => '/session/:sessionId/actions'], 141*04fd306cSNickeau DriverCommand::DISMISS_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/alert/dismiss'], 142*04fd306cSNickeau DriverCommand::EXECUTE_ASYNC_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/async'], 143*04fd306cSNickeau DriverCommand::EXECUTE_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/sync'], 144*04fd306cSNickeau DriverCommand::FULLSCREEN_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window/fullscreen'], 145*04fd306cSNickeau DriverCommand::GET_ACTIVE_ELEMENT => ['method' => 'GET', 'url' => '/session/:sessionId/element/active'], 146*04fd306cSNickeau DriverCommand::GET_ALERT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/alert/text'], 147*04fd306cSNickeau DriverCommand::GET_CURRENT_WINDOW_HANDLE => ['method' => 'GET', 'url' => '/session/:sessionId/window'], 148*04fd306cSNickeau DriverCommand::GET_ELEMENT_LOCATION => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/rect'], 149*04fd306cSNickeau DriverCommand::GET_ELEMENT_PROPERTY => [ 150*04fd306cSNickeau 'method' => 'GET', 151*04fd306cSNickeau 'url' => '/session/:sessionId/element/:id/property/:name', 152*04fd306cSNickeau ], 153*04fd306cSNickeau DriverCommand::GET_ELEMENT_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/rect'], 154*04fd306cSNickeau DriverCommand::GET_WINDOW_HANDLES => ['method' => 'GET', 'url' => '/session/:sessionId/window/handles'], 155*04fd306cSNickeau DriverCommand::GET_WINDOW_POSITION => ['method' => 'GET', 'url' => '/session/:sessionId/window/rect'], 156*04fd306cSNickeau DriverCommand::GET_WINDOW_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/window/rect'], 157*04fd306cSNickeau DriverCommand::IMPLICITLY_WAIT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'], 158*04fd306cSNickeau DriverCommand::MAXIMIZE_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window/maximize'], 159*04fd306cSNickeau DriverCommand::MINIMIZE_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window/minimize'], 160*04fd306cSNickeau DriverCommand::NEW_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window/new'], 161*04fd306cSNickeau DriverCommand::SET_ALERT_VALUE => ['method' => 'POST', 'url' => '/session/:sessionId/alert/text'], 162*04fd306cSNickeau DriverCommand::SET_SCRIPT_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'], 163*04fd306cSNickeau DriverCommand::SET_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'], 164*04fd306cSNickeau DriverCommand::SET_WINDOW_SIZE => ['method' => 'POST', 'url' => '/session/:sessionId/window/rect'], 165*04fd306cSNickeau DriverCommand::SET_WINDOW_POSITION => ['method' => 'POST', 'url' => '/session/:sessionId/window/rect'], 166*04fd306cSNickeau ]; 167*04fd306cSNickeau /** 168*04fd306cSNickeau * @var string 169*04fd306cSNickeau */ 170*04fd306cSNickeau protected $url; 171*04fd306cSNickeau /** 172*04fd306cSNickeau * @var resource 173*04fd306cSNickeau */ 174*04fd306cSNickeau protected $curl; 175*04fd306cSNickeau /** 176*04fd306cSNickeau * @var bool 177*04fd306cSNickeau */ 178*04fd306cSNickeau protected $isW3cCompliant = true; 179*04fd306cSNickeau 180*04fd306cSNickeau /** 181*04fd306cSNickeau * @param string $url 182*04fd306cSNickeau * @param string|null $http_proxy 183*04fd306cSNickeau * @param int|null $http_proxy_port 184*04fd306cSNickeau */ 185*04fd306cSNickeau public function __construct($url, $http_proxy = null, $http_proxy_port = null) 186*04fd306cSNickeau { 187*04fd306cSNickeau self::$w3cCompliantCommands = array_merge(self::$commands, self::$w3cCompliantCommands); 188*04fd306cSNickeau 189*04fd306cSNickeau $this->url = $url; 190*04fd306cSNickeau $this->curl = curl_init(); 191*04fd306cSNickeau 192*04fd306cSNickeau if (!empty($http_proxy)) { 193*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_PROXY, $http_proxy); 194*04fd306cSNickeau if ($http_proxy_port !== null) { 195*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_PROXYPORT, $http_proxy_port); 196*04fd306cSNickeau } 197*04fd306cSNickeau } 198*04fd306cSNickeau 199*04fd306cSNickeau // Get credentials from $url (if any) 200*04fd306cSNickeau $matches = null; 201*04fd306cSNickeau if (preg_match("/^(https?:\/\/)(.*):(.*)@(.*?)/U", $url, $matches)) { 202*04fd306cSNickeau $this->url = $matches[1] . $matches[4]; 203*04fd306cSNickeau $auth_creds = $matches[2] . ':' . $matches[3]; 204*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY); 205*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_USERPWD, $auth_creds); 206*04fd306cSNickeau } 207*04fd306cSNickeau 208*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); 209*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true); 210*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_HTTPHEADER, static::DEFAULT_HTTP_HEADERS); 211*04fd306cSNickeau $this->setRequestTimeout(30000); 212*04fd306cSNickeau $this->setConnectionTimeout(30000); 213*04fd306cSNickeau } 214*04fd306cSNickeau 215*04fd306cSNickeau public function disableW3cCompliance() 216*04fd306cSNickeau { 217*04fd306cSNickeau $this->isW3cCompliant = false; 218*04fd306cSNickeau } 219*04fd306cSNickeau 220*04fd306cSNickeau /** 221*04fd306cSNickeau * Set timeout for the connect phase 222*04fd306cSNickeau * 223*04fd306cSNickeau * @param int $timeout_in_ms Timeout in milliseconds 224*04fd306cSNickeau * @return HttpCommandExecutor 225*04fd306cSNickeau */ 226*04fd306cSNickeau public function setConnectionTimeout($timeout_in_ms) 227*04fd306cSNickeau { 228*04fd306cSNickeau // There is a PHP bug in some versions which didn't define the constant. 229*04fd306cSNickeau curl_setopt( 230*04fd306cSNickeau $this->curl, 231*04fd306cSNickeau /* CURLOPT_CONNECTTIMEOUT_MS */ 232*04fd306cSNickeau 156, 233*04fd306cSNickeau $timeout_in_ms 234*04fd306cSNickeau ); 235*04fd306cSNickeau 236*04fd306cSNickeau return $this; 237*04fd306cSNickeau } 238*04fd306cSNickeau 239*04fd306cSNickeau /** 240*04fd306cSNickeau * Set the maximum time of a request 241*04fd306cSNickeau * 242*04fd306cSNickeau * @param int $timeout_in_ms Timeout in milliseconds 243*04fd306cSNickeau * @return HttpCommandExecutor 244*04fd306cSNickeau */ 245*04fd306cSNickeau public function setRequestTimeout($timeout_in_ms) 246*04fd306cSNickeau { 247*04fd306cSNickeau // There is a PHP bug in some versions (at least for PHP 5.3.3) which 248*04fd306cSNickeau // didn't define the constant. 249*04fd306cSNickeau curl_setopt( 250*04fd306cSNickeau $this->curl, 251*04fd306cSNickeau /* CURLOPT_TIMEOUT_MS */ 252*04fd306cSNickeau 155, 253*04fd306cSNickeau $timeout_in_ms 254*04fd306cSNickeau ); 255*04fd306cSNickeau 256*04fd306cSNickeau return $this; 257*04fd306cSNickeau } 258*04fd306cSNickeau 259*04fd306cSNickeau /** 260*04fd306cSNickeau * @param WebDriverCommand $command 261*04fd306cSNickeau * 262*04fd306cSNickeau * @throws WebDriverException 263*04fd306cSNickeau * @return WebDriverResponse 264*04fd306cSNickeau */ 265*04fd306cSNickeau public function execute(WebDriverCommand $command) 266*04fd306cSNickeau { 267*04fd306cSNickeau $http_options = $this->getCommandHttpOptions($command); 268*04fd306cSNickeau $http_method = $http_options['method']; 269*04fd306cSNickeau $url = $http_options['url']; 270*04fd306cSNickeau 271*04fd306cSNickeau $sessionID = $command->getSessionID(); 272*04fd306cSNickeau $url = str_replace(':sessionId', $sessionID === null ? '' : $sessionID, $url); 273*04fd306cSNickeau $params = $command->getParameters(); 274*04fd306cSNickeau foreach ($params as $name => $value) { 275*04fd306cSNickeau if ($name[0] === ':') { 276*04fd306cSNickeau $url = str_replace($name, $value, $url); 277*04fd306cSNickeau unset($params[$name]); 278*04fd306cSNickeau } 279*04fd306cSNickeau } 280*04fd306cSNickeau 281*04fd306cSNickeau if (is_array($params) && !empty($params) && $http_method !== 'POST') { 282*04fd306cSNickeau throw new BadMethodCallException(sprintf( 283*04fd306cSNickeau 'The http method called for %s is %s but it has to be POST' . 284*04fd306cSNickeau ' if you want to pass the JSON params %s', 285*04fd306cSNickeau $url, 286*04fd306cSNickeau $http_method, 287*04fd306cSNickeau json_encode($params) 288*04fd306cSNickeau )); 289*04fd306cSNickeau } 290*04fd306cSNickeau 291*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_URL, $this->url . $url); 292*04fd306cSNickeau 293*04fd306cSNickeau // https://github.com/facebook/php-webdriver/issues/173 294*04fd306cSNickeau if ($command->getName() === DriverCommand::NEW_SESSION) { 295*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_POST, 1); 296*04fd306cSNickeau } else { 297*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $http_method); 298*04fd306cSNickeau } 299*04fd306cSNickeau 300*04fd306cSNickeau if (in_array($http_method, ['POST', 'PUT'], true)) { 301*04fd306cSNickeau // Disable sending 'Expect: 100-Continue' header, as it is causing issues with eg. squid proxy 302*04fd306cSNickeau // https://tools.ietf.org/html/rfc7231#section-5.1.1 303*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_HTTPHEADER, array_merge(static::DEFAULT_HTTP_HEADERS, ['Expect:'])); 304*04fd306cSNickeau } else { 305*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_HTTPHEADER, static::DEFAULT_HTTP_HEADERS); 306*04fd306cSNickeau } 307*04fd306cSNickeau 308*04fd306cSNickeau $encoded_params = null; 309*04fd306cSNickeau 310*04fd306cSNickeau if ($http_method === 'POST') { 311*04fd306cSNickeau if (is_array($params) && !empty($params)) { 312*04fd306cSNickeau $encoded_params = json_encode($params); 313*04fd306cSNickeau } elseif ($this->isW3cCompliant) { 314*04fd306cSNickeau // POST body must be valid JSON in W3C, even if empty: https://www.w3.org/TR/webdriver/#processing-model 315*04fd306cSNickeau $encoded_params = '{}'; 316*04fd306cSNickeau } 317*04fd306cSNickeau } 318*04fd306cSNickeau 319*04fd306cSNickeau curl_setopt($this->curl, CURLOPT_POSTFIELDS, $encoded_params); 320*04fd306cSNickeau 321*04fd306cSNickeau $raw_results = trim(curl_exec($this->curl)); 322*04fd306cSNickeau 323*04fd306cSNickeau if ($error = curl_error($this->curl)) { 324*04fd306cSNickeau $msg = sprintf( 325*04fd306cSNickeau 'Curl error thrown for http %s to %s', 326*04fd306cSNickeau $http_method, 327*04fd306cSNickeau $url 328*04fd306cSNickeau ); 329*04fd306cSNickeau if (is_array($params) && !empty($params)) { 330*04fd306cSNickeau $msg .= sprintf(' with params: %s', json_encode($params, JSON_UNESCAPED_SLASHES)); 331*04fd306cSNickeau } 332*04fd306cSNickeau 333*04fd306cSNickeau throw new WebDriverCurlException($msg . "\n\n" . $error); 334*04fd306cSNickeau } 335*04fd306cSNickeau 336*04fd306cSNickeau $results = json_decode($raw_results, true); 337*04fd306cSNickeau 338*04fd306cSNickeau if ($results === null && json_last_error() !== JSON_ERROR_NONE) { 339*04fd306cSNickeau throw new WebDriverException( 340*04fd306cSNickeau sprintf( 341*04fd306cSNickeau "JSON decoding of remote response failed.\n" . 342*04fd306cSNickeau "Error code: %d\n" . 343*04fd306cSNickeau "The response: '%s'\n", 344*04fd306cSNickeau json_last_error(), 345*04fd306cSNickeau $raw_results 346*04fd306cSNickeau ) 347*04fd306cSNickeau ); 348*04fd306cSNickeau } 349*04fd306cSNickeau 350*04fd306cSNickeau $value = null; 351*04fd306cSNickeau if (is_array($results) && array_key_exists('value', $results)) { 352*04fd306cSNickeau $value = $results['value']; 353*04fd306cSNickeau } 354*04fd306cSNickeau 355*04fd306cSNickeau $message = null; 356*04fd306cSNickeau if (is_array($value) && array_key_exists('message', $value)) { 357*04fd306cSNickeau $message = $value['message']; 358*04fd306cSNickeau } 359*04fd306cSNickeau 360*04fd306cSNickeau $sessionId = null; 361*04fd306cSNickeau if (is_array($value) && array_key_exists('sessionId', $value)) { 362*04fd306cSNickeau // W3C's WebDriver 363*04fd306cSNickeau $sessionId = $value['sessionId']; 364*04fd306cSNickeau } elseif (is_array($results) && array_key_exists('sessionId', $results)) { 365*04fd306cSNickeau // Legacy JsonWire 366*04fd306cSNickeau $sessionId = $results['sessionId']; 367*04fd306cSNickeau } 368*04fd306cSNickeau 369*04fd306cSNickeau // @see https://w3c.github.io/webdriver/webdriver-spec.html#handling-errors 370*04fd306cSNickeau if (isset($value['error'])) { 371*04fd306cSNickeau // W3C's WebDriver 372*04fd306cSNickeau WebDriverException::throwException($value['error'], $message, $results); 373*04fd306cSNickeau } 374*04fd306cSNickeau 375*04fd306cSNickeau $status = isset($results['status']) ? $results['status'] : 0; 376*04fd306cSNickeau if ($status !== 0) { 377*04fd306cSNickeau // Legacy JsonWire 378*04fd306cSNickeau WebDriverException::throwException($status, $message, $results); 379*04fd306cSNickeau } 380*04fd306cSNickeau 381*04fd306cSNickeau $response = new WebDriverResponse($sessionId); 382*04fd306cSNickeau 383*04fd306cSNickeau return $response 384*04fd306cSNickeau ->setStatus($status) 385*04fd306cSNickeau ->setValue($value); 386*04fd306cSNickeau } 387*04fd306cSNickeau 388*04fd306cSNickeau /** 389*04fd306cSNickeau * @return string 390*04fd306cSNickeau */ 391*04fd306cSNickeau public function getAddressOfRemoteServer() 392*04fd306cSNickeau { 393*04fd306cSNickeau return $this->url; 394*04fd306cSNickeau } 395*04fd306cSNickeau 396*04fd306cSNickeau /** 397*04fd306cSNickeau * @return array 398*04fd306cSNickeau */ 399*04fd306cSNickeau protected function getCommandHttpOptions(WebDriverCommand $command) 400*04fd306cSNickeau { 401*04fd306cSNickeau $commandName = $command->getName(); 402*04fd306cSNickeau if (!isset(self::$commands[$commandName])) { 403*04fd306cSNickeau if ($this->isW3cCompliant && !isset(self::$w3cCompliantCommands[$commandName])) { 404*04fd306cSNickeau throw new InvalidArgumentException($command->getName() . ' is not a valid command.'); 405*04fd306cSNickeau } 406*04fd306cSNickeau } 407*04fd306cSNickeau 408*04fd306cSNickeau if ($this->isW3cCompliant) { 409*04fd306cSNickeau $raw = self::$w3cCompliantCommands[$command->getName()]; 410*04fd306cSNickeau } else { 411*04fd306cSNickeau $raw = self::$commands[$command->getName()]; 412*04fd306cSNickeau } 413*04fd306cSNickeau 414*04fd306cSNickeau if ($command instanceof CustomWebDriverCommand) { 415*04fd306cSNickeau $url = $command->getCustomUrl(); 416*04fd306cSNickeau $method = $command->getCustomMethod(); 417*04fd306cSNickeau } else { 418*04fd306cSNickeau $url = $raw['url']; 419*04fd306cSNickeau $method = $raw['method']; 420*04fd306cSNickeau } 421*04fd306cSNickeau 422*04fd306cSNickeau return [ 423*04fd306cSNickeau 'url' => $url, 424*04fd306cSNickeau 'method' => $method, 425*04fd306cSNickeau ]; 426*04fd306cSNickeau } 427*04fd306cSNickeau} 428