diff --git a/lib/capybara/driver/webkit.rb b/lib/capybara/driver/webkit.rb index 97357b07..d32c973a 100644 --- a/lib/capybara/driver/webkit.rb +++ b/lib/capybara/driver/webkit.rb @@ -2,6 +2,7 @@ require "capybara/driver/webkit/node" require "capybara/driver/webkit/browser" require "capybara/driver/webkit/socket_debugger" +require "capybara/driver/webkit/cookie_jar" class Capybara::Driver::Webkit class WebkitInvalidResponseError < StandardError @@ -103,6 +104,12 @@ def server_port @rack_server.port end + def cookies + @cookie_jar ||= begin + CookieJar.new(browser) + end + end + private def url(path) diff --git a/lib/capybara/driver/webkit/cookie_jar.rb b/lib/capybara/driver/webkit/cookie_jar.rb new file mode 100644 index 00000000..c83e7d1c --- /dev/null +++ b/lib/capybara/driver/webkit/cookie_jar.rb @@ -0,0 +1,55 @@ +require 'webrick' + +# A simple cookie jar implementation. +# Does not take special cookie attributes +# into account like expire, max-age, httponly, secure +class Capybara::Driver::Webkit::CookieJar + attr_reader :browser + + def initialize(browser) + @browser = browser + end + + def [](*args) + cookie = find(*args) + cookie && cookie.value + end + + def find(name, domain = nil, path = "/") + # we are sorting by path size because more specific paths take + # precendence + cookies.sort_by { |c| -c.path.size }.find { |c| + c.name.downcase == name.downcase && + (!domain || valid_domain?(c, domain)) && + (!path || valid_path?(c, path)) + } + end + + protected + + def valid_domain?(cookie, domain) + ends_with?(("." + domain).downcase, + normalize_domain(cookie.domain).downcase) + end + + def normalize_domain(domain) + domain = "." + domain unless domain[0,1] == "." + domain + end + + def valid_path?(cookie, path) + starts_with?(path, cookie.path) + end + + def ends_with?(str, suffix) + str[-suffix.size..-1] == suffix + end + + def starts_with?(str, prefix) + str[0, prefix.size] == prefix + end + + def cookies + browser.get_cookies.map { |c| WEBrick::Cookie.parse_set_cookie(c) } + end +end diff --git a/spec/cookie_jar_spec.rb b/spec/cookie_jar_spec.rb new file mode 100644 index 00000000..3ad94306 --- /dev/null +++ b/spec/cookie_jar_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' +require 'capybara/driver/webkit/cookie_jar' + +describe Capybara::Driver::Webkit::CookieJar do + let(:browser) { + browser = double("Browser") + browser.stub(:get_cookies) { [ + "cookie1=1; domain=.example.org; path=/", + "cookie1=2; domain=.example.org; path=/dir1/", + "cookie1=3; domain=.facebook.com; path=/", + "cookie2=4; domain=.sub1.example.org; path=/", + ] } + browser + } + + subject { Capybara::Driver::Webkit::CookieJar.new(browser) } + + describe "#[]" do + it "should return the right cookie value for every given domain/path" do + subject["cookie1", "example.org"].should == "1" + subject["cookie1", "www.facebook.com"].should == "3" + subject["cookie2", "sub1.example.org"].should == "4" + end + + it "should not return cookie from other domain" do + subject["cookie2", "www.example.org"].should == nil + end + + it "should handle path precedence correctly" do + subject["cookie1", "www.example.org"].should == "1" + subject["cookie1", "www.example.org", "/dir1/123"].should == "2" + end + end +end diff --git a/spec/driver_spec.rb b/spec/driver_spec.rb index 1ee0ec71..97d0b198 100644 --- a/spec/driver_spec.rb +++ b/spec/driver_spec.rb @@ -943,6 +943,10 @@ def echoed_cookie cookie["domain"].should include "127.0.0.1" cookie["path"].should == "/" end + + it "allows reading access to cookies using a nice syntax" do + subject.cookies["cookie"].should == "abc" + end end context "with socket debugger" do