Вход Регистрация
Файл: monst/Xsolla/Guzzle/Http/RedirectPlugin.php
Строк: 394
<?php

namespace GuzzleHttp;

use 
GuzzleCommonEvent;
use 
GuzzleHttpExceptionBadResponseException;
use 
GuzzleHttpUrl;
use 
GuzzleHttpMessageResponse;
use 
GuzzleHttpMessageRequestInterface;
use 
GuzzleHttpMessageRequestFactory;
use 
GuzzleHttpMessageEntityEnclosingRequestInterface;
use 
GuzzleHttpExceptionTooManyRedirectsException;
use 
GuzzleHttpExceptionCouldNotRewindStreamException;
use 
SymfonyComponentEventDispatcherEventSubscriberInterface;

/**
 * Plugin to implement HTTP redirects. Can redirect like a web browser or using strict RFC 2616 compliance
 */
class RedirectPlugin implements EventSubscriberInterface
{
    const 
REDIRECT_COUNT 'redirect.count';
    const 
MAX_REDIRECTS 'redirect.max';
    const 
STRICT_REDIRECTS 'redirect.strict';
    const 
PARENT_REQUEST 'redirect.parent_request';
    const 
DISABLE 'redirect.disable';

    
/**
     * @var int Default number of redirects allowed when no setting is supplied by a request
     */
    
protected $defaultMaxRedirects 5;

    public static function 
getSubscribedEvents()
    {
        return array(
            
'request.sent'        => array('onRequestSent'100),
            
'request.clone'       => 'cleanupRequest',
            
'request.before_send' => 'cleanupRequest'
        
);
    }

    
/**
     * Clean up the parameters of a request when it is cloned
     *
     * @param Event $event Event emitted
     */
    
public function cleanupRequest(Event $event)
    {
        
$params $event['request']->getParams();
        unset(
$params[self::REDIRECT_COUNT]);
        unset(
$params[self::PARENT_REQUEST]);
    }

    
/**
     * Called when a request receives a redirect response
     *
     * @param Event $event Event emitted
     */
    
public function onRequestSent(Event $event)
    {
        
$response $event['response'];
        
$request $event['request'];

        
// Only act on redirect requests with Location headers
        
if (!$response || $request->getParams()->get(self::DISABLE)) {
            return;
        }

        
// Trace the original request based on parameter history
        
$original $this->getOriginalRequest($request);

        
// Terminating condition to set the effective response on the original request
        
if (!$response->isRedirect() || !$response->hasHeader('Location')) {
            if (
$request !== $original) {
                
// This is a terminating redirect response, so set it on the original request
                
$response->getParams()->set(self::REDIRECT_COUNT$original->getParams()->get(self::REDIRECT_COUNT));
                
$original->setResponse($response);
                
$response->setEffectiveUrl($request->getUrl());
            }
            return;
        }

        
$this->sendRedirectRequest($original$request$response);
    }

    
/**
     * Get the original request that initiated a series of redirects
     *
     * @param RequestInterface $request Request to get the original request from
     *
     * @return RequestInterface
     */
    
protected function getOriginalRequest(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;
        }

        return 
$original;
    }

    
/**
     * 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    Request being redirected
     * @param RequestInterface $original   Original request
     * @param int              $statusCode Status code of the redirect
     * @param string           $location   Location header of the redirect
     *
     * @return RequestInterface Returns a new redirect request
     * @throws CouldNotRewindStreamException If the body needs to be rewound but cannot
     */
    
protected function createRedirectRequest(
        
RequestInterface $request,
        
$statusCode,
        
$location,
        
RequestInterface $original
    
) {
        
$redirectRequest null;
        
$strict $original->getParams()->get(self::STRICT_REDIRECTS);

        
// Switch method to GET for 303 redirects.  301 and 302 redirects also switch to GET unless we are forcing RFC
        // compliance to emulate what most browsers do.  NOTE: IE only switches methods on 301/302 when coming from a POST.
        
if ($request instanceof EntityEnclosingRequestInterface && ($statusCode == 303 || (!$strict && $statusCode <= 302))) {
            
$redirectRequest RequestFactory::getInstance()->cloneRequestWithMethod($request'GET');
        } else {
            
$redirectRequest = clone $request;
        }

        
$redirectRequest->setIsRedirect(true);
        
// Always use the same response body when redirecting
        
$redirectRequest->setResponseBody($request->getResponseBody());

        
$location Url::factory($location);
        
// If the location is not absolute, then combine it with the original URL
        
if (!$location->isAbsolute()) {
            
$originalUrl $redirectRequest->getUrl(true);
            
// Remove query string parameters and just take what is present on the redirect Location header
            
$originalUrl->getQuery()->clear();
            
$location $originalUrl->combine((string) $locationtrue);
        }

        
$redirectRequest->setUrl($location);

        
// Add the parent request to the request before it sends (make sure it's before the onRequestClone event too)
        
$redirectRequest->getEventDispatcher()->addListener(
            
'request.before_send',
            
$func = function ($e) use (&$func$request$redirectRequest) {
                
$redirectRequest->getEventDispatcher()->removeListener('request.before_send'$func);
                
$e['request']->getParams()->set(RedirectPlugin::PARENT_REQUEST$request);
            }
        );

        
// Rewind the entity body of the request if needed
        
if ($redirectRequest instanceof EntityEnclosingRequestInterface && $redirectRequest->getBody()) {
            
$body $redirectRequest->getBody();
            
// Only rewind the body if some of it has been read already, and throw an exception if the rewind fails
            
if ($body->ftell() && !$body->rewind()) {
                throw new 
CouldNotRewindStreamException(
                    
'Unable to rewind the non-seekable entity body of the request after redirecting. cURL probably '
                    
'sent part of body before the redirect occurred. Try adding acustom rewind function using on the '
                    
'entity body of the request using setRewindFunction().'
                
);
            }
        }

        return 
$redirectRequest;
    }

    
/**
     * 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 $originalRequestInterface $requestResponse $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
            
);
        }
    }

    
/**
     * Send a redirect request and handle any errors
     *
     * @param RequestInterface $original The originating request
     * @param RequestInterface $request  The current request being redirected
     * @param Response         $response The response of the current request
     *
     * @throws BadResponseException|Exception
     */
    
protected function sendRedirectRequest(RequestInterface $originalRequestInterface $requestResponse $response)
    {
        
// Validate and create a redirect request based on the original request and current response
        
if ($redirectRequest $this->prepareRedirection($original$request$response)) {
            try {
                
$redirectRequest->send();
            } catch (
BadResponseException $e) {
                
$e->getResponse();
                if (!
$e->getResponse()) {
                    throw 
$e;
                }
            }
        }
    }

    
/**
     * Throw a too many redirects exception for a request
     *
     * @param RequestInterface $original Request
     * @param int              $max      Max allowed redirects
     *
     * @throws TooManyRedirectsException when too many redirects have been issued
     */
    
protected function throwTooManyRedirectsException(RequestInterface $original$max)
    {
        
$original->getEventDispatcher()->addListener(
            
'request.complete',
            
$func = function ($e) use (&$func$original$max) {
                
$original->getEventDispatcher()->removeListener('request.complete'$func);
                
$str "{$max} redirects were issued for this request:n" $e['request']->getRawHeaders();
                throw new 
TooManyRedirectsException($str);
            }
        );
    }
}
Онлайн: 0
Реклама