Skip to content

Commit

Permalink
Refactored dispatching. Fixed bug in template rendering setting headers.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismoos committed Jun 23, 2010
1 parent 067ba83 commit 54706c8
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 156 deletions.
1 change: 1 addition & 0 deletions lib/fastr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ module Fastr
autoload :Filter, "#{ROOT}/fastr/filter"
autoload :Async, "#{ROOT}/fastr/async"
autoload :HTTP, "#{ROOT}/fastr/http"
autoload :Dispatch, "#{ROOT}/fastr/dispatch"
end
153 changes: 1 addition & 152 deletions lib/fastr/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@ module Fastr
# @author Chris Moos
class Application
include Fastr::Log
include Fastr::Dispatch

# The file that contains application settings.
SETTINGS_FILE = "app/config/settings.rb"

# The file that is evaluated when fastr finishes booting.
INIT_FILE = "app/config/init.rb"

# The folder containing static content.
PUBLIC_FOLDER = "public"

# The router for this application.
# @return [Fastr::Router]
Expand Down Expand Up @@ -50,51 +48,6 @@ def initialize(path)
boot
end

# Convenience wrapper for do_dispatch
# This is the heart of the server, called indirectly by a Rack aware server.
#
# @param env [Hash]
# @return [Array]
def dispatch(env)
return [500, {}, "Server Not Ready"] if @booting

begin
new_env = plugin_before_dispatch(env)
plugin_after_dispatch(new_env, do_dispatch(new_env))
rescue Exception => e
bt = e.backtrace.join("\n")
[500, {}, "Exception: #{e}\n\n#{bt}"]
end
end

# Runs before_dispatch in all plugins.
#
# @param env [Hash]
# @return [Hash]
def plugin_before_dispatch(env)
new_env = env

self.plugins.each do |plugin|
if plugin.respond_to? :before_dispatch
new_env = plugin.send(:before_dispatch, self, env)
end
end

new_env
end

def plugin_after_dispatch(env, response)
new_response = response

self.plugins.each do |plugin|
if plugin.respond_to? :after_dispatch
new_response = plugin.send(:after_dispatch, self, env, response)
end
end

new_response
end

def plugin_after_boot
self.plugins.each do |plugin|
if plugin.respond_to? :after_boot
Expand All @@ -103,112 +56,8 @@ def plugin_after_boot
end
end

# Route, instantiate controller, return response from controller's action.
def do_dispatch(env)
path = env['PATH_INFO']

# Try to serve a public file
ret = dispatch_public(env, path)
return ret if not ret.nil?

log.debug "Checking for routes that match: #{path}"
route = router.match(env)

if route.has_key? :ok
vars = route[:ok]
controller = vars[:controller]
action = vars[:action].to_sym

raise Fastr::Error.new("Controller and action not present in route") if controller.nil? or action.nil?


klass = "#{controller.capitalize}Controller"

log.info "Routing to controller: #{klass}, action: #{action}"

klass_inst = Module.const_get(klass)
obj = klass_inst.new
setup_controller(obj, env, vars)

# Run before filters
response = Fastr::Filter.run_before_filters(obj, klass_inst, action)

# No before filters halted, send to action
if response.nil?
response = obj.send(action)
end

# Run the after filters
#response = Fastr::Filter.run_filters(obj, klass_inst, action, :after, response)
response = Fastr::Filter.run_after_filters(obj, klass_inst, action, response)

code, hdrs, body = *response

# Merge headers with anything specified in the controller
hdrs.merge!(obj.headers)

[code, hdrs, body]
else
[404, {"Content-Type" => "text/plain"}, "404 Not Found: #{path}"]
end
end

private



def dispatch_public(env, path)
path = "#{self.app_path}/#{PUBLIC_FOLDER}/#{path[1..(path.length - 1)]}"
if not File.directory? path and File.exists? path
f = File.open(path)
hdrs = {}

type = MIME::Types.type_for(File.basename(path))

hdrs["Content-Type"] = type.to_s if not type.nil?

return [200, hdrs, f.read]
else
return nil
end
end

def setup_controller(controller, env, vars)
controller.env = env
controller.headers = {}

# Populate the parameters based on the HTTP method
if Fastr::HTTP.method?(env, :get)
controller.get_params = Fastr::HTTP.parse_query_string(env['QUERY_STRING'])
controller.params = controller.get_params.merge(vars)
elsif Fastr::HTTP.method?(env, :post)
controller.post_params = {}
controller.post_params = Fastr::HTTP.parse_query_string(env['rack.input'].read) if env['rack.input']
controller.params = controller.post_params.merge(vars)
else
controller.params = vars
end

controller.cookies = get_cookies(env)
controller.app = self
end

def get_cookies(env)
if env.has_key? "HTTP_COOKIE"
cookies = env['HTTP_COOKIE'].split(';')
c = {}
cookies.each do |cookie|
info = cookie.strip.split("=")
if info.length == 2
c[info[0].strip] = info[1].strip
end
end
c
else
{}
end
end

#
# This is used to initialize the application.
# It runs in a thread because startup depends on EventMachine running
Expand Down
145 changes: 145 additions & 0 deletions lib/fastr/dispatch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
module Fastr
module Dispatch
# The folder containing static content.
PUBLIC_FOLDER = "public"

# Convenience wrapper for do_dispatch
# This is the heart of the server, called indirectly by a Rack aware server.
#
# @param env [Hash]
# @return [Array]
def dispatch(env)
return [500, {}, "Server Not Ready"] if @booting

begin
new_env = plugin_before_dispatch(env)
plugin_after_dispatch(new_env, do_dispatch(new_env))
rescue Exception => e
bt = e.backtrace.join("\n")
[500, {}, "Exception: #{e}\n\n#{bt}"]
end
end

# Route, instantiate controller, return response from controller's action.
def do_dispatch(env)
path = env['PATH_INFO']

# Try to serve a public file
ret = dispatch_public(env, path)
return ret if not ret.nil?

log.debug "Checking for routes that match: #{path}"
route = router.match(env)

if route.has_key? :ok
vars = route[:ok]
controller = vars[:controller]
action = vars[:action].to_sym

raise Fastr::Error.new("Controller and action not present in route") if controller.nil? or action.nil?


klass = "#{controller.capitalize}Controller"

log.info "Routing to controller: #{klass}, action: #{action}"

klass_inst = Module.const_get(klass)
obj = klass_inst.new
setup_controller(obj, env, vars)

# Run before filters
response = Fastr::Filter.run_before_filters(obj, klass_inst, action)

# No before filters halted, send to action
if response.nil?
response = obj.send(action)
end

# Run after filters
response = Fastr::Filter.run_after_filters(obj, klass_inst, action, response)

code, hdrs, body = *response

# Merge headers with anything specified in the controller
hdrs.merge!(obj.headers)

[code, hdrs, body]
else
[404, {"Content-Type" => "text/plain"}, "404 Not Found: #{path}"]
end
end

def dispatch_public(env, path)
path = "#{self.app_path}/#{PUBLIC_FOLDER}/#{path[1..(path.length - 1)]}"
if not File.directory? path and File.exists? path
f = File.open(path)
hdrs = {}

type = MIME::Types.type_for(File.basename(path))

hdrs["Content-Type"] = type.to_s if not type.nil?

return [200, hdrs, f.read]
else
return nil
end
end

# Sets up a controller for a request.
def setup_controller(controller, env, vars)
controller.env = env
controller.headers = {}

setup_controller_params(controller, env, vars)

controller.cookies = Fastr::HTTP.parse_cookies(env)
controller.app = self
end

# Populate the parameters based on the HTTP method.
def setup_controller_params(controller, env, vars)
if Fastr::HTTP.method?(env, :get)
controller.get_params = Fastr::HTTP.parse_query_string(env['QUERY_STRING'])
controller.params = controller.get_params.merge(vars)
elsif Fastr::HTTP.method?(env, :post)
controller.post_params = {}
controller.post_params = Fastr::HTTP.parse_query_string(env['rack.input'].read) if env['rack.input']
controller.params = controller.post_params.merge(vars)
else
controller.params = vars
end
end

# Runs before_dispatch in all plugins.
#
# @param env [Hash]
# @return [Hash]
def plugin_before_dispatch(env)
new_env = env

self.plugins.each do |plugin|
if plugin.respond_to? :before_dispatch
new_env = plugin.send(:before_dispatch, self, env)
end
end

new_env
end

# Runs after_dispatch in all plugins.
#
# @param env [Hash]
# @return [Hash]
def plugin_after_dispatch(env, response)
new_response = response

self.plugins.each do |plugin|
if plugin.respond_to? :after_dispatch
new_response = plugin.send(:after_dispatch, self, env, response)
end
end

new_response
end
end
end
22 changes: 21 additions & 1 deletion lib/fastr/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module HTTP

# Parses the query string.
#
# @param [String]
# @param qs [String]
# @return [Hash]
def self.parse_query_string(qs)
params = {}
Expand All @@ -20,5 +20,25 @@ def self.parse_query_string(qs)
def self.method?(env, method)
return env['REQUEST_METHOD'].downcase.to_sym == method
end

# Parses the HTTP cookie.
#
# @param env [Hash]
# @return [Hash]
def self.parse_cookies(env)
if env.has_key? "HTTP_COOKIE"
cookies = env['HTTP_COOKIE'].split(';')
c = {}
cookies.each do |cookie|
info = cookie.strip.split("=")
if info.length == 2
c[info[0].strip] = info[1].strip
end
end
c
else
{}
end
end
end
end
6 changes: 3 additions & 3 deletions lib/fastr/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def render(kind, tpl, opts={})
end

def render_template(tpl_path, opts={})
@headers = {"Content-Type" => "text/html"}.merge(opts[:headers] || {})
self.headers['Content-Type'] = 'text/html'
@response_code = opts[:response_code] || 200

[ @response_code, @headers, [render_template_to_string(tpl_path, opts)] ]
Expand All @@ -94,13 +94,13 @@ def render_template_to_string(tpl_path, opts={})
end

def render_text(text, opts={})
@headers = {"Content-Type" => "text/plain"}.merge(opts[:headers] || {})
self.headers['Content-Type'] = 'text/plain'
@response_code = opts[:response_code] || 200
[ @response_code, @headers, [text] ]
end

def render_json(obj, opts={})
@headers = {"Content-Type" => "application/json"}.merge(opts[:headers] || {})
self.headers['Content-Type'] = 'application/json'
@response_code = opts[:response_code] || 200
[ @response_code, @headers, [obj.to_json.to_s] ]
end
Expand Down

0 comments on commit 54706c8

Please sign in to comment.