/** * 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)); } $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); } $this->eventReceivedHeaders = true; } } return strlen($string); }
/** * 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); }
/** * Creates a array of responses from the batch response body. * * @param string $body The HTTP response body. * @param IMimeReaderWriter $mimeSerializer The MIME reader and writer. * * @return array */ private static function _constructResponses($body, $mimeSerializer) { $responses = array(); $parts = $mimeSerializer->decodeMimeMultipart($body); // Decrease the count of parts to remove the batch response body and just // include change sets response body. We may need to undo this action in // case that batch response body has useful info. $count = count($parts) - 1; for ($i = 0; $i < $count; $i++) { $lines = explode("\r\n", $parts[$i]); $response = new \HTTP_Request2_Response($lines[0]); $j = 1; do { $headerLine = $lines[$j++]; $response->parseHeaderLine($headerLine); } while (Resources::EMPTY_STRING != $headerLine); $body = implode("\r\n", array_slice($lines, $j)); $response->appendBody($body); $responses[] = $response; } return $responses; }
/** * Constructor * * @param string $content Http response * as string * * @param WindowsAzure\Common\Internal\Http\BatchRequest $request Source batch * request object */ public function __construct($content, $request = null) { $params['include_bodies'] = true; $params['input'] = $content; $mimeDecoder = new \Mail_mimeDecode($content); $structure = $mimeDecoder->decode($params); $parts = $structure->parts; $this->_contexts = array(); $requestContexts = null; if ($request != null) { Validate::isA($request, 'WindowsAzure\\Common\\Internal\\Http\\BatchRequest', 'request'); $requestContexts = $request->getContexts(); } $i = 0; foreach ($parts as $part) { if (!empty($part->body)) { $headerEndPos = strpos($part->body, "\r\n\r\n"); $header = substr($part->body, 0, $headerEndPos); $body = substr($part->body, $headerEndPos + 4); $headerStrings = explode("\r\n", $header); $response = new \HTTP_Request2_Response(array_shift($headerStrings)); foreach ($headerStrings as $headerString) { $response->parseHeaderLine($headerString); } $response->appendBody($body); $this->_contexts[] = $response; if (is_array($requestContexts)) { $expectedCodes = $requestContexts[$i]->getStatusCodes(); $statusCode = $response->getStatus(); if (!in_array($statusCode, $expectedCodes)) { $reason = $response->getReasonPhrase(); throw new ServiceException($statusCode, $reason, $body); } } $i++; } } }
/** * Reads the remote server's response * * @return HTTP_Request2_Response * @throws HTTP_Request2_Exception */ protected function readResponse() { $bufferSize = $this->request->getConfig('buffer_size'); do { $response = new HTTP_Request2_Response($this->readLine($bufferSize), true); do { $headerLine = $this->readLine($bufferSize); $response->parseHeaderLine($headerLine); } while ('' != $headerLine); } while (in_array($response->getStatus(), array(100, 101))); $this->request->setLastEvent('receivedHeaders', $response); // No body possible in such responses if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod() || HTTP_Request2::METHOD_CONNECT == $this->request->getMethod() && 200 <= $response->getStatus() && 300 > $response->getStatus() || in_array($response->getStatus(), array(204, 304))) { return $response; } $chunked = 'chunked' == $response->getHeader('transfer-encoding'); $length = $response->getHeader('content-length'); $hasBody = false; if ($chunked || null === $length || 0 < intval($length)) { // RFC 2616, section 4.4: // 3. ... If a message is received with both a // Transfer-Encoding header field and a Content-Length header field, // the latter MUST be ignored. $toRead = $chunked || null === $length ? null : $length; $this->chunkLength = 0; while (!feof($this->socket) && (is_null($toRead) || 0 < $toRead)) { if ($chunked) { $data = $this->readChunked($bufferSize); } elseif (is_null($toRead)) { $data = $this->fread($bufferSize); } else { $data = $this->fread(min($toRead, $bufferSize)); $toRead -= strlen($data); } if ('' == $data && (!$this->chunkLength || feof($this->socket))) { break; } $hasBody = true; if ($this->request->getConfig('store_body')) { $response->appendBody($data); } if (!in_array($response->getHeader('content-encoding'), array('identity', null))) { $this->request->setLastEvent('receivedEncodedBodyPart', $data); } else { $this->request->setLastEvent('receivedBodyPart', $data); } } } if ($hasBody) { $this->request->setLastEvent('receivedBody', $response); } return $response; }
protected function readResponseFromFile($filename) { $fp = fopen(dirname(dirname(__FILE__)) . '/_files/' . $filename, 'rb'); $response = new HTTP_Request2_Response(fgets($fp)); do { $headerLine = fgets($fp); $response->parseHeaderLine($headerLine); } while ('' != trim($headerLine)); while (!feof($fp)) { $response->appendBody(fread($fp, 1024)); } return $response; }
/** * Creates a new HTTP_Request2_Response object from a file * * @param resource file pointer returned by fopen() * @return HTTP_Request2_Response * @throws HTTP_Request2_Exception */ public static function createResponseFromFile($fp) { $response = new HTTP_Request2_Response(fgets($fp)); do { $headerLine = fgets($fp); $response->parseHeaderLine($headerLine); } while ('' != trim($headerLine)); while (!feof($fp)) { $response->appendBody(fread($fp, 8192)); } return $response; }
/** * Reads the remote server's response * * @return HTTP_Request2_Response * @throws HTTP_Request2_Exception */ protected function readResponse() { $bufferSize = $this->request->getConfig('buffer_size'); // http://tools.ietf.org/html/rfc2616#section-8.2.3 // ...the client SHOULD NOT wait for an indefinite period before sending the request body $timeout = $this->expect100Continue ? 1 : null; do { try { $response = new HTTP_Request2_Response($this->socket->readLine($bufferSize, $timeout), true, $this->request->getUrl()); do { $headerLine = $this->socket->readLine($bufferSize); $response->parseHeaderLine($headerLine); } while ('' != $headerLine); } catch (HTTP_Request2_MessageException $e) { if (HTTP_Request2_Exception::TIMEOUT === $e->getCode() && $this->expect100Continue) { return null; } throw $e; } if ($this->expect100Continue && 100 == $response->getStatus()) { return $response; } } while (in_array($response->getStatus(), array(100, 101))); $this->request->setLastEvent('receivedHeaders', $response); // No body possible in such responses if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod() || HTTP_Request2::METHOD_CONNECT == $this->request->getMethod() && 200 <= $response->getStatus() && 300 > $response->getStatus() || in_array($response->getStatus(), array(204, 304))) { return $response; } $chunked = 'chunked' == $response->getHeader('transfer-encoding'); $length = $response->getHeader('content-length'); $hasBody = false; if ($chunked || null === $length || 0 < intval($length)) { // RFC 2616, section 4.4: // 3. ... If a message is received with both a // Transfer-Encoding header field and a Content-Length header field, // the latter MUST be ignored. $toRead = $chunked || null === $length ? null : $length; $this->chunkLength = 0; while (!$this->socket->eof() && (is_null($toRead) || 0 < $toRead)) { if ($chunked) { $data = $this->readChunked($bufferSize); } elseif (is_null($toRead)) { $data = $this->socket->read($bufferSize); } else { $data = $this->socket->read(min($toRead, $bufferSize)); $toRead -= strlen($data); } if ('' == $data && (!$this->chunkLength || $this->socket->eof())) { break; } $hasBody = true; if ($this->request->getConfig('store_body')) { $response->appendBody($data); } if (!in_array($response->getHeader('content-encoding'), array('identity', null))) { $this->request->setLastEvent('receivedEncodedBodyPart', $data); } else { $this->request->setLastEvent('receivedBodyPart', $data); } } } if ($hasBody) { $this->request->setLastEvent('receivedBody', $response); } return $response; }