vendor/sentry/sentry/src/HttpClient/HttpClientFactory.php line 103

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Sentry\HttpClient;
  4. use GuzzleHttp\RequestOptions as GuzzleHttpClientOptions;
  5. use Http\Adapter\Guzzle6\Client as GuzzleHttpClient;
  6. use Http\Client\Common\Plugin\AuthenticationPlugin;
  7. use Http\Client\Common\Plugin\DecoderPlugin;
  8. use Http\Client\Common\Plugin\ErrorPlugin;
  9. use Http\Client\Common\Plugin\HeaderSetPlugin;
  10. use Http\Client\Common\Plugin\RetryPlugin;
  11. use Http\Client\Common\PluginClient;
  12. use Http\Client\Curl\Client as CurlHttpClient;
  13. use Http\Client\HttpAsyncClient as HttpAsyncClientInterface;
  14. use Http\Discovery\HttpAsyncClientDiscovery;
  15. use Http\Message\ResponseFactory as ResponseFactoryInterface;
  16. use Http\Message\StreamFactory as StreamFactoryInterface;
  17. use Http\Message\UriFactory as UriFactoryInterface;
  18. use Sentry\HttpClient\Authentication\SentryAuthentication;
  19. use Sentry\HttpClient\Plugin\GzipEncoderPlugin;
  20. use Sentry\Options;
  21. use Symfony\Component\HttpClient\HttpClient as SymfonyHttpClient;
  22. use Symfony\Component\HttpClient\HttplugClient as SymfonyHttplugClient;
  23. /**
  24.  * Default implementation of the {@HttpClientFactoryInterface} interface that uses
  25.  * Httplug to autodiscover the HTTP client if none is passed by the user.
  26.  */
  27. final class HttpClientFactory implements HttpClientFactoryInterface
  28. {
  29.     /**
  30.      * @var int The timeout of the request in seconds
  31.      */
  32.     private const DEFAULT_HTTP_TIMEOUT 5;
  33.     /**
  34.      * @var int The default number of seconds to wait while trying to connect
  35.      *          to a server
  36.      */
  37.     private const DEFAULT_HTTP_CONNECT_TIMEOUT 2;
  38.     /**
  39.      * @var UriFactoryInterface The PSR-7 URI factory
  40.      */
  41.     private $uriFactory;
  42.     /**
  43.      * @var ResponseFactoryInterface The PSR-7 response factory
  44.      */
  45.     private $responseFactory;
  46.     /**
  47.      * @var StreamFactoryInterface The PSR-17 stream factory
  48.      */
  49.     private $streamFactory;
  50.     /**
  51.      * @var HttpAsyncClientInterface|null The HTTP client
  52.      */
  53.     private $httpClient;
  54.     /**
  55.      * @var string The name of the SDK
  56.      */
  57.     private $sdkIdentifier;
  58.     /**
  59.      * @var string The version of the SDK
  60.      */
  61.     private $sdkVersion;
  62.     /**
  63.      * Constructor.
  64.      *
  65.      * @param UriFactoryInterface           $uriFactory      The PSR-7 URI factory
  66.      * @param ResponseFactoryInterface      $responseFactory The PSR-7 response factory
  67.      * @param StreamFactoryInterface        $streamFactory   The PSR-17 stream factory
  68.      * @param HttpAsyncClientInterface|null $httpClient      The HTTP client
  69.      * @param string                        $sdkIdentifier   The SDK identifier
  70.      * @param string                        $sdkVersion      The SDK version
  71.      */
  72.     public function __construct(
  73.         UriFactoryInterface $uriFactory,
  74.         ResponseFactoryInterface $responseFactory,
  75.         StreamFactoryInterface $streamFactory,
  76.         ?HttpAsyncClientInterface $httpClient,
  77.         string $sdkIdentifier,
  78.         string $sdkVersion
  79.     ) {
  80.         $this->uriFactory $uriFactory;
  81.         $this->responseFactory $responseFactory;
  82.         $this->streamFactory $streamFactory;
  83.         $this->httpClient $httpClient;
  84.         $this->sdkIdentifier $sdkIdentifier;
  85.         $this->sdkVersion $sdkVersion;
  86.     }
  87.     /**
  88.      * {@inheritdoc}
  89.      */
  90.     public function create(Options $options): HttpAsyncClientInterface
  91.     {
  92.         if (null === $options->getDsn(false)) {
  93.             throw new \RuntimeException('Cannot create an HTTP client without the Sentry DSN set in the options.');
  94.         }
  95.         $httpClient $this->httpClient;
  96.         if (null !== $httpClient && null !== $options->getHttpProxy()) {
  97.             throw new \RuntimeException('The "http_proxy" option does not work together with a custom HTTP client.');
  98.         }
  99.         if (null === $httpClient) {
  100.             if (class_exists(SymfonyHttplugClient::class)) {
  101.                 $symfonyConfig = [
  102.                     'max_duration' => self::DEFAULT_HTTP_TIMEOUT,
  103.                 ];
  104.                 if (null !== $options->getHttpProxy()) {
  105.                     $symfonyConfig['proxy'] = $options->getHttpProxy();
  106.                 }
  107.                 /** @psalm-suppress UndefinedClass */
  108.                 $httpClient = new SymfonyHttplugClient(
  109.                     SymfonyHttpClient::create($symfonyConfig)
  110.                 );
  111.             } elseif (class_exists(GuzzleHttpClient::class)) {
  112.                 /** @psalm-suppress UndefinedClass */
  113.                 $guzzleConfig = [
  114.                     GuzzleHttpClientOptions::TIMEOUT => self::DEFAULT_HTTP_TIMEOUT,
  115.                     GuzzleHttpClientOptions::CONNECT_TIMEOUT => self::DEFAULT_HTTP_CONNECT_TIMEOUT,
  116.                 ];
  117.                 if (null !== $options->getHttpProxy()) {
  118.                     /** @psalm-suppress UndefinedClass */
  119.                     $guzzleConfig[GuzzleHttpClientOptions::PROXY] = $options->getHttpProxy();
  120.                 }
  121.                 /** @psalm-suppress InvalidPropertyAssignmentValue */
  122.                 $httpClient GuzzleHttpClient::createWithConfig($guzzleConfig);
  123.             } elseif (class_exists(CurlHttpClient::class)) {
  124.                 $curlConfig = [
  125.                     \CURLOPT_TIMEOUT => self::DEFAULT_HTTP_TIMEOUT,
  126.                     \CURLOPT_CONNECTTIMEOUT => self::DEFAULT_HTTP_CONNECT_TIMEOUT,
  127.                 ];
  128.                 if (null !== $options->getHttpProxy()) {
  129.                     $curlConfig[\CURLOPT_PROXY] = $options->getHttpProxy();
  130.                 }
  131.                 /** @psalm-suppress InvalidPropertyAssignmentValue */
  132.                 $httpClient = new CurlHttpClient(nullnull$curlConfig);
  133.             } elseif (null !== $options->getHttpProxy()) {
  134.                 throw new \RuntimeException('The "http_proxy" option requires either the "php-http/curl-client" or the "php-http/guzzle6-adapter" package to be installed.');
  135.             }
  136.         }
  137.         if (null === $httpClient) {
  138.             $httpClient HttpAsyncClientDiscovery::find();
  139.         }
  140.         $httpClientPlugins = [
  141.             new HeaderSetPlugin(['User-Agent' => $this->sdkIdentifier '/' $this->sdkVersion]),
  142.             new AuthenticationPlugin(new SentryAuthentication($options$this->sdkIdentifier$this->sdkVersion)),
  143.             new RetryPlugin(['retries' => $options->getSendAttempts()]),
  144.             new ErrorPlugin(),
  145.         ];
  146.         if ($options->isCompressionEnabled()) {
  147.             $httpClientPlugins[] = new GzipEncoderPlugin($this->streamFactory);
  148.             $httpClientPlugins[] = new DecoderPlugin();
  149.         }
  150.         return new PluginClient($httpClient$httpClientPlugins);
  151.     }
  152. }