From dc53a8c26dc55d21240233b3d83d36efdef6e924 Mon Sep 17 00:00:00 2001 From: schneems Date: Wed, 1 Oct 2014 18:09:37 -0500 Subject: Less allocated objects on each request How many? Using `memory_profiler` and a Rails app (codetriage.com), master uses: ``` rack/lib x 7318 ``` After this patch, the app uses: ``` rack/lib x 4598 ``` Or `(7318 - 4598) / 7318.0 * 100 # => 37.16` % fewer objects __PER REQUEST__. To do this, I extracted really commonly used strings into top level Rack constants. It makes for a bit of a big diff, but I believe the changes are worth it. Running benchmark/ips against the same app, I'm seeing a performance host of `2~4%` across the entire app response. This doesn't just make Rack faster, it will make your app faster. While we could certainly go overboard and pre-define ALL strings as constants, that would be pretty gnarly to work with. This patch goes after the largest of the low hanging fruit. --- lib/rack.rb | 10 ++++++++++ lib/rack/auth/abstract/handler.rb | 8 ++++---- lib/rack/auth/digest/request.rb | 2 +- lib/rack/body_proxy.rb | 11 ++++++++--- lib/rack/cascade.rb | 2 +- lib/rack/chunked.rb | 4 ++-- lib/rack/commonlogger.rb | 8 ++++---- lib/rack/conditionalget.rb | 8 ++++---- lib/rack/content_length.rb | 4 ++-- lib/rack/content_type.rb | 2 +- lib/rack/deflater.rb | 8 ++++---- lib/rack/directory.rb | 10 +++++----- lib/rack/etag.rb | 13 +++++++------ lib/rack/file.rb | 16 ++++++++-------- lib/rack/handler.rb | 2 +- lib/rack/handler/cgi.rb | 2 +- lib/rack/handler/fastcgi.rb | 2 +- lib/rack/handler/lsws.rb | 2 +- lib/rack/handler/mongrel.rb | 2 +- lib/rack/handler/scgi.rb | 4 ++-- lib/rack/handler/webrick.rb | 8 ++++---- lib/rack/head.rb | 2 +- lib/rack/lint.rb | 22 +++++++++++----------- lib/rack/lobster.rb | 4 ++-- lib/rack/methodoverride.rb | 6 +++--- lib/rack/mock.rb | 14 +++++++------- lib/rack/recursive.rb | 11 ++++++----- lib/rack/request.rb | 12 ++++++------ lib/rack/response.rb | 14 ++++++++------ lib/rack/runtime.rb | 3 ++- lib/rack/sendfile.rb | 4 ++-- lib/rack/server.rb | 2 +- lib/rack/showexceptions.rb | 4 ++-- lib/rack/showstatus.rb | 6 +++--- lib/rack/static.rb | 2 +- lib/rack/urlmap.rb | 4 ++-- 36 files changed, 129 insertions(+), 109 deletions(-) diff --git a/lib/rack.rb b/lib/rack.rb index 341514c5..97817bcb 100644 --- a/lib/rack.rb +++ b/lib/rack.rb @@ -22,6 +22,16 @@ module Rack def self.release "1.5" end + PATH_INFO = 'PATH_INFO'.freeze + REQUEST_METHOD = 'REQUEST_METHOD'.freeze + SCRIPT_NAME = 'SCRIPT_NAME'.freeze + QUERY_STRING = 'QUERY_STRING'.freeze + CACHE_CONTROL = 'Cache-Control'.freeze + CONTENT_LENGTH = 'Content-Length'.freeze + CONTENT_TYPE = 'Content-Type'.freeze + + GET = 'GET'.freeze + HEAD = 'HEAD'.freeze autoload :Builder, "rack/builder" autoload :BodyProxy, "rack/body_proxy" diff --git a/lib/rack/auth/abstract/handler.rb b/lib/rack/auth/abstract/handler.rb index 214df629..c657691e 100644 --- a/lib/rack/auth/abstract/handler.rb +++ b/lib/rack/auth/abstract/handler.rb @@ -17,8 +17,8 @@ module Rack def unauthorized(www_authenticate = challenge) return [ 401, - { 'Content-Type' => 'text/plain', - 'Content-Length' => '0', + { CONTENT_TYPE => 'text/plain', + CONTENT_LENGTH => '0', 'WWW-Authenticate' => www_authenticate.to_s }, [] ] @@ -26,8 +26,8 @@ module Rack def bad_request return [ 400, - { 'Content-Type' => 'text/plain', - 'Content-Length' => '0' }, + { CONTENT_TYPE => 'text/plain', + CONTENT_LENGTH => '0' }, [] ] end diff --git a/lib/rack/auth/digest/request.rb b/lib/rack/auth/digest/request.rb index 706c651c..01994364 100644 --- a/lib/rack/auth/digest/request.rb +++ b/lib/rack/auth/digest/request.rb @@ -7,7 +7,7 @@ module Rack module Digest class Request < Auth::AbstractRequest def method - @env['rack.methodoverride.original_method'] || @env['REQUEST_METHOD'] + @env['rack.methodoverride.original_method'] || @env[REQUEST_METHOD] end def digest? diff --git a/lib/rack/body_proxy.rb b/lib/rack/body_proxy.rb index 95a74626..b35167c8 100644 --- a/lib/rack/body_proxy.rb +++ b/lib/rack/body_proxy.rb @@ -4,9 +4,14 @@ module Rack @body, @block, @closed = body, block, false end - def respond_to?(*args) - return false if args.first.to_s =~ /^to_ary$/ - super or @body.respond_to?(*args) + def respond_to?(method_name) + case method_name + when :to_ary + return false + when String + return false if /^to_ary$/ =~ method_name + end + super or @body.respond_to?(method_name) end def close diff --git a/lib/rack/cascade.rb b/lib/rack/cascade.rb index c2891e5f..6b8f415a 100644 --- a/lib/rack/cascade.rb +++ b/lib/rack/cascade.rb @@ -4,7 +4,7 @@ module Rack # status codes). class Cascade - NotFound = [404, {"Content-Type" => "text/plain"}, []] + NotFound = [404, {CONTENT_TYPE => "text/plain"}, []] attr_reader :apps diff --git a/lib/rack/chunked.rb b/lib/rack/chunked.rb index ea221fa9..36c4959d 100644 --- a/lib/rack/chunked.rb +++ b/lib/rack/chunked.rb @@ -56,11 +56,11 @@ module Rack if ! chunkable_version?(env['HTTP_VERSION']) || STATUS_WITH_NO_ENTITY_BODY.include?(status) || - headers['Content-Length'] || + headers[CONTENT_LENGTH] || headers['Transfer-Encoding'] [status, headers, body] else - headers.delete('Content-Length') + headers.delete(CONTENT_LENGTH) headers['Transfer-Encoding'] = 'chunked' [status, headers, Body.new(body)] end diff --git a/lib/rack/commonlogger.rb b/lib/rack/commonlogger.rb index 1c99045e..d2d6dc34 100644 --- a/lib/rack/commonlogger.rb +++ b/lib/rack/commonlogger.rb @@ -46,9 +46,9 @@ module Rack env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-", env["REMOTE_USER"] || "-", now.strftime("%d/%b/%Y:%H:%M:%S %z"), - env["REQUEST_METHOD"], - env["PATH_INFO"], - env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"], + env[REQUEST_METHOD], + env[PATH_INFO], + env[QUERY_STRING].empty? ? "" : "?"+env[QUERY_STRING], env["HTTP_VERSION"], status.to_s[0..3], length, @@ -65,7 +65,7 @@ module Rack end def extract_content_length(headers) - value = headers['Content-Length'] or return '-' + value = headers[CONTENT_LENGTH] or return '-' value.to_s == '0' ? '-' : value end end diff --git a/lib/rack/conditionalget.rb b/lib/rack/conditionalget.rb index 88573166..3d4c78aa 100644 --- a/lib/rack/conditionalget.rb +++ b/lib/rack/conditionalget.rb @@ -20,14 +20,14 @@ module Rack end def call(env) - case env['REQUEST_METHOD'] - when "GET", "HEAD" + case env[REQUEST_METHOD] + when GET, HEAD status, headers, body = @app.call(env) headers = Utils::HeaderHash.new(headers) if status == 200 && fresh?(env, headers) status = 304 - headers.delete('Content-Type') - headers.delete('Content-Length') + headers.delete(CONTENT_TYPE) + headers.delete(CONTENT_LENGTH) original_body = body body = Rack::BodyProxy.new([]) do original_body.close if original_body.respond_to?(:close) diff --git a/lib/rack/content_length.rb b/lib/rack/content_length.rb index 71bc919b..d0f491d1 100644 --- a/lib/rack/content_length.rb +++ b/lib/rack/content_length.rb @@ -16,7 +16,7 @@ module Rack headers = HeaderHash.new(headers) if !STATUS_WITH_NO_ENTITY_BODY.include?(status.to_i) && - !headers['Content-Length'] && + !headers[CONTENT_LENGTH] && !headers['Transfer-Encoding'] && body.respond_to?(:to_ary) @@ -28,7 +28,7 @@ module Rack obody.close if obody.respond_to?(:close) end - headers['Content-Length'] = length.to_s + headers[CONTENT_LENGTH] = length.to_s end [status, headers, body] diff --git a/lib/rack/content_type.rb b/lib/rack/content_type.rb index dd96e959..78ba43b7 100644 --- a/lib/rack/content_type.rb +++ b/lib/rack/content_type.rb @@ -20,7 +20,7 @@ module Rack headers = Utils::HeaderHash.new(headers) unless STATUS_WITH_NO_ENTITY_BODY.include?(status) - headers['Content-Type'] ||= @content_type + headers[CONTENT_TYPE] ||= @content_type end [status, headers, body] diff --git a/lib/rack/deflater.rb b/lib/rack/deflater.rb index 9df510bd..1788463b 100644 --- a/lib/rack/deflater.rb +++ b/lib/rack/deflater.rb @@ -54,20 +54,20 @@ module Rack case encoding when "gzip" headers['Content-Encoding'] = "gzip" - headers.delete('Content-Length') + headers.delete(CONTENT_LENGTH) mtime = headers.key?("Last-Modified") ? Time.httpdate(headers["Last-Modified"]) : Time.now [status, headers, GzipStream.new(body, mtime)] when "deflate" headers['Content-Encoding'] = "deflate" - headers.delete('Content-Length') + headers.delete(CONTENT_LENGTH) [status, headers, DeflateStream.new(body)] when "identity" [status, headers, body] when nil message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found." bp = Rack::BodyProxy.new([message]) { body.close if body.respond_to?(:close) } - [406, {"Content-Type" => "text/plain", "Content-Length" => message.length.to_s}, bp] + [406, {CONTENT_TYPE => "text/plain", CONTENT_LENGTH => message.length.to_s}, bp] end end @@ -138,7 +138,7 @@ module Rack # Skip compressing empty entity body responses and responses with # no-transform set. if Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) || - headers['Cache-Control'].to_s =~ /\bno-transform\b/ || + headers[CACHE_CONTROL].to_s =~ /\bno-transform\b/ || (headers['Content-Encoding'] && headers['Content-Encoding'] !~ /\bidentity\b/) return false end diff --git a/lib/rack/directory.rb b/lib/rack/directory.rb index 602f2d44..98d66e02 100644 --- a/lib/rack/directory.rb +++ b/lib/rack/directory.rb @@ -55,8 +55,8 @@ table { width:100%%; } def _call(env) @env = env - @script_name = env['SCRIPT_NAME'] - @path_info = Utils.unescape(env['PATH_INFO']) + @script_name = env[SCRIPT_NAME] + @path_info = Utils.unescape(env[PATH_INFO]) if forbidden = check_forbidden forbidden @@ -72,7 +72,7 @@ table { width:100%%; } body = "Forbidden\n" size = Rack::Utils.bytesize(body) return [403, {"Content-Type" => "text/plain", - "Content-Length" => size.to_s, + CONTENT_LENGTH => size.to_s, "X-Cascade" => "pass"}, [body]] end @@ -101,7 +101,7 @@ table { width:100%%; } @files << [ url, basename, size, type, mtime ] end - return [ 200, {'Content-Type'=>'text/html; charset=utf-8'}, self ] + return [ 200, { CONTENT_TYPE =>'text/html; charset=utf-8'}, self ] end def stat(node, max = 10) @@ -130,7 +130,7 @@ table { width:100%%; } body = "Entity not found: #{@path_info}\n" size = Rack::Utils.bytesize(body) return [404, {"Content-Type" => "text/plain", - "Content-Length" => size.to_s, + CONTENT_LENGTH => size.to_s, "X-Cascade" => "pass"}, [body]] end diff --git a/lib/rack/etag.rb b/lib/rack/etag.rb index fefe671f..88973131 100644 --- a/lib/rack/etag.rb +++ b/lib/rack/etag.rb @@ -11,6 +11,7 @@ module Rack # used when Etag is absent and a directive when it is present. The first # defaults to nil, while the second defaults to "max-age=0, private, must-revalidate" class ETag + ETAG_STRING = 'ETag'.freeze DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate".freeze def initialize(app, no_cache_control = nil, cache_control = DEFAULT_CACHE_CONTROL) @@ -28,14 +29,14 @@ module Rack body = Rack::BodyProxy.new(new_body) do original_body.close if original_body.respond_to?(:close) end - headers['ETag'] = %(W/"#{digest}") if digest + headers[ETAG_STRING] = %(W/"#{digest}") if digest end - unless headers['Cache-Control'] + unless headers[CACHE_CONTROL] if digest - headers['Cache-Control'] = @cache_control if @cache_control + headers[CACHE_CONTROL] = @cache_control if @cache_control else - headers['Cache-Control'] = @no_cache_control if @no_cache_control + headers[CACHE_CONTROL] = @no_cache_control if @no_cache_control end end @@ -53,8 +54,8 @@ module Rack end def skip_caching?(headers) - (headers['Cache-Control'] && headers['Cache-Control'].include?('no-cache')) || - headers.key?('ETag') || headers.key?('Last-Modified') + (headers[CACHE_CONTROL] && headers[CACHE_CONTROL].include?('no-cache')) || + headers.key?(ETAG_STRING) || headers.key?('Last-Modified') end def digest_body(body) diff --git a/lib/rack/file.rb b/lib/rack/file.rb index c8f8d0d1..bdae6a66 100644 --- a/lib/rack/file.rb +++ b/lib/rack/file.rb @@ -34,11 +34,11 @@ module Rack F = ::File def _call(env) - unless ALLOWED_VERBS.include? env["REQUEST_METHOD"] + unless ALLOWED_VERBS.include? env[REQUEST_METHOD] return fail(405, "Method Not Allowed", {'Allow' => ALLOW_HEADER}) end - path_info = Utils.unescape(env["PATH_INFO"]) + path_info = Utils.unescape(env[PATH_INFO]) clean_path_info = Utils.clean_path_info(path_info) @path = F.join(@root, clean_path_info) @@ -58,19 +58,19 @@ module Rack def serving(env) if env["REQUEST_METHOD"] == "OPTIONS" - return [200, {'Allow' => ALLOW_HEADER, 'Content-Length' => '0'}, []] + return [200, {'Allow' => ALLOW_HEADER, CONTENT_LENGTH => '0'}, []] end last_modified = F.mtime(@path).httpdate return [304, {}, []] if env['HTTP_IF_MODIFIED_SINCE'] == last_modified headers = { "Last-Modified" => last_modified } mime = Mime.mime_type(F.extname(@path), @default_mime) - headers["Content-Type"] = mime if mime + headers[CONTENT_TYPE] = mime if mime # Set custom headers @headers.each { |field, content| headers[field] = content } if @headers - response = [ 200, headers, env["REQUEST_METHOD"] == "HEAD" ? [] : self ] + response = [ 200, headers, env[REQUEST_METHOD] == "HEAD" ? [] : self ] # NOTE: # We check via File::size? whether this file provides size info @@ -97,7 +97,7 @@ module Rack size = @range.end - @range.begin + 1 end - response[1]["Content-Length"] = size.to_s + response[1][CONTENT_LENGTH] = size.to_s response end @@ -122,8 +122,8 @@ module Rack [ status, { - "Content-Type" => "text/plain", - "Content-Length" => body.size.to_s, + CONTENT_TYPE => "text/plain", + CONTENT_LENGTH => body.size.to_s, "X-Cascade" => "pass" }.merge!(headers), [body] diff --git a/lib/rack/handler.rb b/lib/rack/handler.rb index b5fa0268..f11e37e3 100644 --- a/lib/rack/handler.rb +++ b/lib/rack/handler.rb @@ -51,7 +51,7 @@ module Rack options.delete :Port Rack::Handler::FastCGI - elsif ENV.include?("REQUEST_METHOD") + elsif ENV.include?(REQUEST_METHOD) Rack::Handler::CGI elsif ENV.include?("RACK_HANDLER") self.get(ENV["RACK_HANDLER"]) diff --git a/lib/rack/handler/cgi.rb b/lib/rack/handler/cgi.rb index 15af1ac2..78e135e9 100644 --- a/lib/rack/handler/cgi.rb +++ b/lib/rack/handler/cgi.rb @@ -26,7 +26,7 @@ module Rack "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" }) - env["QUERY_STRING"] ||= "" + env[QUERY_STRING] ||= "" env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["REQUEST_PATH"] ||= "/" diff --git a/lib/rack/handler/fastcgi.rb b/lib/rack/handler/fastcgi.rb index b26fabc3..5137992b 100644 --- a/lib/rack/handler/fastcgi.rb +++ b/lib/rack/handler/fastcgi.rb @@ -59,7 +59,7 @@ module Rack "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" }) - env["QUERY_STRING"] ||= "" + env[QUERY_STRING] ||= "" env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["REQUEST_PATH"] ||= "/" env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == "" diff --git a/lib/rack/handler/lsws.rb b/lib/rack/handler/lsws.rb index 1dee78a3..aec27322 100644 --- a/lib/rack/handler/lsws.rb +++ b/lib/rack/handler/lsws.rb @@ -27,7 +27,7 @@ module Rack "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" ) - env["QUERY_STRING"] ||= "" + env[QUERY_STRING] ||= "" env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["REQUEST_PATH"] ||= "/" status, headers, body = app.call(env) diff --git a/lib/rack/handler/mongrel.rb b/lib/rack/handler/mongrel.rb index 20be86b1..ab9891b1 100644 --- a/lib/rack/handler/mongrel.rb +++ b/lib/rack/handler/mongrel.rb @@ -78,7 +78,7 @@ module Rack "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" }) - env["QUERY_STRING"] ||= "" + env[QUERY_STRING] ||= "" status, headers, body = @app.call(env) diff --git a/lib/rack/handler/scgi.rb b/lib/rack/handler/scgi.rb index 40e86fb9..9a465eae 100644 --- a/lib/rack/handler/scgi.rb +++ b/lib/rack/handler/scgi.rb @@ -35,9 +35,9 @@ module Rack env = Hash[request] env.delete "HTTP_CONTENT_TYPE" env.delete "HTTP_CONTENT_LENGTH" - env["REQUEST_PATH"], env["QUERY_STRING"] = env["REQUEST_URI"].split('?', 2) + env["REQUEST_PATH"], env[QUERY_STRING] = env["REQUEST_URI"].split('?', 2) env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["PATH_INFO"] = env["REQUEST_PATH"] + env[PATH_INFO] = env["REQUEST_PATH"] env["QUERY_STRING"] ||= "" env["SCRIPT_NAME"] = "" diff --git a/lib/rack/handler/webrick.rb b/lib/rack/handler/webrick.rb index 023d8b27..dcbf96ca 100644 --- a/lib/rack/handler/webrick.rb +++ b/lib/rack/handler/webrick.rb @@ -79,12 +79,12 @@ module Rack }) env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["QUERY_STRING"] ||= "" - unless env["PATH_INFO"] == "" + env[QUERY_STRING] ||= "" + unless env[PATH_INFO] == "" path, n = req.request_uri.path, env["SCRIPT_NAME"].length - env["PATH_INFO"] = path[n, path.length-n] + env[PATH_INFO] = path[n, path.length-n] end - env["REQUEST_PATH"] ||= [env["SCRIPT_NAME"], env["PATH_INFO"]].join + env["REQUEST_PATH"] ||= [env["SCRIPT_NAME"], env[PATH_INFO]].join status, headers, body = @app.call(env) begin diff --git a/lib/rack/head.rb b/lib/rack/head.rb index 72f3dbdd..f487254a 100644 --- a/lib/rack/head.rb +++ b/lib/rack/head.rb @@ -12,7 +12,7 @@ class Head def call(env) status, headers, body = @app.call(env) - if env["REQUEST_METHOD"] == "HEAD" + if env[REQUEST_METHOD] == HEAD [ status, headers, Rack::BodyProxy.new([]) do body.close if body.respond_to? :close diff --git a/lib/rack/lint.rb b/lib/rack/lint.rb index 667c34a6..5cdef3f8 100644 --- a/lib/rack/lint.rb +++ b/lib/rack/lint.rb @@ -57,7 +57,7 @@ module Rack ## and the *body*. check_content_type status, headers check_content_length status, headers - @head_request = env["REQUEST_METHOD"] == "HEAD" + @head_request = env[REQUEST_METHOD] == "HEAD" [status, headers, self] end @@ -278,7 +278,7 @@ module Rack check_hijack env ## * The REQUEST_METHOD must be a valid token. - assert("REQUEST_METHOD unknown: #{env["REQUEST_METHOD"]}") { + assert("REQUEST_METHOD unknown: #{env[REQUEST_METHOD]}") { env["REQUEST_METHOD"] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/ } @@ -510,20 +510,20 @@ module Rack ## already present, in rack.hijack_io. io = original_hijack.call HijackWrapper.new(io) - ## + ## ## rack.hijack_io must respond to: ## read, write, read_nonblock, write_nonblock, flush, close, ## close_read, close_write, closed? - ## + ## ## The semantics of these IO methods must be a best effort match to ## those of a normal ruby IO or Socket object, using standard ## arguments and raising standard exceptions. Servers are encouraged ## to simply pass on real IO objects, although it is recognized that ## this approach is not directly compatible with SPDY and HTTP 2.0. - ## + ## ## IO provided in rack.hijack_io should preference the ## IO::WaitReadable and IO::WaitWritable APIs wherever supported. - ## + ## ## There is a deliberate lack of full specification around ## rack.hijack_io, as semantics will change from server to server. ## Users are encouraged to utilize this API with a knowledge of their @@ -535,10 +535,10 @@ module Rack io end else - ## + ## ## If rack.hijack? is false, then rack.hijack should not be set. assert("rack.hijack? is false, but rack.hijack is present") { env['rack.hijack'].nil? } - ## + ## ## If rack.hijack? is false, then rack.hijack_io should not be set. assert("rack.hijack? is false, but rack.hijack_io is present") { env['rack.hijack_io'].nil? } end @@ -557,7 +557,7 @@ module Rack ## rack.hijack to an object that responds to call ## accepting an argument that conforms to the rack.hijack_io ## protocol. - ## + ## ## After the headers have been sent, and this hijack callback has been ## called, the application is now responsible for the remaining lifecycle ## of the IO. The application is also responsible for maintaining HTTP @@ -566,7 +566,7 @@ module Rack ## HTTP/1.1, and not Connection:keep-alive, as there is no protocol for ## returning hijacked sockets to the web server. For that purpose, use the ## body streaming API instead (progressively yielding strings via each). - ## + ## ## Servers must ignore the body part of the response tuple when ## the rack.hijack response API is in use. @@ -579,7 +579,7 @@ module Rack original_hijack.call HijackWrapper.new(io) end else - ## + ## ## The special response header rack.hijack must only be set ## if the request env has rack.hijack? true. assert('rack.hijack header must not be present if server does not support hijacking') { diff --git a/lib/rack/lobster.rb b/lib/rack/lobster.rb index 195bd945..b7d15278 100644 --- a/lib/rack/lobster.rb +++ b/lib/rack/lobster.rb @@ -12,7 +12,7 @@ module Rack I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0]) LambdaLobster = lambda { |env| - if env["QUERY_STRING"].include?("flip") + if env[QUERY_STRING].include?("flip") lobster = LobsterString.split("\n"). map { |line| line.ljust(42).reverse }. join("\n") @@ -26,7 +26,7 @@ module Rack "
", lobster, "
", "flip!"] length = content.inject(0) { |a,e| a+e.size }.to_s - [200, {"Content-Type" => "text/html", "Content-Length" => length}, content] + [200, {CONTENT_TYPE => "text/html", CONTENT_LENGTH => length}, content] } def call(env) diff --git a/lib/rack/methodoverride.rb b/lib/rack/methodoverride.rb index 062f3d67..7d2b56eb 100644 --- a/lib/rack/methodoverride.rb +++ b/lib/rack/methodoverride.rb @@ -11,11 +11,11 @@ module Rack end def call(env) - if allowed_methods.include?(env["REQUEST_METHOD"]) + if allowed_methods.include?(env[REQUEST_METHOD]) method = method_override(env) if HTTP_METHODS.include?(method) - env["rack.methodoverride.original_method"] = env["REQUEST_METHOD"] - env["REQUEST_METHOD"] = method + env["rack.methodoverride.original_method"] = env[REQUEST_METHOD] + env[REQUEST_METHOD] = method end end diff --git a/lib/rack/mock.rb b/lib/rack/mock.rb index 3c02c1fe..217ae0f7 100644 --- a/lib/rack/mock.rb +++ b/lib/rack/mock.rb @@ -91,15 +91,15 @@ module Rack env = DEFAULT_ENV.dup - env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET" + env[REQUEST_METHOD] = opts[:method] ? opts[:method].to_s.upcase : "GET" env["SERVER_NAME"] = uri.host || "example.org" env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80" - env["QUERY_STRING"] = uri.query.to_s - env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path + env[QUERY_STRING] = uri.query.to_s + env[PATH_INFO] = (!uri.path || uri.path.empty?) ? "/" : uri.path env["rack.url_scheme"] = uri.scheme || "http" env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off" - env["SCRIPT_NAME"] = opts[:script_name] || "" + env[SCRIPT_NAME] = opts[:script_name] || "" if opts[:fatal] env["rack.errors"] = FatalWarner.new @@ -108,10 +108,10 @@ module Rack end if params = opts[:params] - if env["REQUEST_METHOD"] == "GET" + if env[REQUEST_METHOD] == "GET" params = Utils.parse_nested_query(params) if params.is_a?(String) - params.update(Utils.parse_nested_query(env["QUERY_STRING"])) - env["QUERY_STRING"] = Utils.build_nested_query(params) + params.update(Utils.parse_nested_query(env[QUERY_STRING])) + env[QUERY_STRING] = Utils.build_nested_query(params) elsif !opts.has_key?(:input) opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" if params.is_a?(Hash) diff --git a/lib/rack/recursive.rb b/lib/rack/recursive.rb index b431d4dd..17d17dfd 100644 --- a/lib/rack/recursive.rb +++ b/lib/rack/recursive.rb @@ -14,8 +14,8 @@ module Rack @url = URI(url) @env = env - @env["PATH_INFO"] = @url.path - @env["QUERY_STRING"] = @url.query if @url.query + @env[PATH_INFO] = @url.path + @env[QUERY_STRING] = @url.query if @url.query @env["HTTP_HOST"] = @url.host if @url.host @env["HTTP_PORT"] = @url.port if @url.port @env["rack.url_scheme"] = @url.scheme if @url.scheme @@ -39,7 +39,7 @@ module Rack end def _call(env) - @script_name = env["SCRIPT_NAME"] + @script_name = env[SCRIPT_NAME] @app.call(env.merge('rack.recursive.include' => method(:include))) rescue ForwardRequest => req call(env.merge(req.env)) @@ -51,8 +51,9 @@ module Rack raise ArgumentError, "can only include below #{@script_name}, not #{path}" end - env = env.merge("PATH_INFO" => path, "SCRIPT_NAME" => @script_name, - "REQUEST_METHOD" => "GET", + env = env.merge(PATH_INFO => path, + SCRIPT_NAME => @script_name, + REQUEST_METHOD => "GET", "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "", "rack.input" => StringIO.new("")) @app.call(env) diff --git a/lib/rack/request.rb b/lib/rack/request.rb index 602d0d64..e6e46e9d 100644 --- a/lib/rack/request.rb +++ b/lib/rack/request.rb @@ -18,10 +18,10 @@ module Rack end def body; @env["rack.input"] end - def script_name; @env["SCRIPT_NAME"].to_s end - def path_info; @env["PATH_INFO"].to_s end + def script_name; @env[SCRIPT_NAME].to_s end + def path_info; @env[PATH_INFO].to_s end def request_method; @env["REQUEST_METHOD"] end - def query_string; @env["QUERY_STRING"].to_s end + def query_string; @env[QUERY_STRING].to_s end def content_length; @env['CONTENT_LENGTH'] end def content_type @@ -116,10 +116,10 @@ module Rack def delete?; request_method == "DELETE" end # Checks the HTTP request method (or verb) to see if it was of type GET - def get?; request_method == "GET" end + def get?; request_method == GET end # Checks the HTTP request method (or verb) to see if it was of type HEAD - def head?; request_method == "HEAD" end + def head?; request_method == HEAD end # Checks the HTTP request method (or verb) to see if it was of type OPTIONS def options?; request_method == "OPTIONS" end @@ -173,7 +173,7 @@ module Rack # Content-Type header is provided and the request_method is POST. def form_data? type = media_type - meth = env["rack.methodoverride.original_method"] || env['REQUEST_METHOD'] + meth = env["rack.methodoverride.original_method"] || env[REQUEST_METHOD] (meth == 'POST' && type.nil?) || FORM_DATA_MEDIA_TYPES.include?(type) end diff --git a/lib/rack/response.rb b/lib/rack/response.rb index 12536710..7f0c6b71 100644 --- a/lib/rack/response.rb +++ b/lib/rack/response.rb @@ -20,11 +20,13 @@ module Rack class Response attr_accessor :length + CHUNKED = 'chunked'.freeze + TRANSFER_ENCODING = 'Transfer-Encoding'.freeze def initialize(body=[], status=200, header={}) @status = status.to_i @header = Utils::HeaderHash.new.merge(header) - @chunked = "chunked" == @header['Transfer-Encoding'] + @chunked = CHUNKED == @header[TRANSFER_ENCODING] @writer = lambda { |x| @body << x } @block = nil @length = 0 @@ -72,8 +74,8 @@ module Rack @block = block if [204, 205, 304].include?(status.to_i) - header.delete "Content-Type" - header.delete "Content-Length" + header.delete CONTENT_TYPE + header.delete CONTENT_LENGTH close [status.to_i, header, []] else @@ -98,7 +100,7 @@ module Rack @length += Rack::Utils.bytesize(s) unless @chunked @writer.call s - header["Content-Length"] = @length.to_s unless @chunked + header[CONTENT_LENGTH] = @length.to_s unless @chunked str end @@ -142,11 +144,11 @@ module Rack end def content_type - headers["Content-Type"] + headers[CONTENT_TYPE] end def content_length - cl = headers["Content-Length"] + cl = headers[CONTENT_LENGTH] cl ? cl.to_i : cl end diff --git a/lib/rack/runtime.rb b/lib/rack/runtime.rb index 1bd411fd..83d6c0ca 100644 --- a/lib/rack/runtime.rb +++ b/lib/rack/runtime.rb @@ -12,13 +12,14 @@ module Rack @header_name << "-#{name}" if name end + FORMAT_STRING = "%0.6f" def call(env) start_time = Time.now status, headers, body = @app.call(env) request_time = Time.now - start_time if !headers.has_key?(@header_name) - headers[@header_name] = "%0.6f" % request_time + headers[@header_name] = FORMAT_STRING % request_time end [status, headers, body] diff --git a/lib/rack/sendfile.rb b/lib/rack/sendfile.rb index 8e2c3d67..4a9b428b 100644 --- a/lib/rack/sendfile.rb +++ b/lib/rack/sendfile.rb @@ -116,7 +116,7 @@ module Rack when 'X-Accel-Redirect' path = F.expand_path(body.to_path) if url = map_accel_path(env, path) - headers['Content-Length'] = '0' + headers[CONTENT_LENGTH] = '0' headers[type] = url obody = body body = Rack::BodyProxy.new([]) do @@ -127,7 +127,7 @@ module Rack end when 'X-Sendfile', 'X-Lighttpd-Send-File' path = F.expand_path(body.to_path) - headers['Content-Length'] = '0' + headers[CONTENT_LENGTH] = '0' headers[type] = path obody = body body = Rack::BodyProxy.new([]) do diff --git a/lib/rack/server.rb b/lib/rack/server.rb index d9f971d7..ea1ad82b 100644 --- a/lib/rack/server.rb +++ b/lib/rack/server.rb @@ -310,7 +310,7 @@ module Rack # Don't evaluate CGI ISINDEX parameters. # http://www.meb.uni-bonn.de/docs/cgi/cl.html - args.clear if ENV.include?("REQUEST_METHOD") + args.clear if ENV.include?(REQUEST_METHOD) options.merge! opt_parser.parse!(args) options[:config] = ::File.expand_path(options[:config]) diff --git a/lib/rack/showexceptions.rb b/lib/rack/showexceptions.rb index 731aea49..60999e64 100644 --- a/lib/rack/showexceptions.rb +++ b/lib/rack/showexceptions.rb @@ -39,8 +39,8 @@ module Rack [ 500, { - "Content-Type" => content_type, - "Content-Length" => Rack::Utils.bytesize(body).to_s, + CONTENT_TYPE => content_type, + CONTENT_LENGTH => Rack::Utils.bytesize(body).to_s, }, [body], ] diff --git a/lib/rack/showstatus.rb b/lib/rack/showstatus.rb index 6892a5b7..4426310a 100644 --- a/lib/rack/showstatus.rb +++ b/lib/rack/showstatus.rb @@ -3,7 +3,7 @@ require 'rack/request' require 'rack/utils' module Rack - # Rack::ShowStatus catches all empty responses and replaces them + # Rack::ShowStatus catches all empty responses and replaces them # with a site explaining the error. # # Additional details can be put into rack.showstatus.detail @@ -19,7 +19,7 @@ module Rack def call(env) status, headers, body = @app.call(env) headers = Utils::HeaderHash.new(headers) - empty = headers['Content-Length'].to_i <= 0 + empty = headers[CONTENT_LENGTH].to_i <= 0 # client or server error, or explicit message if (status.to_i >= 400 && empty) || env["rack.showstatus.detail"] @@ -35,7 +35,7 @@ module Rack body = @template.result(binding) size = Rack::Utils.bytesize(body) - [status, headers.merge("Content-Type" => "text/html", "Content-Length" => size.to_s), [body]] + [status, headers.merge(CONTENT_TYPE => "text/html", CONTENT_LENGTH => size.to_s), [body]] else [status, headers, body] end diff --git a/lib/rack/static.rb b/lib/rack/static.rb index 41aec7f3..75e1e555 100644 --- a/lib/rack/static.rb +++ b/lib/rack/static.rb @@ -107,7 +107,7 @@ module Rack end def call(env) - path = env["PATH_INFO"] + path = env[PATH_INFO] if can_serve(path) env["PATH_INFO"] = (path =~ /\/$/ ? path + @index : @urls[path]) if overwrite_file_path(path) diff --git a/lib/rack/urlmap.rb b/lib/rack/urlmap.rb index d75f5a22..c62baecc 100644 --- a/lib/rack/urlmap.rb +++ b/lib/rack/urlmap.rb @@ -41,7 +41,7 @@ module Rack end def call(env) - path = env['PATH_INFO'] + path = env[PATH_INFO] script_name = env['SCRIPT_NAME'] hHost = env['HTTP_HOST'] sName = env['SERVER_NAME'] @@ -66,7 +66,7 @@ module Rack return app.call(env) end - [404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]] + [404, {CONTENT_TYPE => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]] ensure env['PATH_INFO'] = path -- cgit v1.2.3-24-ge0c7