Permalink
Browse files

Merge branch 'master' of github.com:rack/rack

  • Loading branch information...
2 parents 1038c7e + b83d7be commit d084a14fc5be6587fb1720a4f126bae2c7e74d10 @rkh rkh committed Aug 29, 2012
View
@@ -1,4 +1,4 @@
-Copyright (c) 2007, 2008, 2009, 2010 Christian Neukirchen <purl.org/net/chneukirchen>
+Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012 Christian Neukirchen <purl.org/net/chneukirchen>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
@@ -38,7 +38,7 @@ def valid?
end
def stale?
- !self.class.time_limit.nil? && (@timestamp - Time.now.to_i) < self.class.time_limit
+ !self.class.time_limit.nil? && (Time.now.to_i - @timestamp) > self.class.time_limit
end
def fresh?
@@ -17,21 +17,18 @@
require 'uri/common'
module URI
- 256.times do |i|
- TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
- end
- TBLENCWWWCOMP_[' '] = '+'
- TBLENCWWWCOMP_.freeze
-
- 256.times do |i|
- h, l = i>>4, i&15
- TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
- TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
- TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
- TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
+ TBLDECWWWCOMP_ = {} unless const_defined?(:TBLDECWWWCOMP_) #:nodoc:
+ if TBLDECWWWCOMP_.empty?
+ 256.times do |i|
+ h, l = i>>4, i&15
+ TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
+ TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
+ TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
+ TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
+ end
+ TBLDECWWWCOMP_['+'] = ' '
+ TBLDECWWWCOMP_.freeze
end
- TBLDECWWWCOMP_['+'] = ' '
- TBLDECWWWCOMP_.freeze
def self.decode_www_form(str, enc=Encoding::UTF_8)
return [] if str.empty?
@@ -46,22 +43,6 @@ def self.decode_www_form(str, enc=Encoding::UTF_8)
end
def self.decode_www_form_component(str, enc=Encoding::UTF_8)
- if TBLDECWWWCOMP_.empty?
- tbl = {}
- 256.times do |i|
- h, l = i>>4, i&15
- tbl['%%%X%X' % [h, l]] = i.chr
- tbl['%%%x%X' % [h, l]] = i.chr
- tbl['%%%X%x' % [h, l]] = i.chr
- tbl['%%%x%x' % [h, l]] = i.chr
- end
- tbl['+'] = ' '
- begin
- TBLDECWWWCOMP_.replace(tbl)
- TBLDECWWWCOMP_.freeze
- rescue
- end
- end
raise ArgumentError, "invalid %-encoding (#{str})" unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str
str.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc)
end
View
@@ -38,7 +38,7 @@ def self.parse_file(config, opts = Server::Options.new)
end
cfgfile.sub!(/^__END__\n.*\Z/m, '')
app = eval "Rack::Builder.new {\n" + cfgfile + "\n}.to_app",
- TOPLEVEL_BINDING, config
+ TOPLEVEL_BINDING, config, 0
else
require config
app = Object.const_get(::File.basename(config, '.rb').capitalize)
@@ -80,7 +80,7 @@ def list_directory
@files = [['../','Parent Directory','','','']]
glob = F.join(@path, '*')
- url_head = ([@script_name] + @path_info.split('/')).map do |part|
+ url_head = (@script_name.split('/') + @path_info.split('/')).map do |part|
Rack::Utils.escape part
end
View
@@ -28,8 +28,11 @@ def call(env)
end
unless headers['Cache-Control']
- headers['Cache-Control'] =
- (digest ? @cache_control : @no_cache_control) || ""
+ if digest
+ headers['Cache-Control'] = @cache_control if @cache_control
+ else
+ headers['Cache-Control'] = @no_cache_control if @no_cache_control
+ end
end
[status, headers, body]
View
@@ -21,9 +21,16 @@ class File
alias :to_path :path
- def initialize(root, cache_control = nil)
+ def initialize(root, headers={})
@root = root
- @cache_control = cache_control
+ # Allow a cache_control string for backwards compatibility
+ if headers.instance_of? String
+ warn \
+ "Rack::File headers parameter replaces cache_control after Rack 1.5."
+ @headers = { 'Cache-Control' => headers }
+ else
+ @headers = headers
+ end
end
def call(env)
@@ -78,7 +85,9 @@ def serving(env)
},
env["REQUEST_METHOD"] == "HEAD" ? [] : self
]
- response[1]['Cache-Control'] = @cache_control if @cache_control
+
+ # Set custom headers
+ @headers.each { |field, content| response[1][field] = content } if @headers
# NOTE:
# We check via File::size? whether this file provides size info
View
@@ -247,11 +247,14 @@ def start &blk
pp app
end
+ check_pid! if options[:pid]
+
# Touch the wrapped app, so that the config.ru is loaded before
# daemonization (i.e. before chdir, etc).
wrapped_app
daemonize_app if options[:daemonize]
+
write_pid if options[:pid]
trap(:INT) do
@@ -274,7 +277,7 @@ def parse_options(args)
options = default_options
# Don't evaluate CGI ISINDEX parameters.
- # http://hoohoo.ncsa.uiuc.edu/cgi/cl.html
+ # http://www.meb.uni-bonn.de/docs/cgi/cl.html
args.clear if ENV.include?("REQUEST_METHOD")
options.merge! opt_parser.parse!(args)
@@ -319,5 +322,28 @@ def write_pid
::File.open(options[:pid], 'w'){ |f| f.write("#{Process.pid}") }
at_exit { ::File.delete(options[:pid]) if ::File.exist?(options[:pid]) }
end
+
+ def check_pid!
+ case pidfile_process_status
+ when :running, :not_owned
+ $stderr.puts "A server is already running. Check #{options[:pid]}."
+ exit(1)
+ when :dead
+ ::File.delete(options[:pid])
+ end
+ end
+
+ def pidfile_process_status
+ return :exited unless ::File.exist?(options[:pid])
+
+ pid = ::File.read(options[:pid]).to_i
+ Process.kill(0, pid)
+ :running
+ rescue Errno::ESRCH
+ :dead
+ rescue Errno::EPERM
+ :not_owned
+ end
+
end
end
@@ -120,6 +120,11 @@ def empty?
super
end
+ def merge!(hash)
+ load_for_write!
+ super
+ end
+
private
def load_for_read!
View
@@ -32,6 +32,16 @@ module Rack
#
# use Rack::Static, :root => 'public', :cache_control => 'public'
#
+ # Set custom HTTP Headers for all served files:
+ #
+ # use Rack::Static, :root => 'public', :headers =>
+ # {'Cache-Control' => 'public, max-age=31536000',
+ # 'Access-Control-Allow-Origin' => '*'}
+ #
+ # Note: If both :headers => {'Cache-Control' => 'public, max-age=42'}
+ # and :cache_control => 'public, max-age=38' are being provided
+ # the :headers setting takes precedence
+ #
class Static
@@ -40,8 +50,11 @@ def initialize(app, options={})
@urls = options[:urls] || ["/favicon.ico"]
@index = options[:index]
root = options[:root] || Dir.pwd
- cache_control = options[:cache_control]
- @file_server = Rack::File.new(root, cache_control)
+ headers = options[:headers] || {}
+ # Allow for legacy :cache_control option
+ # while prioritizing :headers => {'Cache-Control' => ''} settings
+ headers['Cache-Control'] ||= options[:cache_control] if options[:cache_control]
+ @file_server = Rack::File.new(root, headers)
end
def overwrite_file_path(path)
View
@@ -9,7 +9,7 @@
if major == 1 && minor < 9
require 'rack/backports/uri/common_18'
-elsif major == 1 && minor == 9 && patch == 2 && RUBY_PATCHLEVEL < 318 && RUBY_ENGINE != 'jruby'
+elsif major == 1 && minor == 9 && patch == 2 && RUBY_PATCHLEVEL <= 320 && RUBY_ENGINE != 'jruby'
require 'rack/backports/uri/common_192'
elsif major == 1 && minor == 9 && patch == 3 && RUBY_PATCHLEVEL < 125
require 'rack/backports/uri/common_193'
@@ -0,0 +1 @@
+run lambda{ |env| [200, {'Content-Type' => 'text/plain'}, [__LINE__.to_s]] }
@@ -153,6 +153,20 @@ def assert_bad_request(response)
end
end
+ should 'not rechallenge if nonce is not stale' do
+ begin
+ Rack::Auth::Digest::Nonce.time_limit = 10
+
+ request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', :wait => 1 do |response|
+ response.status.should.equal 200
+ response.body.to_s.should.equal 'Hi Alice'
+ response.headers['WWW-Authenticate'].should.not =~ /\bstale=true\b/
+ end
+ ensure
+ Rack::Auth::Digest::Nonce.time_limit = nil
+ end
+ end
+
should 'rechallenge with stale parameter if nonce is stale' do
begin
Rack::Auth::Digest::Nonce.time_limit = 1
@@ -197,5 +197,11 @@ def config_file(name)
Rack::MockRequest.new(app).get("/").body.to_s.should.equal 'OK'
$:.pop
end
+
+ it "sets __LINE__ correctly" do
+ app, options = Rack::Builder.parse_file config_file('line.ru')
+ options = nil # ignored, prevents warning
+ Rack::MockRequest.new(app).get("/").body.to_s.should.equal '1'
+ end
end
end
@@ -67,4 +67,22 @@
res = mr.get("/cgi/test%2bdirectory/test%2bfile")
res.should.be.ok
end
+
+ should "correctly escape script name" do
+ app2 = Rack::Builder.new do
+ map '/script-path' do
+ run app
+ end
+ end
+
+ mr = Rack::MockRequest.new(Rack::Lint.new(app2))
+
+ res = mr.get("/script-path/cgi/test%2bdirectory")
+
+ res.should.be.ok
+ res.body.should =~ %r[/script-path/cgi/test%2Bdirectory/test%2Bfile]
+
+ res = mr.get("/script-path/cgi/test%2bdirectory/test%2bfile")
+ res.should.be.ok
+ end
end
View
@@ -54,6 +54,12 @@ def res.to_path ; "/tmp/hello.txt" ; end
response[1]['Cache-Control'].should.equal 'public'
end
+ should "not set Cache-Control if directive isn't present" do
+ app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
+ response = etag(app, nil, nil).call(request)
+ response[1]['Cache-Control'].should.equal nil
+ end
+
should "not change ETag if it is already set" do
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'ETag' => '"abc"'}, ["Hello, World!"]] }
response = etag(app).call(request)
View
@@ -65,13 +65,13 @@ def file(*args)
should "not allow unsafe directory traversal" do
req = Rack::MockRequest.new(file(DOCROOT))
- res = req.get("/../README")
+ res = req.get("/../README.rdoc")
res.should.be.client_error
- res = req.get("../test")
+ res = req.get("../test/spec_file.rb")
res.should.be.client_error
- res = req.get("..")
+ res = req.get("../README.rdoc")
res.should.be.client_error
res.should.be.not_found
@@ -145,14 +145,33 @@ def file(*args)
res["Content-Range"].should.equal "bytes */193"
end
- should "support cache control options" do
+ should "support legacy cache control options provided as string" do
env = Rack::MockRequest.env_for("/cgi/test")
status, heads, _ = file(DOCROOT, 'public, max-age=38').call(env)
status.should.equal 200
heads['Cache-Control'].should.equal 'public, max-age=38'
end
+ should "support custom http headers" do
+ env = Rack::MockRequest.env_for("/cgi/test")
+ status, heads, _ = file(DOCROOT, 'Cache-Control' => 'public, max-age=38',
+ 'Access-Control-Allow-Origin' => '*').call(env)
+
+ status.should.equal 200
+ heads['Cache-Control'].should.equal 'public, max-age=38'
+ heads['Access-Control-Allow-Origin'].should.equal '*'
+ end
+
+ should "support not add custom http headers if none are supplied" do
+ env = Rack::MockRequest.env_for("/cgi/test")
+ status, heads, _ = file(DOCROOT).call(env)
+
+ status.should.equal 200
+ heads['Cache-Control'].should.equal nil
+ heads['Access-Control-Allow-Origin'].should.equal nil
+ end
+
should "only support GET and HEAD requests" do
req = Rack::MockRequest.new(file(DOCROOT))
Oops, something went wrong.

0 comments on commit d084a14

Please sign in to comment.