diff options
author | zedshaw <zedshaw@19e92222-5c0b-0410-8929-a290d50e31e9> | 2006-05-04 16:07:56 +0000 |
---|---|---|
committer | zedshaw <zedshaw@19e92222-5c0b-0410-8929-a290d50e31e9> | 2006-05-04 16:07:56 +0000 |
commit | 0ca765c199519f30e99bda26552905f9e4baf0b9 (patch) | |
tree | 80e7257b684f85fd503b0f66d2284addcdf58c38 /lib/mongrel/handlers.rb | |
parent | d529c2b1f34c658842705d614722a91b23534ff5 (diff) | |
download | unicorn-0ca765c199519f30e99bda26552905f9e4baf0b9.tar.gz |
git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@163 19e92222-5c0b-0410-8929-a290d50e31e9
Diffstat (limited to 'lib/mongrel/handlers.rb')
-rw-r--r-- | lib/mongrel/handlers.rb | 87 |
1 files changed, 54 insertions, 33 deletions
diff --git a/lib/mongrel/handlers.rb b/lib/mongrel/handlers.rb index f9ad95f..de328b7 100644 --- a/lib/mongrel/handlers.rb +++ b/lib/mongrel/handlers.rb @@ -95,26 +95,26 @@ module Mongrel # Checks if the given path can be served and returns the full path (or nil if not). def can_serve(path_info) - req = File.expand_path(File.join(@path,path_info), @path) + req_path = File.expand_path(File.join(@path,path_info), @path) - if req.index(@path) == 0 and File.exist? req + if req_path.index(@path) == 0 and File.exist? req_path # it exists and it's in the right location - if File.directory? req + if File.directory? req_path # the request is for a directory - index = File.join(req, @index_html) + index = File.join(req_path, @index_html) if File.exist? index # serve the index return index elsif @listing_allowed # serve the directory - req + return req_path else # do not serve anything return nil end else # it's a file and it's there - return req + return req_path end else # does not exist or isn't in the right spot @@ -156,30 +156,51 @@ module Mongrel # Sends the contents of a file back to the user. Not terribly efficient since it's # opening and closing the file for each read. - def send_file(req, response, header_only=false) + def send_file(req_path, request, response, header_only=false) - # first we setup the headers and status then we do a very fast send on the socket directly - response.status = 200 - stat = File.stat(req) - header = response.header + stat = File.stat(req_path) # Set the last modified times as well and etag for all files - header[Const::LAST_MODIFIED] = stat.mtime.httpdate + mtime = stat.mtime # Calculated the same as apache, not sure how well the works on win32 - header[Const::ETAG] = Const::ETAG_FORMAT % [stat.mtime.to_i, stat.size, stat.ino] - - # set the mime type from our map based on the ending - dot_at = req.rindex(".") - if dot_at - header[Const::CONTENT_TYPE] = MIME_TYPES[req[dot_at .. -1]] || @default_content_type + etag = Const::ETAG_FORMAT % [mtime.to_i, stat.size, stat.ino] + + unmodified_since = request.params[Const::HTTP_IF_UNMODIFIED_SINCE] + none_match = request.params[Const::HTTP_IF_NONE_MATCH] + + # test to see if this is a conditional request, and test if + # the response would be identical to the last response + same_response = case + when unmodified_since && !last_response_time = Time.httpdate(unmodified_since) rescue nil : false + when unmodified_since && last_response_time > Time.now : false + when unmodified_since && mtime > last_response_time : false + when none_match && none_match == '*' : false + when none_match && !none_match.strip.split(/\s*,\s*/).include?(etag) : false + else unmodified_since || none_match # validation successful if we get this far and at least one of the header exists end - # send a status with out content length - response.send_status(stat.size) - response.send_header + if same_response + response.start(304) {} + else + # first we setup the headers and status then we do a very fast send on the socket directly + response.status = 200 + header = response.header + header[Const::LAST_MODIFIED] = mtime.httpdate + header[Const::ETAG] = etag + + # set the mime type from our map based on the ending + dot_at = req_path.rindex('.') + if dot_at + header[Const::CONTENT_TYPE] = MIME_TYPES[req_path[dot_at .. -1]] || @default_content_type + end + + # send a status with out content length + response.send_status(stat.size) + response.send_header - if not header_only - response.send_file(req) + if not header_only + response.send_file(req_path) + end end end @@ -187,25 +208,25 @@ module Mongrel # if allowed (based on the listing_allowed paramter to the constructor). def process(request, response) req_method = request.params[Const::REQUEST_METHOD] || Const::GET - req = can_serve request.params[Const::PATH_INFO] - if not req + req_path = can_serve request.params[Const::PATH_INFO] + if not req_path # not found, return a 404 response.start(404) do |head,out| out << "File not found" end else begin - if File.directory? req - send_dir_listing(request.params[Const::REQUEST_URI],req, response) + if File.directory? req_path + send_dir_listing(request.params[Const::REQUEST_URI], req_path, response) elsif req_method == Const::HEAD - send_file(req, response, true) - elsif req_method == Const::GET - send_file(req, response, false) - else - response.start(403) {|head,out| out.write(ONLY_HEAD_GET) } + send_file(req_path, request, response, true) + elsif req_method == Const::GET + send_file(req_path, request, response, false) + else + response.start(403) {|head,out| out.write(ONLY_HEAD_GET) } end rescue => details - STDERR.puts "Error accessing file #{req}: #{details}" + STDERR.puts "Error accessing file #{req_path}: #{details}" STDERR.puts details.backtrace.join("\n") end end |