Follow up to #2400407: [meta] Ensure vendor (PHP) libraries are on latest stable release.
Use composer to update guzzlehttp/guzzle library to version 6.0.0.
Problem/Motivation
In order to release Drupal 8 with the latest stable release, we need to update to Guzzle 6.
In the last major Guzzle version update, there we issues blocked on goutte and mink-goutte-driver updates, so these should be done at the same time.
Proposed resolution
Guzzle 6 moves to PSR-7 HTTP messages. As these are immutable, Guzzle 6 has swapped the event system with a middleware system.
Remaining tasks
- Update composer.json
- Replace event subscribers with middlewares
- Create a client configurator
User interface changes
None
API changes
Data model changes
Comments
Comment #1
imiksuComment #2
imiksuHmm, no update performed when running:
In
composer.jsonfile this is defined as follow:Do we need to update this?
Comment #3
cilefen commentedCorrect. You will have to make that ~5.3 in order to upgrade. You will probably have to
composer update guzzlehttp/*becauseguzzlehttp/ringphpwill need an upgrade too.Try it and see if the tests pass.
Comment #4
cilefen commentedI was wrong. It was only necessary to
composer update guzzlehttp/*.Comment #5
cilefen commentedIt should be 6.0.0 now.
Comment #6
cilefen commentedNote this is not possible right now because fabpot/goutte requires Guzzle to be less than version 6.
Comment #7
cilefen commentedhttps://github.com/FriendsOfPHP/Goutte/issues/215
Comment #8
berdirGuzzle 6 might be a major API break, didn't check yet how close the old API's are to PSR-7.
Comment #9
berdirAlso, pretty happy that having goutte in core now means we have to wait until that supports it to, actually. Last time we did a major guzzle update days after it was released, I was blocked for weeks from upgrading because of behat/mink/goutte.
Comment #10
imiksuShould we update it to 5.3 and create separate issue about Guzzle 6 that it'll need some extra effort?
Comment #11
berdirWe actually can't switch to Guzzle 6, it requires PHP 5.5: https://twitter.com/mtdowling/status/603415290802614272
Comment #12
catchI replied on twitter to see what the lifespan of Guzzle 5 is likely to be like.
Comment #13
cilefen commented@iMiksu
It probably is not worth upgrading to 5.3 until we know which way to go. It is something we are going to check before the release anyway. See @Berdir's comment on the meta:
#2400407-18: [meta] Ensure vendor (PHP) libraries are on latest stable release
Comment #14
basvredelingI've struggled through Guzzle 3 to 4, 4 to 5 updates (less so) before. And now again Guzzle 6 is quite a big api change. On the other hand, it is based on a PSR. If we can push the php5.5 requirement and I'd vote for adopting 6 and consolidating there for a while. Mtdownling might say there is no new major planned, but I've come to know Guzzle as a quickly changing library, so don't count on it staying at 6 for long.
Comment #15
basvredeling#2296557: [policy] Require PHP 5.5 is confirmed and https://github.com/FriendsOfPHP/Goutte/issues/215 is awaiting a review. So the issues blocking this are pretty much lifted.
Comment #16
basvredelingComment #17
hussainwebThis also implies that we need to update
fabpot/goutte. It makes sense to do it here as current version of Goutte won't work with Guzzle 6 and the update version of Goutte (when it comes) won't work with Guzzle 5. They have to go hand in hand. Should this issue be marked postponed then until we see a new release of Goutte?Comment #18
cilefen commentedYes.
Comment #19
dawehnerYeah there is also a PR for it: https://github.com/FriendsOfPHP/Goutte/pull/218
Comment #20
heddnComment #21
fabpot commentedJust for your information, I've just released Goutte 3.0.0 with Guzzle 6.0 support.
Comment #22
cilefen commentedThank you @fabpot and @csarrazi.
Comment #23
hussainwebPostponing again. :(
I updated composer.json for both goutte and guzzle, and ran composer update. There is a conflict with behat/mink-goutte-extension.
I am raising a PR there at https://github.com/minkphp/MinkGoutteDriver/pull/59.
Comment #24
timmillwoodSorry for hijacking, but these sort of issues will be a lot easier when #2315545: Install composer dependencies to D8 when packaging and #1923582: Add ability for testbot to run 'composer install' during installation are committed because the vendor directory can be removed from the repo.
Comment #25
hussainweb@timmillwood: I know. I have been waiting for that to land since forever. Until then, we can at least try and keep the libraries updated and see if there are test failures.
Comment #26
imiksu+1 on #25, and when #2315545: Install composer dependencies to D8 when packaging lands, I suppose this task (+ others) are about updating only the composer file and identifying potential issues related to library updates?
Comment #27
MattA commentedFYI: Guzzle 6 also fixes the issue where HTTPS connections using self-signed certificates are allowed by default (when the curl extension is disabled).
Also, someone should create a followup to update the comment in Drupal\Core\Http\Client since Guzzle doesn't include a default CA-bundle anymore.
Comment #28
hussainwebThe PR for MinkGoutteDriver I created (https://github.com/minkphp/MinkGoutteDriver/pull/59) is still in works. It now passes on all PHP versions up to 5.6 but fails on HHVM. The reason is that Guzzle itself fails on HHVM. I have created a PR for this at https://github.com/guzzle/guzzle/pull/1143.
Please help there as I am not very sure if the MinkGoutteDriver PR would get merged in without HHVM tests passing.
Comment #29
hussainwebMy PR on MinkGoutteDriver has been merged, but a release has not yet been created. Once that is done, I believe we will be able to move ahead with this issue.
Comment #30
jibranYou can still use the commit hash in composer.json
Comment #31
hussainweb@jibran: True, but let's just wait and use a release. If it takes a long time, yes, we could use the commit hash.
Comment #32
hussainwebCome to think of it, we can at least get a preview of what the tests will look. Tests won't pass, of course, since Guzzle requires PHP 5.5 and our testbots are 5.4, but let's give it a shot.
Comment #34
hussainwebAdding tags and related issues.
Comment #35
hussainwebNow that we have some reference results, postponing again.
Comment #36
catchThis is a major version upgrade, so priority should be at least major.
Comment #37
effulgentsia commentedAccording to the issue summary of #2400407: [meta] Ensure vendor (PHP) libraries are on latest stable release, both major and minor (but not patch-level) upgrades of dependencies should be a critical Drupal issue at this point, and I agree with that. So, raising accordingly.
Comment #38
timmillwood@effulgentsia - It looks as though we won't have RC1 until testbot is updated to 5.5.9 then.
Comment #39
dawehnerI'll try to start working on updating the usages of guzzle inside core.
Comment #40
wim leersIsn't this already the case because of #2508231: Raise minimum required version of PHP to 5.5.9 being critical as well?
So, AFAICT we now have 2 criticals blocked on infrastructure.
Comment #41
dawehnerThe new API is pretty nice to use, is easily grockable and opens up a new area of maintainability of Drupal, see
\Drupal\Core\Test\EventSubscriber\HttpRequestSubscriberComment #42
dawehnerWell, this is critical because it sort of changes the API, BUT
this is actually mostly the case for additional things like subscriber, the other API changes are quite small,
so ->get(), ->post() ... still work.
Btw. this at least runs all the REST requests fine.
Given that I would be fine with moving this just to major, even we should really not ship with a unmaintained HTTP library.
Comment #43
dawehnerI'm sorry, this was wrong, thanks berdir. I ran some OPML test, which uses guzzle.
Comment #45
larowlanNot really novice anymore
Took a look at the BrowserTestBase fails, php 5.5 issues too (nice)
Comment #46
larowlanTravis tests running (unit + functional only) here https://github.com/larowlan/drupal/pull/5
Comment #47
larowlanUnit tests are passing, but functional tests (BrowserTestBase) are not - https://travis-ci.org/larowlan/drupal/jobs/69995483
Comment #48
dawehnerMh, that failing test works fine on my machine.
Comment #49
davidwbarratt commentedCan we specify the hash needed (and range) rather than an open-ended dependency?
https://getcomposer.org/doc/articles/versions.md#range
Maybe something like:
(or whatever the next version will be).
This will help people using Composer directly because they wont be chasing master.
Comment #50
dawehnerSure, we can do that, I personally hope they will tag rather sooner than later.
For now though we are blocked on 5.5
To be clear, this seems to be more of an issue with travis CI somehow.
Comment #51
dawehnerNice we have now a proper bot
Comment #54
dawehnerSome more work. Things are tricky, given that the architecture changed.
I think we need a handler/middleware stack much like our ordinary middlewares.
Just want to check whether we have less test failures with that.
Comment #56
jibranIsn't that true?
Comment #57
jibranCore only patch form #54 because I want to review it. :)
Comment #58
timmillwoodI agree with #54 that we shouldn't be requiring a dev-master this could cause a whole host of issues for those who plan to manage their D8 install with Composer.
+ "behat/mink-goutte-driver": "dev-master",Comment #59
catchNo we can require dev-master now and then open another critical issue to pin to an actual version as soon as that's out. We shouldn't release using a dev version, but 8.0.x is a dev version so people managing sites with composer can deal with it for a few weeks.
That change should be much smaller impact than this one, so makes sense to get in front of things now - and if we find issues in the dev version that should help get upstream get a stable out quicker too.
Comment #60
davidwbarratt commented#59,
Since we have a
minimum-stabiliityofdevandprefer-stableis set totrue, I thinkbehat/mink-goutte-drivershould use the version number^1.3.0. That will installdev-masteruntil 1.3.0 comes out, at which point only stable releases will be used. If we need to update the reference in the future we can do that. But setting it to^1.3.0prevents us from having to create release-blocking critical issue.https://github.com/minkphp/MinkGoutteDriver/issues/63#issuecomment-11995...
Comment #61
dawehnerYeah the focus of this issue should be to make things actually working.
\GuzzleHttp\RedirectMiddleware\GuzzleHttp\Middleware::historyto get out, what is needed. Using that though is not obvious,given that Drupal uses a client instance as service, so the reference in ::history is not just there
Note: There is currently no easy way to figure out the actual URL of a response
Comment #62
webchickIs it worth an upstream issue about that? This seems like an awful lot of work for something very simple, and @mtdowling has been very responsive in the past.
Comment #63
dawehnerWell upstream === PSR-7 interfaces
Comment #64
dawehnerBut sure, let's open a support question: https://github.com/guzzle/guzzle/issues/1166
Comment #65
dawehnerCan't be bad to add some tag.
Comment #66
larowlanpoking about
Comment #67
larowlanSome progress,
- uses a factory for the handler stack - which ensure we always get the redirects etc
- adds catch redirect/store redirect handlers into the stack to catch changes to the url and store them in an X-Effective-Url header
- not sure on the missing E-tag headers on feeds yet
Comment #69
dawehnerWell, let's better use the upstream functionality, which is provided for us.
I think it is in general fine for reach caller to explicitly write a callback, when they want this URL.
Comment #70
larowlanMore work
The __invoke in earlier patches wasn't being used because the default_config key in the constructor is no longer used.
Also ->getHeader() signature has changed
Seeing some tests green locally.
Comment #71
larowlanYep, we can drop our catch_redirect/store_redirect stack handlers when upstream is ready (https://github.com/guzzle/guzzle/pull/1167 for others)
Comment #72
dawehnerThat just doesn't work ... I think we should provide our own factory at least and not make client sort of container aware
Note: this is what we want ... because it has additional documentation we should be able to leverage.
Well, I'm not sure whether we want to introduce a custom interface. Yes it helps developers potentially, but it moves us away from helpful documentation about guzzle. I think we should adapt to their stile of solving things.
Comment #74
larowlanI found it the other way, the
__invokedidn't work. Earlier patches were ignoring the'handler'because we were passing it in$config['default_config']['handler']instead of just$config['handler']. Soon as we pass the handler through it blows up. First, with the stack referencing itself, and then with the __invoke being treated as a middleware and not a closure. And neither did a factory because our container builder tries to set __serviceId on stuff, which you can't do on a closure. And neither does passing the closure as an argument with addMapping, because arguments need to be statics.In the docs http://docs.guzzlephp.org/en/latest/handlers-and-middleware.html#middleware you'll note that the push method requires a closure. We're pushing an object, which when it tries to call it (later on) we get the $request, not the handler.
So we need a way for the container to add a method call that pushes the return of $service() (aka __invoke), not the service itself.
Comment #75
larowlanI've been tinkering on it for the best part of 1/2 a day and the only thing I could come up with that worked was the pseudo container aware approach. We could make it a different service to avoid polluting the http_client.
Comment #76
dawehnerYeah @larowlan, an update seems so obvious and easy at the first view :)
If you want, we can discuss on IRC.
Comment #77
jibranWe decided in critical issues discussion meeting to postpone this on https://github.com/guzzle/guzzle/pull/1167.
Comment #78
dawehnerWhile postponing is not a bad idea there are still tasks which have to be done.
Here is some conversion of using a factory, which allows you to set up custom options.
At the same time this allows us to get rid of a custom client object, which is not that bad.
Comment #79
damiankloip commentedThe $config parameter passed into fromOptions() is not added here.
Looks like the usage of this is more like the Guzzle middlewares rather than just adding a handler to the stack.
Comment #80
jibranPR got merged.
Comment #81
dawehnerNow we just need to wait on packagist
Comment #82
larowlanComment #84
dawehnerUpdates as well as using the new callback.
Comment #86
larowlanSo I was thinking a
service configuratorservice is the go for executing the register method on the http_client_handler services and adding them to the stack, to avoid making the client container aware.I will tackle that in the morning (in 14 hrs).
http://symfony.com/doc/current/components/dependency_injection/configura...
Comment #87
dawehnerWell, I think we could just put the logic + container awareness into the factory. It also helps with the other usecaess,
where you want to be able to specify custom options ...
@larowlan
Do you really think adding a custom interface is a good idea? I can't imagine that doing that is really great ...
Comment #88
larowlantaking a look
Comment #89
larowlanremoves the interface
adds a configurator
fixes the redirect code
changes the tag to http_client_middleware
configurator not working yet
Comment #91
kim.pepperComment #92
benjy commentedA name spaced function, interesting pattern.
This sounds like we should actually be specifying the new path? I'm guessing that happens somewhere else.
I kind of feel like we've lost some info here. Previously, it was obvious we do something before a request is sent from the method name, now that info is lost? Also, is inheritdoc valid here given the class doesn't extend anything?
Could we use getHeaderLine() here?
here as well.
Comment #93
larowlanFailsConfigurator broken during container building because of https://github.com/symfony/symfony/issues/14834
So we need to update symfony/dependency-injection from 2.7.0 to 2.7.1
Do we have an issue for that?
Comment #94
timhilliard commented@larowlan looks like that is covered by #2504967: Upgrade to Symfony 2.7.1
Comment #95
hussainwebIf that issue blocks this, then we should raise the priority for that issue to critical.
Comment #96
dawehner@larowlan
Do you mind explaining why we need a configuration and the factory would not be enough?
Comment #97
dawehnerI think I now totally understand the purpose of the configurator, its just to separate the logic out. I like that.
@larowlan
I rewrote the configurator to do things more lazy. I think its always good to give people an example how to do things, even for this case, it probably practically doesn't matter.
I think we actually don't need it, see
\GuzzleHttp\Client::configureDefaultswhich sets this variable to TRUE as well.Well, the concept of a middleware is that you can wrap both before and after.
Good point.
Comment #101
jibranLet's add the interface as well.
Comment #102
dawehnerLet's see whether this works now.
Comment #104
webchickBased on how disruptive this change has been for core (sad panda :\), this is very likely to be disruptive for contrib as well. Therefore, tagging as a "beta target" for one to try and get in before the next beta (tentatively July 22).
Comment #105
larowlanwrong use of invoke (some times you should trust your own judgement over phpstorm)
Comment #107
benjy commentedSure, my point was that previously we had some context from the method name, now we don't and therefore maybe a comment would help. Something like, "Do x before the request is sent."
Comment #108
dawehnerI doubt you can do anything without reading the official documentation , so I put a link to it into some places.
Comment #109
dawehnerForgot to add the new test.
Comment #112
larowlanBefore I forget: this should be http_client_middleware now
Comment #113
dawehnerAh, good eye!
Comment #114
larowlanCouple of minor changes then I think this is rtbc - thanks @dawehner
Can we pin this to ~6.0?
Can we pin a specific commit here?
Then these should go right?
Drupal drupal (now I have that damn song in my head)
No longer needed
Comment #115
dawehnerWell, yeah not yet, see https://packagist.org/packages/guzzlehttp/guzzle
I think it is still pretty amazing that PHP does not complain about it.
Comment #116
kim.pepperThat says there is a 6.0.2 release?
Comment #117
dawehnerYes there was, but it doesn't include yet the on_redirect feature, see https://github.com/guzzle/guzzle/releases/tag/6.0.2 (its 10 days old)
Comment #118
benjy commentedWe still have the inheritdoc here which doesn't relate to anything that can be parsed?
Comment #119
dawehnerThere we go. I don't think its important that its before, but rather what it does: It manipulates the request.
Comment #120
benjy commentedYeah agreed, that makes sense.
Comment #121
benjy commentedThis is looking good to me, couple of small nitpicks and a question for my own benefit then I think RTBC.
These are both mean to be arrays, one is initialised to NULL, the other is implicitly NULL. Should they both be []?
If you call configure multiple times the middlewares are only initialised once but they're pushed onto the $handler_stack every time. Just asking if that is correct? I couldn't actually find where this was called from.
Confused me at first, but we have two different variables called $uri in this function. One in the closure, one outside.
Comment #122
dawehnerThank you for your review @benjy
Well, the NULL is indented to use the isset() check below.
Yeah this is called from within the container. The configurator is designed in a way that you don't have to care about it, which is great, as the configurator itself can be really simple.
A compiled container looks like the following:
Well, technically this is perfectly fine, but sure, let's rename it.
Comment #123
benjy commentedAwesome, thanks dawehner
Comment #124
alexpottNeeds a reroll.
Also...
Is this really worth it? Most of the usages are tests and i'd be confused about whether I should be using \Drupal::httpClient() vs \Drupal::httpClientFactory()
Comment #125
dawehner/me dreams of a world without dependencies in version control.
Comment #127
dawehnerBest decision ever to not put that onto priority on drupal.org
Comment #129
dawehnerdawehner --
Comment #130
jibranJust a quick review.
Can we move the link to next line?
Why not add a interface here as well?
Comment #131
dawehnerThank you jibran!
Can you describe why we need that? Why would you want to change the behaviour of all other other HTTP clients not part of your module?
If you want to change the behaviour you can also write a middleware.
Comment #132
jibranThat's fair enough. Thanks for the explanation. RTBC as per #123.
Comment #133
dawehnerThank you jibran!
Comment #134
catchNice one getting this green.
One question:
This is much, much more verbose - we can't add an extra method to the service to encapsulate?
Almost the same here, I expect any contirb/custom code using guzzle to make requests will end up copy/pasting this over and over again.
Comment #135
damiankloip commentedThe config option passed as the parameter to fromOptions() needs to come last, otherwise the default options and options from Settings will always override what we pass in. We just don't want that :)
Here is a new test that should show the failure, and the fix.
Comment #136
damiankloip commentedSorry, pretty much x-posted with catch.
Comment #138
dawehner<3
You could also just create a new HandlerStack , but meh
Comment #139
damiankloip commented2. I thought that, but then I would be passing in an empty closure or something to construct it. Which was maybe a bit weird? This makes it more obvious that we don't care about the stack. I could be swayed though :)
Comment #140
dawehnerFair point.
Suggestion. Track the URI in the client itself :(, but then provide something like
$client->getLastEffectiveUrl()or soComment #141
fabianx commentedFrom the D8 Core EU Criticals Meeting:
- Use the new on_redirect function
- Store the redirects on the response and enumerate them:
X-Drupal-Redirect-Count: 2
X-Drupal-Redirect-1: ...
X-Drupal-Redirect-2: ...
etc.
That keeps the data where it belongs (on the value object) and we and/or upstream can provide a helper function to get the redirects (or first/last redirect) out of the response object.
That is also middleware compatible.
Overall HTTP headers go into the direction of getting more and more used for transferring additional metadata and that is a good thing IMHO.
So this feels like the best option at this moment.
Comment #142
dawehnerI just tried to implement that directly in guzzle: https://github.com/guzzle/guzzle/issues/1183
Comment #143
dawehnerHad a look at that and I think the easiest solution is indeed to fix it in guzzle directly. Let's wait, I'd say
Comment #144
wim leersPer #143.
Comment #145
dawehner.
Comment #146
dawehnerI'm curious whether we could commit it with the current state and then get the upstream fix in later or improve the API in Drupal if this doesn't work out?
Comment #147
jibran+1 to the idea because it would not have to be a critical.
Comment #148
hussainwebI think it is fine to commit this now, but I will have to say that the followup would also have to be a critical. I remember reading somewhere that we wouldn't/shouldn't release the RC with composer.json locked to a specific commit (like we have in the patch). That means the followup will be a blocker to release, and hence critical.
The reason I think it is fine to commit now would be to allow reviews for the followup to be carried out on a smaller, more specific patch.
Comment #149
dawehnerWell, that would be a minor update, wouldn't it?
This would be part of the RC1 issue.
Comment #150
damiankloip commentedI also agree that this issue should not wait on that. This one is done, aside from one DX problem/feature that is out of our hands. The upgrade is needed regardless so we are using a supported Guzzle version. A smaller incremental update can take care of that surely?
Comment #151
effulgentsia commentedI also agree with #150. Setting to NR, but if someone who's reviewed this patch believes it's RTBC, go ahead and set to that.
Comment #152
catchThose was my only question on #134 when I looked at it, and I'm fine with the answer to that question being a follow-up postponed on the upstream issue.
Comment #153
dawehnerThank you @effulgentsia and @catch
Reupload the old issue. It still applied cleanly, so this should be RTBC
Comment #154
jibranIt was RTBC in #132. We decided to move #134 to follow up. @dawehner is happy with the changes with #135 so setting it back to RTBC. We just need a follow up here now.
Comment #155
effulgentsia commentedIs the change from
array('defaults' => $default_config)to$default_configintentional? If so, should the comment be updated?Comment #156
effulgentsia commentedShould we change
classtoGuzzleHttp\ClientInterfaceinstead? Is there any reason to disallow swapping the factory with one that returns a ClientInterface implementation that doesn't subclass Guzzle's?Same here. #72.2 says we want this because Client has some nice docs, but I think doing this sends the message that the implementation can't be swapped, and if that's not the case, then let's not send that message.
Since this is no longer an event subscriber, let's rename it and remove the containing
EventSubscriberdirectory. PerhapsDrupal\Core\Test\TestHttpClientMiddleware?Confusing whitespacing. I think it would be clearer to indent the
$actual_uri = (string) $request_uri;line and then have the closing}on its own line, matching the indentation of'on_redirect'.Also, can we file the follow-up referenced in #152 / #154, and add @todo links to that issue above these lines.
Also, I think a CR would be valuable for this, mentioning the upgrade in general, and some key highlights about what module developers should know, such as the switch to PSR-7 and the need to use the factory when wanting a client with customized options.
Comment #157
dawehnerThank you for your review!
Well yeah its a factory, you can put in anything here, even a non existing one :)
Well, that is tricky. $client->get() is not guaranteed on the ClientInterface itself, so effectively there are boundaries of swapping things out. Also almost the entire behaviour you want to swap is in handlers/middlewares which you can swap now.
What about doing
\GuzzleHttp\ClientInterface|\GuzzleHttp\Clientto kind of communicate both things at the same time?Fair point.
Well, I would prefer to do as few as possible and rather link to the official documentation, so people learn where they should actually look for things, but sure, let's create one.
I will work on addressing these reviews when its not 2am in the morning.
Comment #158
effulgentsia commentedD'oh. I should have looked and noticed that myself. In that case, ignore #156.1 and #156.2, because we really are then constraining the service to be a full-fledged
GuzzleHttp\Client.I'm assuming this is referring to my request for a CR. Yeah, I think it can be small. I think it could just mention the adoption of PSR-7, but link to an appropriate docs page for more info. But, I think it should mention explicitly that the client service can still be used when it doesn't need instance-specific options (just like before this change), but that a new client needs to be created from the factory service when any instance-specific options are wanted (a new pattern after this change). And have a before/after code sample to that effect. Such as:
Comment #159
dawehnerYeah the ClientInterface is more of a super PURE http thing.
Here is a feedback addressing #157.3 and #157.4
Writing a CR now.
Comment #160
dawehnerCR is written.
Comment #161
damiankloip commentedComment #162
effulgentsia commentedCR looks good, so removing tag. Adding benjy and iMiksu for commit credit for their substantive comments. Is there anyone else who should be added?
Comment #163
dawehnerWell yeah, thank you mtdowling for the help on github, sadly you can't add them here.
+1 for the list of people.
Comment #164
dawehnerAddressed the missing feedback.
Comment #165
jibranHe has a d.o profile though https://www.drupal.org/u/mtdowling.
Comment #166
dawehner@jibran
I guess though he would have to have a comment on this issue, doesn't he?
Comment #167
effulgentsia commentedPushed to 8.0.x. Thanks for the great work. I added mtdowling to the commit message manually. See #2474609: Not possible to credit people who didn't comment in an issue for improving d.o. to make that easier.
Comment #170
kgoel commentedThis issue may have affected #2595927: Update guzzle to fix 100% CPU usage with curl_multi_exec() in GuzzleHttp\Handler\CurlMultiHandler->tick() during install