private function modifyRedirectRequest(RequestInterface $request, ResponseInterface $response) { $config = $request->getConfig(); // Use a GET request if this is an entity enclosing request and we are // not forcing RFC compliance, but rather emulating what all browsers // would do. $statusCode = $response->getStatusCode(); if ($statusCode == 303 || $statusCode <= 302 && $request->getBody() && !$config->getPath('redirect/strict')) { $request->setMethod('GET'); $request->setBody(null); } $previousUrl = $request->getUrl(); $this->setRedirectUrl($request, $response); $this->rewindEntityBody($request); // Add the Referer header if it is told to do so and only // add the header if we are not redirecting from https to http. if ($config->getPath('redirect/referer') && ($request->getScheme() == 'https' || $request->getScheme() == $config['redirect_scheme'])) { $url = Url::fromString($previousUrl); $url->setUsername(null); $url->setPassword(null); $request->setHeader('Referer', (string) $url); } else { $request->removeHeader('Referer'); } }
/** * Creates a Ring request from a request object. * * This function does not hook up the "then" and "progress" events that * would be required for actually sending a Guzzle request through a * RingPHP handler. * * @param RequestInterface $request Request to convert. * * @return array Converted Guzzle Ring request. */ public static function createRingRequest(RequestInterface $request) { $options = $request->getConfig()->toArray(); $url = $request->getUrl(); // No need to calculate the query string twice (in URL and query). $qs = ($pos = strpos($url, '?')) ? substr($url, $pos + 1) : null; return ['scheme' => $request->getScheme(), 'http_method' => $request->getMethod(), 'url' => $url, 'uri' => $request->getPath(), 'headers' => $request->getHeaders(), 'body' => $request->getBody(), 'version' => $request->getProtocolVersion(), 'client' => $options, 'query_string' => $qs, 'future' => isset($options['future']) ? $options['future'] : false]; }
public function save(RequestInterface $request, ResponseInterface $response) { $ttl = (int) $request->getConfig()->get('cache.ttl'); $key = $this->getCacheKey($request); // Persist the response body if needed if ($response->getBody() && $response->getBody()->getSize() > 0) { $this->cache->save($key, array('code' => $response->getStatusCode(), 'headers' => $response->getHeaders(), 'body' => (string) $response->getBody()), $ttl); $request->getConfig()->set('cache.key', $key); } }
/** * Signs the specified request with an SellerCenter API signing protocol by using the * provided SellerCenter API credentials and adding the required headers to the request * * @param RequestInterface $request Request to add a signature to * @param CredentialsInterface $credentials Signing credentials */ public function signRequest(RequestInterface $request, CredentialsInterface $credentials) { $parameters = $request->getQuery()->toArray(); $parameters['UserID'] = $credentials->getId(); $parameters['Version'] = '1.0'; $parameters['Action'] = $request->getConfig()->get('command')->getName(); $parameters['Timestamp'] = gmdate(DateTime::ISO8601); // the keys MUST be in alphabetical order to correct signature calculation ksort($parameters); $parameters['Signature'] = rawurlencode(hash_hmac('sha256', http_build_query($parameters, '', '&', PHP_QUERY_RFC3986), $credentials->getKey(), false)); $request->setQuery($parameters); }
private function shouldValidate(RequestInterface $request, ResponseInterface $response) { if ($request->getMethod() != 'GET' || $request->getConfig()->get('cache.disable')) { return false; } $validate = Utils::getDirective($request, 'Pragma') === 'no-cache' || Utils::getDirective($response, 'Pragma') === 'no-cache' || Utils::getDirective($request, 'must-revalidate') || Utils::getDirective($response, 'must-revalidate') || Utils::getDirective($request, 'no-cache') || Utils::getDirective($response, 'no-cache') || Utils::getDirective($response, 'max-age') === '0' || Utils::getDirective($response, 's-maxage') === '0'; // Use the strong ETag validator if available and the response contains // no Cache-Control directive if (!$validate && !$response->hasHeader('Cache-Control') && $response->hasHeader('ETag')) { $validate = true; } return $validate; }
public function signRequest(RequestInterface $request, CredentialsInterface $credentials) { /** @var PostBodyInterface $body */ $body = $request->getBody(); $body->setField('Timestamp', gmdate('c')); $body->setField('SignatureVersion', '2'); $body->setField('SignatureMethod', 'HmacSHA256'); $body->setField('AWSAccessKeyId', $credentials->getAccessKeyId()); if ($token = $credentials->getSecurityToken()) { $body->setField('SecurityToken', $token); } // build string to sign $sign = $request->getMethod() . "\n" . $request->getHost() . "\n" . '/' . "\n" . $this->getCanonicalizedParameterString($body); $request->getConfig()->set('aws.signature', $sign); $body->setField('Signature', base64_encode(hash_hmac('sha256', $sign, $credentials->getSecretKey(), true))); }
/** * Create a redirect request for a specific request object * * Takes into account strict RFC compliant redirection (e.g. redirect POST * with POST) vs doing what most clients do (e.g. redirect POST with GET). * * @param RequestInterface $request * @param ResponseInterface $response * * @return RequestInterface Returns a new redirect request * @throws CouldNotRewindStreamException If the body cannot be rewound. */ private function createRedirectRequest(RequestInterface $request, ResponseInterface $response) { $config = $request->getConfig(); // Use a GET request if this is an entity enclosing request and we are // not forcing RFC compliance, but rather emulating what all browsers // would do. Be sure to disable redirects on the clone. $redirectRequest = clone $request; $redirectRequest->getEmitter()->detach($this); $statusCode = $response->getStatusCode(); if ($statusCode == 303 || $statusCode <= 302 && $request->getBody() && !$config->getPath('redirect/strict')) { $redirectRequest->setMethod('GET'); $redirectRequest->setBody(null); } $this->setRedirectUrl($redirectRequest, $response); $this->rewindEntityBody($redirectRequest); // Add the Referer header if it is told to do so and only // add the header if we are not redirecting from https to http. if ($config->getPath('redirect/referer') && ($redirectRequest->getScheme() == 'https' || $redirectRequest->getScheme() == $request->getScheme())) { $url = Url::fromString($request->getUrl()); $url->setUsername(null)->setPassword(null); $redirectRequest->setHeader('Referer', (string) $url); } return $redirectRequest; }
private function add_decode_content(RequestInterface $request, $value) { if ($value === false) { return; } if ($value !== true) { $request->setHeader('Accept-Encoding', $value); } $request->getConfig()['decode_content'] = true; }
/** * Looks for a Certificate Authority file in the CA folder * that matches the host and update the 'verify' option * to its full path. * If no specific file regarding a host is found, uses * curl-ca-bundle.crt by default. * @param RequestInterface $httpRequest */ private function verify(RequestInterface $httpRequest) { $extensions = array('crt', 'pem', 'cer', 'der'); $caDir = __DIR__ . '/../CA/'; // Must be https $url = $httpRequest->getUrl(); if (substr($url, 0, 5) != 'https') { $httpRequest->getConfig()->set('verify', false); return; } // Default $httpRequest->getConfig()->set('verify', $caDir . 'curl-ca-bundle.crt'); // Look for a host specific CA file $host = strtolower(parse_url($url, PHP_URL_HOST)); if (!$host) { return; } $filename = $host; do { // Look for the possible extensions foreach ($extensions as $ext) { if (file_exists($verify = $caDir . $filename . '.' . $ext)) { $httpRequest->getConfig()->set('verify', $verify); return; } } // Remove a subdomain each time $filename = substr($filename, strpos($filename, '.') + 1); } while (substr_count($filename, '.') > 0); // No specific match return; }
protected function applyOptions(RequestInterface $request, array $options = []) { $config = $request->getConfig(); $emitter = $request->getEmitter(); foreach ($options as $key => $value) { if (isset(self::$configMap[$key])) { $config[$key] = $value; continue; } switch ($key) { case 'allow_redirects': if ($value === false) { continue; } if ($value === true) { $value = self::$defaultRedirect; } elseif (!isset($value['max'])) { throw new Iae('allow_redirects must be true, false, or an ' . 'array that contains the \'max\' key'); } else { // Merge the default settings with the provided settings $value += self::$defaultRedirect; } $config['redirect'] = $value; $emitter->attach($this->redirectPlugin); break; case 'decode_content': if ($value === false) { continue; } $config['decode_content'] = true; if ($value !== true) { $request->setHeader('Accept-Encoding', $value); } break; case 'headers': if (!is_array($value)) { throw new Iae('header value must be an array'); } // Do not overwrite existing headers foreach ($value as $k => $v) { if (!$request->hasHeader($k)) { $request->setHeader($k, $v); } } break; case 'exceptions': if ($value === true) { $emitter->attach($this->errorPlugin); } break; case 'body': if (is_array($value)) { $this->addPostData($request, $value); } elseif ($value !== null) { $request->setBody(Stream::factory($value)); } break; case 'auth': if (!$value) { continue; } if (is_array($value)) { $type = isset($value[2]) ? strtolower($value[2]) : 'basic'; } else { $type = strtolower($value); } $config['auth'] = $value; if ($type == 'basic') { $request->setHeader('Authorization', 'Basic ' . base64_encode("{$value['0']}:{$value['1']}")); } elseif ($type == 'digest') { // @todo: Do not rely on curl $config->setPath('curl/' . CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); $config->setPath('curl/' . CURLOPT_USERPWD, "{$value['0']}:{$value['1']}"); } break; case 'query': if ($value instanceof Query) { $original = $request->getQuery(); // Do not overwrite existing query string variables by // overwriting the object with the query string data passed // in the URL $value->overwriteWith($original->toArray()); $request->setQuery($value); } elseif (is_array($value)) { // Do not overwrite existing query string variables $query = $request->getQuery(); foreach ($value as $k => $v) { if (!isset($query[$k])) { $query[$k] = $v; } } } else { throw new Iae('query must be an array or Query object'); } break; case 'cookies': if ($value === true) { static $cookie = null; if (!$cookie) { $cookie = new Cookie(); } $emitter->attach($cookie); } elseif (is_array($value)) { $emitter->attach(new Cookie(CookieJar::fromArray($value, $request->getHost()))); } elseif ($value instanceof CookieJarInterface) { $emitter->attach(new Cookie($value)); } elseif ($value !== false) { throw new Iae('cookies must be an array, true, or CookieJarInterface'); } break; case 'events': if (!is_array($value)) { throw new Iae('events must be an array'); } $this->attachListeners($request, $this->prepareListeners($value, ['before', 'complete', 'error', 'progress', 'end'])); break; case 'subscribers': if (!is_array($value)) { throw new Iae('subscribers must be an array'); } foreach ($value as $subscribers) { $emitter->attach($subscribers); } break; case 'json': $request->setBody(Stream::factory(json_encode($value))); if (!$request->hasHeader('Content-Type')) { $request->setHeader('Content-Type', 'application/json'); } break; default: // Check for custom handler functions. if (isset($this->customOptions[$key])) { $fn = $this->customOptions[$key]; $fn($request, $value); continue; } throw new Iae("No method can handle the {$key} config key"); } } }
public function sign(RequestInterface $request, $client_id, $client_secret) { $request->getConfig()->set('auth', 'basic'); $request->setHeader('Authorization', 'Basic ' . base64_encode("{$client_id}:{$client_secret}")); }
private function addResponseHeaders(RequestInterface $request, ResponseInterface $response) { $params = $request->getConfig(); $lookup = $params['cache_lookup'] . ' from GuzzleCache'; $response->addHeader('X-Cache-Lookup', $lookup); if ($params['cache_hit'] === true) { $response->addHeader('X-Cache', 'HIT from GuzzleCache'); } elseif ($params['cache_hit'] == 'error') { $response->addHeader('X-Cache', 'HIT_ERROR from GuzzleCache'); } else { $response->addHeader('X-Cache', 'MISS from GuzzleCache'); } $freshness = Utils::getFreshness($response); // Only add a Warning header if we are returning a stale response. if ($params['cache_hit'] && $freshness !== null && $freshness <= 0) { $response->addHeader('Warning', sprintf('%d GuzzleCache/' . ClientInterface::VERSION . ' "%s"', 110, 'Response is stale')); } }
protected function add_wait(RequestInterface $request, $wait) { $request->getConfig()->set('wait', $wait); }
private function addExpectHeader(RequestInterface $request, StreamInterface $body) { // Determine if the Expect header should be used if ($request->hasHeader('Expect')) { return; } $expect = $request->getConfig()['expect']; // Return if disabled or if you're not using HTTP/1.1 if ($expect === false || $request->getProtocolVersion() !== '1.1') { return; } // The expect header is unconditionally enabled if ($expect === true) { $request->setHeader('Expect', '100-Continue'); return; } // By default, send the expect header when the payload is > 1mb if ($expect === null) { $expect = 1048576; } // Always add if the body cannot be rewound, the size cannot be // determined, or the size is greater than the cutoff threshold $size = $body->getSize(); if ($size === null || $size >= (int) $expect || !$body->isSeekable()) { $request->setHeader('Expect', '100-Continue'); } }
private function applyTransferOptions(RequestInterface $request, RequestMediator $mediator, array &$options) { static $methods; if (!$methods) { $methods = array_flip(get_class_methods(__CLASS__)); } foreach ($request->getConfig()->toArray() as $key => $value) { $method = "add_{$key}"; if (isset($methods[$method])) { $this->{$method}($request, $mediator, $options, $value); } } }
public function send(RequestInterface $request) { $trans = new Transaction($this, $request); $fn = $this->fsm; // Ensure a future response is returned if one was requested. if ($request->getConfig()->get('future')) { try { $fn($trans); // Turn the normal response into a future if needed. return $trans->response instanceof FutureInterface ? $trans->response : new FutureResponse(new FulfilledPromise($trans->response)); } catch (RequestException $e) { // Wrap the exception in a promise if the user asked for a future. return new FutureResponse(new RejectedPromise($e)); } } else { try { $fn($trans); return $trans->response instanceof FutureInterface ? $trans->response->wait() : $trans->response; } catch (\Exception $e) { throw RequestException::wrapException($trans->request, $e); } } }
private function add_auth(RequestInterface $request, $value) { if (!$value) { return; } elseif (is_array($value)) { $authType = isset($value[2]) ? strtolower($value[2]) : 'basic'; } else { $authType = strtolower($value); } $request->getConfig()->set('auth', $value); if ($authType == 'basic') { $request->setHeader('Authorization', 'Basic ' . base64_encode("{$value['0']}:{$value['1']}")); } elseif ($authType == 'digest') { // Currently only implemented by the cURL adapter. // @todo: Need an event listener solution that does not rely on cURL $config = $request->getConfig(); $config->setPath('curl/' . CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); $config->setPath('curl/' . CURLOPT_USERPWD, "{$value['0']}:{$value['1']}"); } }
/** * Checks wether $request is a redirect by inspecting the "redirect_count" property of the request config * used by to define the number of redirects of a request GuzzleHttp\Subscriber\Redirect * @param RequestInterface $request * @return bool */ private function isRedirectRequest(RequestInterface $request) { $isRedirect = $request->getConfig()->get("redirect_count"); return $isRedirect !== null && $isRedirect > 0; }
private function applyCustomOptions(RequestInterface $request, array &$options) { // Overwrite any generated options with custom options if ($custom = $request->getConfig()['stream_context']) { if (!is_array($custom)) { throw new AdapterException('stream_context must be an array'); } $options = array_replace_recursive($options, $custom); } }
protected function cacheMiss(RequestInterface $request) { $request->getConfig()->set('cache_lookup', 'MISS'); }
public function send(RequestInterface $request) { $isFuture = $request->getConfig()->get('future'); $trans = new Transaction($this, $request, $isFuture); $fn = $this->fsm; try { $fn($trans); if ($isFuture) { // Turn the normal response into a future if needed. return $trans->response instanceof FutureInterface ? $trans->response : new FutureResponse(new FulfilledPromise($trans->response)); } // Resolve deep futures if this is not a future // transaction. This accounts for things like retries // that do not have an immediate side-effect. while ($trans->response instanceof FutureInterface) { $trans->response = $trans->response->wait(); } return $trans->response; } catch (\Exception $e) { if ($isFuture) { // Wrap the exception in a promise return new FutureResponse(new RejectedPromise($e)); } throw RequestException::wrapException($trans->request, $e); } }
/** * @param RequestInterface $request * @return RequestInterface */ public function setupRequest(RequestInterface $request) { $request->getConfig()->set("proxy", $this->getProxyString()); return $request; }