Problem/Motivation

Ideally, Drupal core could enable persistent transport sharing for HTTP client requests. This allows requests to share connections, DNS, and TLS sessions across multiple PHP executions. For example, batch operations could continue a series of HTTP client requests to the same host without a DNS lookup, reconnecting and renegotiating TLS.

Steps to reproduce

Time the HTTP client requests in e.g. Update Status module, and notice that each time you click "Check manually," ~100ms or so of extra time is spent on the first request. Much of that extra time can be saved if connections are reused across multiple PHP executions.

Proposed resolution

Since guzzle doesn't automatically enable transport sharing when a HandlerStack is built, core could introduce its own HandlerStack factory method to configure this automatically via ['transport_sharing' => \GuzzleHttp\TransportSharing::PERSISTENT_PREFER]

Remaining tasks

Review MR.

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

Issue fork drupal-3618392

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mfb created an issue. See original summary.

mfb’s picture

Issue tags: +Performance
mfb’s picture

Issue summary: View changes
catch’s picture

Status: Needs review » Reviewed & tested by the community

This looks good, I can't see anything to complain about.

Should help translation downloads during the multilingual installer too.

quietone made their first commit to this issue’s fork.

quietone’s picture

Checking that the core gates are passed.

I read the MR and made two changes, one to a comment and one to add declare(strict_types=1);. The latter is now policy for new code.

Other than that everything is in order here. The changes I made are straightforward and policy so I am leaving at RTBC

mfb’s picture

@quietone's tweaks look good, rebased since tests were failing, leaving at RTBC

dries’s picture

This looks good to me as well.

The only non-blocking question I have is: why doesn't Guzzle make this the default? It has a fallback system. Maybe the feature is still too new?

mfb’s picture

https://github.com/guzzle/guzzle/blob/8.3/docs/handlers.md#transport-sha... doesn't clearly say why it's not the default, but I would guess it's because of the philosophical question of whether or not you want to share connections with other code running in the same PHP process - which could be different paying customers in the case of shared hosting. There shouldn't be much in the way of practical impacts since guard rails are in place - for example cookies are not shared. Assuming your environment has correctly patched CVE-2026-8932, which e.g. an up-to-date debian curl package has, TLS sessions using client certificates are also not shared.

catch’s picture

The main thing they mention is that curl shares this across applications on the same host, where each of those applications is asking for transport sharing - e.g. it triggers behaviour in the curl binary rather than just PHP.

Drupal core does relatively few outgoing http requests - there is update status, translation download, oembed fetching in core - will be some contrib and custom Guzzle implementations.

I think this would benefit oembed as well, especially if there are multiple embeds from the same provider on the same page. See also #3621396: Use a queue and permanent cache for Drupal\media\OEmbed\ResourceFetcher::fetchResource().

I can't really think of a problem that would actually arise from this in practice, and it seems like a very good performance improvement that we can't otherwise get, but tagging for security/framework manager review to get an extra opinion.