/** * Sends the request and returns the response * * @throws Diglin_HTTP_Request2_Exception * @return Diglin_HTTP_Request2_Response */ public function send() { // Sanity check for URL if (!$this->url instanceof Diglin_Net_URL2) { throw new Diglin_HTTP_Request2_Exception('No URL given'); } elseif (!$this->url->isAbsolute()) { throw new Diglin_HTTP_Request2_Exception('Absolute URL required'); } elseif (!in_array(strtolower($this->url->getScheme()), array('https', 'http'))) { throw new Diglin_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. 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('iso-8859-1'); } 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; }
/** * 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 Diglin_HTTP_Request2 Original request * @param Diglin_HTTP_Request2_Response Response containing redirect * @return Diglin_HTTP_Request2_Response Response from a new location * @throws Diglin_HTTP_Request2_Exception */ protected function handleRedirect(Diglin_HTTP_Request2 $request, Diglin_HTTP_Request2_Response $response) { if (is_null($this->redirectCountdown)) { $this->redirectCountdown = $request->getConfig('max_redirects'); } if (0 == $this->redirectCountdown) { // Copying cURL behaviour throw new Diglin_HTTP_Request2_Exception('Maximum (' . $request->getConfig('max_redirects') . ') redirects followed'); } $redirectUrl = new Diglin_Net_URL2($response->getHeader('location'), array(Diglin_Net_URL2::OPTION_USE_BRACKETS => $request->getConfig('use_brackets'))); // refuse non-HTTP redirect if ($redirectUrl->isAbsolute() && !in_array($redirectUrl->getScheme(), array('http', 'https'))) { throw new Diglin_HTTP_Request2_Exception('Refusing to redirect to a non-HTTP URL ' . $redirectUrl->__toString()); } // 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(Diglin_HTTP_Request2::METHOD_GET); $redirect->setBody(''); } if (0 < $this->redirectCountdown) { $this->redirectCountdown--; } return $this->sendRequest($redirect); }
/** * 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 Diglin_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; } $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 Diglin_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); } // for versions lower than 5.2.10, check the redirection URL protocol if ($this->request->getConfig('follow_redirects') && !defined('CURLOPT_REDIR_PROTOCOLS') && $this->response->isRedirect()) { $redirectUrl = new Diglin_Net_URL2($this->response->getHeader('location')); if ($redirectUrl->isAbsolute() && !in_array($redirectUrl->getScheme(), array('http', 'https'))) { return -1; } } $this->eventReceivedHeaders = true; } } return strlen($string); }