/**
  * {@inheritdoc}
  */
 public function getCacheKey(RequestInterface $request)
 {
     // See if the key has already been calculated
     $key = $request->getParams()->get(self::CACHE_KEY);
     if (!$key) {
         $cloned = clone $request;
         $cloned->removeHeader('Cache-Control');
         // Check to see how and if the key should be filtered
         foreach (explode(';', $request->getParams()->get(self::CACHE_KEY_FILTER)) as $part) {
             $pieces = array_map('trim', explode('=', $part));
             if (isset($pieces[1])) {
                 foreach (array_map('trim', explode(',', $pieces[1])) as $remove) {
                     if ($pieces[0] == 'header') {
                         $cloned->removeHeader($remove);
                     } elseif ($pieces[0] == 'query') {
                         $cloned->getQuery()->remove($remove);
                     }
                 }
             }
         }
         $raw = (string) $cloned;
         $key = 'GZ' . md5($raw);
         $request->getParams()->set(self::CACHE_KEY, $key)->set(self::CACHE_KEY_RAW, $raw);
     }
     return $key;
 }
 /**
  * {@inheritdoc}
  */
 public function signRequest(RequestInterface $request, CredentialsInterface $credentials)
 {
     // Add a date header if one is not set
     if (!$request->hasHeader('date') && !$request->hasHeader('x-amz-date')) {
         $request->setHeader('Date', gmdate(DateFormat::RFC2822));
     }
     $stringToSign = (string) $request->getHeader('Date') ?: (string) $request->getHeader('x-amz-date');
     $request->getParams()->set('aws.string_to_sign', $stringToSign);
     $request->setHeader('Authorization', 'AWS ' . $credentials->getAccessKeyId() . ':' . $this->signString($stringToSign, $credentials));
 }
 /**
  * {@inheritdoc}
  */
 public function signRequest(RequestInterface $request, CredentialsInterface $credentials)
 {
     // Add a date header if one is not set
     if (!$request->hasHeader('date') && !$request->hasHeader('x-amz-date')) {
         $request->setHeader('Date', $this->getDateTime(DateFormat::RFC1123));
     }
     // Add the security token if one is present
     if ($credentials->getSecurityToken()) {
         $request->setHeader('x-amz-security-token', $credentials->getSecurityToken());
     }
     // Determine the string to sign
     $stringToSign = $request->getHeader('Date', true) ?: $request->getHeader('x-amz-date', true);
     $request->getParams()->set('aws.string_to_sign', $stringToSign);
     // Calculate the signature
     $signature = base64_encode(hash_hmac('sha256', $stringToSign, $credentials->getSecretKey(), true));
     // Add the authorization header to the request
     $headerFormat = 'AWS3-HTTPS AWSAccessKeyId=%s,Algorithm=HmacSHA256,Signature=%s';
     $request->setHeader('X-Amzn-Authorization', sprintf($headerFormat, $credentials->getAccessKeyId(), $signature));
 }
 /**
  * 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:
  *    - disabled_wire: This is a performance improvement that will disable
  *         some debugging functionality with cURL.  The functionality
  *         it disabled allows you to see the exact HTTP request sent over
  *         the wire.
  *    - progress: Set to true to enable progress function callbacks. Most
  *         People don't need this, so it has been disabled by default.
  *
  * @param RequestInterface $request Request
  *
  * @return CurlHandle
  */
 public static function factory(RequestInterface $request)
 {
     $handle = curl_init();
     $mediator = new RequestMediator($request);
     $requestCurlOptions = $request->getCurlOptions();
     // Array of default cURL options.
     $curlOptions = array(CURLOPT_URL => $request->getUrl(), CURLOPT_CUSTOMREQUEST => $request->getMethod(), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_RETURNTRANSFER => false, CURLOPT_HEADER => false, CURLOPT_USERAGENT => (string) $request->getHeader('User-Agent'), CURLOPT_ENCODING => '', CURLOPT_PORT => $request->getPort(), CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0' ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1, CURLOPT_HTTPHEADER => array(), CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'));
     // 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('disable_wire')) {
         $curlOptions[CURLOPT_STDERR] = fopen('php://temp', 'r+');
         $curlOptions[CURLOPT_VERBOSE] = true;
     }
     // HEAD requests need no response body, everything else might
     if ($request->getMethod() != 'HEAD') {
         $curlOptions[CURLOPT_WRITEFUNCTION] = array($mediator, 'writeResponseBody');
     }
     // Account for PHP installations with safe_mode or open_basedir enabled
     // @codeCoverageIgnoreStart
     if (Guzzle::getCurlInfo('follow_location')) {
         $curlOptions[CURLOPT_FOLLOWLOCATION] = true;
         $curlOptions[CURLOPT_MAXREDIRS] = 5;
     }
     // @codeCoverageIgnoreEnd
     $headers = $request->getHeaders()->getAll();
     // Specify settings according to the HTTP method
     switch ($request->getMethod()) {
         case 'GET':
             $curlOptions[CURLOPT_HTTPGET] = true;
             break;
         case 'HEAD':
             $curlOptions[CURLOPT_NOBODY] = true;
             unset($curlOptions[CURLOPT_WRITEFUNCTION]);
             break;
         case 'POST':
             $curlOptions[CURLOPT_POST] = true;
             break;
         case 'PUT':
         case 'PATCH':
             $curlOptions[CURLOPT_UPLOAD] = true;
             if ($request->hasHeader('Content-Length')) {
                 unset($headers['Content-Length']);
                 $curlOptions[CURLOPT_INFILESIZE] = (int) (string) $request->getHeader('Content-Length');
             }
             break;
     }
     if ($request instanceof EntityEnclosingRequestInterface) {
         // If no body is being sent, always send Content-Length of 0
         if (!$request->getBody() && !count($request->getPostFields())) {
             $headers['Content-Length'] = 0;
             unset($headers['Transfer-Encoding']);
             // Need to remove CURLOPT_UPLOAD to prevent chunked encoding
             unset($curlOptions[CURLOPT_UPLOAD]);
             unset($curlOptions[CURLOPT_POST]);
             // Not reading from a callback when using empty body
             unset($curlOptions[CURLOPT_READFUNCTION]);
         } else {
             // Add a callback for curl to read data to send with the request
             $curlOptions[CURLOPT_READFUNCTION] = array($mediator, 'readRequestBody');
         }
         // 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
     $client = $request->getClient();
     if ($client) {
         $blacklist = $client->getConfig('curl.blacklist');
         if ($blacklist) {
             foreach ($blacklist as $value) {
                 if (strpos($value, 'header.') === 0) {
                     $blacklistHeader = substr($value, 7);
                     // Remove headers that may have previously been set
                     // but are supposed to be blacklisted
                     unset($headers[$blacklistHeader]);
                     $headers[$blacklistHeader] = '';
                 } else {
                     unset($curlOptions[$value]);
                 }
             }
         }
     }
     // Add any custom headers to the request. Emtpy headers will cause curl to
     // not send the header at all.
     foreach ($headers as $key => $value) {
         foreach ((array) $value as $val) {
             $curlOptions[CURLOPT_HTTPHEADER][] = trim("{$key}: {$val}");
         }
     }
     // Apply the options to the cURL handle.
     curl_setopt_array($handle, $curlOptions);
     $request->getParams()->set('curl.last_options', $curlOptions);
     return new static($handle, $curlOptions);
 }
Example #5
0
 /**
  * Create a canonicalized resource for a request
  *
  * @param RequestInterface $request Request for the resource
  *
  * @return string
  */
 private function createCanonicalizedResource(RequestInterface $request)
 {
     $buffer = $request->getParams()->get('s3.resource');
     // When sending a raw HTTP request (e.g. $client->get())
     if (null === $buffer) {
         $bucket = $request->getParams()->get('bucket') ?: $this->parseBucketName($request);
         // Use any specified bucket name, the parsed bucket name, or no bucket name when interacting with GetService
         $buffer = $bucket ? "/{$bucket}" : '';
         // Remove encoding from the path and use the S3 specific encoding
         $path = ObsClient::encodeKey(rawurldecode($request->getPath()));
         // if the bucket was path style, then ensure that the bucket wasn't duplicated in the resource
         $buffer .= preg_replace("#^/{$bucket}/{$bucket}#", "/{$bucket}", $path);
     }
     // Remove double slashes
     $buffer = str_replace('//', '/', $buffer);
     // Add sub resource parameters
     $query = $request->getQuery();
     $first = true;
     foreach ($this->signableQueryString as $key) {
         if ($query->hasKey($key)) {
             $value = $query[$key];
             $buffer .= $first ? '?' : '&';
             $first = false;
             $buffer .= $key;
             // Don't add values for empty sub-resources
             if ($value !== '' && $value !== false && $value !== null && $value !== QueryString::BLANK) {
                 $buffer .= "={$value}";
             }
         }
     }
     return $buffer;
 }
Example #6
0
 /**
  * Add the plugin's headers to a response
  *
  * @param RequestInterface $request  Request
  * @param Response         $response Response to add headers to
  */
 protected function addResponseHeaders(RequestInterface $request, Response $response)
 {
     $params = $request->getParams();
     $response->setHeader('Via', sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION));
     $lookup = ($params['cache.lookup'] === true ? 'HIT' : 'MISS') . ' from GuzzleCache';
     if ($header = $response->getHeader('X-Cache-Lookup')) {
         // Don't add duplicates
         $values = $header->toArray();
         $values[] = $lookup;
         $response->setHeader('X-Cache-Lookup', array_unique($values));
     } else {
         $response->setHeader('X-Cache-Lookup', $lookup);
     }
     if ($params['cache.hit'] === true) {
         $xcache = 'HIT from GuzzleCache';
     } elseif ($params['cache.hit'] == 'error') {
         $xcache = 'HIT_ERROR from GuzzleCache';
     } else {
         $xcache = 'MISS from GuzzleCache';
     }
     if ($header = $response->getHeader('X-Cache')) {
         // Don't add duplicates
         $values = $header->toArray();
         $values[] = $xcache;
         $response->setHeader('X-Cache', array_unique($values));
     } else {
         $response->setHeader('X-Cache', $xcache);
     }
     if ($response->isFresh() === false) {
         $response->addHeader('Warning', sprintf('110 GuzzleCache/%s "Response is stale"', Version::VERSION));
         if ($params['cache.hit'] === 'error') {
             $response->addHeader('Warning', sprintf('111 GuzzleCache/%s "Revalidation failed"', Version::VERSION));
         }
     }
 }
Example #7
0
protected function visit_params(RequestInterface $request, $value, $flags)
{
if (!is_array($value)) {
throw new InvalidArgumentException('params value must be an array');
}

$request->getParams()->overwriteWith($value);
}
 /**
  * Trigger a request to retry
  *
  * @param RequestInterface $request Request to retry
  */
 protected function retryRequest(RequestInterface $request)
 {
     $params = $request->getParams();
     $retries = (int) $params->get(self::RETRY_PARAM) + 1;
     $params->set(self::RETRY_PARAM, $retries);
     // If this request has been retried too many times, then throw an exception
     if ($retries <= $this->maxRetries) {
         // Calculate how long to wait until the request should be retried
         $delay = call_user_func($this->delayClosure, $retries);
         $delayTime = microtime(true) + $delay;
         // Send the request again
         $request->setState(RequestInterface::STATE_TRANSFER);
         $params->set(self::DELAY_PARAM, $delay);
     }
 }
 /**
  * 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);
 }
Example #10
0
 /**
  * Prepare the request for redirection and enforce the maximum number of allowed redirects per client
  *
  * @param RequestInterface $request Request to prepare and validate
  *
  * @return RequestInterface Returns the original request
  */
 protected function prepareRedirection(RequestInterface $request)
 {
     $original = $request;
     // The number of redirects is held on the original request, so determine which request that is
     while ($parent = $original->getParams()->get(self::PARENT_REQUEST)) {
         $original = $parent;
     }
     // Always associate the parent response with the current response so that a chain can be established
     if ($parent = $request->getParams()->get(self::PARENT_REQUEST)) {
         $request->getResponse()->setPreviousResponse($parent->getResponse());
     }
     $params = $original->getParams();
     // This is a new redirect, so increment the redirect counter
     $current = $params->get(self::REDIRECT_COUNT) + 1;
     $params->set(self::REDIRECT_COUNT, $current);
     // Use a provided maximum value or default to a max redirect count of 5
     $max = $params->hasKey(self::MAX_REDIRECTS) ? $params->get(self::MAX_REDIRECTS) : $this->defaultMaxRedirects;
     // Throw an exception if the redirect count is exceeded
     if ($current > $max) {
         return $this->throwTooManyRedirectsException($request);
     }
     return $original;
 }
Example #11
0
 /**
  * Factory method to create a new curl handle based on an HTTP request.
  *
  * Note that the HTTP request may be modified by this method
  *
  * There are some helpful options you can set to enable specific behavior:
  *
  *    - disabled_wire: This is a performance improvement that will disable
  *                     some debugging functionality with cURL.  The
  *                     functionality it disabled allows you to see the
  *                     exact HTTP request sent over the wire.
  *    - progress:      Set to true to enable progress function callbacks.
  *                     Most people don't 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();
     $tempHeaders = array();
     // Array of default cURL options.
     $curlOptions = array(CURLOPT_URL => $request->getUrl(), CURLOPT_CUSTOMREQUEST => $request->getMethod(), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_RETURNTRANSFER => false, CURLOPT_HEADER => false, CURLOPT_USERAGENT => (string) $request->getHeader('User-Agent'), CURLOPT_ENCODING => '', CURLOPT_PORT => $request->getPort(), CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0' ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1, CURLOPT_HTTPHEADER => array(), CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'));
     // 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('disable_wire')) {
         $curlOptions[CURLOPT_STDERR] = fopen('php://temp', 'r+');
         $curlOptions[CURLOPT_VERBOSE] = true;
     }
     // HEAD requests need no response body, everything else might
     if ($request->getMethod() != '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 ($request->getMethod()) {
         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())) {
                 $curlOptions[CURLOPT_POSTFIELDS] = $request->getPostFields()->getAll();
                 $request->removeHeader('Content-Length');
             } elseif (count($request->getPostFields())) {
                 $curlOptions[CURLOPT_POSTFIELDS] = (string) $request->getPostFields();
                 $request->removeHeader('Content-Length');
             }
             break;
         case 'PUT':
         case 'PATCH':
             $curlOptions[CURLOPT_UPLOAD] = true;
             // Let cURL handle setting the Content-Length header
             $contentLength = $request->getHeader('Content-Length');
             if ($contentLength != null) {
                 $contentLength = (int) (string) $contentLength;
                 $curlOptions[CURLOPT_INFILESIZE] = $contentLength;
                 $tempHeaders['Content-Length'] = $contentLength;
                 $request->removeHeader('Content-Length');
             }
             break;
     }
     // Special handling for requests sending raw data
     if ($request instanceof EntityEnclosingRequestInterface) {
         // Don't modify POST requests using POST fields and files via cURL
         if (!isset($curlOptions[CURLOPT_POSTFIELDS])) {
             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');
             } else {
                 // If no body is being sent, always send Content-Length of 0
                 $request->setHeader('Content-Length', 0);
                 $request->removeHeader('Transfer-Encoding');
                 // Need to remove CURLOPT_UPLOAD to prevent chunked encoding
                 unset($curlOptions[CURLOPT_UPLOAD]);
                 unset($curlOptions[CURLOPT_POST]);
             }
         }
         // 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
     $client = $request->getClient();
     if ($client) {
         $blacklist = $client->getConfig('curl.blacklist');
         if ($blacklist) {
             foreach ($blacklist as $value) {
                 if (strpos($value, 'header.') === 0) {
                     // 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 . ':';
                 } else {
                     unset($curlOptions[$value]);
                 }
             }
         }
     }
     // Add any custom headers to the request. Emtpy headers will cause curl to
     // not send the header at all.
     foreach ($request->getHeaders() as $headerName => $values) {
         foreach ($values as $value) {
             $curlOptions[CURLOPT_HTTPHEADER][] = trim("{$headerName}: {$value}");
         }
     }
     // Apply the options to a new cURL handle.
     $handle = curl_init();
     curl_setopt_array($handle, $curlOptions);
     $request->getParams()->set('curl.last_options', $curlOptions);
     // Some fields need to be removed from the request in order to properly
     // send a cURL request message.  The fields that were removed for this
     // purpose (e.g. Content-Length) should be aggregated in this array and
     // added back to the request. Does not apply to blacklisted headers.
     foreach ($tempHeaders as $key => $value) {
         $request->setHeader($key, $value);
     }
     return new static($handle, $curlOptions);
 }
Example #12
0
 /**
  * Get application and plugin specific parameters set on the message.
  *
  * @return Collection
  */
 public function getParams()
 {
     return $this->wrapped->getParams();
 }
 /**
  * Prepare a request to be sent from the Client by adding client specific behaviors and properties to the request.
  *
  * @param RequestInterface $request Request to prepare for the client
  *
  * @return RequestInterface
  */
 protected function prepareRequest(RequestInterface $request)
 {
     $request->setClient($this);
     // Add any curl options to the request
     if ($options = $this->config->get(self::CURL_OPTIONS)) {
         $request->getCurlOptions()->merge(CurlHandle::parseCurlConfig($options));
     }
     // Add request parameters to the request
     if ($options = $this->config->get(self::REQUEST_PARAMS)) {
         $request->getParams()->merge($options);
     }
     // Attach client observers to the request
     $request->setEventDispatcher(clone $this->getEventDispatcher());
     // Set the User-Agent if one is specified on the client but not explicitly on the request
     if ($this->userAgent && !$request->hasHeader('User-Agent')) {
         $request->setHeader('User-Agent', $this->userAgent);
     }
     $this->dispatch('client.create_request', array('client' => $this, 'request' => $request));
     return $request;
 }
Example #14
0
 /**
  * Sends a request.
  *
  * @param \Guzzle\Http\Message\RequestInterface $request The request.
  *
  * @throws \Widop\HttpAdapter\HttpAdapterException If an error occured.
  *
  * @return \Widop\HttpAdapter\HttpResponse The response.
  */
 private function sendRequest(RequestInterface $request)
 {
     $request->getParams()->set('redirect.max', $this->getMaxRedirects());
     try {
         $response = $request->send();
     } catch (\Exception $e) {
         throw HttpAdapterException::cannotFetchUrl($request->getUrl(), $this->getName(), $e->getMessage());
     }
     return $this->createResponse($response->getStatusCode(), $request->getUrl(), $response->getHeaders()->toArray(), $response->getBody(true), $response->getEffectiveUrl());
 }
Example #15
0
 /**
  * Prepare a request to be sent from the Client by adding client specific
  * behaviors and properties to the request.
  *
  * @param RequestInterface $request Request to prepare for the client
  *
  * @return RequestInterface
  */
 protected function prepareRequest(RequestInterface $request)
 {
     $request->setClient($this);
     foreach ($this->getConfig()->getAll() as $key => $value) {
         if ($key == 'curl.blacklist') {
             continue;
         }
         // Add any curl options that might in the config to the request
         if (strpos($key, 'curl.') === 0) {
             $curlOption = substr($key, 5);
             // Convert constants represented as string to constant int values
             if (defined($curlOption)) {
                 $value = is_string($value) && defined($value) ? constant($value) : $value;
                 $curlOption = constant($curlOption);
             }
             $request->getCurlOptions()->set($curlOption, $value);
         } elseif (strpos($key, 'params.') === 0) {
             // Add request specific parameters to all requests (prefix with 'params.')
             $request->getParams()->set(substr($key, 7), $value);
         }
     }
     // Attach client observers to the request
     $request->setEventDispatcher(clone $this->getEventDispatcher());
     $this->dispatch('client.create_request', array('client' => $this, 'request' => $request));
     return $request;
 }
Example #16
0
 /**
  * Set the associated CurlHandle object
  *
  * @param CurlHandle $handle Curl handle
  *
  * @return RequestMediator
  */
 public function setCurlHandle(CurlHandle $handle)
 {
     $this->curlHandle = $handle;
     $this->request->getParams()->set('curl_handle', $handle);
     return $this;
 }
 /**
  * Prepare a request to be sent from the Client by adding client specific
  * behaviors and properties to the request.
  *
  * @param RequestInterface $request Request to prepare for the client
  *
  * @return RequestInterface
  */
 protected function prepareRequest(RequestInterface $request)
 {
     $request->setClient($this);
     // Add any curl options to the request
     $request->getCurlOptions()->merge(CurlHandle::parseCurlConfig($this->config));
     foreach ($this->config as $key => $value) {
         if (strpos($key, 'params.') === 0) {
             // Add request specific parameters to all requests (prefix with 'params.')
             $request->getParams()->set(substr($key, 7), $value);
         }
     }
     // Attach client observers to the request
     $request->setEventDispatcher(clone $this->getEventDispatcher());
     $this->dispatch('client.create_request', array('client' => $this, 'request' => $request));
     return $request;
 }
 /**
  * Add the plugin's headers to a response
  *
  * @param string           $cacheKey Cache key
  * @param RequestInterface $request  Request
  * @param Response         $response Response to add headers to
  */
 protected function addResponseHeaders($cacheKey, RequestInterface $request, Response $response)
 {
     if (!$response->hasHeader('X-Guzzle-Cache')) {
         $response->setHeader('X-Guzzle-Cache', "key={$cacheKey}");
     }
     $response->addHeader('Via', sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION));
     if ($this->debugHeaders) {
         if ($request->getParams()->get('cache.lookup') === true) {
             $response->addHeader('X-Cache-Lookup', 'HIT from GuzzleCache');
         } else {
             $response->addHeader('X-Cache-Lookup', 'MISS from GuzzleCache');
         }
         if ($request->getParams()->get('cache.hit') === true) {
             $response->addHeader('X-Cache', 'HIT from GuzzleCache');
         } elseif ($request->getParams()->get('cache.hit') === 'error') {
             $response->addHeader('X-Cache', 'HIT_ERROR from GuzzleCache');
         } else {
             $response->addHeader('X-Cache', 'MISS from GuzzleCache');
         }
     }
     if ($response->isFresh() === false) {
         $response->addHeader('Warning', sprintf('110 GuzzleCache/%s "Response is stale"', Version::VERSION));
         if ($request->getParams()->get('cache.hit') === 'error') {
             $response->addHeader('Warning', sprintf('111 GuzzleCache/%s "Revalidation failed"', Version::VERSION));
         }
     }
 }
Example #19
0
 /**
  * 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;
 }
 /**
  * Prepare a request to be sent from the Client by adding client specific behaviors and properties to the request.
  *
  * @param RequestInterface $request Request to prepare for the client
  *
  * @return RequestInterface
  */
 protected function prepareRequest(RequestInterface $request)
 {
     $request->setClient($this);
     // Add any curl options to the request
     if ($options = $this->config->get(self::CURL_OPTIONS)) {
         $request->getCurlOptions()->merge(CurlHandle::parseCurlConfig($options));
     }
     // Add request parameters to the request
     if ($options = $this->config->get(self::REQUEST_PARAMS)) {
         $request->getParams()->merge($options);
     }
     // Attach client observers to the request
     $request->setEventDispatcher(clone $this->getEventDispatcher());
     $this->dispatch('client.create_request', array('client' => $this, 'request' => $request));
     return $request;
 }
Example #21
0
 /**
  * Parse cURL log messages
  *
  * @param RequestInterface $request Request that has a curl handle
  *
  * @return string
  */
 protected function parseCurlLog(RequestInterface $request)
 {
     $message = '';
     $handle = $request->getParams()->get('curl_handle');
     $stderr = $handle->getStderr(true);
     if ($stderr) {
         rewind($stderr);
         while ($line = fgets($stderr)) {
             // * - Debug | < - Downstream | > - Upstream
             if ($line[0] == '*') {
                 if ($this->settings & self::LOG_DEBUG) {
                     $message .= $line;
                 }
             } elseif ($this->settings & self::LOG_HEADERS) {
                 $message .= $line;
             }
             // Add the request body if needed
             if ($this->settings & self::LOG_BODY) {
                 if (trim($line) == '' && $request instanceof EntityEnclosingRequestInterface) {
                     if ($request->getParams()->get('request_wire')) {
                         $message .= (string) $request->getParams()->get('request_wire') . "\r\n";
                     } else {
                         $message .= (string) $request->getBody() . "\r\n";
                     }
                 }
             }
         }
     }
     return $message;
 }
Example #22
0
 /**
  * Prepare the request for redirection and enforce the maximum number of allowed redirects per client
  *
  * @param RequestInterface $original  Original request
  * @param RequestInterface $request   Request to prepare and validate
  * @param Response         $response  The current response
  *
  * @return RequestInterface
  */
 protected function prepareRedirection(RequestInterface $original, RequestInterface $request, Response $response)
 {
     $params = $original->getParams();
     // This is a new redirect, so increment the redirect counter
     $current = $params[self::REDIRECT_COUNT] + 1;
     $params[self::REDIRECT_COUNT] = $current;
     // Use a provided maximum value or default to a max redirect count of 5
     $max = isset($params[self::MAX_REDIRECTS]) ? $params[self::MAX_REDIRECTS] : $this->defaultMaxRedirects;
     // Throw an exception if the redirect count is exceeded
     if ($current > $max) {
         $this->throwTooManyRedirectsException($original, $max);
         return false;
     } else {
         // Create a redirect request based on the redirect rules set on the request
         return $this->createRedirectRequest($request, $response->getStatusCode(), trim($response->getLocation()), $original);
     }
 }
 /**
  * @param RequestInterface $request Request to mediate
  */
 public function __construct(RequestInterface $request)
 {
     $this->request = $request;
     $this->emitIo = $request->getParams()->get('curl.emit_io');
 }
Example #24
0
 /**
  * Clone a request while changing the method. Emulates the behavior of
  * {@see Guzzle\Http\Message\Request::clone}, but can change the HTTP method.
  *
  * @param RequestInterface $request Request to clone
  * @param string           $method  Method to set
  *
  * @return RequestInterface
  */
 public function cloneRequestWithMethod(RequestInterface $request, $method)
 {
     // Create the request with the same client if possible
     if ($client = $request->getClient()) {
         $cloned = $request->getClient()->createRequest($method, $request->getUrl(), $request->getHeaders());
     } else {
         $cloned = $this->create($method, $request->getUrl(), $request->getHeaders());
     }
     $cloned->getCurlOptions()->replace($request->getCurlOptions()->getAll());
     $cloned->setEventDispatcher(clone $request->getEventDispatcher());
     // Ensure that that the Content-Length header is not copied if changing to GET or HEAD
     if (!$cloned instanceof EntityEnclosingRequestInterface) {
         $cloned->removeHeader('Content-Length');
     } elseif ($request instanceof EntityEnclosingRequestInterface) {
         $cloned->setBody($request->getBody());
     }
     $cloned->getParams()->replace($request->getParams()->getAll())->remove('curl_handle')->remove('curl_multi');
     return $cloned;
 }
Example #25
0
 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);
 }
 /**
  * Prepare a request to be sent from the Client by adding client specific behaviors and properties to the request.
  *
  * @param RequestInterface $request Request to prepare for the client
  * @param array            $options Options to apply to the request
  *
  * @return RequestInterface
  */
 protected function prepareRequest(RequestInterface $request, array $options = array())
 {
     $request->setClient($this)->setEventDispatcher(clone $this->getEventDispatcher());
     if ($curl = $this->config[self::CURL_OPTIONS]) {
         $request->getCurlOptions()->overwriteWith(CurlHandle::parseCurlConfig($curl));
     }
     if ($params = $this->config[self::REQUEST_PARAMS]) {
         Version::warn('request.params is deprecated. Use request.options to add default request options.');
         $request->getParams()->overwriteWith($params);
     }
     if ($this->userAgent && !$request->hasHeader('User-Agent')) {
         $request->setHeader('User-Agent', $this->userAgent);
     }
     if ($defaults = $this->config[self::REQUEST_OPTIONS]) {
         $this->requestFactory->applyOptions($request, $defaults, RequestFactoryInterface::OPTIONS_AS_DEFAULTS);
     }
     if ($options) {
         $this->requestFactory->applyOptions($request, $options);
     }
     $this->dispatch('client.create_request', array('client' => $this, 'request' => $request));
     return $request;
 }
Example #27
0
 protected function prepareRedirection(RequestInterface $original, RequestInterface $request, Response $response)
 {
     $params = $original->getParams();
     $current = $params[self::REDIRECT_COUNT] + 1;
     $params[self::REDIRECT_COUNT] = $current;
     $max = isset($params[self::MAX_REDIRECTS]) ? $params[self::MAX_REDIRECTS] : $this->defaultMaxRedirects;
     if ($current > $max) {
         $this->throwTooManyRedirectsException($original, $max);
         return false;
     } else {
         return $this->createRedirectRequest($request, $response->getStatusCode(), trim($response->getLocation()), $original);
     }
 }
Example #28
0
 /**
  * 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;
 }
 /**
  * Trigger a request to retry
  *
  * @param RequestInterface $request  Request to retry
  * @param Response         $response Response received
  * @param CurlHandle       $handle   Curl handle
  */
 protected function retryRequest(RequestInterface $request, Response $response = null, CurlHandle $handle = null)
 {
     $params = $request->getParams();
     $retries = (int) $params->get(self::RETRY_PARAM) + 1;
     $params->set(self::RETRY_PARAM, $retries);
     // If this request has been retried too many times, then throw an exception
     if ($retries <= $this->maxRetries) {
         // Calculate how long to wait until the request should be retried
         $delay = call_user_func($this->delayClosure, $retries, $request);
         $delayTime = microtime(true) + $delay;
         // Send the request again
         $request->setState(RequestInterface::STATE_TRANSFER);
         $params->set(self::DELAY_PARAM, $delayTime);
         $this->dispatch(self::RETRY_EVENT, array('request' => $request, 'response' => $response, 'handle' => $handle, 'retries' => $retries, 'delay' => $delay));
     }
 }