Skip to content
This repository has been archived by the owner on Dec 16, 2023. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Fixed Zombie retaining multiple values for the same cookie (domain/pa…
…th/key).
  • Loading branch information
assaf committed May 10, 2012
1 parent d86d7ce commit ffe8b35
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 16 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Expand Up @@ -12,8 +12,10 @@ stupid idea).
Support for opening link in specified target (named window, `_self`, `_parent`, `_top` or
`_blank`).

469 tests
11.6 sec to complete
Fixed Zombie retaining multiple values for the same cookie (domain/path/key).

485 tests
11.9 sec to complete


## Version 0.13.13 2012-05-09
Expand Down
29 changes: 21 additions & 8 deletions lib/zombie/cookies.coffee
Expand Up @@ -13,7 +13,7 @@ class Access

# Returns all the cookies for this domain/path.
all: ->
return @_cookies.filter((cookie)=>
return @_cookies.all().filter((cookie)=>
return Tough.domainMatch(@domain, cookie.domain) && Tough.pathMatch(@path, cookie.path) && cookie.TTL() > 0
).sort(Tough.cookieCompare)

Expand Down Expand Up @@ -42,18 +42,21 @@ class Access
cookie.secure = !!options.secure
cookie.httpOnly = !!options.httpOnly

# Delete cookie before setting it, so we only store one cookie (per
# domain/path/name)
@_cookies.filter((c)=> !(cookie.key == c.key && cookie.domain == c.domain && cookie.path == c.path) )
if Tough.domainMatch(cookie.domain, @domain) && Tough.pathMatch(cookie.path, @path) && cookie.TTL() > 0
@_cookies.push cookie

# Deletes a cookie.
#
# * name -- Cookie name
remove: (name)->
@_cookies = @_cookies.filter((cookie)=> !(cookie.key == name && cookie.domain == @domain && cookie.path == @path) )
@_cookies.filter((cookie)=> !(cookie.key == name && cookie.domain == @domain && cookie.path == @path) )

# Clears all cookies.
clear: ->
@_cookies = @_cookies.filter((cookie)=> !(cookie.domain == @domain && cookie.path == @path) )
@_cookies.filter((cookie)=> !(cookie.domain == @domain && cookie.path == @path) )

# Update cookies from serialized form. This method works equally well for
# the Set-Cookie header and value passed to document.cookie setter.
Expand All @@ -67,10 +70,11 @@ class Access
cookie = Cookie.parse(cookie)
cookie.domain ||= @domain
cookie.path ||= @path
if Tough.domainMatch(@domain, cookie.domain) && Tough.pathMatch(@path, cookie.path)
#@remove cookie.key
if cookie.TTL() > 0
@_cookies.push cookie
# Delete cookie before setting it, so we only store one cookie (per
# domain/path/name)
@_cookies.filter((c)-> !(cookie.key == c.key && cookie.domain == c.domain && cookie.path == c.path) )
if Tough.domainMatch(@domain, cookie.domain) && Tough.pathMatch(@path, cookie.path) && cookie.TTL() > 0
@_cookies.push cookie

# Adds Cookie header suitable for sending to the server.
addHeader: (headers)->
Expand All @@ -94,7 +98,7 @@ class Cookies

# Creates and returns cookie access scopes to given host/path.
access: (hostname, pathname)->
return new Access(@_cookies, hostname, pathname)
return new Access(this, hostname, pathname)

# Add cookies accessor to window: documents need this.
extend: (window)->
Expand All @@ -121,6 +125,15 @@ class Cookies
continue if line[0] == "#" || line == ""
@_cookies.push Cookie.parse(line)

filter: (fn)->
@_cookies = @_cookies.filter(fn)

push: (cookie)->
@_cookies.push cookie

all: ->
@_cookies.slice()


# Returns name=value pairs
HTML.HTMLDocument.prototype.__defineGetter__ "cookie", ->
Expand Down
37 changes: 31 additions & 6 deletions test/cookies_test.coffee
Expand Up @@ -16,9 +16,10 @@ describe "Cookies", ->
res.cookie "_domain1", "here", domain: ".localhost"
res.cookie "_domain2", "not here", domain: "not.localhost"
res.cookie "_domain3", "wrong", domain: "notlocalhost"
res.cookie "_dup", "specific", path: "/cookies"
res.cookie "_dup", "general", path: "/"
res.cookie "_multiple", "specific", path: "/cookies"
res.cookie "_multiple", "general", path: "/"
res.cookie "_http_only","value", httpOnly: true
res.cookie "_dup", "one", path: "/"
res.send "<html></html>"

brains.get "/cookies/echo", (req,res)->
Expand Down Expand Up @@ -62,7 +63,7 @@ describe "Cookies", ->
assert cookies.get("_domain2") == undefined
assert cookies.get("_domain3") == undefined
it "should access most specific cookie", ->
assert.equal cookies.get("_dup"), "specific"
assert.equal cookies.get("_multiple"), "specific"


describe "host in domain", ->
Expand Down Expand Up @@ -95,7 +96,7 @@ describe "Cookies", ->

it "should include only visible cookies", ->
keys = (key for key, value of pairs).sort()
assert.deepEqual keys, "_domain1 _dup _expires1 _expires2 _name _path1 _path4".split(" ")
assert.deepEqual keys, "_domain1 _dup _expires1 _expires2 _multiple _name _path1 _path4".split(" ")
it "should match name to value", ->
assert.equal pairs._name, "value"
assert.equal pairs._path1, "yummy"
Expand Down Expand Up @@ -134,6 +135,29 @@ describe "Cookies", ->
assert.equal cookies.get("_expires4"), "3s"


describe "duplicates", ->
browser = new Browser()

before (done)->
brains.get "/cookies2", (req, res)->
res.cookie "_dup", "two", path: "/"
res.send ""
brains.get "/cookies3", (req, res)->
res.cookie "_dup", "three", path: "/"
res.send ""

browser.visit "http://localhost:3003/cookies", ->
browser.visit "http://localhost:3003/cookies2", ->
browser.visit "http://localhost:3003/cookies3", done

it "should retain last value", ->
console.log browser.cookies().all()
assert.equal browser.cookies().get("_dup"), "three"
it "should only retain last cookie", ->
dups = browser.cookies().all().filter((c)-> c.key == "_dup")
assert.equal dups.length, 1


describe "send cookies", ->
cookies = null

Expand Down Expand Up @@ -234,12 +258,12 @@ describe "Cookies", ->

before (done)->
browser.visit "http://localhost:3003/cookies", ->
browser.document.cookie = "foo=qux" # more specific, /cookies/echo hides it
browser.document.cookie = "foo=bar" #
done()

before (done)->
browser.visit "http://localhost:3003/cookies/other", ->
browser.document.cookie = "bar=qux" # different domain, not visible
browser.document.cookie = "foo=qux" # more specific path, not visible to /cookies.echo
done()

before (done)->
Expand All @@ -265,6 +289,7 @@ describe "Cookies", ->
it "should be available from document", ->
assert.equal browser.cookies().get("foo"), "bar\"baz"


describe "setting cookie with semicolon", ->
before (done)->
browser.visit "http://localhost:3003/cookies/empty", ->
Expand Down

0 comments on commit ffe8b35

Please sign in to comment.