Permalink
Browse files

removed StaticHandler (used Rack::Directory instead); refactored File…

…Resolver
  • Loading branch information...
1 parent e80bd9e commit 159fa1e496ccba5f76a59dd00cf48d471da39a7b @jlong committed Mar 18, 2011
View
@@ -1,15 +1,15 @@
#!/usr/bin/env ruby
+
lib = File.dirname(__FILE__) + '/../lib'
-require 'rubygems'
-gem 'activesupport'
-require 'active_support/all'
+require 'rubygems'
if File.file?(lib + '/serve/version.rb')
$LOAD_PATH << lib
else
gem 'serve'
end
+
require 'serve'
require 'serve/application'
View
@@ -14,6 +14,5 @@ def singleton_class
require 'serve/handlers/sass_handler'
require 'serve/handlers/email_handler'
require 'serve/handlers/redirect_handler'
-require 'serve/handlers/static_handler'
require 'serve/response_cache'
require 'serve/rack'
View
@@ -1,21 +1,36 @@
module Serve
class FileResolver
- cattr_accessor :alternate_extensions
+ def self.instance
+ @instance ||= FileResolver.new
+ end
+
+ # Resolve a path to a valid file name in root. Return nil if no
+ # file exists for that path.
def resolve(root, path)
path = normalize_path(path)
+
+ return if path.nil? # If it's not a valid path. Return nothing.
+
+ full_path = File.join(root, path)
+
case
- when path.nil?
- return
- when path =~ /\.css\Z/ && !File.file?(File.join(root, path)) # if .css not found, try .scss, .sass:
+ when File.file?(full_path)
+ # A file exists! Return the matching path.
+ path
+ when File.directory?(full_path)
+ # It's a directory? Try a directory index.
+ resolve(root, File.join(path, 'index'))
+ when path.ends_with?('.css')
+ # CSS not found? try SCSS or Sass
alternates = %w{.scss .sass}.map { |ext| path.sub(/\.css\Z/, ext) }
sass_path = alternates.find do |p|
File.file?(File.join(root, p))
- end
- when File.directory?(File.join(root, path))
- resolve(root, File.join(path, 'index'))
+ end
else
- resolve_with_extension(root, path)
+ # Still no luck? Check to see if a file with an extension exists by that name.
+ result = Dir.glob(full_path + ".*", File::FNM_CASEFOLD).first
+ result.sub(/^#{root}/, '').sub(/^\//, '') if result && File.file?(result)
end
end
@@ -27,25 +42,6 @@ def normalize_path(path)
path unless path =~ /\.\./ # guard against evil paths
end
- def resolve_with_extension(root, path)
- full_path = File.join(root, path)
- if File.file?(full_path)
- path
- else
- result = Dir.glob(full_path + ".*", File::FNM_CASEFOLD).first
- result.sub(/^#{root}/, '').sub(/^\//, '') if result && File.file?(result)
- end
- end
-
- def find_extension(extensions_to_try, full_path)
- extensions_to_try.find do |ext|
- File.file?("#{full_path}.#{ext}")
- end
- end
-
- def self.instance
- @instance ||= FileResolver.new
- end
end
def self.resolve_filename(*args)
@@ -1,6 +1,9 @@
module Serve #:nodoc:
+
+ # TODO: Figure out how to remove the Sass Handler in favor of Tilt
# The Sass handler seems to be necessary to keep Tilt from applying a layout
# to Sass files. Any one know how to turn this Tilt feature off?
+
class SassHandler < FileTypeHandler #:nodoc:
extension 'sass', 'scss'
@@ -1,31 +0,0 @@
-module Serve #:nodoc:
-
- # TODO: Figure out a way to remove the need for this handler. Right now
- # Serve requires this in order to deliver these files with the right content
- # type headers.
-
- class StaticHandler < FileTypeHandler #:nodoc:
- extension 'txt', 'text', 'xml', 'atom', 'rss', 'rdf', 'css', 'htm', 'html'
-
- def content_type
- case File.extname(@script_filename)
- when '.txt', '.text'
- 'text/plain'
- when '.xml'
- 'text/xml'
- when '.atom'
- 'application/atom+xml'
- when '.rss'
- 'application/rss+xml'
- when '.rdf'
- 'application/rdf+xml'
- when '.htc'
- 'text/x-component'
- when 'css'
- 'text/css'
- else
- 'text/html'
- end
- end
- end
-end
View
@@ -3,20 +3,35 @@
module Serve
class Request < Rack::Request
+ # Returns a Hash of the query params for a request's URL.
def query
@query ||= Rack::Utils.parse_nested_query(query_string)
end
+ # Returns the protocol part of the URL for a request: "http://", "https://", etc.
def protocol
@scheme ||= scheme + "://"
end
+ # Returns a specialized hash of the headers on the request.
def headers
@headers ||= Headers.new(@env)
end
+
+ # Returns the value of the "REQUEST_URI" environment variable.
+ def request_uri
+ @env["REQUEST_URI"].to_s
+ end
+
+ # Set the value of the "REQUEST_URI" environment variable.
+ def request_uri=(s)
+ @env["REQUEST_URI"] = s.to_s
+ end
end
class Response < Rack::Response
+
+ # Set the body of a response.
def body=(value)
# needed for Ruby 1.9
if value.respond_to? :each
@@ -25,9 +40,11 @@ def body=(value)
super([value])
end
end
+
end
- # Borrowed from ActionDispatch in Rails
+ # A specialized hash for the environment variables on a request.
+ # Borrowed from ActionDispatch in Rails.
class Headers < Hash
extend ActiveSupport::Memoizable
@@ -57,36 +74,59 @@ def env_name(header_name)
end
class RackAdapter
+
+ # Initialize a Rack endpoint for Serve with the root path to
+ # the views directory.
def initialize(root)
@root = root
end
+ # Called by Rack to process a request.
def call(env)
request = Request.new(env)
response = Response.new()
process(request, response).to_a
end
- def process(request, response)
- path = Serve.resolve_filename(@root, request.path)
- if path
- ext = File.extname(path)[1..-1]
- handler = Serve::FileTypeHandler.handlers[ext]
- if handler
- handler.new(@root, path).process(request, response)
- response
+ protected
+
+ # Process the request and response. Paths are transformed so that
+ # URLs without extensions and directory indexes work.
+ def process(request, response)
+ path = Serve.resolve_filename(@root, request.path_info)
+ if path
+ # Fetch the file handler for a file with a given extension/
+ ext = File.extname(path)[1..-1]
+ handler = Serve::FileTypeHandler.handlers[ext]
+ if handler
+ # Handler exists? Process the request and response.
+ handler.new(@root, path).process(request, response)
+ response
+ else
+ # Handler doesn't exist? Rewrite the request to use the new path.
+ # This allows Rack::Cascade or Passenger to deliver a file that is
+ # not handled by one of the Serve handlers.
+ rewrite(request, response, path)
+ end
else
- default(request, response)
+ # Return a 404 response.
+ not_found(request, response)
end
- else
- default(request, response)
end
- end
+
+ # Returns a 404 response.
+ def not_found(request, response)
+ response.status = 404
+ response.body = "Not found!"
+ response
+ end
+
+ # Rewrite the request to use a new path. Return a 404 response so that Rack::Cascade works.
+ def rewrite(request, response, path)
+ request.request_uri = path + request.query_string
+ request.path_info = path
+ not_found(request, response)
+ end
- def default(request, response)
- response.status = 404
- response.body = "Not found!"
- response
- end
end
end
View
@@ -21,7 +21,7 @@ def connection
end
def resolve_path(path)
- Serve.resolve_file(@root_path, path)
+ Serve.resolve_filename(@root_path, path)
end
def view_helpers
@@ -44,6 +44,8 @@ def capture_erb(&block)
@out_var = old_buffer
end
+ # TODO: Fix content_for so that it works with other template languages like slim
+
def content_for(symbol, &block)
if @haml_buffer
set_content_for(symbol, capture_haml(&block))
View
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<feed xmlns="http://www.w3.org/2005/Atom">
+
+ <title>Example Feed</title>
+ <subtitle>A subtitle.</subtitle>
+ <link href="http://example.org/feed/" rel="self" />
+ <link href="http://example.org/" />
+ <id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>
+ <updated>2003-12-13T18:30:02Z</updated>
+ <author>
+ <name>John Doe</name>
+ <email>johndoe@example.com</email>
+ </author>
+
+ <entry>
+ <title>Atom-Powered Robots Run Amok</title>
+ <link href="http://example.org/2003/12/13/atom03" />
+ <link rel="alternate" type="text/html" href="http://example.org/2003/12/13/atom03.html"/>
+ <link rel="edit" href="http://example.org/2003/12/13/atom03/edit"/>
+ <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+ <updated>2003-12-13T18:30:02Z</updated>
+ <summary>Some text.</summary>
+ </entry>
+
+</feed>

0 comments on commit 159fa1e

Please sign in to comment.