Skip to content


Subversion checkout URL

You can clone with
Download ZIP


Cookies are not updated on redirect request. #149

glennpratt opened this Issue · 8 comments

4 participants


I'm dealing with a single sign-on system that adds a cookie and redirects back to the current URL when you arrive on a satellite site you haven't visited recently.

Guzzle receives the new set cookie and adds it to the cookie jar correctly, but the request to the site doesn't have the cookie, so ends up in a redirect loop.

I've tried adding the cookies to the Request object a few different ways, but it doesn't appear any changes make it to cURL during the redirect.

If I catch the Maximum (5) redirects followed exception and re-issue the request, the cookie is now sent correctly and all is well.

    try {
      $response = $request->send();
    } catch (\Guzzle\Http\Exception\CurlException $e) {
      if (!$e->getErrorNo() == 47) {
        throw $e;
      $response = $request->send();

I'd be happy to make a patch here, but I don't know how or if it's possible to change the request during the redirect... perhaps Guzzle would need to handle redirects on it's own.

I assume if this issue could be fixed, #120 could handled seamlessly as well.


Thanks for the report. I'd prefer not to implement redirect logic in Guzzle, so let's first see if cURL handles can be updated in the middle of a redirect. I bet that they can.

I think the best thing to do right now would be to create a branch and write a failing test using the node.js test server. We can then work on figuring out how we can update the cURL handle while it's transferring.

@glennpratt glennpratt referenced this issue from a commit
Commit has since been removed from the repository and is no longer available.

Hey, that was pretty painless: #150.

@glennpratt glennpratt referenced this issue from a commit in glennpratt/guzzle
@glennpratt glennpratt Add failing test for #149, redirected request doesn't have newly adde…
…d cookies.

Well crap. Looks like cURL's CURLOPT_HEADERFUNCTION callback is invoked only after initiating a redirect request. There doesn't seem to be a way to intercept curl and update the curl handle before sending the redirect request.

Here's what I was working on, but it shows that the event is only emitted after the followup request is sent:

diff --git a/src/Guzzle/Http/Curl/CurlMulti.php b/src/Guzzle/Http/Curl/CurlMulti.php
index d324ed6..94fd537 100644
--- a/src/Guzzle/Http/Curl/CurlMulti.php
+++ b/src/Guzzle/Http/Curl/CurlMulti.php
@@ -352,7 +352,6 @@ class CurlMulti extends AbstractHasDispatcher implements CurlMultiInterface
         $wrapper = CurlHandle::factory($request);
         $this->handles->attach($request, $wrapper);
         $this->resourceHash[(int) $wrapper->getHandle()] = $request;
-        $request->getParams()->set('curl_handle', $wrapper);

         return $wrapper;
@@ -387,12 +386,15 @@ class CurlMulti extends AbstractHasDispatcher implements CurlMultiInterface

             // Get messages from curl handles
             while ($done = curl_multi_info_read($this->multiHandle)) {
-                $request = $this->resourceHash[(int) $done['handle']];
-                $handle = $this->handles[$request];
-                try {
-                    $this->processResponse($request, $handle, $done);
-                } catch (\Exception $e) {
-                    $this->removeErroredRequest($request, $e);
+                $id = (int) $done['handle'];
+                if (isset($this->resourceHash[$id])) {
+                    $request = $this->resourceHash[$id];
+                    $handle = $this->handles[$request];
+                    try {
+                        $this->processResponse($request, $handle, $done);
+                    } catch (\Exception $e) {
+                        $this->removeErroredRequest($request, $e);
+                    }

diff --git a/src/Guzzle/Http/Curl/RequestMediator.php b/src/Guzzle/Http/Curl/RequestMediator.php
index f7ca06b..b85bc08 100644
--- a/src/Guzzle/Http/Curl/RequestMediator.php
+++ b/src/Guzzle/Http/Curl/RequestMediator.php
@@ -43,6 +43,7 @@ class RequestMediator
     public function setCurlHandle(CurlHandle $handle)
         $this->curlHandle = $handle;
+        $this->request->getParams()->set('curl_handle', $handle);

         return $this;
diff --git a/src/Guzzle/Plugin/Cookie/CookiePlugin.php b/src/Guzzle/Plugin/Cookie/CookiePlugin.php
index 4686ce0..428d9f6 100644
--- a/src/Guzzle/Plugin/Cookie/CookiePlugin.php
+++ b/src/Guzzle/Plugin/Cookie/CookiePlugin.php
@@ -80,8 +80,40 @@ class CookiePlugin implements EventSubscriberInterface
     public function onRequestReceiveStatusLine(Event $event)
-        if ($event['previous_response']) {
-            $this->cookieJar->addCookiesFromResponse($event['previous_response']);
+        if (!($response = $event['previous_response'])) {
+            return;
+        }
+        $this->cookieJar->addCookiesFromResponse($response);
+        if ($response->isRedirect()) {
+            $request = $response->getRequest();
+            $event['request'] = $request;
+            // Re-Trigger the request.before_send to ensure cookies are updated
+            $this->onRequestBeforeSend($event);
+            if ($request->hasHeader('Cookie')) {
+                $cookie = (string) $request->getHeader('Cookie');
+                if ($handle = $request->getParams()->get('curl_handle')) {
+                    // Remove any existing cookie headers
+                    $headers = array_filter(
+                        $handle->getOptions()->get(CURLOPT_HTTPHEADER),
+                        function ($value) use ($cookie) {
+                            return strpos($value, 'Cookie:') === false;
+                        }
+                    );
+                    // Add the new cookie header
+                    $headers[] = "Cookie: {$cookie}";
+                    // Update the curl handle with the new cookie value
+                    curl_setopt($handle->getHandle(), CURLOPT_HTTPHEADER, $headers);
+                    fwrite(STDERR, 'Updating handle' . "\n\n");
+                }
+            }
diff --git a/tests/Guzzle/Tests/Plugin/Cookie/CookiePluginTest.php b/tests/Guzzle/Tests/Plugin/Cookie/CookiePluginTest.php
index e979b39..1ecebb6 100644
--- a/tests/Guzzle/Tests/Plugin/Cookie/CookiePluginTest.php
+++ b/tests/Guzzle/Tests/Plugin/Cookie/CookiePluginTest.php
@@ -76,6 +76,9 @@ class CookiePluginTest extends \Guzzle\Tests\GuzzleTestCase

         $client = new Client($this->getServer()->getUrl());
+        $client->getConfig()->set('curl.options', array(
+            CURLOPT_VERBOSE => true
+        ));

         $request = $client->get();
@@ -90,7 +93,6 @@ class CookiePluginTest extends \Guzzle\Tests\GuzzleTestCase

         // Confirm subsequent requests have the cookie.
         $this->assertEquals('test=583551', $requests[2]->getHeader('Cookie'));
         // Confirm the redirected request has the cookie.
         $this->assertEquals('test=583551', $requests[1]->getHeader('Cookie'));

Looks like Guzzle will need to handle redirects in PHP rather than cURL... Actually, this will be a good thing for Guzzle. It will make it easier to recover from redirect requests that cannot be rewound, will make it possible to support cookies in redirects, and will generally be easier to understand. It won't be easy though. We'll need to be very careful when implementing POST redirects and probably allow the same level of customization found in curl when dealing with POST redirects.

@mtdowling mtdowling closed this issue from a commit
Commit has since been removed from the repository and is no longer available.
@mtdowling mtdowling closed this in cf6cbc0

Just wondering what the status of this is? I'm currently using Guzzle 3.7.4 and the Cookie plugin and I'm not seeing my cookies being set on redirects. Was this supposed to be fixed?


Same than @greatwitenorth using guzzle 5.2.0: if allow_redirects is set to false, there is no cookie in reponse. See for more information.


Debug mode show that cookies seems to be ignored in case of redirect:

* Hostname was found in DNS cache
* Hostname in DNS cache was stale, zapped
*   Trying
* Connected to ( port 80 (#27)
> POST /index.php HTTP/1.1
User-Agent: Guzzle/5.2.0 curl/7.35.0 PHP/5.5.9-1ubuntu4.5
Content-Type: application/x-www-form-urlencoded
Content-Length: 54

* upload completely sent off: 54 out of 54 bytes
< HTTP/1.1 302 Found
< Date: Mon, 16 Feb 2015 11:25:02 GMT
* Server Apache is not blacklisted
< Server: Apache
< Location: admin/index.php
< Content-Length: 0
< Content-Type: 'text/html'
* Connection #27 to host left intact
* Found bundle for host 0x7f2744d389a0
* Re-using existing connection! (#27) with host
* Connected to ( port 80 (#27)
> GET /admin/index.php HTTP/1.1
User-Agent: Guzzle/5.2.0 curl/7.35.0 PHP/5.5.9-1ubuntu4.5
Content-Type: application/x-www-form-urlencoded

< HTTP/1.1 200 OK
< Date: Mon, 16 Feb 2015 11:25:02 GMT
* Server Apache is not blacklisted
< Server: Apache
< Set-Cookie: sessionID=phpads54e1d38ed5b760-97980772; path=/;
< Transfer-Encoding: chunked
< Content-Type: text/html; charset=ISO-8859-1
* Connection #27 to host left intact

Ok, guys, sorry for the noise, seems that i'm using the bad URL...
All my apologize.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.