Skip to content
This repository has been archived by the owner on Jan 30, 2020. It is now read-only.

Commit

Permalink
Merge pull request zendframework/zendframework#5286 from ClemensSahs/…
Browse files Browse the repository at this point in the history
…hotfix/5118

Hotfix/5118
  • Loading branch information
weierophinney committed Oct 23, 2013
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 33 deletions.
32 changes: 31 additions & 1 deletion src/Header/SetCookie.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ class SetCookie implements MultipleHeaderInterface
*/
protected $secure = null;

/**
* If the value need to be quoted or not
*
* @var bool
*/
protected $quoteFieldValue = false;

/**
* @var bool|null
*/
Expand Down Expand Up @@ -206,8 +213,11 @@ public function getFieldValue()
}

$value = urlencode($this->getValue());
if ( $this->hasQuoteFieldValue() ) {
$value = '"'. $value . '"';
}

$fieldValue = $this->getName() . '="' . $value . '"';
$fieldValue = $this->getName() . '=' . $value;

$version = $this->getVersion();
if ($version!==null) {
Expand Down Expand Up @@ -423,6 +433,16 @@ public function setSecure($secure)
return $this;
}

/**
* @param bool $quotedValue
* @return SetCookie
*/
public function setQuoteFieldValue($quotedValue)
{
$this->quoteFieldValue = (bool) $quotedValue;
return $this;
}

/**
* @return bool
*/
Expand Down Expand Up @@ -480,6 +500,16 @@ public function isSessionCookie()
return ($this->expires === null);
}

/**
* Check whether the cookie is a session cookie (has no expiry time set)
*
* @return bool
*/
public function hasQuoteFieldValue()
{
return $this->quoteFieldValue;
}

public function isValidForRequest($requestDomain, $path, $isSecure = false)
{
if ($this->getDomain() && (strrpos($requestDomain, $this->getDomain()) === false)) {
Expand Down
92 changes: 60 additions & 32 deletions test/Header/SetCookieTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ public function testSetCookieConstructor()
$this->assertEquals(9, $setCookieHeader->getVersion());
}

public function testSetCookieFromStringWithQuotedValue()
{
$setCookieHeader = SetCookie::fromString('Set-Cookie: myname="quotedValue"');
$this->assertEquals('quotedValue', $setCookieHeader->getValue());
$this->assertEquals('myname=quotedValue', $setCookieHeader->getFieldValue());
}

public function testSetCookieFromStringCreatesValidSetCookieHeader()
{
$setCookieHeader = SetCookie::fromString('Set-Cookie: xxx');
Expand Down Expand Up @@ -107,7 +114,7 @@ public function testSetCookieGetFieldValueReturnsProperValue()
$setCookieHeader->setSecure(true);
$setCookieHeader->setHttponly(true);

$target = 'myname="myvalue"; Expires=Wed, 13-Jan-2021 22:23:01 GMT;'
$target = 'myname=myvalue; Expires=Wed, 13-Jan-2021 22:23:01 GMT;'
. ' Domain=docs.foo.com; Path=/accounts;'
. ' Secure; HttpOnly';

Expand All @@ -125,7 +132,7 @@ public function testSetCookieToStringReturnsHeaderFormattedString()
$setCookieHeader->setSecure(true);
$setCookieHeader->setHttponly(true);

$target = 'Set-Cookie: myname="myvalue"; Expires=Wed, 13-Jan-2021 22:23:01 GMT;'
$target = 'Set-Cookie: myname=myvalue; Expires=Wed, 13-Jan-2021 22:23:01 GMT;'
. ' Domain=docs.foo.com; Path=/accounts;'
. ' Secure; HttpOnly';

Expand All @@ -146,16 +153,16 @@ public function testSetCookieCanAppendOtherHeadersInWhenCreatingString()
$appendCookie = new SetCookie('othername', 'othervalue');
$headerLine = $setCookieHeader->toStringMultipleHeaders(array($appendCookie));

$target = 'Set-Cookie: myname="myvalue"; Expires=Wed, 13-Jan-2021 22:23:01 GMT;'
$target = 'Set-Cookie: myname=myvalue; Expires=Wed, 13-Jan-2021 22:23:01 GMT;'
. ' Domain=docs.foo.com; Path=/accounts;'
. ' Secure; HttpOnly, othername="othervalue"';
. ' Secure; HttpOnly, othername=othervalue';
$this->assertNotEquals($target, $headerLine);

$target = 'Set-Cookie: myname="myvalue"; Expires=Wed, 13-Jan-2021 22:23:01 GMT;'
$target = 'Set-Cookie: myname=myvalue; Expires=Wed, 13-Jan-2021 22:23:01 GMT;'
. ' Domain=docs.foo.com; Path=/accounts;'
. ' Secure; HttpOnly';
$target.= "\n";
$target.= 'Set-Cookie: othername="othervalue"';
$target.= 'Set-Cookie: othername=othervalue';
$this->assertEquals($target, $headerLine);
}

Expand All @@ -170,7 +177,7 @@ public function testSetCookieAttributesAreUnsettable()
$setCookieHeader->setSecure(true);
$setCookieHeader->setHttponly(true);

$target = 'myname="myvalue"; Expires=Wed, 13-Jan-2021 22:23:01 GMT;'
$target = 'myname=myvalue; Expires=Wed, 13-Jan-2021 22:23:01 GMT;'
. ' Domain=docs.foo.com; Path=/accounts;'
. ' Secure; HttpOnly';
$this->assertSame($target, $setCookieHeader->getFieldValue()); // attributes set
Expand All @@ -180,10 +187,10 @@ public function testSetCookieAttributesAreUnsettable()
$setCookieHeader->setPath(NULL);
$setCookieHeader->setSecure(NULL);
$setCookieHeader->setHttponly(NULL);
$this->assertSame('myname="myvalue"', $setCookieHeader->getFieldValue()); // attributes unset
$this->assertSame('myname=myvalue', $setCookieHeader->getFieldValue()); // attributes unset

$setCookieHeader->setValue(NULL);
$this->assertSame('myname=""', $setCookieHeader->getFieldValue());
$this->assertSame('myname=', $setCookieHeader->getFieldValue());
$this->assertNull($setCookieHeader->getValue());
$this->assertNull($setCookieHeader->getExpires());
$this->assertNull($setCookieHeader->getDomain());
Expand All @@ -205,7 +212,7 @@ public function testSetCookieFieldValueIsEmptyStringWhenNameIsUnset()
$setCookieHeader->setSecure(true);
$setCookieHeader->setHttponly(true);

$target = 'myname="myvalue"; Expires=Wed, 13-Jan-2021 22:23:01 GMT;'
$target = 'myname=myvalue; Expires=Wed, 13-Jan-2021 22:23:01 GMT;'
. ' Domain=docs.foo.com; Path=/accounts;'
. ' Secure; HttpOnly';
$this->assertSame($target, $setCookieHeader->getFieldValue()); // not empty
Expand All @@ -226,7 +233,7 @@ public function testSetCookieSetExpiresWithZeroTimeStamp()
$setCookieHeader->setExpires(0);
$this->assertSame('Thu, 01-Jan-1970 00:00:00 GMT', $setCookieHeader->getExpires());

$target = 'myname="myvalue"; Expires=Thu, 01-Jan-1970 00:00:00 GMT';
$target = 'myname=myvalue; Expires=Thu, 01-Jan-1970 00:00:00 GMT';
$this->assertSame($target, $setCookieHeader->getFieldValue());
}

Expand All @@ -243,7 +250,7 @@ public function testSetCookieSetExpiresWithUnixEpochString()
$this->assertSame('Thu, 01-Jan-1970 00:00:00 GMT', $setCookieHeader->getExpires());
$this->assertSame(0, $setCookieHeader->getExpires(true));

$target = 'myname="myvalue"; Expires=Thu, 01-Jan-1970 00:00:00 GMT';
$target = 'myname=myvalue; Expires=Thu, 01-Jan-1970 00:00:00 GMT';
$this->assertSame($target, $setCookieHeader->getFieldValue());
}

Expand All @@ -266,7 +273,7 @@ public function testIsValidForRequestSubdomainMatch()
*/
public function testZF2_169()
{
$cookie = 'Set-Cookie: leo_auth_token="example"; Version=1; Max-Age=1799; Expires=Mon, 20-Feb-2012 02:49:57 GMT; Path=/';
$cookie = 'Set-Cookie: leo_auth_token=example; Version=1; Max-Age=1799; Expires=Mon, 20-Feb-2012 02:49:57 GMT; Path=/';
$setCookieHeader = SetCookie::fromString($cookie);
$this->assertEquals($cookie, $setCookieHeader->toString());
}
Expand All @@ -276,7 +283,7 @@ public function testZF2_169()
*/
public function testDoesNotAcceptCookieNameFromArbitraryLocationInHeaderValue()
{
$cookie = 'Set-Cookie: Version=1; Max-Age=1799; Expires=Mon, 20-Feb-2012 02:49:57 GMT; Path=/; leo_auth_token="example"';
$cookie = 'Set-Cookie: Version=1; Max-Age=1799; Expires=Mon, 20-Feb-2012 02:49:57 GMT; Path=/; leo_auth_token=example';
$setCookieHeader = SetCookie::fromString($cookie);
$this->assertNotEquals('leo_auth_token', $setCookieHeader->getName());
}
Expand Down Expand Up @@ -312,14 +319,35 @@ public function testToString($cStr, $info, $expected)
$this->assertEquals($cookie->getFieldName() . ': ' . $expected, $cookie->toString());
}

public function testRfcCompatibility()
{
$name = 'myname';
$value = 'myvalue';
$formatUnquoted = '%s: %s=%s';
$formatQuoted = '%s: %s="%s"';

$cookie = new SetCookie( $name, $value );

// default
$this->assertEquals( $cookie->toString(), sprintf($formatUnquoted,$cookie->getFieldName(),$name,$value));

// rfc with quote
$cookie->setQuoteFieldValue(true);
$this->assertEquals( $cookie->toString(), sprintf($formatQuoted,$cookie->getFieldName(),$name,$value));

// rfc without quote
$cookie->setQuoteFieldValue(false);
$this->assertEquals( $cookie->toString(), sprintf($formatUnquoted,$cookie->getFieldName(),$name,$value));
}

public function testSetJsonValue()
{
$cookieName ="fooCookie";
$jsonData = json_encode(array('foo'=>'bar'));

$cookie= new SetCookie($cookieName,$jsonData);

$regExp = sprintf('#^%s="%s"#',$cookieName,urlencode($jsonData));
$regExp = sprintf('#^%s=%s#',$cookieName,urlencode($jsonData));
$this->assertRegExp($regExp,$cookie->getFieldValue());

$cookieName ="fooCookie";
Expand All @@ -328,7 +356,7 @@ public function testSetJsonValue()
$cookie= new SetCookie($cookieName,$jsonData);
$cookie->setDomain('example.org');

$regExp = sprintf('#^%s="%s"; Domain=#',$cookieName,urlencode($jsonData));
$regExp = sprintf('#^%s=%s; Domain=#',$cookieName,urlencode($jsonData));
$this->assertRegExp($regExp,$cookie->getFieldValue());
}

Expand All @@ -344,7 +372,7 @@ public static function validCookieWithInfoProvider()

return array(
array(
'Set-Cookie: justacookie="foo"; domain=example.com',
'Set-Cookie: justacookie=foo; domain=example.com',
array(
'name' => 'justacookie',
'value' => 'foo',
Expand All @@ -354,10 +382,10 @@ public static function validCookieWithInfoProvider()
'secure' => false,
'httponly'=> false
),
'justacookie="foo"; Domain=example.com'
'justacookie=foo; Domain=example.com'
),
array(
'Set-Cookie: expires="tomorrow"; secure; path=/Space Out/; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=.example.com',
'Set-Cookie: expires=tomorrow; secure; path=/Space Out/; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=.example.com',
array(
'name' => 'expires',
'value' => 'tomorrow',
Expand All @@ -367,10 +395,10 @@ public static function validCookieWithInfoProvider()
'secure' => true,
'httponly'=> false
),
'expires="tomorrow"; Expires=Tue, 21-Nov-2006 08:33:44 GMT; Domain=.example.com; Path=/Space Out/; Secure'
'expires=tomorrow; Expires=Tue, 21-Nov-2006 08:33:44 GMT; Domain=.example.com; Path=/Space Out/; Secure'
),
array(
'Set-Cookie: domain="unittests"; expires=' . gmdate('D, d-M-Y H:i:s', $now) . ' GMT; domain=example.com; path=/some%20value/',
'Set-Cookie: domain=unittests; expires=' . gmdate('D, d-M-Y H:i:s', $now) . ' GMT; domain=example.com; path=/some%20value/',
array(
'name' => 'domain',
'value' => 'unittests',
Expand All @@ -380,10 +408,10 @@ public static function validCookieWithInfoProvider()
'secure' => false,
'httponly'=> false
),
'domain="unittests"; Expires=' . gmdate('D, d-M-Y H:i:s', $now) . ' GMT; Domain=example.com; Path=/some%20value/'
'domain=unittests; Expires=' . gmdate('D, d-M-Y H:i:s', $now) . ' GMT; Domain=example.com; Path=/some%20value/'
),
array(
'Set-Cookie: path="indexAction"; path=/; domain=.foo.com; expires=' . gmdate('D, d-M-Y H:i:s', $yesterday) . ' GMT',
'Set-Cookie: path=indexAction; path=/; domain=.foo.com; expires=' . gmdate('D, d-M-Y H:i:s', $yesterday) . ' GMT',
array(
'name' => 'path',
'value' => 'indexAction',
Expand All @@ -393,11 +421,11 @@ public static function validCookieWithInfoProvider()
'secure' => false,
'httponly'=> false
),
'path="indexAction"; Expires=' . gmdate('D, d-M-Y H:i:s', $yesterday) . ' GMT; Domain=.foo.com; Path=/'
'path=indexAction; Expires=' . gmdate('D, d-M-Y H:i:s', $yesterday) . ' GMT; Domain=.foo.com; Path=/'
),

array(
'Set-Cookie: secure="sha1"; secure; SECURE; domain=some.really.deep.domain.com',
'Set-Cookie: secure=sha1; secure; SECURE; domain=some.really.deep.domain.com',
array(
'name' => 'secure',
'value' => 'sha1',
Expand All @@ -407,10 +435,10 @@ public static function validCookieWithInfoProvider()
'secure' => true,
'httponly'=> false
),
'secure="sha1"; Domain=some.really.deep.domain.com; Secure'
'secure=sha1; Domain=some.really.deep.domain.com; Secure'
),
array(
'Set-Cookie: justacookie="foo"; domain=example.com; httpOnly',
'Set-Cookie: justacookie=foo; domain=example.com; httpOnly',
array(
'name' => 'justacookie',
'value' => 'foo',
Expand All @@ -420,10 +448,10 @@ public static function validCookieWithInfoProvider()
'secure' => false,
'httponly'=> true
),
'justacookie="foo"; Domain=example.com; HttpOnly'
'justacookie=foo; Domain=example.com; HttpOnly'
),
array(
'Set-Cookie: PHPSESSID="123456789+abcd%2Cef"; secure; domain=.localdomain; path=/foo/baz; expires=Tue, 21-Nov-2006 08:33:44 GMT;',
'Set-Cookie: PHPSESSID=123456789+abcd%2Cef; secure; domain=.localdomain; path=/foo/baz; expires=Tue, 21-Nov-2006 08:33:44 GMT;',
array(
'name' => 'PHPSESSID',
'value' => '123456789+abcd%2Cef',
Expand All @@ -433,10 +461,10 @@ public static function validCookieWithInfoProvider()
'secure' => true,
'httponly'=> false
),
'PHPSESSID="123456789+abcd%2Cef"; Expires=Tue, 21-Nov-2006 08:33:44 GMT; Domain=.localdomain; Path=/foo/baz; Secure'
'PHPSESSID=123456789+abcd%2Cef; Expires=Tue, 21-Nov-2006 08:33:44 GMT; Domain=.localdomain; Path=/foo/baz; Secure'
),
array(
'Set-Cookie: myname="myvalue"; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 13-Jan-2021 22:23:01 GMT; Secure; HttpOnly',
'Set-Cookie: myname=myvalue; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 13-Jan-2021 22:23:01 GMT; Secure; HttpOnly',
array(
'name' => 'myname',
'value' => 'myvalue',
Expand All @@ -446,7 +474,7 @@ public static function validCookieWithInfoProvider()
'secure' => true,
'httponly'=> true
),
'myname="myvalue"; Expires=Wed, 13-Jan-2021 22:23:01 GMT; Domain=docs.foo.com; Path=/accounts; Secure; HttpOnly'
'myname=myvalue; Expires=Wed, 13-Jan-2021 22:23:01 GMT; Domain=docs.foo.com; Path=/accounts; Secure; HttpOnly'
),
array(
'Set-Cookie:',
Expand Down

0 comments on commit 50ef50b

Please sign in to comment.