diff --git a/core/core.services.yml b/core/core.services.yml index 29ac197..0aec7ac 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -377,10 +377,13 @@ services: http_handler_stack: class: GuzzleHttp\HandlerStack public: false - factory: [GuzzleHttp\HandlerStack, create] + factory: GuzzleHttp\HandlerStack::create http_client: class: Drupal\Core\Http\Client - arguments: ['@http_handler_stack', '@service_container'] + factory: http_client_factory:fromOptions + http_client_factory: + class: Drupal\Core\Http\ClientFactory + arguments: ['@handler_stack'] theme.negotiator: class: Drupal\Core\Theme\ThemeNegotiator arguments: ['@access_check.theme'] diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php index 1830d5b..9ff3861 100644 --- a/core/lib/Drupal.php +++ b/core/lib/Drupal.php @@ -403,6 +403,13 @@ public static function httpClient() { } /** + * @return \Drupal\Core\Http\ClientFactory + */ + public static function httpClientFactory() { + return static::getContainer()->get('http_client_factory'); + } + + /** * Returns the entity query object for this entity type. * * @param string $entity_type diff --git a/core/lib/Drupal/Core/Http/ClientFactory.php b/core/lib/Drupal/Core/Http/ClientFactory.php new file mode 100644 index 0000000..9c2eee2 --- /dev/null +++ b/core/lib/Drupal/Core/Http/ClientFactory.php @@ -0,0 +1,70 @@ +stack = $stack; + } + + /** + * Constructs a new client object from some configuration. + * + * @param array $config + * The config for the client. + * + * @return \GuzzleHttp\Client + * The HTTP client. + */ + public function fromOptions(array $config = []) { + $default_config = array( + // Security consideration: we must not use the certificate authority + // file shipped with Guzzle because it can easily get outdated if a + // certificate authority is hacked. Instead, we rely on the certificate + // authority file provided by the operating system which is more likely + // going to be updated in a timely fashion. This overrides the default + // path to the pem file bundled with Guzzle. + 'verify' => TRUE, + 'timeout' => 30, + 'headers' => array( + 'User-Agent' => 'Drupal/' . \Drupal::VERSION . ' (+https://www.drupal.org/) ' . \GuzzleHttp\default_user_agent(), + ), + 'handler' => $this->stack, + ); + + // The entire config array is merged/configurable to allow Guzzle client + // options outside of 'defaults' to be changed, such as 'adapter', or + // 'message_factory'. + $config = NestedArray::mergeDeep(array($default_config), Settings::get('http_client_config', array())); + + return new Client($config); + } + +} diff --git a/core/modules/statistics/src/Tests/StatisticsAdminTest.php b/core/modules/statistics/src/Tests/StatisticsAdminTest.php index 476b2ff..cdd8a48 100644 --- a/core/modules/statistics/src/Tests/StatisticsAdminTest.php +++ b/core/modules/statistics/src/Tests/StatisticsAdminTest.php @@ -54,8 +54,8 @@ protected function setUp() { $this->privilegedUser = $this->drupalCreateUser(array('administer statistics', 'view post access counter', 'create page content')); $this->drupalLogin($this->privilegedUser); $this->testNode = $this->drupalCreateNode(array('type' => 'page', 'uid' => $this->privilegedUser->id())); - $this->client = \Drupal::httpClient(); - $this->client->setDefaultOption('config/curl', array(CURLOPT_TIMEOUT => 10)); + $this->client = \Drupal::httpClientFactory() + ->fromOptions(['config/curl' => [CURLOPT_TIMEOUT => 10]]); } /** diff --git a/core/modules/statistics/src/Tests/StatisticsLoggingTest.php b/core/modules/statistics/src/Tests/StatisticsLoggingTest.php index 02dcfbc..ce58e0e 100644 --- a/core/modules/statistics/src/Tests/StatisticsLoggingTest.php +++ b/core/modules/statistics/src/Tests/StatisticsLoggingTest.php @@ -61,8 +61,8 @@ protected function setUp() { // Clear the logs. db_truncate('node_counter'); - $this->client = \Drupal::httpClient(); - $this->client->setDefaultOption('config/curl', array(CURLOPT_TIMEOUT => 10)); + $this->client = \Drupal::httpClientFactory() + ->fromOptions(['config/curl' => [CURLOPT_TIMEOUT => 10]]); } /** diff --git a/core/modules/statistics/src/Tests/StatisticsReportsTest.php b/core/modules/statistics/src/Tests/StatisticsReportsTest.php index 50e5f5e..c35d091 100644 --- a/core/modules/statistics/src/Tests/StatisticsReportsTest.php +++ b/core/modules/statistics/src/Tests/StatisticsReportsTest.php @@ -30,8 +30,8 @@ function testPopularContentBlock() { $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); global $base_url; $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; - $client = \Drupal::httpClient(); - $client->setDefaultOption('config/curl', array(CURLOPT_TIMEOUT => 10)); + $client = \Drupal::httpClientFactory() + ->fromOptions(['config/curl' => [CURLOPT_TIMEOUT => 10]]); $client->post($stats_path, array('headers' => $headers, 'body' => $post)); // Configure and save the block. diff --git a/core/modules/statistics/src/Tests/StatisticsTokenReplaceTest.php b/core/modules/statistics/src/Tests/StatisticsTokenReplaceTest.php index 9534c8a..a219e28 100644 --- a/core/modules/statistics/src/Tests/StatisticsTokenReplaceTest.php +++ b/core/modules/statistics/src/Tests/StatisticsTokenReplaceTest.php @@ -33,8 +33,8 @@ function testStatisticsTokenReplacement() { $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); global $base_url; $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; - $client = \Drupal::httpClient(); - $client->setDefaultOption('config/curl', array(CURLOPT_TIMEOUT => 10)); + $client = \Drupal::httpClientFactory() + ->fromOptions(['config/curl' => [CURLOPT_TIMEOUT => 10]]); $client->post($stats_path, array('headers' => $headers, 'body' => $post)); $statistics = statistics_get($node->id());