Skip to content

Commit

Permalink
Add support for cookies
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikolai Weibull committed Dec 20, 2010
1 parent 319428d commit 663d29c
Show file tree
Hide file tree
Showing 6 changed files with 344 additions and 11 deletions.
79 changes: 79 additions & 0 deletions fixtures/app.rb
Expand Up @@ -20,4 +20,83 @@ class Lookout::Rack::FakeApp < Sinatra::Base
get '/target' do
'you have been successfully redirected to target'
end

get '/cookies/show' do
request.cookies.inspect
end

get '/cookies/set' do
response.set_cookie 'value',
:value => params['value'],
:path => '/cookies',
:expires => Time.now + 60

'cookie has been set'
end

get '/cookies/expired' do
response.set_cookie 'value',
:value => params['value'],
:path => '/cookies',
:expires => Time.now - 60

'expired cookie have been set'
end

get '/no-cookies/show' do
request.cookies.inspect
end

get '/cookies/delete' do
response.delete_cookie 'value'
end

get '/COOKIES/show' do
request.cookies.inspect
end

get '/cookies/set-uppercase' do
response.set_cookie 'VALUE',
:value => params['value'],
:path => '/cookies',
:expires => Time.now + 60

'cookie has been set'
end

get '/cookies/set-simple' do
response.set_cookie 'simple', params['value']

'cookie has been set'
end

get '/cookies/set-secure' do
response.set_cookie 'value',
:value => params['value'],
:secure => true

'cookie has been set'
end

get '/cookies/subdomain' do
response.set_cookie 'count',
:value => ((request.cookies['count'].to_i or 0) + 1).to_s,
:domain => '.example.com'

'cookie has been set'
end

get '/cookies/set-multiple' do
response.set_cookie 'value', :value => '1'
response.set_cookie 'other', :value => '2'

'cookies have been set'
end

get '/cookies/count' do
response.set_cookie 'count',
:value => ((request.cookies['count'].to_i or 0) + 1).to_s

'cookie has been set'
end
end
5 changes: 5 additions & 0 deletions lib/lookout/rack.rb
Expand Up @@ -2,14 +2,19 @@

require 'lookout'
require 'rack'
require 'time'
require 'uri'

module Lookout::Rack
DefaultHost = 'example.org'

Error = Class.new(StandardError)
RedirectError = Class.new(Error)
RequestError = Class.new(Error)
ResponseError = Class.new(Error)

autoload :Cookie, 'lookout/rack/cookie'
autoload :Cookies, 'lookout/rack/cookies'
autoload :Methods, 'lookout/rack/methods'
autoload :Request, 'lookout/rack/request'
autoload :Session, 'lookout/rack/session'
Expand Down
79 changes: 79 additions & 0 deletions lib/lookout/rack/cookie.rb
@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-

class Lookout::Rack::Cookie
include Comparable

def initialize(header, uri = nil, default_host = Lookout::Rack::DefaultHost)
@default_host = default_host
uri ||= default_uri

@cookie, options = header.split(/[;,] */n, 2)

@name, @value = Rack::Utils.parse_query(@cookie, ';').to_a.first

@options = Hash[Rack::Utils.parse_query(options, ';').map{ |k, v| [k.downcase, v] }]
@options['domain'] ||= uri.host || default_host
@options['path'] ||= uri.path.sub(%r{/[^/]*\Z}, '')
end

def empty?
@value.nil? or @value.empty?
end

def valid?(uri)
uri ||= default_uri
uri.host ||= @default_host

real_domain = domain.start_with?('.') ? domain[1..-1] : domain
secure? uri and
uri.host.downcase.end_with? real_domain.downcase and
uri.path.start_with? path
end

def matches?(uri)
valid? uri and not expired?
end

def eql?(other)
self.class === other and self == other
end

def <=>(other)
[name.downcase, path, domain.reverse] <=>
[other.name.downcase, other.path, other.domain.reverse]
end

def hash
name.downcase.hash ^ path.hash ^ domain.hash
end

def to_s
@cookie
end

attr_reader :name

protected

def domain
@options['domain']
end

def path
@options['path'].strip
end

private

def default_uri
URI('//%s/' % @default_host)
end

def secure?(uri)
not @options.include? 'secure' or uri.scheme == 'https'
end

def expired?
@options['expires'] and Time.parse(@options['expires']) < Time.now
end
end
21 changes: 21 additions & 0 deletions lib/lookout/rack/cookies.rb
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-

class Lookout::Rack::Cookies
def initialize(default_host = Lookout::Rack::DefaultHost)
@default_host = default_host
@cookies = {}
end

def merge!(headers, uri = nil)
headers.split("\n").reject{ |c| c.empty? }.each do |header|
cookie = Lookout::Rack::Cookie.new(header, uri, @default_host)
@cookies[cookie] = cookie if cookie.valid? uri
end
self
end

def for(uri)
@cookies.values.select{ |c| c.matches? uri }.sort.
reduce({}){ |h, c| h[c.name] = c; h }.values.join(';')
end
end
37 changes: 26 additions & 11 deletions lib/lookout/rack/session.rb
Expand Up @@ -5,30 +5,35 @@ def initialize(app, options = {})
@app = app
@request = nil
@response = nil
clear
end

def get(uri, options = {})
dispatch('GET', uri, options)
def get(uri, params = {}, env = {})
dispatch('GET', uri, params, env)
end

def post(uri, options = {})
dispatch('POST', uri, options)
def post(uri, params = {}, env = {})
dispatch('POST', uri, params, env)
end

def put(uri, options = {})
dispatch('PUT', uri, options)
def put(uri, params = {}, env = {})
dispatch('PUT', uri, params, env)
end

def delete(uri, options = {})
dispatch('DELETE', uri, options)
def delete(uri, params = {}, env = {})
dispatch('DELETE', uri, params, env)
end

def dispatch(method, uri = '', options = {})
env = Rack::MockRequest.env_for(uri, options.merge(:method => method))
def dispatch(method, uri = '', params = {}, env = {})
uri = URI(uri)
uri.host ||= Lookout::Rack::DefaultHost
env = Rack::MockRequest.env_for(uri.to_s, env.merge(:method => method, :params => params))
env['HTTP_COOKIE'] ||= @cookies.for(uri)
@request = Rack::Request.new(env)
errors = env['rack.errors']
@response = Rack::MockResponse.
new(*((options[:lint] ? Rack::Lint.new(@app) : @app).call(env) + [errors]))
new(*((env[:lint] ? Rack::Lint.new(@app) : @app).call(env) + [errors]))
@cookies.merge! @response.headers['Set-Cookie'], uri if @response.headers['Set-Cookie']
self
end

Expand All @@ -45,4 +50,14 @@ def follow_redirect!
raise Lookout::Rack::RedirectError, 'most recent response was not a redirect'
get(response['Location'])
end

def cookie(cookie, uri = nil)
@cookies.merge! cookie
self
end

def clear
@cookies = Lookout::Rack::Cookies.new
self
end
end

0 comments on commit 663d29c

Please sign in to comment.