Skip to content

Commit

Permalink
Add cookie support in responses.
Browse files Browse the repository at this point in the history
  • Loading branch information
josevalim committed Apr 2, 2011
1 parent 4963c11 commit 625ed70
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 8 deletions.
96 changes: 92 additions & 4 deletions lib/ex_bridge/response.ex
@@ -1,6 +1,7 @@
% elixir: cache
% elixir: cache [date_time]

module ExBridge::Response
% TODO: Maybe an ordered dict is not the best/fastest way to represent the headers
object Headers
def initialize(response, headers)
@('response: response, 'headers: headers)
Expand All @@ -27,26 +28,68 @@ module ExBridge::Response
end
end

% TODO: Maybe an ordered dict is not the best/fastest way to represent cookies
object Cookies
def initialize(response, cookies)
@('response: response, 'cookies: cookies)
end

def [](key)
@cookies[key]
end

def set(key, value, options := {:})
@response.cookies @cookies.set(key, options.set('value, value))
end
def clear
@response.cookies {:}
end
def delete(key, options := {:})
set(key, "deleted", options.merge('expires: unix_1970))
end

def to_dict
@cookies
end

private

def unix_1970
DateTime.new({{1970,1,1},{0,0,1}})
end
end

attr_reader ['docroot]
attr_writer ['headers]
attr_writer ['headers, 'cookies]
attr_accessor ['status, 'body, 'file]

def initialize(request, docroot)
@('request: request, 'docroot: docroot && docroot.to_bin, 'headers: {:})
@('request: request, 'docroot: docroot && docroot.to_bin, 'headers: {:}, 'cookies: {:})
end

def headers
ExBridge::Response::Headers.new(self, @headers)
end

def cookies
ExBridge::Response::Cookies.new(self, @cookies)
end

def respond
if @file
self.serve_file(@file, @headers)
else
self.respond(@status, @headers, @body)
headers = serialize_cookies(@headers, @cookies)
self.respond(@status || 200, headers, @body || "")
end
end

def respond(given)
body(given).respond
end

def serve_file_conditionally(path, function)
if @docroot
if ~r"\.\.".match?(path)
Expand All @@ -64,4 +107,49 @@ module ExBridge::Response
error { 'nodocroot, "Cannot send file without docroot" }
end
end

private

def serialize_cookies(headers, {:})
headers
end

def serialize_cookies(headers, cookies)
headers.to_list + cookies.to_list.map -> (c) { "Set-Cookie", serialize_cookie(c) }
end

def serialize_cookie({key, options})
string = "#{key}=#{options['value]}"
if expires = options['expires]
string = string + "; expires=#{serialize_expires(expires)}"
end

if path = options['path]
string = string + "; path=#{path}"
end
if domain = options['domain]
string = string + "; domain=#{domain}"
end

if options['secure]
string = string + "; secure"
end
unless options['httponly] == false
string = string + "; httponly"
end

string
end

def serialize_expires(expires)
% TODO Duck type when we have respond_to?
if expires.__parent_name__ == 'Time
expires.rfc1123
else
expires
end
end
end
12 changes: 11 additions & 1 deletion test/support/http_client.ex
Expand Up @@ -10,6 +10,16 @@ module HTTPClient
private

def convert_headers(headers)
OrderedDict.from_list(headers.map -> ({k,v}) { String.new(k), String.new(v) })
HTTPClient::PropList.new headers.map -> ({k,v}) { String.new(k), String.new(v) }
end

object PropList
def initialize(list)
@('list: Erlang.lists.sort(list))
end
def [](key)
Erlang.proplists.get_all_values(key, @list)
end
end
end
23 changes: 20 additions & 3 deletions test/support/server_case.ex
Expand Up @@ -24,7 +24,7 @@ module ServerCase
def respond_test
response = HTTPClient.request('get, "http://127.0.0.1:#{self.port}/respond")
{ 200, headers, "Hello world\n" } = response
"text/plain" = headers["Content-Type"]
["text/plain"] = headers["Content-Type"]
end

def respond_file_test
Expand All @@ -36,7 +36,7 @@ module ServerCase
def respond_args_test
response = HTTPClient.request('get, "http://127.0.0.1:#{self.port}/respond_args")
{ 200, headers, "Hello world\n" } = response
"text/plain" = headers["Content-Type"]
["text/plain"] = headers["Content-Type"]
end

def serve_file_test
Expand All @@ -48,7 +48,7 @@ module ServerCase
def serve_file_with_headers_test
response = HTTPClient.request('get, "http://127.0.0.1:#{self.port}/serve_file_with_headers")
{ 200, headers, _body } = response
"attachment; filename=\"cool.ex\"" = headers["Content-Disposition"]
["attachment; filename=\"cool.ex\""] = headers["Content-Disposition"]
end

def serve_forbidden_file_test
Expand All @@ -65,6 +65,16 @@ module ServerCase
{ 200, _headers, _body } = HTTPClient.request('get, "http://127.0.0.1:#{self.port}/accessors")
end
def cookies_test
response = HTTPClient.request('get, "http://127.0.0.1:#{self.port}/cookies")
{ 200, headers, "" } = response
cookies = headers["Set-Cookie"]
3 = cookies.size
"key1=value1; httponly" = cookies[0]
"key2=value2; path=/blog; domain=plataformatec.com.br; secure" = cookies[1]
"key3=deleted; expires=1970-01-01 00:00:01; path=/blog; httponly" = cookies[2]
end

% Server loops

def respond_loop(_request, response)
Expand Down Expand Up @@ -109,6 +119,13 @@ module ServerCase
response.serve_file "test/../test/test_helper.ex"
end
def cookies_loop(_request, response)
response = response.cookies.set 'key1, "value1"
response = response.cookies.set 'key2, "value2", 'domain: "plataformatec.com.br", 'path: "/blog", 'secure: true, 'httponly: false
response = response.cookies.delete 'key3, 'path: "/blog"
response.respond
end
def accessors_loop request, response
'GET = request.request_method
"/accessors" = request.path
Expand Down

0 comments on commit 625ed70

Please sign in to comment.