ZF-11726: Zend_Http_CookieJar::getAllCookies(Zend_Http_CookieJar::COOKIE_STRING_CONCAT) creates an invalid (RFC 6265) Cookie string

Description

If the Zend_Http_CookieJar method 'getAllCookies()' with the 1 parameter set to Zend_Http_CookieJar::COOKIE_STRING_CONCAT, the returned string is invalid and not matches the RCF 6265 (http://tools.ietf.org/html/rfc6265).

Description:

The returned string not contains a space between each cookie key-value element and the ending semicolon. The RCF 6265 describes the Cookie string as following (EBNF): ;SP (space) ;WSP (whitespace) ;CR (carriage return) ;CRLF (CR LF) ;LF (line feed) OWS = *( [ obs-fold ] WSP ); "optional" whitespace obs-fold = CRLF cookie-header = "Cookie:" OWS cookie-string OWS cookie-string = cookie-pair *( ";" SP cookie-pair ) cookie-pair = cookie-name "=" cookie-value ...

Expected result:

CookieJar with two cookies: 1. foo=bar; Path=/; Domain=example.com 2. acme=login; Path=/; Domain=example.com

(string) 'foobar=bar; acme=login'

Actual result:

(string) 'foobar=bar;acme=login;'

There are two problems here. First, the space between the two cookies is missing. Second, the last character cannot be a semicolon.

Patch:

I created an patch to this issue: https://gist.github.com/1205916

Comments

Patch to solve the cookie problem

Yes, {{Zend_Http_CookieJar}} (and {{Zend_Http_Cookie}} as well) don't adhere exactly to the spec, but does it cause any real-world problems? I suspect that changing this behavior could qualify as a backwards-compatibility break (unlikely, IMHO).

Reproducing unit test:


Index: tests/Zend/Http/CookieJarTest.php
===================================================================
--- tests/Zend/Http/CookieJarTest.php   (revision 24549)
+++ tests/Zend/Http/CookieJarTest.php   (working copy)
@@ -470,4 +470,33 @@
         $jar->reset();
         $this->assertTrue($jar->isEmpty());
     }
+
+    /**
+     * @group ZF-11726
+     */
+    public function testEnsureCookieJarWithSingleCookieAdheresToSyntaxSpecifiedInRfc6265()
+    {
+        $jar = new Zend_Http_CookieJar();
+        $jar->addCookie(Zend_Http_Cookie::fromString('foo1=bar1; domain=.example.com; path=/a/b'));
+
+        $cookies = $jar->getAllCookies(Zend_Http_CookieJar::COOKIE_STRING_CONCAT);
+        // Assert that last key-value pair does not end with separator (;)
+        $this->assertNotRegExp('/;$/',ltrim($cookies));
+    }
+
+    /**
+     * @group ZF-11726
+     */
+    public function testEnsureCookieJarWithMultipleCookiesAdheresToSyntaxSpecifiedInRfc6265()
+    {
+        $jar = new Zend_Http_CookieJar();
+        $jar->addCookie(Zend_Http_Cookie::fromString('foo1=bar1; domain=.example.com; path=/a/b'));
+        $jar->addCookie(Zend_Http_Cookie::fromString('foo2=bar2; domain=.example.com; path=/c/d'));
+
+        $cookies = $jar->getAllCookies(Zend_Http_CookieJar::COOKIE_STRING_CONCAT);
+        // Assert that parts have a space right after the separator (;)
+        $this->assertRegExp('/^[^=]+=[^;]+; [^=]+=[^;]+$/',ltrim($cookies));
+        // Assert that last key-value pair does not end with separator (;)
+        $this->assertNotRegExp('/;$/',ltrim($cookies));
+    }
 }

Dear Adam

I had problem with a cPanel Server, with only allows RFC conform cookies. This harmed my application to fail and took me hours to figure out what caused the problem. I wasn't thinking a missing space makes the difference. Because I was such annoyed, I wrote this patch to avoid frustration in the future.

Dominic: Thank you for your feedback. I'm not entirely certain it's possible to directly alter the current behavior of {{Zend_Http_CookieJar}}, as there may be implementations which rely on the current (albeit non-standard) behavior. One thing we can investigate, though, is adding a "strict" mode so that the default behavior remains intact but one can switch on strict RFC6265 compatibility if necessary.

Fixed in trunk r24856