Skip to content

setTrustedHost breaks the CachingHttpClient #50276

@jderusse

Description

@jderusse

Symfony version(s) affected

6.2 and probably before

Description

The CachingHttpClient creates a new Request object, then uses it to call the decorated HttpClient.

Sadly, the Request class contains a static variable with the list of trusted hosts. Usually defined in the front controller or via parameters.

When someone uses the CachingHttpClient to call an external endpoint (not trusted), the request removes the Host part of the URL, leading to an invalid URL

How to reproduce

minimal reproducer

<?php

use Symfony\Component\HttpClient\CachingHttpClient;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpCache\Store;

include __DIR__.'/vendor/autoload.php';

Request::setTrustedHosts(['notsymfony.com']);

$client = new CachingHttpClient(HttpClient::create(), new Store('/tmp/xxx'));
$response = $client->request('GET', 'https://symfony.com/foo');

echo $response->getStatusCode();

returns

PHP Fatal error:  Uncaught Symfony\Component\HttpClient\Exception\InvalidArgumentException: Malformed URL "https:///foo". in /data/oss/test/vendor/symfony/http-client/HttpClientTrait.php:505
Stack trace:
#0 /data/oss/test/vendor/symfony/http-client/HttpClientTrait.php(169): Symfony\Component\HttpClient\CurlHttpClient::parseUrl()
#1 /data/oss/test/vendor/symfony/http-client/CurlHttpClient.php(87): Symfony\Component\HttpClient\CurlHttpClient::prepareRequest()
#2 /data/oss/test/vendor/symfony/http-kernel/HttpClientKernel.php(53): Symfony\Component\HttpClient\CurlHttpClient->request()
#3 /data/oss/test/vendor/symfony/http-kernel/HttpCache/SubRequestHandler.php(86): Symfony\Component\HttpKernel\HttpClientKernel->handle()
#4 /data/oss/test/vendor/symfony/http-kernel/HttpCache/HttpCache.php(464): Symfony\Component\HttpKernel\HttpCache\SubRequestHandler::handle()
#5 /data/oss/test/vendor/symfony/http-kernel/HttpCache/HttpCache.php(264): Symfony\Component\HttpKernel\HttpCache\HttpCache->forward()
#6 /data/oss/test/vendor/symfony/http-kernel/HttpCache/HttpCache.php(331): Symfony\Component\HttpKernel\HttpCache\HttpCache->pass()
#7 /data/oss/test/vendor/symfony/http-kernel/HttpCache/HttpCache.php(215): Symfony\Component\HttpKernel\HttpCache\HttpCache->lookup()
#8 /data/oss/test/vendor/symfony/http-client/CachingHttpClient.php(98): Symfony\Component\HttpKernel\HttpCache\HttpCache->handle()
#9 /data/oss/test/index.php(12): Symfony\Component\HttpClient\CachingHttpClient->request()
#10 {main}
  thrown in /data/oss/test/vendor/symfony/http-client/HttpClientTrait.php on line 505

Possible Solution

🤷

  • Long solution: remove global state from request in order to use the object for non-incoming requests + without side effects
  • Short solution: In the CachingHttpClient amends the list of trustedHost with the requested host

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions