public function open($timeOut = null) { /** * @var $that self */ $that = new FullAccessWrapper($this); $uri = new Uri($this->url); $isSecured = 'wss' === $uri->getScheme(); $defaultPort = $isSecured ? 443 : 80; $connector = new Connector($this->loop, $this->dns, $this->streamOptions); if ($isSecured) { $connector = new \React\SocketClient\SecureConnector($connector, $this->loop); } $deferred = new Deferred(); $connector->create($uri->getHost(), $uri->getPort() ?: $defaultPort)->then(function (\React\Stream\Stream $stream) use($that, $uri, $deferred, $timeOut) { if ($timeOut) { $timeOutTimer = $that->loop->addTimer($timeOut, function () use($promise, $stream, $that) { $stream->close(); $that->logger->notice("Timeout occured, closing connection"); $that->emit("error"); $promise->reject("Timeout occured"); }); } else { $timeOutTimer = null; } $transport = new WebSocketTransportHybi($stream); $transport->setLogger($that->logger); $that->transport = $transport; $that->stream = $stream; $stream->on("close", function () use($that) { $that->isClosing = false; $that->state = WebSocket::STATE_CLOSED; }); // Give the chance to change request $transport->on("request", function (Request $handshake) use($that) { $that->emit("request", func_get_args()); }); $transport->on("handshake", function (Handshake $handshake) use($that) { $that->request = $handshake->getRequest(); $that->response = $handshake->getRequest(); $that->emit("handshake", array($handshake)); }); $transport->on("connect", function () use(&$state, $that, $transport, $timeOutTimer, $deferred) { if ($timeOutTimer) { $timeOutTimer->cancel(); } $deferred->resolve($transport); $that->state = WebSocket::STATE_CONNECTED; $that->emit("connect"); }); $transport->on('message', function ($message) use($that, $transport) { $that->emit("message", array("message" => $message)); }); $transport->initiateHandshake($uri); $that->state = WebSocket::STATE_HANDSHAKE_SENT; }, function ($reason) use($that) { $that->logger->err($reason); }); return $deferred->promise(); }
protected function getDomain($uriString = null) { if ($uriString == null) { $uriString = $this->getRequest()->getUri(); } $uri = new Uri($uriString); return $uri->getHost(); }
/** * Send request to the proxy server with streaming support * * @param string $method * @param \Zend\Uri\Uri $uri * @param string $http_ver * @param array $headers * @param string $body * @return string Request as string */ public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') { // If no proxy is set, throw an error if (!$this->config['proxy_host']) { throw new Adapter\Exception('No proxy host set!'); } // Make sure we're properly connected if (!$this->socket) { throw new Adapter\Exception('Trying to write but we are not connected'); } $host = $this->config['proxy_host']; $port = $this->config['proxy_port']; if ($this->connected_to[0] != $host || $this->connected_to[1] != $port) { throw new Adapter\Exception('Trying to write but we are connected to the wrong proxy ' . 'server'); } // Add Proxy-Authorization header if ($this->config['proxy_user'] && !isset($headers['proxy-authorization'])) { $headers['proxy-authorization'] = \Zend\Http\Client::encodeAuthHeader($this->config['proxy_user'], $this->config['proxy_pass'], $this->config['proxy_auth']); } // if we are proxying HTTPS, preform CONNECT handshake with the proxy if ($uri->getScheme() == 'https' && !$this->negotiated) { $this->connectHandshake($uri->getHost(), $uri->getPort(), $http_ver, $headers); $this->negotiated = true; } // Save request method for later $this->method = $method; // Build request headers $request = "{$method} {$uri->toString()} HTTP/{$http_ver}\r\n"; // Add all headers to the request string foreach ($headers as $k => $v) { if (is_string($k)) { $v = "{$k}: {$v}"; } $request .= "{$v}\r\n"; } $request .= "\r\n"; // Send the request headers if (!@fwrite($this->socket, $request)) { throw new Adapter\Exception('Error writing request to proxy server'); } //read from $body, write to socket while ($body->hasData()) { if (!@fwrite($this->socket, $body->read(self::CHUNK_SIZE))) { throw new Adapter\Exception('Error writing request to server'); } } return 'Large upload, request is not cached.'; }
/** * Send request to the remote server with streaming support. * * @param string $method * @param \Zend\Uri\Uri $uri * @param string $http_ver * @param array $headers * @param string $body * @return string Request as string */ public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') { // Make sure we're properly connected if (! $this->socket) { throw new Adapter\Exception( 'Trying to write but we are not connected'); } $host = $uri->getHost(); $host = (strtolower($uri->getScheme()) == 'https' ? $this->config['ssltransport'] : 'tcp') . '://' . $host; if ($this->connected_to[0] != $host || $this->connected_to[1] != $uri->getPort()) { throw new Adapter\Exception( 'Trying to write but we are connected to the wrong host'); } // Save request method for later $this->method = $method; // Build request headers $path = $uri->getPath(); if ($uri->getQuery()) $path .= '?' . $uri->getQuery(); $request = "{$method} {$path} HTTP/{$http_ver}\r\n"; foreach ($headers as $k => $v) { if (is_string($k)) $v = ucfirst($k) . ": $v"; $request .= "$v\r\n"; } // Send the headers over $request .= "\r\n"; if (! @fwrite($this->socket, $request)) { throw new Adapter\Exception( 'Error writing request to server'); } //read from $body, write to socket $chunk = $body->read(self::CHUNK_SIZE); while ($chunk !== FALSE) { if (! @fwrite($this->socket, $chunk)) { throw new Adapter\Exception( 'Error writing request to server'); } $chunk = $body->read(self::CHUNK_SIZE); } $body->closeFileHandle(); return 'Large upload, request is not cached.'; }
/** * Send request to the remote server * * @param string $method * @param \Zend\Uri\Uri $uri * @param string $http_ver * @param array $headers * @param string $body * @return string Request as string */ public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') { $host = $uri->getHost(); $host = strtolower($uri->getScheme()) == 'https' ? 'sslv2://' . $host : $host; // Build request headers $path = $uri->getPath(); if (empty($path)) { $path = '/'; } if ($uri->getQuery()) { $path .= '?' . $uri->getQuery(); } $request = "{$method} {$path} HTTP/{$http_ver}\r\n"; foreach ($headers as $k => $v) { if (is_string($k)) { $v = ucfirst($k) . ": {$v}"; } $request .= "{$v}\r\n"; } // Add the request body $request .= "\r\n" . $body; // Do nothing - just return the request as string return $request; }
/** * Send request to the remote server * * @param string $method * @param \Zend\Uri\Uri $uri * @param string $httpVer * @param array $headers * @param string $body * @throws AdapterException\RuntimeException * @return string Request as string */ public function write($method, $uri, $httpVer = '1.1', $headers = array(), $body = '') { // Make sure we're properly connected if (!$this->socket) { throw new AdapterException\RuntimeException('Trying to write but we are not connected'); } $host = $uri->getHost(); $host = (strtolower($uri->getScheme()) == 'https' ? $this->config['ssltransport'] : 'tcp') . '://' . $host; if ($this->connectedTo[0] != $host || $this->connectedTo[1] != $uri->getPort()) { throw new AdapterException\RuntimeException('Trying to write but we are connected to the wrong host'); } // Save request method for later $this->method = $method; // Build request headers $path = $uri->getPath(); if ($uri->getQuery()) { $path .= '?' . $uri->getQuery(); } $request = "{$method} {$path} HTTP/{$httpVer}\r\n"; foreach ($headers as $k => $v) { if (is_string($k)) { $v = ucfirst($k) . ": {$v}"; } $request .= "{$v}\r\n"; } if (is_resource($body)) { $request .= "\r\n"; } else { // Add the request body $request .= "\r\n" . $body; } // Send the request ErrorHandler::start(); $test = fwrite($this->socket, $request); $error = ErrorHandler::stop(); if (false === $test) { throw new AdapterException\RuntimeException('Error writing request to server', 0, $error); } if (is_resource($body)) { if (stream_copy_to_stream($body, $this->socket) == 0) { throw new AdapterException\RuntimeException('Error writing request to server'); } } return $request; }
public function initiateHandshake(Uri $uri) { $challenge = self::randHybiKey(); $request = new Request(); $requestUri = $uri->getPath(); if ($uri->getQuery()) { $requestUri .= "?" . $uri->getQuery(); } $request->setUri($requestUri); $request->getHeaders()->addHeaderLine("Connection", "Upgrade"); $request->getHeaders()->addHeaderLine("Host", $uri->getHost()); $request->getHeaders()->addHeaderLine("Sec-WebSocket-Key", $challenge); $request->getHeaders()->addHeaderLine("Sec-WebSocket-Version", 13); $request->getHeaders()->addHeaderLine("Upgrade", "websocket"); $this->setRequest($request); $this->emit("request", array($request)); $this->_socket->write($request->toString()); return $request; }
/** * Test that we can set the host part to 'null' * */ public function testSetNullHost() { $uri = new Uri('http://example.com/bar'); $uri->setHost(null); $this->assertNull($uri->getHost()); }
/** * Send request to the remote server * * @param string $method * @param \Zend\Uri\Uri $uri * @param float $httpVersion * @param array $headers * @param string $body * @return string $request * @throws AdapterException\RuntimeException If connection fails, connected to wrong host, no PUT file defined, unsupported method, or unsupported cURL option * @throws AdapterException\InvalidArgumentException if $method is currently not supported */ public function write($method, $uri, $httpVersion = 1.1, $headers = array(), $body = '') { // Make sure we're properly connected if (!$this->curl) { throw new AdapterException\RuntimeException("Trying to write but we are not connected"); } if ($this->connectedTo[0] != $uri->getHost() || $this->connectedTo[1] != $uri->getPort()) { throw new AdapterException\RuntimeException("Trying to write but we are connected to the wrong host"); } // set URL curl_setopt($this->curl, CURLOPT_URL, $uri->__toString()); // ensure correct curl call $curlValue = true; switch ($method) { case 'GET': $curlMethod = CURLOPT_HTTPGET; break; case 'POST': $curlMethod = CURLOPT_POST; break; case 'PUT': // There are two different types of PUT request, either a Raw Data string has been set // or CURLOPT_INFILE and CURLOPT_INFILESIZE are used. if (is_resource($body)) { $this->config['curloptions'][CURLOPT_INFILE] = $body; } if (isset($this->config['curloptions'][CURLOPT_INFILE])) { // Now we will probably already have Content-Length set, so that we have to delete it // from $headers at this point: if (!isset($headers['Content-Length']) && !isset($this->config['curloptions'][CURLOPT_INFILESIZE])) { throw new AdapterException\RuntimeException("Cannot set a file-handle for cURL option CURLOPT_INFILE without also setting its size in CURLOPT_INFILESIZE."); } if (isset($headers['Content-Length'])) { $this->config['curloptions'][CURLOPT_INFILESIZE] = (int) $headers['Content-Length']; unset($headers['Content-Length']); } if (is_resource($body)) { $body = ''; } $curlMethod = CURLOPT_UPLOAD; } else { $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "PUT"; } break; case 'PATCH': $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "PATCH"; break; case 'DELETE': $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "DELETE"; break; case 'OPTIONS': $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "OPTIONS"; break; case 'TRACE': $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "TRACE"; break; case 'HEAD': $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "HEAD"; break; default: // For now, through an exception for unsupported request methods throw new AdapterException\InvalidArgumentException("Method '{$method}' currently not supported"); } if (is_resource($body) && $curlMethod != CURLOPT_UPLOAD) { throw new AdapterException\RuntimeException("Streaming requests are allowed only with PUT"); } // get http version to use $curlHttp = $httpVersion == 1.1 ? CURL_HTTP_VERSION_1_1 : CURL_HTTP_VERSION_1_0; // mark as HTTP request and set HTTP method curl_setopt($this->curl, $curlHttp, true); curl_setopt($this->curl, $curlMethod, $curlValue); if ($this->outputStream) { // headers will be read into the response curl_setopt($this->curl, CURLOPT_HEADER, false); curl_setopt($this->curl, CURLOPT_HEADERFUNCTION, array($this, "readHeader")); // and data will be written into the file curl_setopt($this->curl, CURLOPT_FILE, $this->outputStream); } else { // ensure headers are also returned curl_setopt($this->curl, CURLOPT_HEADER, true); // ensure actual response is returned curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); } // Treating basic auth headers in a special way if (array_key_exists('Authorization', $headers) && 'Basic' == substr($headers['Authorization'], 0, 5)) { curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($this->curl, CURLOPT_USERPWD, base64_decode(substr($headers['Authorization'], 6))); unset($headers['Authorization']); } // set additional headers if (!isset($headers['Accept'])) { $headers['Accept'] = ''; } $curlHeaders = array(); foreach ($headers as $key => $value) { $curlHeaders[] = $key . ': ' . $value; } curl_setopt($this->curl, CURLOPT_HTTPHEADER, $curlHeaders); /** * Make sure POSTFIELDS is set after $curlMethod is set: * @link http://de2.php.net/manual/en/function.curl-setopt.php#81161 */ if ($method == 'POST') { curl_setopt($this->curl, CURLOPT_POSTFIELDS, $body); } elseif ($curlMethod == CURLOPT_UPLOAD) { // this covers a PUT by file-handle: // Make the setting of this options explicit (rather than setting it through the loop following a bit lower) // to group common functionality together. curl_setopt($this->curl, CURLOPT_INFILE, $this->config['curloptions'][CURLOPT_INFILE]); curl_setopt($this->curl, CURLOPT_INFILESIZE, $this->config['curloptions'][CURLOPT_INFILESIZE]); unset($this->config['curloptions'][CURLOPT_INFILE]); unset($this->config['curloptions'][CURLOPT_INFILESIZE]); } elseif ($method == 'PUT') { // This is a PUT by a setRawData string, not by file-handle curl_setopt($this->curl, CURLOPT_POSTFIELDS, $body); } elseif ($method == 'PATCH') { curl_setopt($this->curl, CURLOPT_POSTFIELDS, $body); } // set additional curl options if (isset($this->config['curloptions'])) { foreach ((array) $this->config['curloptions'] as $k => $v) { if (!in_array($k, $this->invalidOverwritableCurlOptions)) { if (curl_setopt($this->curl, $k, $v) == false) { throw new AdapterException\RuntimeException(sprintf("Unknown or erroreous cURL option '%s' set", $k)); } } } } // send the request $response = curl_exec($this->curl); // if we used streaming, headers are already there if (!is_resource($this->outputStream)) { $this->response = $response; } $request = curl_getinfo($this->curl, CURLINFO_HEADER_OUT); $request .= $body; if (empty($this->response)) { throw new AdapterException\RuntimeException("Error in cURL request: " . curl_error($this->curl)); } // cURL automatically decodes chunked-messages, this means we have to disallow the Zend\Http\Response to do it again if (stripos($this->response, "Transfer-Encoding: chunked\r\n")) { $this->response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $this->response); } // cURL can automatically handle content encoding; prevent double-decoding from occurring if (isset($this->config['curloptions'][CURLOPT_ENCODING]) && '' == $this->config['curloptions'][CURLOPT_ENCODING] && stripos($this->response, "Content-Encoding: gzip\r\n")) { $this->response = str_ireplace("Content-Encoding: gzip\r\n", '', $this->response); } // Eliminate multiple HTTP responses. do { $parts = preg_split('|(?:\\r?\\n){2}|m', $this->response, 2); $again = false; if (isset($parts[1]) && preg_match("|^HTTP/1\\.[01](.*?)\r\n|mi", $parts[1])) { $this->response = $parts[1]; $again = true; } } while ($again); // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string: if (stripos($this->response, "HTTP/1.0 200 Connection established\r\n\r\n") !== false) { $this->response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $this->response); } return $request; }
/** * @inheritdoc */ public function parse($uri) { $uri = new Uri($uri); return $this->formatResults(['scheme' => $uri->getScheme(), 'userinfo' => $uri->getUserInfo(), 'host' => $uri->getHost(), 'port' => $uri->getPort(), 'path' => $uri->getPath(), 'query' => $uri->getQuery(), 'fragment' => $uri->getFragment()]); }
/** * Extract a single review into a review instance * @param DomElement $node * @return Review */ public function extractReview(DomElement $node) { $review = new Review(); $doc = new DomDocument(); $html = $node->ownerDocument->saveHtml($node); $doc->loadHtml('<?xml encoding="utf-8" ?>' . $html); $xpath = new DOMXpath($doc); /** * Author Username * // member_info/ * /username/span */ $nodes = $xpath->query("//div[contains(@class, 'member_info')]/*/div[contains(@class, 'username')]/span"); if ($nodes->length === 1) { $review->setAuthor(trim($nodes->item(0)->nodeValue)); } /** * Author Location */ $nodes = $xpath->query("//div[contains(@class, 'member_info')]/div[contains(@class, 'location')]"); if ($nodes->length === 1) { $review->setAuthorLocation(trim($nodes->item(0)->nodeValue)); } /** * Review Permalink */ $nodes = $xpath->query("//div[contains(@class, 'quote')]/a"); if ($nodes->length === 1) { // URL linked to from the title is an absolute path without host/scheme // Also, URL contains a fragment that should be removed $path = trim($nodes->item(0)->getAttribute('href')); $url = new Uri($this->getOptions()->getUrl()); $new = sprintf('%s://%s/%s', $url->getScheme(), $url->getHost(), ltrim($path, '/')); $url = new Uri($new); $url->setFragment(null); $review->setUrl((string) $url); } /** * Title Quote */ $nodes = $xpath->query("//div[contains(@class, 'quote')]/a/span[contains(@class, 'noQuotes')]"); if ($nodes->length === 1) { $review->setTitle(trim($nodes->item(0)->nodeValue)); } /** * Rating as an alt tag in an image */ $nodes = $xpath->query("//div[contains(@class, 'rating')]/span[contains(@class, 'rate')]/img"); if ($nodes->length === 1) { $img = $nodes->item(0); $alt = $img->getAttribute('alt'); if (preg_match('/([0-9\\.]+)\\s[\\w]+\\s([0-9\\.]+)/', $alt, $match)) { $review->setStarRating((double) $match[1]); $review->setMaxStarRating((double) $match[2]); } } /** * Rating Date */ $nodes = $xpath->query("//div[contains(@class, 'rating')]/span[contains(@class, 'ratingDate')]"); if ($nodes->length === 1) { $span = $nodes->item(0); if ($span->hasAttribute('title')) { $dateString = $span->getAttribute('title'); $date = DateTime::createFromFormat('d F Y', $dateString); if (false !== $date) { $review->setDate($date); } } else { if (preg_match('/([0-9]{1,2}\\s[\\w]+\\s[0-9]{4})/i', trim($span->nodeValue), $match)) { $date = DateTime::createFromFormat('d F Y', $match[1]); if (false !== $date) { $review->setDate($date); } } } } /** * Review Excerpt */ $nodes = $xpath->query("//div[contains(@class, 'entry')]/p[contains(@class, 'partial_entry')]"); if ($nodes->length === 1) { // Use first child node->nodeValue to skip links for 'more...' $review->setExcerpt(trim($nodes->item(0)->childNodes->item(0)->nodeValue)); } return $review; }
public function testParseTwice() { $uri = new Uri(); $uri->parse('http://user@example.com:1/absolute/url?query#fragment'); $uri->parse('/relative/url'); $this->assertNull($uri->getScheme()); $this->assertNull($uri->getHost()); $this->assertNull($uri->getUserInfo()); $this->assertNull($uri->getPort()); $this->assertNull($uri->getQuery()); $this->assertNull($uri->getFragment()); }
/** * Make sure we get the correct domain when it's set in a reference URL * * @dataProvider refUrlProvider */ public function testGetDomainInRefUrl(Uri\Uri $uri) { $domain = $uri->getHost(); $cookie = Http\Cookie::fromString('foo=baz; path=/', 'http://' . $domain); if (!$cookie instanceof Http\Cookie) { $this->fail("Failed creating a cookie object with URL '{$uri}'"); } $this->assertEquals($domain, $cookie->getDomain()); }
/** * Get the URI host * * @return string|null */ public function getHost() { return $this->uri->getHost(); }