Browse Source

Add cookie parsing to convert from psr7 to cakephp.

Re-purpose the cookie parsing code that lives in the 2.x HttpSocket
here. I figured that was a good place to draw an implementation from as
its fairly battle tested and works well.
Mark Story 9 years ago
parent
commit
6a72463c72
2 changed files with 86 additions and 0 deletions
  1. 50 0
      src/Http/ResponseTransformer.php
  2. 36 0
      tests/TestCase/Http/ResponseTransformerTest.php

+ 50 - 0
src/Http/ResponseTransformer.php

@@ -43,6 +43,9 @@ class ResponseTransformer
             'body' => static::getBody($response),
         ];
         $cake = new CakeResponse($data);
+        foreach (static::parseCookies($response->getHeader('Set-Cookie')) as $cookie) {
+            $cake->cookie($cookie);
+        }
         $cake->header(static::collapseHeaders($response));
         return $cake;
     }
@@ -64,6 +67,53 @@ class ResponseTransformer
     }
 
     /**
+     * Parse the Set-Cookie headers in a PSR7 response
+     * into the format CakePHP expects.
+     *
+     * @param array $cookieHeader A list of Set-Cookie headers.
+     * @return array Parsed cookie data.
+     */
+    protected static function parseCookies(array $cookieHeader)
+    {
+        $cookies = [];
+        foreach ($cookieHeader as $cookie) {
+            if (strpos($cookie, '";"') !== false) {
+                $cookie = str_replace('";"', "{__cookie_replace__}", $cookie);
+                $parts = preg_split('/\;[ \t]*/', $cookie);
+                $parts = str_replace("{__cookie_replace__}", '";"', $parts);
+            } else {
+                $parts = preg_split('/\;[ \t]*/', $cookie);
+            }
+
+            list($name, $value) = explode('=', array_shift($parts), 2);
+            $parsed = compact('name', 'value');
+
+            foreach ($parts as $part) {
+                if (strpos($part, '=') !== false) {
+                    list($key, $value) = explode('=', $part);
+                } else {
+                    $key = $part;
+                    $value = true;
+                }
+
+                $key = strtolower($key);
+                if ($key === 'httponly') {
+                    $key = 'httpOnly';
+                }
+                if ($key === 'expires') {
+                    $key = 'expire';
+                    $value = strtotime($value);
+                }
+                if (!isset($parsed[$key])) {
+                    $parsed[$key] = $value;
+                }
+            }
+            $cookies[] = $parsed;
+        }
+        return $cookies;
+    }
+
+    /**
      * Convert a PSR7 Response headers into a flat array
      *
      * @param PsrResponse $response The response to convert.

+ 36 - 0
tests/TestCase/Http/ResponseTransformerTest.php

@@ -119,6 +119,42 @@ class ResponseTransformerTest extends TestCase
     }
 
     /**
+     * Test conversion getting cookies.
+     *
+     * @return void
+     */
+    public function testToCakeCookies()
+    {
+        $cookies = [
+            'remember me=1";"1',
+            'forever=yes; Expires=Wed, 13 Jan 2021 12:30:40 GMT; Path=/some/path; Domain=example.com; HttpOnly; Secure'
+        ];
+        $psr = new PsrResponse('php://memory', 200, ['Set-Cookie' => $cookies]);
+        $result = ResponseTransformer::toCake($psr);
+        $expected = [
+            'name' => 'remember me',
+            'value' => '1";"1',
+            'path' => '/',
+            'domain' => '',
+            'expire' => 0,
+            'secure' => false,
+            'httpOnly' => false,
+        ];
+        $this->assertEquals($expected, $result->cookie('remember me'));
+
+        $expected = [
+            'name' => 'forever',
+            'value' => 'yes',
+            'path' => '/some/path',
+            'domain' => 'example.com',
+            'expire' => 1610541040,
+            'secure' => true,
+            'httpOnly' => true,
+        ];
+        $this->assertEquals($expected, $result->cookie('forever'));
+    }
+
+    /**
      * Test conversion setting the status code.
      *
      * @return void