/** * Separating this from send method allows subclasses to wrap * the interaction with the adapter * * @param Http $uri * @param string $method * @param bool $secure * @param array $headers * @param string $body * @return string the raw response * @throws Exception\RuntimeException */ protected function doRequest(Http $uri, $method, $secure = false, $headers = array(), $body = '') { // Open the connection, send the request and read the response $this->adapter->connect($uri->getHost(), $uri->getPort(), $secure); if ($this->config['outputstream']) { if ($this->adapter instanceof Client\Adapter\StreamInterface) { $stream = $this->openTempStream(); $this->adapter->setOutputStream($stream); } else { throw new Exception\RuntimeException('Adapter does not support streaming'); } } // HTTP connection $this->lastRawRequest = $this->adapter->write($method, $uri, $this->config['httpversion'], $headers, $body); return $this->adapter->read(); }
/** * Send HTTP request * * @param Request $request * @return Response */ public function send(Request $request = null) { if ($request !== null) { $this->setRequest($request); } $this->redirectCounter = 0; $response = null; // Make sure the adapter is loaded if ($this->adapter == null) { $this->setAdapter($this->config['adapter']); } // Send the first request. If redirected, continue. do { // uri $uri = $this->getUri(); // query $query = $this->getRequest()->query(); if (!empty($query)) { $queryArray = $query->toArray(); if (!empty($queryArray)) { $newUri = $uri->toString(); $queryString = http_build_query($query); if ($this->config['rfc3986strict']) { $queryString = str_replace('+', '%20', $queryString); } if (strpos($newUri, '?') !== false) { $newUri .= '&' . $queryString; } else { $newUri .= '?' . $queryString; } $uri = new \Zend\Uri\Http($newUri); } } // If we have no ports, set the defaults if (!$uri->getPort()) { $uri->setPort($uri->getScheme() == 'https' ? 443 : 80); } // method $method = $this->getRequest()->getMethod(); // body $body = $this->prepareBody(); // headers $headers = $this->prepareHeaders($body, $uri); $secure = $uri->getScheme() == 'https' ? true : false; // cookies $cookie = $this->prepareCookies($uri->getHost(), $uri->getPath(), $secure); if ($cookie->getFieldValue()) { $headers['Cookie'] = $cookie->getFieldValue(); } // check that adapter supports streaming before using it if (is_resource($body) && !$this->adapter instanceof Client\Adapter\Stream) { throw new Client\Exception\RuntimeException('Adapter does not support streaming'); } // Open the connection, send the request and read the response $this->adapter->connect($uri->getHost(), $uri->getPort(), $secure); if ($this->config['outputstream']) { if ($this->adapter instanceof Client\Adapter\Stream) { $stream = $this->openTempStream(); $this->adapter->setOutputStream($stream); } else { throw new Exception\RuntimeException('Adapter does not support streaming'); } } // HTTP connection $this->lastRawRequest = $this->adapter->write($method, $uri, $this->config['httpversion'], $headers, $body); $response = $this->adapter->read(); if (!$response) { throw new Exception\RuntimeException('Unable to read response, or response is empty'); } if ($this->config['storeresponse']) { $this->lastRawResponse = $response; } else { $this->lastRawResponse = null; } if ($this->config['outputstream']) { $streamMetaData = stream_get_meta_data($stream); if ($streamMetaData['seekable']) { rewind($stream); } // cleanup the adapter $this->adapter->setOutputStream(null); $response = Response\Stream::fromStream($response, $stream); $response->setStreamName($this->streamName); if (!is_string($this->config['outputstream'])) { // we used temp name, will need to clean up $response->setCleanup(true); } } else { $response = Response::fromString($response); } // Get the cookies from response (if any) $setCookie = $response->cookie(); if (!empty($setCookie)) { $this->addCookie($setCookie); } // If we got redirected, look for the Location header if ($response->isRedirect() && $response->headers()->has('Location')) { // Avoid problems with buggy servers that add whitespace at the // end of some headers $location = trim($response->headers()->get('Location')->getFieldValue()); // Check whether we send the exact same request again, or drop the parameters // and send a GET request if ($response->getStatusCode() == 303 || !$this->config['strictredirects'] && ($response->getStatusCode() == 302 || $response->getStatusCode() == 301)) { $this->resetParameters(); $this->setMethod(Request::METHOD_GET); } // If we got a well formed absolute URI if (($scheme = substr($location, 0, 6)) && ($scheme == 'http:/' || $scheme == 'https:')) { $this->setUri($location); } else { // Split into path and query and set the query if (strpos($location, '?') !== false) { list($location, $query) = explode('?', $location, 2); } else { $query = ''; } $this->getUri()->setQuery($query); // Else, if we got just an absolute path, set it if (strpos($location, '/') === 0) { $this->getUri()->setPath($location); // Else, assume we have a relative path } else { // Get the current path directory, removing any trailing slashes $path = $this->getUri()->getPath(); $path = rtrim(substr($path, 0, strrpos($path, '/')), "/"); $this->getUri()->setPath($path . '/' . $location); } } ++$this->redirectCounter; } else { // If we didn't get any location, stop redirecting break; } } while ($this->redirectCounter < $this->config['maxredirects']); $this->response = $response; return $response; }