Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0023a71

Browse filesBrowse files
Thomas Talbotnicolas-grekas
Thomas Talbot
authored andcommitted
[FrameworkBundle] Add integration of http-client component
1 parent 3abf9eb commit 0023a71
Copy full SHA for 0023a71

19 files changed

+512
-3
lines changed

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+122Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Bundle\FullStack;
1818
use Symfony\Component\Asset\Package;
1919
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
20+
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
2021
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
2122
use Symfony\Component\Config\Definition\ConfigurationInterface;
2223
use Symfony\Component\DependencyInjection\Exception\LogicException;
@@ -109,6 +110,7 @@ public function getConfigTreeBuilder()
109110
$this->addLockSection($rootNode);
110111
$this->addMessengerSection($rootNode);
111112
$this->addRobotsIndexSection($rootNode);
113+
$this->addHttpClientSection($rootNode);
112114

113115
return $treeBuilder;
114116
}
@@ -1170,4 +1172,124 @@ private function addRobotsIndexSection(ArrayNodeDefinition $rootNode)
11701172
->end()
11711173
;
11721174
}
1175+
1176+
private function addHttpClientSection(ArrayNodeDefinition $rootNode)
1177+
{
1178+
$subNode = $rootNode
1179+
->children()
1180+
->arrayNode('http_client')
1181+
->info('HTTP Client configuration')
1182+
->canBeEnabled()
1183+
->fixXmlConfig('client')
1184+
->children();
1185+
1186+
$this->addHttpClientOptionsSection($subNode);
1187+
1188+
$subNode = $subNode
1189+
->arrayNode('clients')
1190+
->useAttributeAsKey('name')
1191+
->normalizeKeys(false)
1192+
->arrayPrototype()
1193+
->children();
1194+
1195+
$this->addHttpClientOptionsSection($subNode);
1196+
1197+
$subNode = $subNode
1198+
->end()
1199+
->end()
1200+
->end()
1201+
->end()
1202+
->end()
1203+
->end()
1204+
;
1205+
}
1206+
1207+
private function addHttpClientOptionsSection(NodeBuilder $rootNode)
1208+
{
1209+
$rootNode
1210+
->integerNode('max_host_connections')
1211+
->info('The maximum number of connections to a single host.')
1212+
->end()
1213+
->arrayNode('default_options')
1214+
->fixXmlConfig('header')
1215+
->children()
1216+
->scalarNode('auth')
1217+
->info('An HTTP Basic authentication "username:password".')
1218+
->end()
1219+
->arrayNode('query')
1220+
->info('Associative array of query string values merged with URL parameters.')
1221+
->useAttributeAsKey('key')
1222+
->normalizeKeys(false)
1223+
->scalarPrototype()->end()
1224+
->end()
1225+
->arrayNode('headers')
1226+
->info('Associative array: header => value(s).')
1227+
->useAttributeAsKey('name')
1228+
->normalizeKeys(false)
1229+
->variablePrototype()->end()
1230+
->end()
1231+
->integerNode('max_redirects')
1232+
->info('The maximum number of redirects to follow.')
1233+
->end()
1234+
->scalarNode('http_version')
1235+
->info('The default HTTP version, typically 1.1 or 2.0. Leave to null for the best version.')
1236+
->end()
1237+
->scalarNode('base_uri')
1238+
->info('The URI to resolve relative URLs, following rules in RFC 3986, section 2.')
1239+
->end()
1240+
->booleanNode('buffer')
1241+
->info('Indicates if the response should be buffered or not.')
1242+
->end()
1243+
->arrayNode('resolve')
1244+
->info('Associative array: domain => IP.')
1245+
->useAttributeAsKey('host')
1246+
->normalizeKeys(false)
1247+
->scalarPrototype()->end()
1248+
->end()
1249+
->scalarNode('proxy')
1250+
->info('The URL of the proxy to pass requests through or null for automatic detection.')
1251+
->end()
1252+
->scalarNode('no_proxy')
1253+
->info('A comma separated list of hosts that do not require a proxy to be reached.')
1254+
->end()
1255+
->floatNode('timeout')
1256+
->info('Defaults to "default_socket_timeout" ini parameter.')
1257+
->end()
1258+
->scalarNode('bindto')
1259+
->info('A network interface name, IP address, a host name or a UNIX socket to bind to.')
1260+
->end()
1261+
->booleanNode('verify_peer')
1262+
->info('Indicates if the peer should be verified in a SSL/TLS context.')
1263+
->end()
1264+
->booleanNode('verify_host')
1265+
->info('Indicates if the host should exist as a certificate common name.')
1266+
->end()
1267+
->scalarNode('cafile')
1268+
->info('A certificate authority file.')
1269+
->end()
1270+
->scalarNode('capath')
1271+
->info('A directory that contains multiple certificate authority files.')
1272+
->end()
1273+
->scalarNode('local_cert')
1274+
->info('A PEM formatted certificate file.')
1275+
->end()
1276+
->scalarNode('local_pk')
1277+
->info('A private key file.')
1278+
->end()
1279+
->scalarNode('passphrase')
1280+
->info('The passphrase used to encrypt the "local_pk" file.')
1281+
->end()
1282+
->scalarNode('ciphers')
1283+
->info('A list of SSL/TLS ciphers separated by colons, commas or spaces (e.g. "RC4-SHA:TLS13-AES-128-GCM-SHA256"...)')
1284+
->end()
1285+
->arrayNode('peer_fingerprint')
1286+
->info('Associative array: hashing algorithm => hash(es).')
1287+
->useAttributeAsKey('algo')
1288+
->normalizeKeys(false)
1289+
->variablePrototype()->end()
1290+
->end()
1291+
->end()
1292+
->end()
1293+
;
1294+
}
11731295
}

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+52Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Doctrine\Common\Annotations\Reader;
1616
use Psr\Cache\CacheItemPoolInterface;
1717
use Psr\Container\ContainerInterface as PsrContainerInterface;
18+
use Psr\Http\Client\ClientInterface;
1819
use Psr\Log\LoggerAwareInterface;
1920
use Symfony\Bridge\Monolog\Processor\DebugProcessor;
2021
use Symfony\Bridge\Twig\Extension\CsrfExtension;
@@ -57,6 +58,9 @@
5758
use Symfony\Component\Form\FormTypeExtensionInterface;
5859
use Symfony\Component\Form\FormTypeGuesserInterface;
5960
use Symfony\Component\Form\FormTypeInterface;
61+
use Symfony\Component\HttpClient\HttpClient;
62+
use Symfony\Component\HttpClient\HttpClientTrait;
63+
use Symfony\Component\HttpClient\Psr18Client;
6064
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
6165
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
6266
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
@@ -110,6 +114,8 @@
110114
use Symfony\Component\Yaml\Command\LintCommand as BaseYamlLintCommand;
111115
use Symfony\Component\Yaml\Yaml;
112116
use Symfony\Contracts\Cache\CacheInterface;
117+
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
118+
use Symfony\Contracts\HttpClient\HttpClientInterface;
113119
use Symfony\Contracts\Service\ResetInterface;
114120
use Symfony\Contracts\Service\ServiceSubscriberInterface;
115121

@@ -301,6 +307,10 @@ public function load(array $configs, ContainerBuilder $container)
301307
$this->registerLockConfiguration($config['lock'], $container, $loader);
302308
}
303309

310+
if ($this->isConfigEnabled($container, $config['http_client'])) {
311+
$this->registerHttpClientConfiguration($config['http_client'], $container, $loader);
312+
}
313+
304314
if ($this->isConfigEnabled($container, $config['web_link'])) {
305315
if (!class_exists(HttpHeaderSerializer::class)) {
306316
throw new LogicException('WebLink support cannot be enabled as the WebLink component is not installed. Try running "composer require symfony/weblink".');
@@ -1747,6 +1757,48 @@ private function registerCacheConfiguration(array $config, ContainerBuilder $con
17471757
}
17481758
}
17491759

1760+
private function registerHttpClientConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
1761+
{
1762+
if (!class_exists(HttpClient::class)) {
1763+
throw new LogicException('HttpClient support cannot be enabled as the component is not installed. Try running "composer require symfony/http-client".');
1764+
}
1765+
1766+
$loader->load('http_client.xml');
1767+
1768+
$merger = new class() {
1769+
use HttpClientTrait;
1770+
1771+
public function merge(array $options, array $defaultOptions)
1772+
{
1773+
try {
1774+
[, $options] = $this->prepareRequest(null, null, $options, $defaultOptions);
1775+
1776+
return $options;
1777+
} catch (TransportExceptionInterface $e) {
1778+
throw new InvalidArgumentException($e->getMessage(), 0, $e);
1779+
}
1780+
}
1781+
};
1782+
1783+
$defaultOptions = $merger->merge($config['default_options'] ?? [], []);
1784+
$container->getDefinition('http_client')->setArguments([$defaultOptions, $config['max_host_connections'] ?? 6]);
1785+
1786+
foreach ($config['clients'] as $name => $clientConfig) {
1787+
$options = $merger->merge($clientConfig['default_options'] ?? [], $defaultOptions);
1788+
1789+
$container->register($name, HttpClientInterface::class)
1790+
->setFactory([HttpClient::class, 'create'])
1791+
->setArguments([$options, $clientConfig['max_host_connections'] ?? $config['max_host_connections'] ?? 6]);
1792+
1793+
$container->register('psr18.'.$name, Psr18Client::class)
1794+
->setAutowired(true)
1795+
->setArguments([new Reference($name)]);
1796+
1797+
$container->registerAliasForArgument($name, HttpClientInterface::class);
1798+
$container->registerAliasForArgument('psr18.'.$name, ClientInterface::class, $name);
1799+
}
1800+
}
1801+
17501802
/**
17511803
* Returns the base path for the XSD files.
17521804
*
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<services>
8+
<service id="http_client" class="Symfony\Contracts\HttpClient\HttpClientInterface">
9+
<factory class="Symfony\Component\HttpClient\HttpClient" method="create" />
10+
<argument type="collection" /> <!-- default options -->
11+
<argument /> <!-- max host connections -->
12+
</service>
13+
<service id="Symfony\Contracts\HttpClient\HttpClientInterface" alias="http_client" />
14+
15+
<service id="psr18.http_client" class="Symfony\Component\HttpClient\Psr18Client" autowire="true">
16+
<argument type="service" id="http_client" />
17+
</service>
18+
<service id="Psr\Http\Client\ClientInterface" alias="psr18.http_client" />
19+
</services>
20+
</container>

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+61Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
<xsd:element name="php-errors" type="php-errors" minOccurs="0" maxOccurs="1" />
3333
<xsd:element name="lock" type="lock" minOccurs="0" maxOccurs="1" />
3434
<xsd:element name="messenger" type="messenger" minOccurs="0" maxOccurs="1" />
35+
<xsd:element name="http_client" type="http_client" minOccurs="0" maxOccurs="1" />
3536
</xsd:choice>
3637

3738
<xsd:attribute name="http-method-override" type="xsd:boolean" />
@@ -444,4 +445,64 @@
444445
</xsd:sequence>
445446
<xsd:attribute name="id" type="xsd:string" use="required"/>
446447
</xsd:complexType>
448+
449+
<xsd:complexType name="http_client">
450+
<xsd:sequence>
451+
<xsd:element name="max_host_connections" type="xsd:integer" minOccurs="0" />
452+
<xsd:element name="default_options" type="http_client_options" minOccurs="0" />
453+
<xsd:element name="client" type="http_client_client" minOccurs="0" maxOccurs="unbounded" />
454+
</xsd:sequence>
455+
<xsd:attribute name="enabled" type="xsd:boolean" />
456+
</xsd:complexType>
457+
458+
<xsd:complexType name="http_client_options">
459+
<xsd:sequence>
460+
<xsd:element name="auth" type="xsd:string" minOccurs="0" />
461+
<xsd:element name="query" type="http_query" minOccurs="0" />
462+
<xsd:element name="headers" type="http_headers" minOccurs="0" />
463+
<xsd:element name="max_redirects" type="xsd:integer" minOccurs="0" />
464+
<xsd:element name="http_version" type="xsd:string" minOccurs="0" />
465+
<xsd:element name="base_uri" type="xsd:string" minOccurs="0" />
466+
<xsd:element name="buffer" type="xsd:boolean" minOccurs="0" />
467+
<xsd:element name="resolve" type="metadata" minOccurs="0" maxOccurs="unbounded" />
468+
<xsd:element name="proxy" type="xsd:string" minOccurs="0" />
469+
<xsd:element name="no_proxy" type="xsd:string" minOccurs="0" />
470+
<xsd:element name="timeout" type="xsd:float" minOccurs="0" />
471+
<xsd:element name="bindto" type="xsd:string" minOccurs="0" />
472+
<xsd:element name="verify_peer" type="xsd:boolean" minOccurs="0" />
473+
<xsd:element name="verify_host" type="xsd:boolean" minOccurs="0" />
474+
<xsd:element name="cafile" type="xsd:string" minOccurs="0" />
475+
<xsd:element name="capath" type="xsd:string" minOccurs="0" />
476+
<xsd:element name="local_cert" type="xsd:string" minOccurs="0" />
477+
<xsd:element name="local_pk" type="xsd:string" minOccurs="0" />
478+
<xsd:element name="passphrase" type="xsd:string" minOccurs="0" />
479+
<xsd:element name="ciphers" type="xsd:string" minOccurs="0" />
480+
<xsd:element name="peer_fingerprint" type="fingerprint" minOccurs="0" maxOccurs="unbounded" />
481+
</xsd:sequence>
482+
</xsd:complexType>
483+
484+
<xsd:complexType name="http_client_client">
485+
<xsd:sequence>
486+
<xsd:element name="default_options" type="http_client_options" minOccurs="0" />
487+
</xsd:sequence>
488+
<xsd:attribute name="name" type="xsd:string" />
489+
</xsd:complexType>
490+
491+
<xsd:complexType name="fingerprint">
492+
<xsd:sequence>
493+
<xsd:any minOccurs="0" processContents="lax" maxOccurs="unbounded" />
494+
</xsd:sequence>
495+
</xsd:complexType>
496+
497+
<xsd:complexType name="http_query">
498+
<xsd:sequence>
499+
<xsd:any minOccurs="0" processContents="lax" maxOccurs="unbounded" />
500+
</xsd:sequence>
501+
</xsd:complexType>
502+
503+
<xsd:complexType name="http_headers">
504+
<xsd:sequence>
505+
<xsd:any minOccurs="0" processContents="lax" maxOccurs="unbounded" />
506+
</xsd:sequence>
507+
</xsd:complexType>
447508
</xsd:schema>

‎src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,11 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor
331331
'buses' => ['messenger.bus.default' => ['default_middleware' => true, 'middleware' => []]],
332332
],
333333
'disallow_search_engine_index' => true,
334+
'http_client' => [
335+
'enabled' => false,
336+
'max_host_connections' => 6,
337+
'clients' => [],
338+
],
334339
];
335340
}
336341
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
$container->loadFromExtension('framework', [
4+
'http_client' => [
5+
'max_host_connections' => 4,
6+
'default_options' => null,
7+
'clients' => [
8+
'foo' => [
9+
'default_options' => null,
10+
],
11+
],
12+
],
13+
]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
$container->loadFromExtension('framework', [
4+
'http_client' => [
5+
'default_options' => [
6+
'auth' => 'foo:bar',
7+
'query' => ['foo' => 'bar', 'bar' => 'baz'],
8+
'headers' => ['X-powered' => 'PHP'],
9+
'max_redirects' => 2,
10+
'http_version' => '2.0',
11+
'base_uri' => 'http://example.com',
12+
'buffer' => true,
13+
'resolve' => ['localhost' => '127.0.0.1'],
14+
'proxy' => 'proxy.org',
15+
'timeout' => 3.5,
16+
'bindto' => '127.0.0.1',
17+
'verify_peer' => true,
18+
'verify_host' => true,
19+
'cafile' => '/etc/ssl/cafile',
20+
'capath' => '/etc/ssl',
21+
'local_cert' => '/etc/ssl/cert.pem',
22+
'local_pk' => '/etc/ssl/private_key.pem',
23+
'passphrase' => 'password123456',
24+
'ciphers' => 'RC4-SHA:TLS13-AES-128-GCM-SHA256',
25+
'peer_fingerprint' => [
26+
'pin-sha256' => ['14s5erg62v1v8471g2revg48r7==', 'jsda84hjtyd4821bgfesd215bsfg5412='],
27+
'md5' => 'sdhtb481248721thbr=',
28+
],
29+
],
30+
],
31+
]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
$container->loadFromExtension('framework', [
4+
'http_client' => [
5+
'default_options' => [
6+
'headers' => ['foo' => 'bar'],
7+
],
8+
'clients' => [
9+
'foo' => [
10+
'default_options' => [
11+
'headers' => ['bar' => 'baz'],
12+
],
13+
],
14+
],
15+
],
16+
]);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.