Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enable persistent CurlShareHandle objects #15603

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

ericnorris
Copy link
Contributor

This PR introduces a new function, curl_share_init_persistent, that creates a php_curlsh struct that can live beyond a single PHP request.

Persisting a curl share handle would allow PHP userspace to cache things like DNS lookups, or even entire connections, between multiple PHP requests, thus reducing work for subsequent requests.

I created a new function instead of reusing the existing curl_share_init function since it also takes an array of curl_share_setopt options to set when the persistent handle doesn't yet exist.

It is noteworthy that calling curl_share_setopt on the persistent handle would affect future requests using the handle; we could consider preventing this.

It is also noteworthy that changing the persistent share options would not take effect if the persistent share already existed; changing the persistent share ID would be sufficient to resolve that.

I'm open to any feedback whatsoever, including the name! I would also add documentation if people were amenable to this PR.

@cmb69
Copy link
Member

cmb69 commented Aug 28, 2024

Thanks for the PR!

However, persistent resources are broken by design for ZTS builds, since EG(persistent_list) is stored in TLS, so multiple threads won't share the persistent resources, and it seems to me that ZTS builds are way more important nowadays than they have been years ago.

Additionally, the usage of resources is frowned upon (https://wiki.php.net/rfc/resource_to_object_conversion), so I don't think we should introduce any new resource types.

@ericnorris
Copy link
Contributor Author

Thanks!

However, persistent resources are broken by design for ZTS builds...

I see, well I'm not tied to this particular implementation but as far as I can tell this is similar to how existing persistent handles work, like persistent streams, memcached connections, mysql connections, etc. If there's a better way to do this that is ZTS-compatible though I'm happy to make the change!

Additionally, the usage of resources is frowned upon (https://wiki.php.net/rfc/resource_to_object_conversion), so I don't think we should introduce any new resource types.

If I understand correctly, this is using a resource under the hood, but it is still exposed as a CurlShareHandle to userspace. That said, same thing as above - not tied to this particular implementation, anything that allows us to persist the handle across multiple requests works for me.

@cmb69
Copy link
Member

cmb69 commented Aug 28, 2024

[…] but as far as I can tell this is similar to how existing persistent handles work, like persistent streams, memcached connections, mysql connections,

Right, and we have at least one bug report about mysqli about this.

If there's a better way to do this that is ZTS-compatible though I'm happy to make the change!

It seems to me that the only proper way to handle persistent objects would be to keep them in shared memory. It probably makes no sense to use OPcache for that, since OPcache is about unmodifiable data, so we would need to introduce some other SHM cache (with all the glitches that may arise; e.g. users may not want to use, ASLR issues on Windows and maybe other platforms, platform dependend implementations, etc). Methinks this is not a small task, and would go far beyond this feature (persistent curl shared handles), and probably requires the RFC process.

If I understand correctly, this is using a resource under the hood,

Right, but we even want to get rid of these "hidden" resources, see e.g. #14282.

@ericnorris
Copy link
Contributor Author

ericnorris commented Aug 28, 2024

Right, and we have at least one bug report about mysqli about this.

If I understand correctly, the behavior in that bug report is exactly what we would expect. That is, we expect that each mod_php worker would have its own persistent curl share handle (like it currently does with persistent memcached connections). I'm not sure I would classify that as a bug, but I can understand why others might feel differently.

Methinks this is not a small task, and would go far beyond this feature (persistent curl shared handles), and probably requires the RFC process.

I'm definitely open to creating an RFC! However the scope seems somewhat undefined to me - would we be aiming to achieve a thread-safe persistent resource replacement? Would suggesting a change to all existing persistent resources be in-scope? Is there already a plan for fixing all existing persistent resources that I could build on top of?

@cmb69
Copy link
Member

cmb69 commented Aug 28, 2024

However the scope seems somewhat undefined to me - would we be aiming to achieve a thread-safe persistent resource replacement? Would suggesting a change to all existing persistent resources be in-scope?

I think so. Likely controversial, since as you've said, some may expect the current behavior, and others a different behavior. And given that SHM may not work, there would need to be fallback anyway (i.e. that shared cache would need to be optional somehow).

Is there already a plan for fixing all existing persistent resources that I could build on top of?

Not that I'm aware of. Maybe @kocsismate is, since he is driving forward the resource to object conversion (which is long overdue, since resources have a couple of issues).

@ericnorris
Copy link
Contributor Author

Not that I'm aware of. Maybe @kocsismate is, since he is driving forward the resource to object conversion

If we are really going to get rid of internal resources (and not just userspace ones), then I'd expect we'd either need some solution for things like mysqli persistent connections, or they'd need to be deprecated and removed as a backwards-incompatible change. So it seems to me that the underlying question is: should PHP support persistence across requests?

If we agree that it should, might we consider merging this (barring any other code improvements) while the current pattern exists? I imagine that any solution we come to for refactoring the other cases of persistence would apply here as well, so migrating this to a hypothetical new pattern would be straightforward. I'm obviously biased, but I do think this is a valuable change, since it would provide a way of reusing work from earlier PHP requests which would reduce end-user latency.

If alternatively we decide that PHP should no longer support persistence, that would surprise me since I'd expect it to be controversial. But if so, I'd understand not wanting to merge this as it would only move us further from that goal.

(which is long overdue, since resources have a couple of issues).

To clarify my understanding a bit, I understand why userspace resources have a number of issues, but I'm not sure I understand the downside of resources used internally, like in this case. Is it that people have differing expectations of how they interact with threads and processes? Architecturally it seems clear to me that these things would be per-thread or per-process, and not shared globally, so it feels like this may be more of an issue of expectations than a technical underpinning. Maybe there are other problems that I'm not aware of, however!

@cmb69
Copy link
Member

cmb69 commented Aug 29, 2024

To clarify my understanding a bit, I understand why userspace resources have a number of issues, but I'm not sure I understand the downside of resources used internally, like in this case.

From the RFC mentioned indirectly above:

They [resources] have quite a few disadvantages like the inability of using resource type declarations, lack of garbage collection (they have to be explicitly freed), bad feedback about memory leaks, etc.

While only the last point would be relevant for internal resources, there is additionally the problem that resources get a unique ID (32bit unsigned integer) which eventually leads to depletion especially with long running processes (which are rather important nowadays, consider Swoole or FrankenPHP etc.)

There is pretty broad consensus that we want to finally rid resources, and it seems that according to that RFC persistent dba and odbc connections have already been replaced with objects (so basically behave the same as non-persistent connections). From skimming https://externals.io/message/121660 and https://externals.io/message/122116, persistent resources apparently have not been discussed at all. I don't know why.

@ericnorris
Copy link
Contributor Author

While only the last point would be relevant for internal resources, there is additionally the problem that resources get a unique ID (32bit unsigned integer) which eventually leads to depletion especially with long running processes (which are rather important nowadays, consider Swoole or FrankenPHP etc.)

Right, I had read the RFC and it seemed to me like it didn't quite apply to internal resources. That said, your point about using 32 bit unsigned integers makes sense - though I'm surprised that there aren't other issues with long running processes. That is, I'd expect other types of PHP runtimes to do something similar to Apache's MaxConnectionsPerChild, for reasons like memory leaks, etc.

There is pretty broad consensus that we want to finally rid resources, and it seems that according to that RFC persistent dba and odbc connections have already been replaced with objects (so basically behave the same as non-persistent connections)...

Thanks for mentioning dba and odbc! I took a look a noticed they were using GC_MAKE_PERSISTENT_LOCAL to achieve persistence. Reading more about GC_MAKE_PERSISTENT_LOCAL, it seems like this would also do exactly what I want. Is there opposition to me re-working this PR to use GC_MAKE_PERSISTENT_LOCAL instead?

To clarify, I don't actually care about using a persistent resource here, I was mainly copying from other examples of persistence in PHP (like mysqli, and memcached). The main thing that I want is persistence, not the resource part.

@cmb69
Copy link
Member

cmb69 commented Aug 29, 2024

That is, I'd expect other types of PHP runtimes to do something similar to Apache's MaxConnectionsPerChild, for reasons like memory leaks, etc.

May make sense, but that's up to the SAPIs; the engine should still be able to work without such measures. And frankly, 32bit unsigned is a lot, but nowadays it might just not be enough.

I took a look a noticed they were using GC_MAKE_PERSISTENT_LOCAL to achieve persistence.

Ah, thanks! I had a closer look and found that persistent resources are only freed in the global shutdown handler (i.e. when the process/thread terminates), but not in the request shutdown handler. So that it basically the same as persistent resource lists. Note, though, that GC_MAKE_PERSISTENT_LOCAL is just a secondary tool to avoid reporting memory leaks after request shutdown.

To clarify, I don't actually care about using a persistent resource here, I was mainly copying from other examples of persistence in PHP (like mysqli, and memcached). The main thing that I want is persistence, not the resource part.

Then it should be fine to do it as it's done in the other PRs.

@ericnorris
Copy link
Contributor Author

ericnorris commented Aug 29, 2024

Note, though, that GC_MAKE_PERSISTENT_LOCAL is just a secondary tool to avoid reporting memory leaks after request shutdown.

Ah, I'm looking into this more and you're right, it seems like the actual key to persistence for those drivers is the PHP_GINIT_FUNCTION setup. I'll attempt a solution using that (edit: and update this PR) instead of the persistent resource list.

Thanks for the help so far!

@ericnorris
Copy link
Contributor Author

@cmb69 upon further inspection, it seems like both the dba and odbc drivers both still use the persistent list (and thus persistent resources).

In dba:

if ((le = zend_hash_str_find_ptr(&EG(persistent_list), resource_key, resource_key_len)) != NULL) {

php-src/ext/dba/dba.c

Lines 937 to 944 in 367f303

if (persistent) {
if (zend_register_persistent_resource(resource_key, resource_key_len, connection->info, le_pdb) == NULL) {
php_error_docref(NULL, E_WARNING, "Could not register persistent resource");
efree(resource_key);
zval_ptr_dtor(return_value);
RETURN_FALSE;
}
}

and in odbc:

if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hashed_details, hashed_details_len)) == NULL) {

php-src/ext/odbc/php_odbc.c

Lines 2344 to 2348 in 367f303

if (zend_register_persistent_resource(hashed_details, hashed_details_len, db_conn, le_pconn) == NULL) {
efree(hashed_details);
zval_ptr_dtor(return_value);
RETURN_FALSE;
}

I'm not entirely sure why, since they have a persistent HashTable in their module globals; they should be able to search for the connections in that hash table.

I'll continue trying to write this without a persistent resource, but maybe someone could provide some more information here? It seems to me like internal resources may still be the correct pattern for persistence for the time being, despite their drawbacks.

@cmb69
Copy link
Member

cmb69 commented Sep 2, 2024

@cmb69 upon further inspection, it seems like both the dba and odbc drivers both still use the persistent list (and thus persistent resources).

Indeed. See #14239 (comment). Apparently noone followed up.

I'm not entirely sure why, since they have a persistent HashTable in their module globals; they should be able to search for the connections in that hash table.

Right. As is, the implementation in dba.c (haven't checked odbc.c) seems to be broken; at least the resource would be unnecessary. I'll have a closer look as soon as possible.

I'll continue trying to write this without a persistent resource, […]

Please do so. :)

@kocsismate
Copy link
Member

Indeed. See #14239 (comment). Apparently noone followed up.

I planned some changes, and discussed them with Niels on PHPF slack (https://phpfoundation.slack.com/archives/CSSNEANGY/p1716414441035159?thread_ts=1716048807.178419&cid=CSSNEANGY). TLDR: he was against introducing a new API until we can remove the current one. Unfortunately, it won't be possible for quite a while we have to respect the current ABI for 3rd party extensions... So I guess it will be a PHP 10 thing.

@kocsismate
Copy link
Member

I'm not entirely sure why, since they have a persistent HashTable in their module globals; they should be able to search for the connections in that hash table.

We cannot shouldn't simply stop using the persistent_list executor global. Mostly because get_resources() wouldn't return these resources then. I don't know whether it's really hurts or not, but since my RFC didn't mention this side-effect beforehand, I think there was no other option than to rely on the old API.

@ericnorris
Copy link
Contributor Author

Thanks for the info @kocsismate!

I planned some changes, and discussed them with Niels on PHPF slack (https://phpfoundation.slack.com/archives/CSSNEANGY/p1716414441035159?thread_ts=1716048807.178419&cid=CSSNEANGY).

I cannot view this discussion, as it seems to require a PHP Foundation slack account, and I can't seem to find a way to join (though I'd be happy to!). Thanks for the TLDR though.

TLDR: he was against introducing a new API until we can remove the current one.
...
We cannot shouldn't simply stop using the persistent_list executor global. Mostly because get_resources() wouldn't return these resources then.

I'm close to finishing up a non-persistent resource approach for the curl share handle, so I will hopefully push that up soon. That said - and I realize I've made a case for sticking with the status quo before - your above comments give me pause in moving away from the persistent internal resource approach in this PR.

Would we want get_resources() to return these persistent curl share handles as well? That would be a strong argument for sticking with the PR as-is.

@ericnorris ericnorris force-pushed the feat-persistent-curl-share-handle branch from 7316e84 to 428e25c Compare September 3, 2024 20:27
@ericnorris
Copy link
Contributor Author

@cmb69 (and @kocsismate, if you don't mind taking a look), I've updated this PR to use PHP_MODULE_GLOBALS instead of an internal persistent resource. Please let me know what you think!

@cmb69
Copy link
Member

cmb69 commented Sep 4, 2024

We cannot shouldn't simply stop using the persistent_list executor global. Mostly because get_resources() wouldn't return these resources then. I don't know whether it's really hurts or not, but since my RFC didn't mention this side-effect beforehand, I think there was no other option than to rely on the old API.

Okay, that makes some sense. Although I consider get_resources() a terrible function; it looks so unsuspicious, but allows spooky action from a distance, e.g. array_map("fclose", get_resources("stream"));. Anyway, I'll try to join slack (and r11) as soon as possible.

I've updated this PR to use PHP_MODULE_GLOBALS instead of an internal persistent resource. Please let me know what you think!

From a quick look, this is generally okay, but you should add a test (or three); these likely will not work with ZTS, since you're not using CURL_G but rather curl_globals directly. I'll have a closer look soonish.

Anyhow, this needs at least approval from @adoy as code owner, and one of the RMs (@ericmann, @NattyNarwhal, @SakiTakamachi), but given that it introduces a new concept to ext/curl, might require the RFC process. It's unfortunate that nobody replied to your mail to the internals list so it's hard to assess what people generally think of this feature.

@SakiTakamachi
Copy link
Member

SakiTakamachi commented Sep 4, 2024

Anyhow, this needs at least approval from @adoy as code owner, and one of the RMs (@ericmann, @NattyNarwhal, @SakiTakamachi), but given that it introduces a new concept to ext/curl, might require the RFC process.

Yes, I agree that this requires an RFC.

And regardless of the need for RFC, this cannot be incorporated into 8.4. Because this is clearly a new feature (that means it's not a bugfix) and not a change that passed an RFC before the feature freeze.

Of course, we can discuss by targeting the next version from 8.4 :)

@NattyNarwhal
Copy link
Member

I agree it's probably a bit too late for 8.4.

I will also say persistent objects also tend to be a bit awkward, especially in the transition to using class objects instead of resources. One such case is closing a connection in the cases you may need to. You would manually close a persistent resource, but an object's destructor is hit when references go away, but the persistent list holds a reference.

@ericnorris
Copy link
Contributor Author

From a quick look, this is generally okay, but you should add a test (or three);

I'm not confident on how exactly to test this, so if this ends up needing an RFC I'll likely defer adding tests until I get a feel for which way the vote is going.

these likely will not work with ZTS, since you're not using CURL_G but rather curl_globals directly.

I don't believe I'm ever using curl_globals directly - the only place I reference curl_globals is in PHP_GINIT_FUNCTION(curl) and PHP_GSHUTDOWN_FUNCTION(curl), which I believe define curl_globals as a function parameter. For example, PHP_GINIT_FUNCTION eventually is defined as:

#define ZEND_MODULE_GLOBALS_CTOR_D(module) void ZEND_MODULE_GLOBALS_CTOR_N(module)(zend_##module##_globals *module##_globals)

Everywhere else I use CURL_G. Please let me know if I missed a spot though!

but given that it introduces a new concept to ext/curl, might require the RFC process. It's unfortunate that nobody replied to your mail to the internals list so it's hard to assess what people generally think of this feature.

Agreed. I'll bump that email thread to see if I can get any other input, and if an RFC is required I'm open to doing that.

@ericnorris
Copy link
Contributor Author

And regardless of the need for RFC, this cannot be incorporated into 8.4.
Of course, we can discuss by targeting the next version from 8.4 :)

I agree it's probably a bit too late for 8.4.

I don't have a particular deadline in mind, so any release version is fine with me! We're (Etsy) comfortable with running our own patched version of PHP so just knowing that it will make it into any version is enough.

@cmb69
Copy link
Member

cmb69 commented Sep 4, 2024

One such case is closing a connection in the cases you may need to. You would manually close a persistent resource, but an object's destructor is hit when references go away, but the persistent list holds a reference.

This can be solved by having a ::close() method on the object, like e.g. https://www.php.net/manual/en/sqlite3.close.php.

@NattyNarwhal
Copy link
Member

This can be solved by having a ::close() method on the object, like e.g. https://www.php.net/manual/en/sqlite3.close.php.

Sounds like we should be doing this for PDO, it's something I've run into with clients. (Sorry to disrupt your thread Eric, I'll make a separate issue for this tangent.)

@mnapoli
Copy link

mnapoli commented Sep 13, 2024

Hi, can you clarify that this allows reusing the same CURL handle between FPM requests? (FPM wasn't clearly mentioned in the thread so I want to make sure)

FYI this is something we discussed with Roman Pronskiy, also with @dunglas. If this is it, I think this could have HUGE benefits to applications out there.

Switching from PHP-FPM to a runtime like FrankenPHP, Laravel Octane (Roadrunner/Swoole), or similar, usually gives the following benefits:

  • no longer need to boot the framework on every request (saves a significant amount of time)
  • but also no longer need to open new HTTPS connections on every request

The second part is much less talked about, but very important in terms of performance. Opening an HTTPS request can sometimes take 100ms or more!

I believe such a feature could be a performance game changer for the PHP ecosystem, without having to rewrite apps so that they work in long-lived processes (assuming libraries like Guzzle, etc. take advantage of it ofc).

@ericnorris
Copy link
Contributor Author

@mnapoli I believe this would work in any form of PHP, i.e. mod_php, php-fpm, etc. I tested this patch with PHP's built-in web-server, for example.

The thing to keep in mind is that this will only persist share handles between requests to the same SAPI worker, so if you had 100 php-fpm workers, you'd have 100 persistent share handles. If you're using a ZTS build of PHP, it's the same math, but replace workers with threads.

I do think this would potentially have large performance benefits for certain PHP applications, even considering the above.

@mnapoli
Copy link

mnapoli commented Sep 16, 2024

Very clear, that makes sense! Thanks for clarifying!

@@ -416,6 +422,19 @@ PHP_MINIT_FUNCTION(curl)
}
/* }}} */

/* {{{ PHP_GINIT_FUNCTION */
Copy link
Member

@kocsismate kocsismate Sep 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please no more Vim fold markers. The PHP_GINIT_FUNCTION is extraneous too.

Suggested change
/* {{{ PHP_GINIT_FUNCTION */

ext/curl/share.c Outdated
CURLSHcode error;

ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STR_EX(id, 1, 0)
Copy link
Member

@kocsismate kocsismate Sep 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are equivalent:

Suggested change
Z_PARAM_STR_EX(id, 1, 0)
Z_PARAM_STR_OR_NULL(id)

ext/curl/share.c Outdated
error = curl_share_setopt(sh->share, CURLSHOPT_SHARE, zval_get_long(entry));

if (error != CURLSHE_OK) {
php_error_docref(NULL, E_WARNING, "could not construct persistent curl share: %s", curl_share_strerror(error));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warnings were canonized a few years ago to start with a capital letter (at least most of them):

Suggested change
php_error_docref(NULL, E_WARNING, "could not construct persistent curl share: %s", curl_share_strerror(error));
php_error_docref(NULL, E_WARNING, "Could not construct persistent cURL share: %s", curl_share_strerror(error));

The curl spelling is not consistent with

zend_argument_value_error(2, "is not a valid cURL share option");
, so I suggested a change here as well

ext/curl/share.c Outdated
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), entry) {
ZVAL_DEREF(entry);

error = curl_share_setopt(sh->share, CURLSHOPT_SHARE, zval_get_long(entry));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be nice not to use weak mode when retrieving the int value from entry. Instead, zval_get_long_ex(entry, true) could be used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but the is_strict parameter of zval_get_long_ex() must not be confused with strict typing.

@@ -3687,6 +3687,9 @@ function curl_share_errno(CurlShareHandle $share_handle): int {}
/** @refcount 1 */
function curl_share_init(): CurlShareHandle {}

/** @refcount 1 */
function curl_share_init_persistent(string $persistent_id, array $shares): CurlShareHandle|false {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer a bit expressive name for the 2nd parameter. I'm thinking about $share_types or something similar.

ext/curl/share.c Outdated
error:
zval_ptr_dtor(return_value);

RETURN_FALSE;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you think it would be possible to throw instead of returning false?

/* {{{ PHP_GINIT_FUNCTION */
PHP_GINIT_FUNCTION(curl)
{
zend_hash_init(&curl_globals->persistent_share_handles, 0, NULL, curl_share_free_persistent, true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it will need some discussion in the RFC whether we want to stop using the EG(persistent_list).


PHP_GSHUTDOWN_FUNCTION(curl)
{
zend_hash_destroy(&curl_globals->persistent_share_handles);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if it would make sense to explicitly close persistent shares with curl_share_close? It's a no-op for regular shares, but it may be useful for persistent ones?

@ericnorris
Copy link
Contributor Author

Thanks for the feedback @kocsismate. I've submitted an RFC (https://wiki.php.net/rfc/curl_share_persistence), so I'll address your changes and any others from the RFC process once we come to a consensus.

This commit introduces a new function, curl_share_init_persistent, that
creates a php_curlsh struct that can live beyond a single PHP request.

Persisting a curl share handle would allow PHP userspace to cache things
like DNS lookups, or even entire connections, between multiple PHP
requests, thus reducing work for subsequent requests.

I created a new function instead of reusing the existing curl_share_init
function since it also takes an array of curl_share_setopt options to
set when the persistent handle doesn't yet exist.

It is noteworthy that calling curl_share_setopt on the persistent handle
would affect future requests using the handle; we could consider
preventing this.

It is also noteworthy that changing the persistent share options would
not take effect if the persistent share already existed; changing the
persistent share ID would be sufficient to resolve that.
@ericnorris ericnorris force-pushed the feat-persistent-curl-share-handle branch 2 times, most recently from 8596760 to c772d79 Compare November 20, 2024 22:36
- The signature of curl_share_init now takes two optional parameters,
  $share_options and $persistent_id.
- I've removed vim markers, and made other small edits per suggestions
  from the pull request.
- curl_share_close now closes persistent share handles. The php_curlsh
  struct needs to keep track of the persistent ID string in order to
  remove it from the module global hash table.
- curl_share_init throws an exception if the share options are invalid.
  This should be backwards compatible as share options are optional, so
  it can only throw once they are specified incorrectly.
@ericnorris ericnorris force-pushed the feat-persistent-curl-share-handle branch from c772d79 to e52ca6e Compare November 21, 2024 20:13
I opted to use the existing Caddy testing infrastructure since it
supports keepalives, whereas it seems the PHP development server does
not.

Alternatively I could write just enough of a socket listener to confirm
that there is only ever a single connection coming from curl, but I
believe it is safe to rely on connect_time being zero when a connection
is reused.
@ericnorris
Copy link
Contributor Author

Hey @kocsismate and @cmb69! I am working to get this PR into a mergeable state now that the vote has passed. I believe I've addressed all of the comments so far.

I have also submitted an alternative PR in #16937 in order to attempt to address some of the concerns from the RFC vote discussion.

Let me know what you think, and if there is any other feedback you may have!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants