public function canCacheRequest(RequestInterface $request) { if ($request->getMethod() != RequestInterface::GET && $request->getMethod() != RequestInterface::HEAD) { return false; } if ($request->hasHeader('Cache-Control') && $request->getHeader('Cache-Control')->hasDirective('no-store')) { return false; } return true; }
public function canCacheRequest(RequestInterface $request) { // Only GET and HEAD requests can be cached if ($request->getMethod() != RequestInterface::GET && $request->getMethod() != RequestInterface::HEAD) { return false; } // Never cache requests when using no-store if ($request->hasHeader('Cache-Control') && $request->getHeader('Cache-Control')->hasDirective('no-store')) { return false; } return true; }
/** * {@inheritdoc} */ public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { if (null === $request) { throw new \UnexpectedValueException('$request can not be null'); } $context = $this->_matcher->getContext(); $context->setMethod($request->getMethod()); $context->setHost($request->getHost()); try { $parameters = $this->_matcher->match($request->getPath()); } catch (MethodNotAllowedException $nae) { return $this->close($conn, 403); } catch (ResourceNotFoundException $nfe) { return $this->close($conn, 404); } if ($parameters['_controller'] instanceof ServingCapableInterface) { $parameters['_controller']->serve($conn, $request, $parameters); } else { $query = array(); foreach ($query as $key => $value) { if (is_string($key) && '_' !== substr($key, 0, 1)) { $query[$key] = $value; } } $url = Url::factory($request->getPath()); $url->setQuery($query); $request->setUrl($url); $conn->controller = $parameters['_controller']; $conn->controller->onOpen($conn, $request); } }
/** * @param RequestInterface|EntityEnclosingRequestInterface $request * @param Credentials $credentials */ public function signRequest($request, $credentials) { $request->setHeader('X-HMB-Signature-Method', self::DEFAULT_METHOD); $request->setHeader('X-HMB-Signature-Version', self::DEFAULT_SIGN_VERSION); $request->setHeader('X-HMB-TimeStamp', time()); $contentMd5 = $request instanceof EntityEnclosingRequestInterface ? md5($request->getBody()) : ''; if ($contentMd5) { $request->setHeader('Content-MD5', $contentMd5); } $sign = array(); $sign[] = strtoupper($request->getMethod()); $sign[] = $request->getHost(); if ($request->getHeader('Content-MD5')) { $sign[] = $request->getHeader('Content-MD5'); } if ($request->getHeader('Content-Type')) { $sign[] = $request->getHeader('Content-Type'); } $sign[] = $request->getHeader('X-HMB-Signature-Method'); $sign[] = $request->getHeader('X-HMB-Signature-Version'); $sign[] = $request->getHeader('X-HMB-TimeStamp'); if ($request->getHeader('X-HMB-User-Session-Token')) { $sign[] = $request->getHeader('X-HMB-User-Session-Token'); } $sign[] = $request->getQuery(true) ? $request->getPath() . '?' . $request->getQuery(true) : $request->getPath(); $signature = base64_encode(hash_hmac(strtolower($request->getHeader('X-HMB-Signature-Method')), implode("\n", $sign), $credentials->getSecret())); $request->setHeader('Authorization', sprintf('%s %s:%s', self::AUTHORIZATION_SCHME, $credentials->getKey(), $signature)); }
/** * {@inheritdoc} */ public function signRequest(RequestInterface $request, CredentialsInterface $credentials) { // Refresh the cached timestamp $this->getTimestamp(true); // Add default headers $request->setHeader('x-amz-date', $this->getDateTime(DateFormat::RFC1123)); // Add the security token if one is present if ($credentials->getSecurityToken()) { $request->setHeader('x-amz-security-token', $credentials->getSecurityToken()); } // Grab the path and ensure that it is absolute $path = '/' . ltrim($request->getUrl(true)->normalizePath()->getPath(), '/'); // Begin building the string to sign $sign = $request->getMethod() . "\n" . "{$path}\n" . $this->getCanonicalizedQueryString($request) . "\n"; // Get all of the headers that must be signed (host and x-amz-*) $headers = $this->getHeadersToSign($request); foreach ($headers as $key => $value) { $sign .= $key . ':' . $value . "\n"; } $sign .= "\n"; // Add the body of the request if a body is present if ($request instanceof EntityEnclosingRequestInterface) { $sign .= (string) $request->getBody(); } // Add the string to sign to the request for debugging purposes $request->getParams()->set('aws.string_to_sign', $sign); $signature = base64_encode(hash_hmac('sha256', hash('sha256', $sign, true), $credentials->getSecretKey(), true)); // Add the authorization header to the request $request->setHeader('x-amzn-authorization', sprintf('AWS3 AWSAccessKeyId=%s,Algorithm=HmacSHA256,SignedHeaders=%s,Signature=%s', $credentials->getAccessKeyId(), implode(';', array_keys($headers)), $signature)); }
protected function invokeWrappedIfEntityEnclosed($method, array $params = []) { if (!$this->wrapped instanceof EntityEnclosingRequestInterface) { throw new BadMethodCallException(sprintf('Cannot call method "%s" on a request that does not enclose an entity.' . ' Did you expect a POST/PUT request instead of %s %s?', $method, $this->wrapped->getMethod(), $this->wrapped->getPath())); } return call_user_func_array([$this->wrapped, $method], $params); }
/** * {@inheritdoc} * @throws \UnexpectedValueException If a controller is not \Ratchet\Http\HttpServerInterface */ public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { if (null === $request) { throw new \UnexpectedValueException('$request can not be null'); } $context = $this->_matcher->getContext(); $context->setMethod($request->getMethod()); $context->setHost($request->getHost()); try { $route = $this->_matcher->match($request->getPath()); } catch (MethodNotAllowedException $nae) { return $this->close($conn, 403); } catch (ResourceNotFoundException $nfe) { return $this->close($conn, 404); } if (is_string($route['_controller']) && class_exists($route['_controller'])) { $route['_controller'] = new $route['_controller'](); } if (!$route['_controller'] instanceof HttpServerInterface) { throw new \UnexpectedValueException('All routes must implement Ratchet\\Http\\HttpServerInterface'); } $parameters = array(); foreach ($route as $key => $value) { if (is_string($key) && '_' !== substr($key, 0, 1)) { $parameters[$key] = $value; } } $url = Url::factory($request->getPath()); $url->setQuery($parameters); $request->setUrl($url); $conn->controller = $route['_controller']; $conn->controller->onOpen($conn, $request); }
protected function addDefaultContextOptions(RequestInterface $request) { $this->setContextValue('http', 'method', $request->getMethod()); $headers = $request->getHeaderLines(); if (!$request->hasHeader('Connection')) { $headers[] = 'Connection: close'; } $this->setContextValue('http', 'header', $headers); $this->setContextValue('http', 'protocol_version', $request->getProtocolVersion()); $this->setContextValue('http', 'ignore_errors', true); }
/** * {@inheritdoc} */ public function createCanonicalizedString(RequestInterface $request, $expires = null) { $buffer = $request->getMethod() . "\n"; // Add the interesting headers foreach ($this->signableHeaders as $header) { $buffer .= (string) $request->getHeader($header) . "\n"; } // Choose dates from left to right based on what's set $date = $expires ?: (string) $request->getHeader('date'); $buffer .= "{$date}\n" . $this->createCanonicalizedAmzHeaders($request) . $this->createCanonicalizedResource($request); return $buffer; }
public function match(RequestInterface $request) { if ($request->getMethod() !== $this->method) { return null; } foreach ($this->responses as $uri => $response) { if (preg_match('~' . $uri . '~', $request->getUrl()) > 0) { return $response; } } return null; }
/** * Given an array of the headers this method will run through all verification methods * @param \Guzzle\Http\Message\RequestInterface $request * @return bool TRUE if all headers are valid, FALSE if 1 or more were invalid */ public function verifyAll(RequestInterface $request) { $passes = 0; $passes += (int) $this->verifyMethod($request->getMethod()); $passes += (int) $this->verifyHTTPVersion($request->getProtocolVersion()); $passes += (int) $this->verifyRequestURI($request->getPath()); $passes += (int) $this->verifyHost((string) $request->getHeader('Host')); $passes += (int) $this->verifyUpgradeRequest((string) $request->getHeader('Upgrade')); $passes += (int) $this->verifyConnection((string) $request->getHeader('Connection')); $passes += (int) $this->verifyKey((string) $request->getHeader('Sec-WebSocket-Key')); //$passes += (int)$this->verifyVersion($headers['Sec-WebSocket-Version']); // Temporarily breaking functionality return 7 === $passes; }
public function shouldRevalidate(RequestInterface $request, Response $response) { if ($request->getMethod() != RequestInterface::GET) { return false; } $reqCache = $request->getHeader('Cache-Control'); $resCache = $response->getHeader('Cache-Control'); $revalidate = $request->getHeader('Pragma') == 'no-cache' || $reqCache && ($reqCache->hasDirective('no-cache') || $reqCache->hasDirective('must-revalidate')) || $resCache && ($resCache->hasDirective('no-cache') || $resCache->hasDirective('must-revalidate')); if (!$revalidate && !$resCache && $response->hasHeader('ETag')) { $revalidate = true; } return $revalidate; }
/** * Get the canonicalized query/parameter string for a request * * @param RequestInterface $request Request used to build canonicalized string * * @return string */ public function getCanonicalizedParameterString(RequestInterface $request) { if ($request->getMethod() == 'POST') { $params = $request->getPostFields()->toArray(); } else { $params = $request->getQuery()->toArray(); } // Don't resign a previous signature value unset($params['Signature']); uksort($params, 'strcmp'); $str = ''; foreach ($params as $key => $val) { $str .= rawurlencode($key) . '=' . rawurlencode($val) . '&'; } return substr($str, 0, -1); }
/** * Sign the Pusher request * * @link http://pusher.com/docs/rest_api#authentication * @param RequestInterface $request * @param Credentials $credentials */ public function signRequest(RequestInterface $request, Credentials $credentials) { $queryParameters = array('auth_key' => $credentials->getKey(), 'auth_timestamp' => time(), 'auth_version' => self::AUTH_VERSION); if ($request instanceof EntityEnclosingRequestInterface) { $body = $request->getBody(); $queryParameters['body_md5'] = $body->getContentLength() ? $body->getContentMd5() : ''; } // The signature algorithm asks that keys are all lowercased $queryParameters = array_change_key_case($request->getQuery()->toArray()) + $queryParameters; $queryParameters = array_filter($queryParameters); ksort($queryParameters); $method = strtoupper($request->getMethod()); $requestPath = $request->getPath(); $query = urldecode(http_build_query($queryParameters)); $signature = $this->signString(implode("\n", array($method, $requestPath, $query)), $credentials); $queryParameters['auth_signature'] = $signature; $request->getQuery()->replace($queryParameters); }
/** * {@inheritdoc} * @throws \UnexpectedValueException If a controller is not \Ratchet\Http\HttpServerInterface */ public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { if (null === $request) { throw new \UnexpectedValueException('$request can not be null'); } $context = $this->_matcher->getContext(); $context->setMethod($request->getMethod()); $context->setHost($request->getHost()); try { $route = $this->_matcher->match($request->getPath()); } catch (MethodNotAllowedException $nae) { return $this->close($conn, 403); } catch (ResourceNotFoundException $nfe) { return $this->close($conn, 404); } if (is_string($route['_controller']) && class_exists($route['_controller'])) { $route['_controller'] = new $route['_controller'](); } if (!$route['_controller'] instanceof HttpServerInterface) { throw new \UnexpectedValueException('All routes must implement Ratchet\\Http\\HttpServerInterface'); } $conn->controller = $route['_controller']; $conn->controller->onOpen($conn, $request); }
/** * Check if a cache response satisfies a request's caching constraints * * @param RequestInterface $request Request to validate * @param Response $response Response to validate * * @return bool */ public function canResponseSatisfyRequest(RequestInterface $request, Response $response) { $responseAge = $response->getAge(); // Check the request's max-age header against the age of the response if ($request->hasCacheControlDirective('max-age') && $responseAge > $request->getCacheControlDirective('max-age')) { return false; } // Check the response's max-age header if ($response->isFresh() === false) { $maxStale = $request->getCacheControlDirective('max-stale'); if (null !== $maxStale) { if ($maxStale !== true && $response->getFreshness() < -1 * $maxStale) { return false; } } elseif ($response->hasCacheControlDirective('max-age') && $responseAge > $response->getCacheControlDirective('max-age')) { return false; } } // Only revalidate GET requests if ($request->getMethod() == RequestInterface::GET) { // Check if the response must be validated against the origin server if ($request->getHeader('Pragma') == 'no-cache' || $request->hasCacheControlDirective('no-cache') || $request->hasCacheControlDirective('must-revalidate') || $response->hasCacheControlDirective('must-revalidate') || $response->hasCacheControlDirective('no-cache')) { // no-cache: When no parameters are present, always revalidate // When parameters are present in no-cache and the request includes those same parameters, then the // response must re-validate. I'll need an example of what fields look like in order to implement a // smarter version of no-cache // Requests can decline to revalidate against the origin server by setting the cache.revalidate param: // - never - To never revalidate and always contact the origin server // - skip - To skip revalidation and just use what is in cache switch ($request->getParams()->get('cache.revalidate')) { case 'never': return false; case 'skip': return true; default: return $this->revalidation->revalidate($request, $response); } } } return true; }
/** * Factory method to create a new curl handle based on an HTTP request. * * There are some helpful options you can set to enable specific behavior: * - debug: Set to true to enable cURL debug functionality to track the actual headers sent over the wire. * - progress: Set to true to enable progress function callbacks. * * @param RequestInterface $request Request * * @return CurlHandle * @throws RuntimeException */ public static function factory(RequestInterface $request) { $requestCurlOptions = $request->getCurlOptions(); $mediator = new RequestMediator($request, $requestCurlOptions->get('emit_io')); $tempContentLength = null; $method = $request->getMethod(); $bodyAsString = $requestCurlOptions->get(self::BODY_AS_STRING); // Prepare url $url = (string) $request->getUrl(); if (($pos = strpos($url, '#')) !== false) { // strip fragment from url $url = substr($url, 0, $pos); } // Array of default cURL options. $curlOptions = array(CURLOPT_URL => $url, CURLOPT_CONNECTTIMEOUT => 150, CURLOPT_RETURNTRANSFER => false, CURLOPT_HEADER => false, CURLOPT_PORT => $request->getPort(), CURLOPT_HTTPHEADER => array(), CURLOPT_WRITEFUNCTION => array($mediator, 'writeResponseBody'), CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'), CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0' ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1, CURLOPT_SSL_VERIFYPEER => 1, CURLOPT_SSL_VERIFYHOST => 2); if (defined('CURLOPT_PROTOCOLS')) { // Allow only HTTP and HTTPS protocols $curlOptions[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; } // Add CURLOPT_ENCODING if Accept-Encoding header is provided if ($acceptEncodingHeader = $request->getHeader('Accept-Encoding')) { $curlOptions[CURLOPT_ENCODING] = (string) $acceptEncodingHeader; // Let cURL set the Accept-Encoding header, prevents duplicate values $request->removeHeader('Accept-Encoding'); } // Enable curl debug information if the 'debug' param was set if ($requestCurlOptions->get('debug')) { $curlOptions[CURLOPT_STDERR] = fopen('php://temp', 'r+'); // @codeCoverageIgnoreStart if (false === $curlOptions[CURLOPT_STDERR]) { throw new RuntimeException('Unable to create a stream for CURLOPT_STDERR'); } // @codeCoverageIgnoreEnd $curlOptions[CURLOPT_VERBOSE] = true; } // Specify settings according to the HTTP method if ($method == 'GET') { $curlOptions[CURLOPT_HTTPGET] = true; } elseif ($method == 'HEAD') { $curlOptions[CURLOPT_NOBODY] = true; // HEAD requests do not use a write function unset($curlOptions[CURLOPT_WRITEFUNCTION]); } elseif (!$request instanceof EntityEnclosingRequest) { $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; } else { $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; // Handle sending raw bodies in a request if ($request->getBody()) { // You can send the body as a string using curl's CURLOPT_POSTFIELDS if ($bodyAsString) { $curlOptions[CURLOPT_POSTFIELDS] = (string) $request->getBody(); // Allow curl to add the Content-Length for us to account for the times when // POST redirects are followed by GET requests if ($tempContentLength = $request->getHeader('Content-Length')) { $tempContentLength = (int) (string) $tempContentLength; } // Remove the curl generated Content-Type header if none was set manually if (!$request->hasHeader('Content-Type')) { $curlOptions[CURLOPT_HTTPHEADER][] = 'Content-Type:'; } } else { $curlOptions[CURLOPT_UPLOAD] = true; // Let cURL handle setting the Content-Length header if ($tempContentLength = $request->getHeader('Content-Length')) { $tempContentLength = (int) (string) $tempContentLength; $curlOptions[CURLOPT_INFILESIZE] = $tempContentLength; } // Add a callback for curl to read data to send with the request only if a body was specified $curlOptions[CURLOPT_READFUNCTION] = array($mediator, 'readRequestBody'); // Attempt to seek to the start of the stream $request->getBody()->seek(0); } } else { // Special handling for POST specific fields and files $postFields = false; if (count($request->getPostFiles())) { $postFields = $request->getPostFields()->useUrlEncoding(false)->urlEncode(); foreach ($request->getPostFiles() as $key => $data) { $prefixKeys = count($data) > 1; foreach ($data as $index => $file) { // Allow multiple files in the same key $fieldKey = $prefixKeys ? "{$key}[{$index}]" : $key; $postFields[$fieldKey] = $file->getCurlValue(); } } } elseif (count($request->getPostFields())) { $postFields = (string) $request->getPostFields()->useUrlEncoding(true); } if ($postFields !== false) { if ($method == 'POST') { unset($curlOptions[CURLOPT_CUSTOMREQUEST]); $curlOptions[CURLOPT_POST] = true; } $curlOptions[CURLOPT_POSTFIELDS] = $postFields; $request->removeHeader('Content-Length'); } } // If the Expect header is not present, prevent curl from adding it if (!$request->hasHeader('Expect')) { $curlOptions[CURLOPT_HTTPHEADER][] = 'Expect:'; } } // If a Content-Length header was specified but we want to allow curl to set one for us if (null !== $tempContentLength) { $request->removeHeader('Content-Length'); } // Set custom cURL options foreach ($requestCurlOptions->toArray() as $key => $value) { if (is_numeric($key)) { $curlOptions[$key] = $value; } } // Do not set an Accept header by default if (!isset($curlOptions[CURLOPT_ENCODING])) { $curlOptions[CURLOPT_HTTPHEADER][] = 'Accept:'; } // Add any custom headers to the request. Empty headers will cause curl to not send the header at all. foreach ($request->getHeaderLines() as $line) { $curlOptions[CURLOPT_HTTPHEADER][] = $line; } // Add the content-length header back if it was temporarily removed if ($tempContentLength) { $request->setHeader('Content-Length', $tempContentLength); } // Apply the options to a new cURL handle. $handle = curl_init(); // Enable the progress function if the 'progress' param was set if ($requestCurlOptions->get('progress')) { // Wrap the function in a function that provides the curl handle to the mediator's progress function // Using this rather than injecting the handle into the mediator prevents a circular reference $curlOptions[CURLOPT_PROGRESSFUNCTION] = function () use($mediator, $handle) { $args = func_get_args(); $args[] = $handle; // PHP 5.5 pushed the handle onto the start of the args if (is_resource($args[0])) { array_shift($args); } call_user_func_array(array($mediator, 'progress'), $args); }; $curlOptions[CURLOPT_NOPROGRESS] = false; } curl_setopt_array($handle, $curlOptions); return new static($handle, $curlOptions); }
/** * Factory method to create a new curl handle based on an HTTP request. * * There are some helpful options you can set to enable specific behavior: * - debug: Set to true to enable cURL debug functionality to track the * actual headers sent over the wire. The * - progress: Set to true to enable progress function callbacks. Most * users do not need this, so it has been disabled by default. * * @param RequestInterface $request Request * * @return CurlHandle */ public static function factory(RequestInterface $request) { $mediator = new RequestMediator($request); $requestCurlOptions = $request->getCurlOptions(); $tempContentLength = null; $method = $request->getMethod(); $client = $request->getClient(); // Array of default cURL options. $curlOptions = array(CURLOPT_URL => $request->getUrl(), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_RETURNTRANSFER => false, CURLOPT_HEADER => false, CURLOPT_USERAGENT => (string) $request->getHeader('User-Agent'), CURLOPT_ENCODING => '', CURLOPT_PORT => $request->getPort(), CURLOPT_HTTPHEADER => array(), CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'), CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0' ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1); // Enable the progress function if the 'progress' param was set if ($requestCurlOptions->get('progress')) { $curlOptions[CURLOPT_PROGRESSFUNCTION] = array($mediator, 'progress'); $curlOptions[CURLOPT_NOPROGRESS] = false; } // Enable curl debug information if the 'debug' param was set if ($requestCurlOptions->get('debug')) { $curlOptions[CURLOPT_STDERR] = fopen('php://temp', 'r+'); // @codeCoverageIgnoreStart if (false === $curlOptions[CURLOPT_STDERR]) { throw new RuntimeException('Unable to create a stream for CURLOPT_STDERR'); } // @codeCoverageIgnoreEnd $curlOptions[CURLOPT_VERBOSE] = true; } // HEAD requests need no response body, everything else might if ($method != 'HEAD') { $curlOptions[CURLOPT_WRITEFUNCTION] = array($mediator, 'writeResponseBody'); } // Account for PHP installations with safe_mode or open_basedir enabled // @codeCoverageIgnoreStart if (CurlVersion::getInstance()->get('follow_location')) { $curlOptions[CURLOPT_FOLLOWLOCATION] = true; $curlOptions[CURLOPT_MAXREDIRS] = 5; } // @codeCoverageIgnoreEnd // Specify settings according to the HTTP method switch ($method) { case 'GET': $curlOptions[CURLOPT_HTTPGET] = true; break; case 'HEAD': $curlOptions[CURLOPT_NOBODY] = true; break; case 'POST': $curlOptions[CURLOPT_POST] = true; // Special handling for POST specific fields and files if (count($request->getPostFiles())) { $fields = $request->getPostFields()->useUrlEncoding(false)->urlEncode(); foreach ($request->getPostFiles() as $key => $data) { $prefixKeys = count($data) > 1; foreach ($data as $index => $file) { // Allow multiple files in the same key $fieldKey = $prefixKeys ? "{$key}[{$index}]" : $key; $fields[$fieldKey] = $file->getCurlString(); } } $curlOptions[CURLOPT_POSTFIELDS] = $fields; $request->removeHeader('Content-Length'); } elseif (count($request->getPostFields())) { $curlOptions[CURLOPT_POSTFIELDS] = (string) $request->getPostFields()->useUrlEncoding(true); $request->removeHeader('Content-Length'); } elseif (!$request->getBody()) { // Need to remove CURLOPT_POST to prevent chunked encoding for an empty POST unset($curlOptions[CURLOPT_POST]); $curlOptions[CURLOPT_CUSTOMREQUEST] = 'POST'; } break; case 'PUT': case 'PATCH': case 'DELETE': $curlOptions[CURLOPT_UPLOAD] = true; if ($method != 'PUT') { $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; } // Let cURL handle setting the Content-Length header $contentLength = $request->getHeader('Content-Length'); if ($contentLength !== null) { $contentLength = (int) (string) $contentLength; $curlOptions[CURLOPT_INFILESIZE] = $contentLength; $tempContentLength = $contentLength; $request->removeHeader('Content-Length'); } break; default: $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; } // Special handling for requests sending raw data if ($request instanceof EntityEnclosingRequestInterface) { if ($request->getBody()) { // Add a callback for curl to read data to send with the request only if a body was specified $curlOptions[CURLOPT_READFUNCTION] = array($mediator, 'readRequestBody'); // Attempt to seek to the start of the stream $request->getBody()->seek(0); } // If the Expect header is not present, prevent curl from adding it if (!$request->hasHeader('Expect')) { $curlOptions[CURLOPT_HTTPHEADER][] = 'Expect:'; } } // Set custom cURL options foreach ($requestCurlOptions as $key => $value) { if (is_numeric($key)) { $curlOptions[$key] = $value; } } // Check if any headers or cURL options are blacklisted if ($client && ($blacklist = $client->getConfig('curl.blacklist'))) { foreach ($blacklist as $value) { if (strpos($value, 'header.') !== 0) { unset($curlOptions[$value]); } else { // Remove headers that may have previously been set but are supposed to be blacklisted $key = substr($value, 7); $request->removeHeader($key); $curlOptions[CURLOPT_HTTPHEADER][] = $key . ':'; } } } // Add any custom headers to the request. Empty headers will cause curl to not send the header at all. foreach ($request->getHeaderLines() as $line) { $curlOptions[CURLOPT_HTTPHEADER][] = $line; } // Apply the options to a new cURL handle. $handle = curl_init(); curl_setopt_array($handle, $curlOptions); $request->getParams()->set('curl.last_options', $curlOptions); if ($tempContentLength) { $request->setHeader('Content-Length', $tempContentLength); } $handle = new static($handle, $curlOptions); $mediator->setCurlHandle($handle); return $handle; }
protected function getDelay($retries, RequestInterface $request, Response $response = null, HttpException $e = null) { if ($response && $request->getMethod() === 'POST' && $request instanceof EntityEnclosingRequestInterface && $response->getStatusCode() == 200 && strpos($request->getBody(), '<CompleteMultipartUpload xmlns') !== false && strpos($response->getBody(), '<CompleteMultipartUploadResult xmlns') === false) { return true; } }
/** * Returns a formatted message * * @param RequestInterface $request Request that was sent * @param Response $response Response that was received * @param CurlHandle $handle Curl handle associated with the message * @param array $customData Associative array of custom template data * * @return string */ public function format(RequestInterface $request, Response $response = null, CurlHandle $handle = null, array $customData = array()) { $cache = $customData; return preg_replace_callback('/{\\s*([A-Za-z_\\-\\.0-9]+)\\s*}/', function (array $matches) use($request, $response, $handle, &$cache) { if (array_key_exists($matches[1], $cache)) { return $cache[$matches[1]]; } $result = ''; switch ($matches[1]) { case 'request': $result = (string) $request; break; case 'response': $result = (string) $response; break; case 'req_body': $result = $request instanceof EntityEnclosingRequestInterface ? (string) $request->getBody() : ''; break; case 'res_body': $result = $response ? $response->getBody(true) : ''; break; case 'ts': $result = gmdate('c'); break; case 'method': $result = $request->getMethod(); break; case 'url': $result = (string) $request->getUrl(); break; case 'resource': $result = $request->getResource(); break; case 'protocol': $result = 'HTTP'; break; case 'version': $result = $request->getProtocolVersion(); break; case 'host': $result = $request->getHost(); break; case 'hostname': $result = gethostname(); break; case 'port': $result = $request->getPort(); break; case 'code': $result = $response ? $response->getStatusCode() : ''; break; case 'phrase': $result = $response ? $response->getReasonPhrase() : ''; break; case 'connect_time': if ($handle) { $result = $handle->getInfo(CURLINFO_CONNECT_TIME); } elseif ($response) { $result = $response->getInfo('connect_time'); } break; case 'total_time': if ($handle) { $result = $handle->getInfo(CURLINFO_TOTAL_TIME); } elseif ($response) { $result = $response->getInfo('total_time'); } break; case 'curl_error': $result = $handle ? $handle->getError() : ''; break; case 'curl_code': $result = $handle ? $handle->getErrorNo() : ''; break; case 'curl_stderr': $result = $handle ? $handle->getStderr() : ''; break; default: if (strpos($matches[1], 'req_header_') === 0) { $result = $request->getHeader(substr($matches[1], 11)); } elseif (strpos($matches[1], 'res_header_') === 0) { $result = $response->getHeader(substr($matches[1], 11)); } } $cache[$matches[1]] = $result; return $result; }, $this->template); }
/** * Retrieves the HTTP method of the request. * * @return string Returns the request method. */ public function getMethod() { return $this->request->getMethod(); }
/** * Collect & sanitize data about a Guzzle request * * @param Guzzle\Http\Message\RequestInterface $request * * @return array */ private function collectRequest(GuzzleRequestInterface $request) { $body = null; if ($request instanceof EntityEnclosingRequestInterface) { $body = (string) $request->getBody(); } return array('headers' => $request->getHeaders(), 'method' => $request->getMethod(), 'scheme' => $request->getScheme(), 'host' => $request->getHost(), 'port' => $request->getPort(), 'path' => $request->getPath(), 'query' => $request->getQuery(), 'body' => $body); }
/** * Add the request's signature * * @param RequestInterface $request Request which will be modified */ protected function addQueryStringSignature(RequestInterface $request) { $qs = $request->getQuery(); $requestToSign = $this->signature->composeRequestToSign($qs->getAll(), array('endpoint' => $request->getUrl(), 'method' => $request->getMethod())); $qs->set('Signature', $this->signature->signRequest($requestToSign)); return true; }
/** * Create the canonical representation of a request * * @param RequestInterface $request Request to canonicalize * @param string $payload Request payload (typically the value * of the x-amz-content-sha256 header. * * @return array Returns an array of context information including: * - canonical_request * - signed_headers */ private function createSigningContext(RequestInterface $request, $payload) { $signable = array('host' => true, 'date' => true, 'content-md5' => true); // Normalize the path as required by SigV4 and ensure it's absolute $canon = $request->getMethod() . "\n" . $this->createCanonicalizedPath($request) . "\n" . $this->getCanonicalizedQueryString($request) . "\n"; $canonHeaders = array(); foreach ($request->getHeaders()->getAll() as $key => $values) { $key = strtolower($key); if (isset($signable[$key]) || substr($key, 0, 6) === 'x-amz-') { $values = $values->toArray(); if (count($values) == 1) { $values = $values[0]; } else { sort($values); $values = implode(',', $values); } $canonHeaders[$key] = $key . ':' . preg_replace('/\\s+/', ' ', $values); } } ksort($canonHeaders); $signedHeadersString = implode(';', array_keys($canonHeaders)); $canon .= implode("\n", $canonHeaders) . "\n\n" . $signedHeadersString . "\n" . $payload; return array('canonical_request' => $canon, 'signed_headers' => $signedHeadersString); }
/** * Log a message based on a request and response * * @param RequestInterface $request Request to log * @param Response $response Response to log */ private function log(RequestInterface $request, Response $response = null) { $message = ''; if ($this->settings & self::LOG_CONTEXT) { // Log common contextual information $message = $request->getHost() . ' - "' . $request->getMethod() . ' ' . $request->getResource() . ' ' . strtoupper($request->getScheme()) . '/' . $request->getProtocolVersion() . '"'; // If a response is set, then log additional contextual information if ($response) { $message .= sprintf(' - %s %s - %s %s %s', $response->getStatusCode(), $response->getContentLength() ?: 0, $response->getInfo('total_time'), $response->getInfo('speed_upload'), $response->getInfo('speed_download')); } } // Check if we are logging anything that will come from cURL if ($request->getParams()->get('curl_handle') && ($this->settings & self::LOG_DEBUG || $this->settings & self::LOG_HEADERS || $this->settings & self::LOG_BODY)) { // If context logging too, then add a new line for cleaner messages if ($this->settings & self::LOG_CONTEXT) { $message .= "\n"; } // Filter cURL's verbose output based on config settings $message .= $this->parseCurlLog($request); // Log the response body if the response is available if ($this->settings & self::LOG_BODY && $response) { if ($request->getParams()->get('response_wire')) { $message .= (string) $request->getParams()->get('response_wire'); } else { $message .= $response->getBody(true); } } } // Send the log message to the adapter, adding a category and host $priority = $response && !$response->isSuccessful() ? LOG_ERR : LOG_DEBUG; $this->logAdapter->log(trim($message), $priority, array('category' => 'guzzle.request', 'host' => $this->hostname)); }
/** * Create the canonical representation of a request * * @param RequestInterface $request Request to canonicalize * @param string $payload Request payload (typically the value * of the x-amz-content-sha256 header. * * @return array Returns an array of context information including: * - canonical_request * - signed_headers */ private function createSigningContext(RequestInterface $request, $payload) { // Normalize the path as required by SigV4 and ensure it's absolute $canon = $request->getMethod() . "\n" . '/' . ltrim($request->getPath(), '/') . "\n" . $this->getCanonicalizedQueryString($request) . "\n"; // Create the canonical headers $headers = array(); foreach ($request->getHeaders()->getAll() as $key => $values) { $key = strtolower($key); if ($key != 'user-agent') { $headers[$key] = array(); foreach ($values as $value) { $headers[$key][] = preg_replace('/\\s+/', ' ', trim($value)); } // Sort the value if there is more than one if (count($values) > 1) { sort($headers[$key]); } } } // The headers must be sorted ksort($headers); // Continue to build the canonical request by adding headers foreach ($headers as $key => $values) { // Combine multi-value headers into a comma separated list $canon .= $key . ':' . implode(',', $values) . "\n"; } // Create the signed headers $signedHeaders = implode(';', array_keys($headers)); $canon .= "\n{$signedHeaders}\n{$payload}"; return array('canonical_request' => $canon, 'signed_headers' => $signedHeaders); }
/** * Hash a request URL into a string that returns cache metadata * * @param RequestInterface $request * * @return string */ protected function getCacheKey(RequestInterface $request) { // Allow cache.key_filter to trim down the URL cache key by removing generate query string values (e.g. auth) if ($filter = $request->getParams()->get('cache.key_filter')) { $url = $request->getUrl(true); foreach (explode(',', $filter) as $remove) { $url->getQuery()->remove(trim($remove)); } } else { $url = $request->getUrl(); } return $this->keyPrefix . md5($request->getMethod() . ' ' . $url); }
/** * Adds the default context options to the stream context options * * @param RequestInterface $request Request */ protected function addDefaultContextOptions(RequestInterface $request) { $this->setContextValue('http', 'method', $request->getMethod()); $this->setContextValue('http', 'header', $request->getHeaderLines()); // Force 1.0 for now until PHP fully support chunked transfer-encoding decoding $this->setContextValue('http', 'protocol_version', '1.0'); $this->setContextValue('http', 'ignore_errors', true); }
public static function factory(RequestInterface $request) { $requestCurlOptions = $request->getCurlOptions(); $mediator = new RequestMediator($request, $requestCurlOptions->get('emit_io')); $tempContentLength = null; $method = $request->getMethod(); $bodyAsString = $requestCurlOptions->get(self::BODY_AS_STRING); $url = (string) $request->getUrl(); if (($pos = strpos($url, '#')) !== false) { $url = substr($url, 0, $pos); } $curlOptions = array(CURLOPT_URL => $url, CURLOPT_CONNECTTIMEOUT => 150, CURLOPT_RETURNTRANSFER => false, CURLOPT_HEADER => false, CURLOPT_PORT => $request->getPort(), CURLOPT_HTTPHEADER => array(), CURLOPT_WRITEFUNCTION => array($mediator, 'writeResponseBody'), CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'), CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0' ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1, CURLOPT_SSL_VERIFYPEER => 1, CURLOPT_SSL_VERIFYHOST => 2); if (defined('CURLOPT_PROTOCOLS')) { $curlOptions[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; } if ($acceptEncodingHeader = $request->getHeader('Accept-Encoding')) { $curlOptions[CURLOPT_ENCODING] = (string) $acceptEncodingHeader; $request->removeHeader('Accept-Encoding'); } if ($requestCurlOptions->get('debug')) { $curlOptions[CURLOPT_STDERR] = fopen('php://temp', 'r+'); if (false === $curlOptions[CURLOPT_STDERR]) { throw new RuntimeException('Unable to create a stream for CURLOPT_STDERR'); } $curlOptions[CURLOPT_VERBOSE] = true; } if ($method == 'GET') { $curlOptions[CURLOPT_HTTPGET] = true; } elseif ($method == 'HEAD') { $curlOptions[CURLOPT_NOBODY] = true; unset($curlOptions[CURLOPT_WRITEFUNCTION]); } elseif (!$request instanceof EntityEnclosingRequest) { $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; } else { $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; if ($request->getBody()) { if ($bodyAsString) { $curlOptions[CURLOPT_POSTFIELDS] = (string) $request->getBody(); if ($tempContentLength = $request->getHeader('Content-Length')) { $tempContentLength = (int) (string) $tempContentLength; } if (!$request->hasHeader('Content-Type')) { $curlOptions[CURLOPT_HTTPHEADER][] = 'Content-Type:'; } } else { $curlOptions[CURLOPT_UPLOAD] = true; if ($tempContentLength = $request->getHeader('Content-Length')) { $tempContentLength = (int) (string) $tempContentLength; $curlOptions[CURLOPT_INFILESIZE] = $tempContentLength; } $curlOptions[CURLOPT_READFUNCTION] = array($mediator, 'readRequestBody'); $request->getBody()->seek(0); } } else { $postFields = false; if (count($request->getPostFiles())) { $postFields = $request->getPostFields()->useUrlEncoding(false)->urlEncode(); foreach ($request->getPostFiles() as $key => $data) { $prefixKeys = count($data) > 1; foreach ($data as $index => $file) { $fieldKey = $prefixKeys ? "{$key}[{$index}]" : $key; $postFields[$fieldKey] = $file->getCurlValue(); } } } elseif (count($request->getPostFields())) { $postFields = (string) $request->getPostFields()->useUrlEncoding(true); } if ($postFields !== false) { if ($method == 'POST') { unset($curlOptions[CURLOPT_CUSTOMREQUEST]); $curlOptions[CURLOPT_POST] = true; } $curlOptions[CURLOPT_POSTFIELDS] = $postFields; $request->removeHeader('Content-Length'); } } if (!$request->hasHeader('Expect')) { $curlOptions[CURLOPT_HTTPHEADER][] = 'Expect:'; } } if (null !== $tempContentLength) { $request->removeHeader('Content-Length'); } foreach ($requestCurlOptions->toArray() as $key => $value) { if (is_numeric($key)) { $curlOptions[$key] = $value; } } if (!isset($curlOptions[CURLOPT_ENCODING])) { $curlOptions[CURLOPT_HTTPHEADER][] = 'Accept:'; } foreach ($request->getHeaderLines() as $line) { $curlOptions[CURLOPT_HTTPHEADER][] = $line; } if ($tempContentLength) { $request->setHeader('Content-Length', $tempContentLength); } $handle = curl_init(); if ($requestCurlOptions->get('progress')) { $curlOptions[CURLOPT_PROGRESSFUNCTION] = function () use($mediator, $handle) { $args = func_get_args(); $args[] = $handle; if (is_resource($args[0])) { array_shift($args); } call_user_func_array(array($mediator, 'progress'), $args); }; $curlOptions[CURLOPT_NOPROGRESS] = false; } curl_setopt_array($handle, $curlOptions); return new static($handle, $curlOptions); }
protected function getCacheKey(RequestInterface $request) { if ($filter = $request->getParams()->get('cache.key_filter')) { $url = $request->getUrl(true); foreach (explode(',', $filter) as $remove) { $url->getQuery()->remove(trim($remove)); } } else { $url = $request->getUrl(); } return $this->keyPrefix . md5($request->getMethod() . ' ' . $url); }