Skip to content

Commit 7a8bed7

Browse files
author
Łukasz Śliwa
committed
Cookies management
1 parent f7fb74a commit 7a8bed7

File tree

5 files changed

+137
-0
lines changed

5 files changed

+137
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ tmtags
1414
## VIM
1515
*.swp
1616

17+
## RUBYMINE
18+
.idea
19+
1720
## PROJECT::GENERAL
1821
coverage
1922
doc

lib/grape.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module Grape
88
autoload :Client, 'grape/client'
99
autoload :Route, 'grape/route'
1010
autoload :Entity, 'grape/entity'
11+
autoload :Cookies, 'grape/cookies'
1112

1213
module Middleware
1314
autoload :Base, 'grape/middleware/base'

lib/grape/cookies.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module Grape
2+
class Cookies
3+
4+
def initialize
5+
@send = true
6+
@cookies = {}
7+
@send_cookies = {}
8+
end
9+
10+
def without_send
11+
@send = false
12+
yield self if block_given?
13+
@send = true
14+
end
15+
16+
def [](name)
17+
@cookies[name]
18+
end
19+
20+
def []=(name, value)
21+
@cookies[name.to_sym] = value
22+
@send_cookies[name.to_sym] = true if @send
23+
end
24+
25+
def each(opt = nil, &block)
26+
if opt == :to_send
27+
@cookies.select { |key, value|
28+
@send_cookies[key.to_sym] == true
29+
}.each(&block)
30+
else
31+
@cookies.each(&block)
32+
end
33+
end
34+
35+
def delete(name)
36+
self.[]=(name, { :value => 'deleted', :expires => Time.at(0) })
37+
end
38+
end
39+
end

lib/grape/endpoint.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,18 @@ def header(key = nil, val = nil)
7272
end
7373
end
7474

75+
# Set or get a cookie
76+
#
77+
# @example
78+
# cookies[:mycookie] = 'mycookie val'
79+
# cookies['mycookie-string'] = 'mycookie string val'
80+
# cookies[:more] = { :value => '123', :expires => Time.at(0) }
81+
# cookies.delete :more
82+
#
83+
def cookies
84+
@cookies ||= Cookies.new
85+
end
86+
7587
# Allows you to define the response body as something other than the
7688
# return value.
7789
#
@@ -126,10 +138,14 @@ def call(env)
126138
@header = {}
127139
@request = Rack::Request.new(@env)
128140

141+
get_cookies
142+
129143
run_filters self.class.options[:befores]
130144
response_text = instance_eval &self.class.block
131145
run_filters self.class.options[:afters]
132146

147+
set_cookies
148+
133149
[status, header, [body || response_text]]
134150
end
135151

@@ -140,5 +156,20 @@ def run_filters(filters)
140156
instance_eval &filter
141157
end
142158
end
159+
160+
def get_cookies
161+
cookies.without_send do |c|
162+
@request.cookies.each do |name, value|
163+
c[name] = value
164+
end
165+
end
166+
end
167+
168+
def set_cookies
169+
cookies.each(:to_send) do |name, value|
170+
Rack::Utils.set_cookie_header!(
171+
header, name, value.instance_of?(Hash) ? value : { :value => value })
172+
end
173+
end
143174
end
144175
end

spec/grape/endpoint_spec.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,69 @@ def app; subject end
2929
last_response.headers['X-Awesome'].should == 'true'
3030
end
3131
end
32+
33+
describe '#cookies' do
34+
it 'should be callable from within a block' do
35+
subject.get('/get/cookies') do
36+
cookies['my-awesome-cookie1'] = 'is cool'
37+
cookies['my-awesome-cookie2'] = {
38+
:value => 'is cool too',
39+
:domain => 'my.example.com',
40+
:path => '/',
41+
:secure => true,
42+
}
43+
cookies[:cookie3] = 'symbol'
44+
cookies['cookie4'] = 'secret code here'
45+
end
46+
47+
get('/get/cookies')
48+
49+
last_response.headers['Set-Cookie'].tap { |set_cookies|
50+
set_cookies.should =~ /my-awesome-cookie1=is\+cool\n/
51+
set_cookies.should =~ /my-awesome-cookie2=is\+cool\+too;\ domain=my\.example\.com;\ path=\/;\ secure\n/
52+
set_cookies.should =~ /cookie3=symbol\n/
53+
set_cookies.should =~ /cookie4=secret\+code\+here/
54+
}
55+
end
56+
57+
it "should set browser cookies and should not set response cookies" do
58+
subject.get('/username') do
59+
cookies[:username]
60+
end
61+
get('/username', {}, 'HTTP_COOKIE' => 'username=mrplum; sandbox=true')
62+
63+
last_response.body.should == 'mrplum'
64+
last_response.headers['Set-Cookie'].should_not =~ /username=mrplum/
65+
last_response.headers['Set-Cookie'].should_not =~ /sandbox=true/
66+
end
67+
68+
it "should set and update browser cookies" do
69+
subject.get('/username') do
70+
cookies[:sandbox] = true if cookies[:sandbox] == 'false'
71+
cookies[:username] += "_test"
72+
end
73+
get('/username', {}, 'HTTP_COOKIE' => 'username=user; sandbox=false')
74+
last_response.body.should == 'user_test'
75+
last_response.headers['Set-Cookie'].should =~ /username=user_test/
76+
last_response.headers['Set-Cookie'].should =~ /sandbox=true/
77+
end
78+
79+
it "should delete cookie" do
80+
subject.get('/test') do
81+
sum = 0
82+
cookies.each do |name, val|
83+
sum += val.to_i
84+
cookies.delete name
85+
end
86+
sum
87+
end
88+
get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
89+
last_response.body.should == '3'
90+
last_response.headers['Set-Cookie'].should ==
91+
"delete_this_cookie=deleted; expires=Thu, 01-Jan-1970 00:00:00 GMT\n" +
92+
'and_this=deleted; expires=Thu, 01-Jan-1970 00:00:00 GMT'
93+
end
94+
end
3295

3396
describe '#params' do
3497
it 'should be available to the caller' do

0 commit comments

Comments
 (0)