/** * Sends the request and returns the response * * @throws HTTP_Request2_Exception * @return HTTP_Request2_Response */ public function send() { // Sanity check for URL if (!$this->url instanceof Net_URL2) { throw new HTTP_Request2_Exception('No URL given'); } elseif (!$this->url->isAbsolute()) { throw new HTTP_Request2_Exception('Absolute URL required'); } elseif (!in_array(strtolower($this->url->getScheme()), array('https', 'http'))) { throw new HTTP_Request2_Exception('Not a HTTP URL'); } if (empty($this->adapter)) { $this->setAdapter($this->getConfig('adapter')); } // magic_quotes_runtime may break file uploads and chunked response // processing; see bug #4543 if ($magicQuotes = ini_get('magic_quotes_runtime')) { ini_set('magic_quotes_runtime', false); } // force using single byte encoding if mbstring extension overloads // strlen() and substr(); see bug #1781, bug #10605 if (extension_loaded('mbstring') && 2 & ini_get('mbstring.func_overload')) { $oldEncoding = mb_internal_encoding(); mb_internal_encoding('iso-8859-1'); } try { $response = $this->adapter->sendRequest($this); } catch (Exception $e) { } // cleanup in either case (poor man's "finally" clause) if ($magicQuotes) { ini_set('magic_quotes_runtime', true); } if (!empty($oldEncoding)) { mb_internal_encoding($oldEncoding); } // rethrow the exception if (!empty($e)) { throw $e; } return $response; }
/** * Handles HTTP redirection * * This method will throw an Exception if redirect to a non-HTTP(S) location * is attempted, also if number of redirects performed already is equal to * 'max_redirects' configuration parameter. * * @param HTTP_Request2 Original request * @param HTTP_Request2_Response Response containing redirect * @return HTTP_Request2_Response Response from a new location * @throws HTTP_Request2_Exception */ protected function handleRedirect(HTTP_Request2 $request, HTTP_Request2_Response $response) { if (is_null($this->redirectCountdown)) { $this->redirectCountdown = $request->getConfig('max_redirects'); } if (0 == $this->redirectCountdown) { $this->redirectCountdown = null; // Copying cURL behaviour throw new HTTP_Request2_MessageException('Maximum (' . $request->getConfig('max_redirects') . ') redirects followed', HTTP_Request2_Exception::TOO_MANY_REDIRECTS); } $redirectUrl = new Net_URL2($response->getHeader('location'), array(Net_URL2::OPTION_USE_BRACKETS => $request->getConfig('use_brackets'))); // refuse non-HTTP redirect if ($redirectUrl->isAbsolute() && !in_array($redirectUrl->getScheme(), array('http', 'https'))) { $this->redirectCountdown = null; throw new HTTP_Request2_MessageException('Refusing to redirect to a non-HTTP URL ' . $redirectUrl->__toString(), HTTP_Request2_Exception::NON_HTTP_REDIRECT); } // Theoretically URL should be absolute (see http://tools.ietf.org/html/rfc2616#section-14.30), // but in practice it is often not if (!$redirectUrl->isAbsolute()) { $redirectUrl = $request->getUrl()->resolve($redirectUrl); } $redirect = clone $request; $redirect->setUrl($redirectUrl); if (303 == $response->getStatus() || !$request->getConfig('strict_redirects') && in_array($response->getStatus(), array(301, 302))) { $redirect->setMethod(HTTP_Request2::METHOD_GET); $redirect->setBody(''); } if (0 < $this->redirectCountdown) { $this->redirectCountdown--; } return $this->sendRequest($redirect); }
/** * Sends the request and returns the response * * @throws HTTP_Request2_Exception * @return HTTP_Request2_Response */ public function send() { // Sanity check for URL if (!$this->url instanceof Net_URL2 || !$this->url->isAbsolute() || !in_array(strtolower($this->url->getScheme()), array('https', 'http'))) { throw new HTTP_Request2_LogicException('HTTP_Request2 needs an absolute HTTP(S) request URL, ' . ($this->url instanceof Net_URL2 ? "'" . $this->url->__toString() . "'" : 'none') . ' given', HTTP_Request2_Exception::INVALID_ARGUMENT); } if (empty($this->adapter)) { $this->setAdapter($this->getConfig('adapter')); } // magic_quotes_runtime may break file uploads and chunked response // processing; see bug #4543. Don't use ini_get() here; see bug #16440. if ($magicQuotes = get_magic_quotes_runtime()) { set_magic_quotes_runtime(false); } // force using single byte encoding if mbstring extension overloads // strlen() and substr(); see bug #1781, bug #10605 if (extension_loaded('mbstring') && 2 & ini_get('mbstring.func_overload')) { $oldEncoding = mb_internal_encoding(); mb_internal_encoding('8bit'); } try { $response = $this->adapter->sendRequest($this); } catch (Exception $e) { } // cleanup in either case (poor man's "finally" clause) if ($magicQuotes) { set_magic_quotes_runtime(true); } if (!empty($oldEncoding)) { mb_internal_encoding($oldEncoding); } // rethrow the exception if (!empty($e)) { throw $e; } return $response; }
/** * Callback function called by cURL for saving the response headers * * @param resource cURL handle * @param string response header (with trailing CRLF) * @return integer number of bytes saved * @see HTTP_Request2_Response::parseHeaderLine() */ protected function callbackWriteHeader($ch, $string) { // we may receive a second set of headers if doing e.g. digest auth if ($this->eventReceivedHeaders || !$this->eventSentHeaders) { // don't bother with 100-Continue responses (bug #15785) if (!$this->eventSentHeaders || $this->response->getStatus() >= 200) { $this->request->setLastEvent('sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)); } $upload = curl_getinfo($ch, CURLINFO_SIZE_UPLOAD); // if body wasn't read by a callback, send event with total body size if ($upload > $this->position) { $this->request->setLastEvent('sentBodyPart', $upload - $this->position); $this->position = $upload; } if ($upload && (!$this->eventSentHeaders || $this->response->getStatus() >= 200)) { $this->request->setLastEvent('sentBody', $upload); } $this->eventSentHeaders = true; // we'll need a new response object if ($this->eventReceivedHeaders) { $this->eventReceivedHeaders = false; $this->response = null; } } if (empty($this->response)) { $this->response = new HTTP_Request2_Response($string, false); } else { $this->response->parseHeaderLine($string); if ('' == trim($string)) { // don't bother with 100-Continue responses (bug #15785) if (200 <= $this->response->getStatus()) { $this->request->setLastEvent('receivedHeaders', $this->response); } if ($this->request->getConfig('follow_redirects') && $this->response->isRedirect()) { $redirectUrl = new Net_URL2($this->response->getHeader('location')); // for versions lower than 5.2.10, check the redirection URL protocol if (!defined('CURLOPT_REDIR_PROTOCOLS') && $redirectUrl->isAbsolute() && !in_array($redirectUrl->getScheme(), array('http', 'https'))) { return -1; } if ($jar = $this->request->getCookieJar()) { $jar->addCookiesFromResponse($this->response, $this->request->getUrl()); if (!$redirectUrl->isAbsolute()) { $redirectUrl = $this->request->getUrl()->resolve($redirectUrl); } if ($cookies = $jar->getMatching($redirectUrl, true)) { curl_setopt($ch, CURLOPT_COOKIE, $cookies); } } } $this->eventReceivedHeaders = true; } } return strlen($string); }
/** * Returns all cookies matching a given request URL * * The following checks are made: * - cookie domain should match request host * - cookie path should be a prefix for request path * - 'secure' cookies will only be sent for HTTPS requests * * @param Net_URL2 $url Request url * @param bool $asString Whether to return cookies as string for "Cookie: " header * * @return array|string Matching cookies */ public function getMatching(Net_URL2 $url, $asString = false) { $host = $url->getHost(); $path = $url->getPath(); $secure = 0 == strcasecmp($url->getScheme(), 'https'); $matched = $ret = array(); foreach (array_keys($this->cookies) as $domain) { if ($this->domainMatch($host, $domain)) { foreach (array_keys($this->cookies[$domain]) as $cPath) { if (0 === strpos($path, $cPath)) { foreach ($this->cookies[$domain][$cPath] as $name => $cookie) { if (!$cookie['secure'] || $secure) { $matched[$name][strlen($cookie['path'])] = $cookie; } } } } } } foreach ($matched as $cookies) { krsort($cookies); $ret = array_merge($ret, $cookies); } if (!$asString) { return $ret; } else { $str = ''; foreach ($ret as $c) { $str .= (empty($str) ? '' : '; ') . $c['name'] . '=' . $c['value']; } return $str; } }
/** * Return true is the request URI is a secure URI (https or ssl) or false * otherwise. * * @return bool Whether the request URI is secure or not. */ public function isSecure() { if ($this->_uri === null) { return false; } $scheme = $this->_uri->getScheme(); return $scheme === 'https' || $scheme === 'ssl'; }