Update Vendored Rack to 1.2.0
Also update tests for itextomml 1.3.25.
This commit is contained in:
parent
4f8759cdf3
commit
6491d70326
|
@ -8,12 +8,12 @@ module Rack
|
||||||
class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet
|
class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet
|
||||||
def self.run(app, options={})
|
def self.run(app, options={})
|
||||||
options[:BindAddress] = options.delete(:Host) if options[:Host]
|
options[:BindAddress] = options.delete(:Host) if options[:Host]
|
||||||
server = ::WEBrick::HTTPServer.new(options)
|
@server = ::WEBrick::HTTPServer.new(options)
|
||||||
server.mount "/", Rack::Handler::WEBrick, app
|
@server.mount "/", Rack::Handler::WEBrick, app
|
||||||
trap(:INT) { server.shutdown }
|
trap(:INT) { @server.shutdown }
|
||||||
trap(:TERM) { server.shutdown }
|
trap(:TERM) { @server.shutdown }
|
||||||
yield server if block_given?
|
yield @server if block_given?
|
||||||
server.start
|
@server.start
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -39,7 +39,7 @@ module Rack
|
||||||
entire_buffer_written_out = false
|
entire_buffer_written_out = false
|
||||||
while !entire_buffer_written_out
|
while !entire_buffer_written_out
|
||||||
written = @rewindable_io.write(buffer)
|
written = @rewindable_io.write(buffer)
|
||||||
entire_buffer_written_out = written == buffer.size
|
entire_buffer_written_out = written == Rack::Utils.bytesize(buffer)
|
||||||
if !entire_buffer_written_out
|
if !entire_buffer_written_out
|
||||||
buffer.slice!(0 .. written - 1)
|
buffer.slice!(0 .. written - 1)
|
||||||
end
|
end
|
||||||
|
|
|
@ -226,6 +226,15 @@ END_THM
|
||||||
|
|
||||||
def test_have_latest_itex2mml
|
def test_have_latest_itex2mml
|
||||||
|
|
||||||
|
assert_markup_parsed_as(
|
||||||
|
%{<p>boxed equation <math class='maruku-mathml' } +
|
||||||
|
%{display='inline' xmlns='http://www.w3.org/1998} +
|
||||||
|
%{/Math/MathML'><menclose notation='box'><mrow><} +
|
||||||
|
%{menclose notation='updiagonalstrike'><mi>D</mi} +
|
||||||
|
%{></menclose><mi>\317\210</mi><mo>=</mo><mn>0</} +
|
||||||
|
%{mn></mrow></menclose></math></p>},
|
||||||
|
"boxed equation $\\boxed{\\slash{D}\\psi=0}$")
|
||||||
|
|
||||||
assert_markup_parsed_as(
|
assert_markup_parsed_as(
|
||||||
%{<p>equation <math class='maruku-mathml' displa} +
|
%{<p>equation <math class='maruku-mathml' displa} +
|
||||||
%{y='inline' xmlns='http://www.w3.org/1998/Math/} +
|
%{y='inline' xmlns='http://www.w3.org/1998/Math/} +
|
||||||
|
|
2
vendor/plugins/rack/COPYING
vendored
2
vendor/plugins/rack/COPYING
vendored
|
@ -1,4 +1,4 @@
|
||||||
Copyright (c) 2007, 2008, 2009 Christian Neukirchen <purl.org/net/chneukirchen>
|
Copyright (c) 2007, 2008, 2009, 2010 Christian Neukirchen <purl.org/net/chneukirchen>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to
|
of this software and associated documentation files (the "Software"), to
|
||||||
|
|
51
vendor/plugins/rack/README
vendored
51
vendor/plugins/rack/README
vendored
|
@ -9,16 +9,6 @@ middleware) into a single method call.
|
||||||
The exact details of this are described in the Rack specification,
|
The exact details of this are described in the Rack specification,
|
||||||
which all Rack applications should conform to.
|
which all Rack applications should conform to.
|
||||||
|
|
||||||
== Specification changes in this release
|
|
||||||
|
|
||||||
With Rack 1.1, the Rack specification (found in SPEC) changed in the
|
|
||||||
following backward-incompatible ways.
|
|
||||||
|
|
||||||
* Rack::VERSION has been pushed to [1,1].
|
|
||||||
* rack.logger is now specified.
|
|
||||||
* The SPEC now allows subclasses of the required types.
|
|
||||||
* rack.input has to be opened in binary mode.
|
|
||||||
|
|
||||||
== Supported web servers
|
== Supported web servers
|
||||||
|
|
||||||
The included *handlers* connect all kinds of web servers to Rack:
|
The included *handlers* connect all kinds of web servers to Rack:
|
||||||
|
@ -46,9 +36,6 @@ changing anything.
|
||||||
|
|
||||||
== Supported web frameworks
|
== Supported web frameworks
|
||||||
|
|
||||||
The included *adapters* connect Rack with existing Ruby web frameworks:
|
|
||||||
* Camping
|
|
||||||
|
|
||||||
These frameworks include Rack adapters in their distributions:
|
These frameworks include Rack adapters in their distributions:
|
||||||
* Camping
|
* Camping
|
||||||
* Coset
|
* Coset
|
||||||
|
@ -143,9 +130,9 @@ at my site:
|
||||||
|
|
||||||
== Running the tests
|
== Running the tests
|
||||||
|
|
||||||
Testing Rack requires the test/spec testing framework:
|
Testing Rack requires the bacon testing framework:
|
||||||
|
|
||||||
gem install test-spec
|
gem install bacon
|
||||||
|
|
||||||
There are two rake-based test tasks:
|
There are two rake-based test tasks:
|
||||||
|
|
||||||
|
@ -153,11 +140,10 @@ There are two rake-based test tasks:
|
||||||
rake fulltest runs all the tests
|
rake fulltest runs all the tests
|
||||||
|
|
||||||
The fast testsuite has no dependencies outside of the core Ruby
|
The fast testsuite has no dependencies outside of the core Ruby
|
||||||
installation and test-spec.
|
installation and bacon.
|
||||||
|
|
||||||
To run the test suite completely, you need:
|
To run the test suite completely, you need:
|
||||||
|
|
||||||
* camping
|
|
||||||
* fcgi
|
* fcgi
|
||||||
* memcache-client
|
* memcache-client
|
||||||
* mongrel
|
* mongrel
|
||||||
|
@ -278,7 +264,7 @@ run on port 11211) and memcache-client installed.
|
||||||
* Make sure WEBrick respects the :Host option
|
* Make sure WEBrick respects the :Host option
|
||||||
* Many Ruby 1.9 fixes.
|
* Many Ruby 1.9 fixes.
|
||||||
|
|
||||||
* December ??th, 2009: Ninth public release 1.1.0.
|
* January 3rd, 2010: Ninth public release 1.1.0.
|
||||||
* Moved Auth::OpenID to rack-contrib.
|
* Moved Auth::OpenID to rack-contrib.
|
||||||
* SPEC change that relaxes Lint slightly to allow subclasses of the
|
* SPEC change that relaxes Lint slightly to allow subclasses of the
|
||||||
required types
|
required types
|
||||||
|
@ -313,17 +299,26 @@ run on port 11211) and memcache-client installed.
|
||||||
* Enforce binary encoding in RewindableInput
|
* Enforce binary encoding in RewindableInput
|
||||||
* Set correct external_encoding for handlers that don't use RewindableInput
|
* Set correct external_encoding for handlers that don't use RewindableInput
|
||||||
|
|
||||||
|
* June 13th, 2010: Tenth public release 1.2.0.
|
||||||
|
* Removed Camping adapter: Camping 2.0 supports Rack as-is
|
||||||
|
* Removed parsing of quoted values
|
||||||
|
* Add Request.trace? and Request.options?
|
||||||
|
* Add mime-type for .webm and .htc
|
||||||
|
* Fix HTTP_X_FORWARDED_FOR
|
||||||
|
* Various multipart fixes
|
||||||
|
* Switch test suite to bacon
|
||||||
|
|
||||||
== Contact
|
== Contact
|
||||||
|
|
||||||
Please post bugs, suggestions and patches to
|
Please post bugs, suggestions and patches to
|
||||||
the bug tracker at <http://rack.lighthouseapp.com/>.
|
the bug tracker at <http://github.com/rack/rack/issues>.
|
||||||
|
|
||||||
Mailing list archives are available at
|
Mailing list archives are available at
|
||||||
<http://groups.google.com/group/rack-devel>.
|
<http://groups.google.com/group/rack-devel>.
|
||||||
|
|
||||||
Git repository (send Git patches to the mailing list):
|
Git repository (send Git patches to the mailing list):
|
||||||
* http://github.com/rack/rack
|
* http://github.com/rack/rack
|
||||||
* http://git.vuxu.org/cgi-bin/gitweb.cgi?p=rack.git
|
* http://git.vuxu.org/cgi-bin/gitweb.cgi?p=rack-github.git
|
||||||
|
|
||||||
You are also welcome to join the #rack channel on irc.freenode.net.
|
You are also welcome to join the #rack channel on irc.freenode.net.
|
||||||
|
|
||||||
|
@ -345,12 +340,14 @@ would like to thank:
|
||||||
* Tim Fletcher, for the HTTP authentication code.
|
* Tim Fletcher, for the HTTP authentication code.
|
||||||
* Luc Heinrich for the Cookie sessions, the static file handler and bugfixes.
|
* Luc Heinrich for the Cookie sessions, the static file handler and bugfixes.
|
||||||
* Armin Ronacher, for the logo and racktools.
|
* Armin Ronacher, for the logo and racktools.
|
||||||
* Aredridel, Ben Alpert, Dan Kubb, Daniel Roethlisberger, Matt Todd,
|
* Alex Beregszaszi, Alexander Kahn, Anil Wadghule, Aredridel, Ben
|
||||||
Tom Robinson, Phil Hagelberg, S. Brent Faulkner, Bosko Milekic,
|
Alpert, Dan Kubb, Daniel Roethlisberger, Matt Todd, Tom Robinson,
|
||||||
Daniel Rodríguez Troitiño, Genki Takiuchi, Geoffrey Grosenbach,
|
Phil Hagelberg, S. Brent Faulkner, Bosko Milekic, Daniel Rodríguez
|
||||||
Julien Sanchez, Kamal Fariz Mahyuddin, Masayoshi Takahashi, Patrick
|
Troitiño, Genki Takiuchi, Geoffrey Grosenbach, Julien Sanchez, Kamal
|
||||||
Aljordm, Mig, and Kazuhiro Nishiyama for bug fixing and other
|
Fariz Mahyuddin, Masayoshi Takahashi, Patrick Aljordm, Mig, Kazuhiro
|
||||||
improvements.
|
Nishiyama, Jon Bardin, Konstantin Haase, Larry Siden, Matias
|
||||||
|
Korhonen, Sam Ruby, Simon Chiang, Tim Connor, Timur Batyrshin, and
|
||||||
|
Zach Brock for bug fixing and other improvements.
|
||||||
* Eric Wong, Hongli Lai, Jeremy Kemper for their continuous support
|
* Eric Wong, Hongli Lai, Jeremy Kemper for their continuous support
|
||||||
and API improvements.
|
and API improvements.
|
||||||
* Yehuda Katz and Carl Lerche for refactoring rackup.
|
* Yehuda Katz and Carl Lerche for refactoring rackup.
|
||||||
|
@ -368,7 +365,7 @@ would like to thank:
|
||||||
|
|
||||||
== Copyright
|
== Copyright
|
||||||
|
|
||||||
Copyright (C) 2007, 2008, 2009 Christian Neukirchen <http://purl.org/net/chneukirchen>
|
Copyright (C) 2007, 2008, 2009, 2010 Christian Neukirchen <http://purl.org/net/chneukirchen>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to
|
of this software and associated documentation files (the "Software"), to
|
||||||
|
|
31
vendor/plugins/rack/Rakefile
vendored
31
vendor/plugins/rack/Rakefile
vendored
|
@ -1,16 +1,13 @@
|
||||||
# Rakefile for Rack. -*-ruby-*-
|
# Rakefile for Rack. -*-ruby-*-
|
||||||
require 'rake/rdoctask'
|
require 'rake/rdoctask'
|
||||||
require 'rake/testtask'
|
|
||||||
|
|
||||||
|
|
||||||
desc "Run all the tests"
|
desc "Run all the tests"
|
||||||
task :default => [:test]
|
task :default => [:test]
|
||||||
|
|
||||||
desc "Make an archive as .tar.gz"
|
desc "Make an archive as .tar.gz"
|
||||||
task :dist => [:chmod, :changelog, :rdoc, "SPEC"] do
|
task :dist => [:chmod, :changelog, :rdoc, "SPEC"] do
|
||||||
FileUtils.touch("RDOX")
|
|
||||||
sh "git archive --format=tar --prefix=#{release}/ HEAD^{tree} >#{release}.tar"
|
sh "git archive --format=tar --prefix=#{release}/ HEAD^{tree} >#{release}.tar"
|
||||||
sh "pax -waf #{release}.tar -s ':^:#{release}/:' RDOX SPEC ChangeLog doc rack.gemspec"
|
sh "pax -waf #{release}.tar -s ':^:#{release}/:' SPEC ChangeLog doc rack.gemspec"
|
||||||
sh "gzip -f -9 #{release}.tar"
|
sh "gzip -f -9 #{release}.tar"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -23,19 +20,19 @@ task :officialrelease do
|
||||||
sh "mv stage/#{release}.tar.gz stage/#{release}.gem ."
|
sh "mv stage/#{release}.tar.gz stage/#{release}.gem ."
|
||||||
end
|
end
|
||||||
|
|
||||||
task :officialrelease_really => [:fulltest, "RDOX", "SPEC", :dist, :gem] do
|
task :officialrelease_really => ["SPEC", :dist, :gem] do
|
||||||
sh "sha1sum #{release}.tar.gz #{release}.gem"
|
sh "sha1sum #{release}.tar.gz #{release}.gem"
|
||||||
end
|
end
|
||||||
|
|
||||||
def release
|
def release
|
||||||
require File.dirname(__FILE__) + "/lib/rack"
|
require File.dirname(__FILE__) + "/lib/rack"
|
||||||
"rack-#{Rack.release}"
|
"rack-#{Rack.release}.0"
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Make binaries executable"
|
desc "Make binaries executable"
|
||||||
task :chmod do
|
task :chmod do
|
||||||
Dir["bin/*"].each { |binary| File.chmod(0775, binary) }
|
Dir["bin/*"].each { |binary| File.chmod(0775, binary) }
|
||||||
Dir["test/cgi/test*"].each { |binary| File.chmod(0775, binary) }
|
Dir["spec/cgi/spec*"].each { |binary| File.chmod(0775, binary) }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Generate a ChangeLog"
|
desc "Generate a ChangeLog"
|
||||||
|
@ -57,11 +54,6 @@ task :changelog do
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
desc "Generate RDox"
|
|
||||||
task "RDOX" do
|
|
||||||
sh "specrb -Ilib:test -a --rdox >RDOX"
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "Generate Rack Specification"
|
desc "Generate Rack Specification"
|
||||||
task "SPEC" do
|
task "SPEC" do
|
||||||
File.open("SPEC", "wb") { |file|
|
File.open("SPEC", "wb") { |file|
|
||||||
|
@ -75,24 +67,29 @@ end
|
||||||
|
|
||||||
desc "Run all the fast tests"
|
desc "Run all the fast tests"
|
||||||
task :test do
|
task :test do
|
||||||
sh "specrb -Ilib:test -w #{ENV['TEST'] || '-a'} #{ENV['TESTOPTS'] || '-t "^(?!Rack::Handler|Rack::Adapter|Rack::Session::Memcache|rackup)"'}"
|
opts = ENV['TEST'] || '-a'
|
||||||
|
specopts = ENV['TESTOPTS'] ||
|
||||||
|
"-q -t '^(?!Rack::Handler|Rack::Adapter|Rack::Session::Memcache|rackup)'"
|
||||||
|
|
||||||
|
sh "bacon -I./lib:./spec -w #{opts} #{specopts}"
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Run all the tests"
|
desc "Run all the tests"
|
||||||
task :fulltest => [:chmod] do
|
task :fulltest => [:chmod] do
|
||||||
sh "specrb -Ilib:test -w #{ENV['TEST'] || '-a'} #{ENV['TESTOPTS']}"
|
opts = ENV['TEST'] || '-a'
|
||||||
|
specopts = ENV['TESTOPTS'] || '-q'
|
||||||
|
sh "bacon -I./lib:./spec -w #{opts} #{specopts}"
|
||||||
end
|
end
|
||||||
|
|
||||||
task :gem => ["SPEC"] do
|
task :gem => ["SPEC"] do
|
||||||
FileUtils.touch("RDOX")
|
|
||||||
sh "gem build rack.gemspec"
|
sh "gem build rack.gemspec"
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Generate RDoc documentation"
|
desc "Generate RDoc documentation"
|
||||||
task :rdoc do
|
task :rdoc => ["SPEC"] do
|
||||||
sh(*%w{rdoc --line-numbers --main README
|
sh(*%w{rdoc --line-numbers --main README
|
||||||
--title 'Rack\ Documentation' --charset utf-8 -U -o doc} +
|
--title 'Rack\ Documentation' --charset utf-8 -U -o doc} +
|
||||||
%w{README KNOWN-ISSUES SPEC RDOX} +
|
%w{README KNOWN-ISSUES SPEC} +
|
||||||
Dir["lib/**/*.rb"])
|
Dir["lib/**/*.rb"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
2
vendor/plugins/rack/bin/rackup
vendored
2
vendor/plugins/rack/bin/rackup
vendored
|
@ -1,2 +1,4 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
require "rack"
|
require "rack"
|
||||||
Rack::Server.start
|
Rack::Server.start
|
||||||
|
|
15
vendor/plugins/rack/lib/rack.rb
vendored
15
vendor/plugins/rack/lib/rack.rb
vendored
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (C) 2007, 2008, 2009 Christian Neukirchen <purl.org/net/chneukirchen>
|
# Copyright (C) 2007, 2008, 2009, 2010 Christian Neukirchen <purl.org/net/chneukirchen>
|
||||||
#
|
#
|
||||||
# Rack is freely distributable under the terms of an MIT-style license.
|
# Rack is freely distributable under the terms of an MIT-style license.
|
||||||
# See COPYING or http://www.opensource.org/licenses/mit-license.php.
|
# See COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
@ -20,7 +20,7 @@ module Rack
|
||||||
|
|
||||||
# Return the Rack release as a dotted string.
|
# Return the Rack release as a dotted string.
|
||||||
def self.release
|
def self.release
|
||||||
"1.1"
|
"1.2"
|
||||||
end
|
end
|
||||||
|
|
||||||
autoload :Builder, "rack/builder"
|
autoload :Builder, "rack/builder"
|
||||||
|
@ -78,15 +78,4 @@ module Rack
|
||||||
autoload :Pool, "rack/session/pool"
|
autoload :Pool, "rack/session/pool"
|
||||||
autoload :Memcache, "rack/session/memcache"
|
autoload :Memcache, "rack/session/memcache"
|
||||||
end
|
end
|
||||||
|
|
||||||
# *Adapters* connect Rack with third party web frameworks.
|
|
||||||
#
|
|
||||||
# Rack includes an adapter for Camping, see README for other
|
|
||||||
# frameworks supporting Rack in their code bases.
|
|
||||||
#
|
|
||||||
# Refer to the submodules for framework-specific calling details.
|
|
||||||
|
|
||||||
module Adapter
|
|
||||||
autoload :Camping, "rack/adapter/camping"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
22
vendor/plugins/rack/lib/rack/adapter/camping.rb
vendored
22
vendor/plugins/rack/lib/rack/adapter/camping.rb
vendored
|
@ -1,22 +0,0 @@
|
||||||
module Rack
|
|
||||||
module Adapter
|
|
||||||
class Camping
|
|
||||||
def initialize(app)
|
|
||||||
@app = app
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
env["PATH_INFO"] ||= ""
|
|
||||||
env["SCRIPT_NAME"] ||= ""
|
|
||||||
controller = @app.run(env['rack.input'], env)
|
|
||||||
h = controller.headers
|
|
||||||
h.each_pair do |k,v|
|
|
||||||
if v.kind_of? URI
|
|
||||||
h[k] = v.to_s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
[controller.status, controller.headers, [controller.body.to_s]]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -35,7 +35,7 @@ module Rack
|
||||||
super k.to_s, v.to_s
|
super k.to_s, v.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
UNQUOTED = ['qop', 'nc', 'stale']
|
UNQUOTED = ['nc', 'stale']
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
inject([]) do |parts, (k, v)|
|
inject([]) do |parts, (k, v)|
|
||||||
|
|
480
vendor/plugins/rack/lib/rack/auth/openid.rb
vendored
480
vendor/plugins/rack/lib/rack/auth/openid.rb
vendored
|
@ -1,480 +0,0 @@
|
||||||
# AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
|
|
||||||
|
|
||||||
gem 'ruby-openid', '~> 2' if defined? Gem
|
|
||||||
require 'rack/request'
|
|
||||||
require 'rack/utils'
|
|
||||||
require 'rack/auth/abstract/handler'
|
|
||||||
require 'uri'
|
|
||||||
require 'openid' #gem
|
|
||||||
require 'openid/extension' #gem
|
|
||||||
require 'openid/store/memory' #gem
|
|
||||||
|
|
||||||
module Rack
|
|
||||||
class Request
|
|
||||||
def openid_request
|
|
||||||
@env['rack.auth.openid.request']
|
|
||||||
end
|
|
||||||
|
|
||||||
def openid_response
|
|
||||||
@env['rack.auth.openid.response']
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module Auth
|
|
||||||
|
|
||||||
# Rack::Auth::OpenID provides a simple method for setting up an OpenID
|
|
||||||
# Consumer. It requires the ruby-openid library from janrain to operate,
|
|
||||||
# as well as a rack method of session management.
|
|
||||||
#
|
|
||||||
# The ruby-openid home page is at http://openidenabled.com/ruby-openid/.
|
|
||||||
#
|
|
||||||
# The OpenID specifications can be found at
|
|
||||||
# http://openid.net/specs/openid-authentication-1_1.html
|
|
||||||
# and
|
|
||||||
# http://openid.net/specs/openid-authentication-2_0.html. Documentation
|
|
||||||
# for published OpenID extensions and related topics can be found at
|
|
||||||
# http://openid.net/developers/specs/.
|
|
||||||
#
|
|
||||||
# It is recommended to read through the OpenID spec, as well as
|
|
||||||
# ruby-openid's documentation, to understand what exactly goes on. However
|
|
||||||
# a setup as simple as the presented examples is enough to provide
|
|
||||||
# Consumer functionality.
|
|
||||||
#
|
|
||||||
# This library strongly intends to utilize the OpenID 2.0 features of the
|
|
||||||
# ruby-openid library, which provides OpenID 1.0 compatiblity.
|
|
||||||
#
|
|
||||||
# NOTE: Due to the amount of data that this library stores in the
|
|
||||||
# session, Rack::Session::Cookie may fault.
|
|
||||||
|
|
||||||
class OpenID
|
|
||||||
|
|
||||||
class NoSession < RuntimeError; end
|
|
||||||
class BadExtension < RuntimeError; end
|
|
||||||
# Required for ruby-openid
|
|
||||||
ValidStatus = [:success, :setup_needed, :cancel, :failure]
|
|
||||||
|
|
||||||
# = Arguments
|
|
||||||
#
|
|
||||||
# The first argument is the realm, identifying the site they are trusting
|
|
||||||
# with their identity. This is required, also treated as the trust_root
|
|
||||||
# in OpenID 1.x exchanges.
|
|
||||||
#
|
|
||||||
# The optional second argument is a hash of options.
|
|
||||||
#
|
|
||||||
# == Options
|
|
||||||
#
|
|
||||||
# <tt>:return_to</tt> defines the url to return to after the client
|
|
||||||
# authenticates with the openid service provider. This url should point
|
|
||||||
# to where Rack::Auth::OpenID is mounted. If <tt>:return_to</tt> is not
|
|
||||||
# provided, return_to will be the current url which allows flexibility
|
|
||||||
# with caveats.
|
|
||||||
#
|
|
||||||
# <tt>:session_key</tt> defines the key to the session hash in the env.
|
|
||||||
# It defaults to 'rack.session'.
|
|
||||||
#
|
|
||||||
# <tt>:openid_param</tt> defines at what key in the request parameters to
|
|
||||||
# find the identifier to resolve. As per the 2.0 spec, the default is
|
|
||||||
# 'openid_identifier'.
|
|
||||||
#
|
|
||||||
# <tt>:store</tt> defined what OpenID Store to use for persistant
|
|
||||||
# information. By default a Store::Memory will be used.
|
|
||||||
#
|
|
||||||
# <tt>:immediate</tt> as true will make initial requests to be of an
|
|
||||||
# immediate type. This is false by default. See OpenID specification
|
|
||||||
# documentation.
|
|
||||||
#
|
|
||||||
# <tt>:extensions</tt> should be a hash of openid extension
|
|
||||||
# implementations. The key should be the extension main module, the value
|
|
||||||
# should be an array of arguments for extension::Request.new.
|
|
||||||
# The hash is iterated over and passed to #add_extension for processing.
|
|
||||||
# Please see #add_extension for further documentation.
|
|
||||||
#
|
|
||||||
# == Examples
|
|
||||||
#
|
|
||||||
# simple_oid = OpenID.new('http://mysite.com/')
|
|
||||||
#
|
|
||||||
# return_oid = OpenID.new('http://mysite.com/', {
|
|
||||||
# :return_to => 'http://mysite.com/openid'
|
|
||||||
# })
|
|
||||||
#
|
|
||||||
# complex_oid = OpenID.new('http://mysite.com/',
|
|
||||||
# :immediate => true,
|
|
||||||
# :extensions => {
|
|
||||||
# ::OpenID::SReg => [['email'],['nickname']]
|
|
||||||
# }
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# = Advanced
|
|
||||||
#
|
|
||||||
# Most of the functionality of this library is encapsulated such that
|
|
||||||
# expansion and overriding functions isn't difficult nor tricky.
|
|
||||||
# Alternately, to avoid opening up singleton objects or subclassing, a
|
|
||||||
# wrapper rack middleware can be composed to act upon Auth::OpenID's
|
|
||||||
# responses. See #check and #finish for locations of pertinent data.
|
|
||||||
#
|
|
||||||
# == Responses
|
|
||||||
#
|
|
||||||
# To change the responses that Auth::OpenID returns, override the methods
|
|
||||||
# #redirect, #bad_request, #unauthorized, #access_denied, and
|
|
||||||
# #foreign_server_failure.
|
|
||||||
#
|
|
||||||
# Additionally #confirm_post_params is used when the URI would exceed
|
|
||||||
# length limits on a GET request when doing the initial verification
|
|
||||||
# request.
|
|
||||||
#
|
|
||||||
# == Processing
|
|
||||||
#
|
|
||||||
# To change methods of processing completed transactions, override the
|
|
||||||
# methods #success, #setup_needed, #cancel, and #failure. Please ensure
|
|
||||||
# the returned object is a rack compatible response.
|
|
||||||
#
|
|
||||||
# The first argument is an OpenID::Response, the second is a
|
|
||||||
# Rack::Request of the current request, the last is the hash used in
|
|
||||||
# ruby-openid handling, which can be found manually at
|
|
||||||
# env['rack.session'][:openid].
|
|
||||||
#
|
|
||||||
# This is useful if you wanted to expand the processing done, such as
|
|
||||||
# setting up user accounts.
|
|
||||||
#
|
|
||||||
# oid_app = Rack::Auth::OpenID.new realm, :return_to => return_to
|
|
||||||
# def oid_app.success oid, request, session
|
|
||||||
# user = Models::User[oid.identity_url]
|
|
||||||
# user ||= Models::User.create_from_openid oid
|
|
||||||
# request['rack.session'][:user] = user.id
|
|
||||||
# redirect MyApp.site_home
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# site_map['/openid'] = oid_app
|
|
||||||
# map = Rack::URLMap.new site_map
|
|
||||||
# ...
|
|
||||||
|
|
||||||
def initialize(realm, options={})
|
|
||||||
realm = URI(realm)
|
|
||||||
raise ArgumentError, "Invalid realm: #{realm}" \
|
|
||||||
unless realm.absolute? \
|
|
||||||
and realm.fragment.nil? \
|
|
||||||
and realm.scheme =~ /^https?$/ \
|
|
||||||
and realm.host =~ /^(\*\.)?#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+/
|
|
||||||
realm.path = '/' if realm.path.empty?
|
|
||||||
@realm = realm.to_s
|
|
||||||
|
|
||||||
if ruri = options[:return_to]
|
|
||||||
ruri = URI(ruri)
|
|
||||||
raise ArgumentError, "Invalid return_to: #{ruri}" \
|
|
||||||
unless ruri.absolute? \
|
|
||||||
and ruri.scheme =~ /^https?$/ \
|
|
||||||
and ruri.fragment.nil?
|
|
||||||
raise ArgumentError, "return_to #{ruri} not within realm #{realm}" \
|
|
||||||
unless self.within_realm?(ruri)
|
|
||||||
@return_to = ruri.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
@session_key = options[:session_key] || 'rack.session'
|
|
||||||
@openid_param = options[:openid_param] || 'openid_identifier'
|
|
||||||
@store = options[:store] || ::OpenID::Store::Memory.new
|
|
||||||
@immediate = !!options[:immediate]
|
|
||||||
|
|
||||||
@extensions = {}
|
|
||||||
if extensions = options.delete(:extensions)
|
|
||||||
extensions.each do |ext, args|
|
|
||||||
add_extension ext, *args
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Undocumented, semi-experimental
|
|
||||||
@anonymous = !!options[:anonymous]
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_reader :realm, :return_to, :session_key, :openid_param, :store,
|
|
||||||
:immediate, :extensions
|
|
||||||
|
|
||||||
# Sets up and uses session data at <tt>:openid</tt> within the session.
|
|
||||||
# Errors in this setup will raise a NoSession exception.
|
|
||||||
#
|
|
||||||
# If the parameter 'openid.mode' is set, which implies a followup from
|
|
||||||
# the openid server, processing is passed to #finish and the result is
|
|
||||||
# returned. However, if there is no appropriate openid information in the
|
|
||||||
# session, a 400 error is returned.
|
|
||||||
#
|
|
||||||
# If the parameter specified by <tt>options[:openid_param]</tt> is
|
|
||||||
# present, processing is passed to #check and the result is returned.
|
|
||||||
#
|
|
||||||
# If neither of these conditions are met, #unauthorized is called.
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
env['rack.auth.openid'] = self
|
|
||||||
env_session = env[@session_key]
|
|
||||||
unless env_session and env_session.is_a?(Hash)
|
|
||||||
raise NoSession, 'No compatible session'
|
|
||||||
end
|
|
||||||
# let us work in our own namespace...
|
|
||||||
session = (env_session[:openid] ||= {})
|
|
||||||
unless session and session.is_a?(Hash)
|
|
||||||
raise NoSession, 'Incompatible openid session'
|
|
||||||
end
|
|
||||||
|
|
||||||
request = Rack::Request.new(env)
|
|
||||||
consumer = ::OpenID::Consumer.new(session, @store)
|
|
||||||
|
|
||||||
if mode = request.GET['openid.mode']
|
|
||||||
if session.key?(:openid_param)
|
|
||||||
finish(consumer, session, request)
|
|
||||||
else
|
|
||||||
bad_request
|
|
||||||
end
|
|
||||||
elsif request.GET[@openid_param]
|
|
||||||
check(consumer, session, request)
|
|
||||||
else
|
|
||||||
unauthorized
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# As the first part of OpenID consumer action, #check retrieves the data
|
|
||||||
# required for completion.
|
|
||||||
#
|
|
||||||
# If all parameters fit within the max length of a URI, a 303 redirect
|
|
||||||
# will be returned. Otherwise #confirm_post_params will be called.
|
|
||||||
#
|
|
||||||
# Any messages from OpenID's request are logged to env['rack.errors']
|
|
||||||
#
|
|
||||||
# <tt>env['rack.auth.openid.request']</tt> is the openid checkid request
|
|
||||||
# instance.
|
|
||||||
#
|
|
||||||
# <tt>session[:openid_param]</tt> is set to the openid identifier
|
|
||||||
# provided by the user.
|
|
||||||
#
|
|
||||||
# <tt>session[:return_to]</tt> is set to the return_to uri given to the
|
|
||||||
# identity provider.
|
|
||||||
|
|
||||||
def check(consumer, session, req)
|
|
||||||
oid = consumer.begin(req.GET[@openid_param], @anonymous)
|
|
||||||
req.env['rack.auth.openid.request'] = oid
|
|
||||||
req.env['rack.errors'].puts(oid.message)
|
|
||||||
p oid if $DEBUG
|
|
||||||
|
|
||||||
## Extension support
|
|
||||||
extensions.each do |ext,args|
|
|
||||||
oid.add_extension(ext::Request.new(*args))
|
|
||||||
end
|
|
||||||
|
|
||||||
session[:openid_param] = req.GET[openid_param]
|
|
||||||
return_to_uri = return_to ? return_to : req.url
|
|
||||||
session[:return_to] = return_to_uri
|
|
||||||
immediate = session.key?(:setup_needed) ? false : immediate
|
|
||||||
|
|
||||||
if oid.send_redirect?(realm, return_to_uri, immediate)
|
|
||||||
uri = oid.redirect_url(realm, return_to_uri, immediate)
|
|
||||||
redirect(uri)
|
|
||||||
else
|
|
||||||
confirm_post_params(oid, realm, return_to_uri, immediate)
|
|
||||||
end
|
|
||||||
rescue ::OpenID::DiscoveryFailure => e
|
|
||||||
# thrown from inside OpenID::Consumer#begin by yadis stuff
|
|
||||||
req.env['rack.errors'].puts([e.message, *e.backtrace]*"\n")
|
|
||||||
return foreign_server_failure
|
|
||||||
end
|
|
||||||
|
|
||||||
# This is the final portion of authentication.
|
|
||||||
# If successful, a redirect to the realm is be returned.
|
|
||||||
# Data gathered from extensions are stored in session[:openid] with the
|
|
||||||
# extension's namespace uri as the key.
|
|
||||||
#
|
|
||||||
# Any messages from OpenID's response are logged to env['rack.errors']
|
|
||||||
#
|
|
||||||
# <tt>env['rack.auth.openid.response']</tt> will contain the openid
|
|
||||||
# response.
|
|
||||||
|
|
||||||
def finish(consumer, session, req)
|
|
||||||
oid = consumer.complete(req.GET, req.url)
|
|
||||||
req.env['rack.auth.openid.response'] = oid
|
|
||||||
req.env['rack.errors'].puts(oid.message)
|
|
||||||
p oid if $DEBUG
|
|
||||||
|
|
||||||
raise unless ValidStatus.include?(oid.status)
|
|
||||||
__send__(oid.status, oid, req, session)
|
|
||||||
end
|
|
||||||
|
|
||||||
# The first argument should be the main extension module.
|
|
||||||
# The extension module should contain the constants:
|
|
||||||
# * class Request, should have OpenID::Extension as an ancestor
|
|
||||||
# * class Response, should have OpenID::Extension as an ancestor
|
|
||||||
# * string NS_URI, which defining the namespace of the extension
|
|
||||||
#
|
|
||||||
# All trailing arguments will be passed to extension::Request.new in
|
|
||||||
# #check.
|
|
||||||
# The openid response will be passed to
|
|
||||||
# extension::Response#from_success_response, #get_extension_args will be
|
|
||||||
# called on the result to attain the gathered data.
|
|
||||||
#
|
|
||||||
# This method returns the key at which the response data will be found in
|
|
||||||
# the session, which is the namespace uri by default.
|
|
||||||
|
|
||||||
def add_extension(ext, *args)
|
|
||||||
raise BadExtension unless valid_extension?(ext)
|
|
||||||
extensions[ext] = args
|
|
||||||
return ext::NS_URI
|
|
||||||
end
|
|
||||||
|
|
||||||
# Checks the validitity, in the context of usage, of a submitted
|
|
||||||
# extension.
|
|
||||||
|
|
||||||
def valid_extension?(ext)
|
|
||||||
if not %w[NS_URI Request Response].all?{|c| ext.const_defined?(c) }
|
|
||||||
raise ArgumentError, 'Extension is missing constants.'
|
|
||||||
elsif not ext::Response.respond_to?(:from_success_response)
|
|
||||||
raise ArgumentError, 'Response is missing required method.'
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
rescue
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Checks the provided uri to ensure it'd be considered within the realm.
|
|
||||||
# is currently not compatible with wildcard realms.
|
|
||||||
|
|
||||||
def within_realm? uri
|
|
||||||
uri = URI.parse(uri.to_s)
|
|
||||||
realm = URI.parse(self.realm)
|
|
||||||
return false unless uri.absolute?
|
|
||||||
return false unless uri.path[0, realm.path.size] == realm.path
|
|
||||||
return false unless uri.host == realm.host or realm.host[/^\*\./]
|
|
||||||
# for wildcard support, is awkward with URI limitations
|
|
||||||
realm_match = Regexp.escape(realm.host).
|
|
||||||
sub(/^\*\./,"^#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+.")+'$'
|
|
||||||
return false unless uri.host.match(realm_match)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
alias_method :include?, :within_realm?
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
### These methods define some of the boilerplate responses.
|
|
||||||
|
|
||||||
# Returns an html form page for posting to an Identity Provider if the
|
|
||||||
# GET request would exceed the upper URI length limit.
|
|
||||||
|
|
||||||
def confirm_post_params(oid, realm, return_to, immediate)
|
|
||||||
Rack::Response.new.finish do |r|
|
|
||||||
r.write '<html><head><title>Confirm...</title></head><body>'
|
|
||||||
r.write oid.form_markup(realm, return_to, immediate)
|
|
||||||
r.write '</body></html>'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a 303 redirect with the destination of that provided by the
|
|
||||||
# argument.
|
|
||||||
|
|
||||||
def redirect(uri)
|
|
||||||
[ 303, {'Content-Length'=>'0', 'Content-Type'=>'text/plain',
|
|
||||||
'Location' => uri},
|
|
||||||
[] ]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns an empty 400 response.
|
|
||||||
|
|
||||||
def bad_request
|
|
||||||
[ 400, {'Content-Type'=>'text/plain', 'Content-Length'=>'0'},
|
|
||||||
[''] ]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a basic unauthorized 401 response.
|
|
||||||
|
|
||||||
def unauthorized
|
|
||||||
[ 401, {'Content-Type' => 'text/plain', 'Content-Length' => '13'},
|
|
||||||
['Unauthorized.'] ]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a basic access denied 403 response.
|
|
||||||
|
|
||||||
def access_denied
|
|
||||||
[ 403, {'Content-Type' => 'text/plain', 'Content-Length' => '14'},
|
|
||||||
['Access denied.'] ]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a 503 response to be used if communication with the remote
|
|
||||||
# OpenID server fails.
|
|
||||||
|
|
||||||
def foreign_server_failure
|
|
||||||
[ 503, {'Content-Type'=>'text/plain', 'Content-Length' => '23'},
|
|
||||||
['Foreign server failure.'] ]
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
### These methods are called after a transaction is completed, depending
|
|
||||||
# on its outcome. These should all return a rack compatible response.
|
|
||||||
# You'd want to override these to provide additional functionality.
|
|
||||||
|
|
||||||
# Called to complete processing on a successful transaction.
|
|
||||||
# Within the openid session, :openid_identity and :openid_identifier are
|
|
||||||
# set to the user friendly and the standard representation of the
|
|
||||||
# validated identity. All other data in the openid session is cleared.
|
|
||||||
|
|
||||||
def success(oid, request, session)
|
|
||||||
session.clear
|
|
||||||
session[:openid_identity] = oid.display_identifier
|
|
||||||
session[:openid_identifier] = oid.identity_url
|
|
||||||
extensions.keys.each do |ext|
|
|
||||||
label = ext.name[/[^:]+$/].downcase
|
|
||||||
response = ext::Response.from_success_response(oid)
|
|
||||||
session[label] = response.data
|
|
||||||
end
|
|
||||||
redirect(realm)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Called if the Identity Provider indicates further setup by the user is
|
|
||||||
# required.
|
|
||||||
# The identifier is retrived from the openid session at :openid_param.
|
|
||||||
# And :setup_needed is set to true to prevent looping.
|
|
||||||
|
|
||||||
def setup_needed(oid, request, session)
|
|
||||||
identifier = session[:openid_param]
|
|
||||||
session[:setup_needed] = true
|
|
||||||
redirect req.script_name + '?' + openid_param + '=' + identifier
|
|
||||||
end
|
|
||||||
|
|
||||||
# Called if the user indicates they wish to cancel identification.
|
|
||||||
# Data within openid session is cleared.
|
|
||||||
|
|
||||||
def cancel(oid, request, session)
|
|
||||||
session.clear
|
|
||||||
access_denied
|
|
||||||
end
|
|
||||||
|
|
||||||
# Called if the Identity Provider indicates the user is unable to confirm
|
|
||||||
# their identity. Data within the openid session is left alone, in case
|
|
||||||
# of swarm auth attacks.
|
|
||||||
|
|
||||||
def failure(oid, request, session)
|
|
||||||
unauthorized
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# A class developed out of the request to use OpenID as an authentication
|
|
||||||
# middleware. The request will be sent to the OpenID instance unless the
|
|
||||||
# block evaluates to true. For example in rackup, you can use it as such:
|
|
||||||
#
|
|
||||||
# use Rack::Session::Pool
|
|
||||||
# use Rack::Auth::OpenIDAuth, realm, openid_options do |env|
|
|
||||||
# env['rack.session'][:authkey] == a_string
|
|
||||||
# end
|
|
||||||
# run RackApp
|
|
||||||
#
|
|
||||||
# Or simply:
|
|
||||||
#
|
|
||||||
# app = Rack::Auth::OpenIDAuth.new app, realm, openid_options, &auth
|
|
||||||
|
|
||||||
class OpenIDAuth < Rack::Auth::AbstractHandler
|
|
||||||
attr_reader :oid
|
|
||||||
def initialize(app, realm, options={}, &auth)
|
|
||||||
@oid = OpenID.new(realm, options)
|
|
||||||
super(app, &auth)
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
to = auth.call(env) ? @app : @oid
|
|
||||||
to.call env
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -13,7 +13,7 @@ module Rack
|
||||||
status, headers, body = @app.call(env)
|
status, headers, body = @app.call(env)
|
||||||
headers = HeaderHash.new(headers)
|
headers = HeaderHash.new(headers)
|
||||||
|
|
||||||
if !STATUS_WITH_NO_ENTITY_BODY.include?(status) &&
|
if !STATUS_WITH_NO_ENTITY_BODY.include?(status.to_i) &&
|
||||||
!headers['Content-Length'] &&
|
!headers['Content-Length'] &&
|
||||||
!headers['Transfer-Encoding'] &&
|
!headers['Transfer-Encoding'] &&
|
||||||
(body.respond_to?(:to_ary) || body.respond_to?(:to_str))
|
(body.respond_to?(:to_ary) || body.respond_to?(:to_str))
|
||||||
|
|
19
vendor/plugins/rack/lib/rack/etag.rb
vendored
19
vendor/plugins/rack/lib/rack/etag.rb
vendored
|
@ -11,13 +11,22 @@ module Rack
|
||||||
status, headers, body = @app.call(env)
|
status, headers, body = @app.call(env)
|
||||||
|
|
||||||
if !headers.has_key?('ETag')
|
if !headers.has_key?('ETag')
|
||||||
parts = []
|
digest, body = digest_body(body)
|
||||||
body.each { |part| parts << part.to_s }
|
headers['ETag'] = %("#{digest}")
|
||||||
headers['ETag'] = %("#{Digest::MD5.hexdigest(parts.join(""))}")
|
end
|
||||||
[status, headers, parts]
|
|
||||||
else
|
|
||||||
[status, headers, body]
|
[status, headers, body]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def digest_body(body)
|
||||||
|
digest = Digest::MD5.new
|
||||||
|
parts = []
|
||||||
|
body.each do |part|
|
||||||
|
digest << part
|
||||||
|
parts << part
|
||||||
|
end
|
||||||
|
[digest.hexdigest, parts]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
4
vendor/plugins/rack/lib/rack/file.rb
vendored
4
vendor/plugins/rack/lib/rack/file.rb
vendored
|
@ -3,8 +3,10 @@ require 'rack/utils'
|
||||||
require 'rack/mime'
|
require 'rack/mime'
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
# Rack::File serves files below the +root+ given, according to the
|
# Rack::File serves files below the +root+ directory given, according to the
|
||||||
# path info of the Rack request.
|
# path info of the Rack request.
|
||||||
|
# e.g. when Rack::File.new("/etc") is used, you can access 'passwd' file
|
||||||
|
# as http://localhost:9292/passwd
|
||||||
#
|
#
|
||||||
# Handlers can detect if bodies are a Rack::File, and use mechanisms
|
# Handlers can detect if bodies are a Rack::File, and use mechanisms
|
||||||
# like sendfile on the +path+.
|
# like sendfile on the +path+.
|
||||||
|
|
18
vendor/plugins/rack/lib/rack/handler/cgi.rb
vendored
18
vendor/plugins/rack/lib/rack/handler/cgi.rb
vendored
|
@ -1,9 +1,11 @@
|
||||||
require 'rack/content_length'
|
require 'rack/content_length'
|
||||||
|
require 'rack/rewindable_input'
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
module Handler
|
module Handler
|
||||||
class CGI
|
class CGI
|
||||||
def self.run(app, options=nil)
|
def self.run(app, options=nil)
|
||||||
|
$stdin.binmode
|
||||||
serve app
|
serve app
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -15,8 +17,8 @@ module Rack
|
||||||
|
|
||||||
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
|
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
|
||||||
|
|
||||||
env.update({"rack.version" => [1,1],
|
env.update({"rack.version" => Rack::VERSION,
|
||||||
"rack.input" => $stdin,
|
"rack.input" => Rack::RewindableInput.new($stdin),
|
||||||
"rack.errors" => $stderr,
|
"rack.errors" => $stderr,
|
||||||
|
|
||||||
"rack.multithread" => false,
|
"rack.multithread" => false,
|
||||||
|
@ -40,20 +42,20 @@ module Rack
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.send_headers(status, headers)
|
def self.send_headers(status, headers)
|
||||||
STDOUT.print "Status: #{status}\r\n"
|
$stdout.print "Status: #{status}\r\n"
|
||||||
headers.each { |k, vs|
|
headers.each { |k, vs|
|
||||||
vs.split("\n").each { |v|
|
vs.split("\n").each { |v|
|
||||||
STDOUT.print "#{k}: #{v}\r\n"
|
$stdout.print "#{k}: #{v}\r\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
STDOUT.print "\r\n"
|
$stdout.print "\r\n"
|
||||||
STDOUT.flush
|
$stdout.flush
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.send_body(body)
|
def self.send_body(body)
|
||||||
body.each { |part|
|
body.each { |part|
|
||||||
STDOUT.print part
|
$stdout.print part
|
||||||
STDOUT.flush
|
$stdout.flush
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,7 +36,7 @@ module Rack
|
||||||
|
|
||||||
rack_input = RewindableInput.new(request.in)
|
rack_input = RewindableInput.new(request.in)
|
||||||
|
|
||||||
env.update({"rack.version" => [1,1],
|
env.update({"rack.version" => Rack::VERSION,
|
||||||
"rack.input" => rack_input,
|
"rack.input" => rack_input,
|
||||||
"rack.errors" => request.err,
|
"rack.errors" => request.err,
|
||||||
|
|
||||||
|
|
2
vendor/plugins/rack/lib/rack/handler/lsws.rb
vendored
2
vendor/plugins/rack/lib/rack/handler/lsws.rb
vendored
|
@ -20,7 +20,7 @@ module Rack
|
||||||
rack_input = RewindableInput.new($stdin.read.to_s)
|
rack_input = RewindableInput.new($stdin.read.to_s)
|
||||||
|
|
||||||
env.update(
|
env.update(
|
||||||
"rack.version" => [1,1],
|
"rack.version" => Rack::VERSION,
|
||||||
"rack.input" => rack_input,
|
"rack.input" => rack_input,
|
||||||
"rack.errors" => $stderr,
|
"rack.errors" => $stderr,
|
||||||
"rack.multithread" => false,
|
"rack.multithread" => false,
|
||||||
|
|
|
@ -52,7 +52,7 @@ module Rack
|
||||||
rack_input = request.body || StringIO.new('')
|
rack_input = request.body || StringIO.new('')
|
||||||
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
||||||
|
|
||||||
env.update({"rack.version" => [1,1],
|
env.update({"rack.version" => Rack::VERSION,
|
||||||
"rack.input" => rack_input,
|
"rack.input" => rack_input,
|
||||||
"rack.errors" => $stderr,
|
"rack.errors" => $stderr,
|
||||||
|
|
||||||
|
|
5
vendor/plugins/rack/lib/rack/handler/scgi.rb
vendored
5
vendor/plugins/rack/lib/rack/handler/scgi.rb
vendored
|
@ -17,9 +17,6 @@ module Rack
|
||||||
|
|
||||||
def initialize(settings = {})
|
def initialize(settings = {})
|
||||||
@app = Rack::Chunked.new(Rack::ContentLength.new(settings[:app]))
|
@app = Rack::Chunked.new(Rack::ContentLength.new(settings[:app]))
|
||||||
@log = Object.new
|
|
||||||
def @log.info(*args); end
|
|
||||||
def @log.error(*args); end
|
|
||||||
super(settings)
|
super(settings)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -36,7 +33,7 @@ module Rack
|
||||||
rack_input = StringIO.new(input_body)
|
rack_input = StringIO.new(input_body)
|
||||||
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
||||||
|
|
||||||
env.update({"rack.version" => [1,1],
|
env.update({"rack.version" => Rack::VERSION,
|
||||||
"rack.input" => rack_input,
|
"rack.input" => rack_input,
|
||||||
"rack.errors" => $stderr,
|
"rack.errors" => $stderr,
|
||||||
"rack.multithread" => true,
|
"rack.multithread" => true,
|
||||||
|
|
17
vendor/plugins/rack/lib/rack/handler/webrick.rb
vendored
17
vendor/plugins/rack/lib/rack/handler/webrick.rb
vendored
|
@ -7,12 +7,15 @@ module Rack
|
||||||
class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet
|
class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet
|
||||||
def self.run(app, options={})
|
def self.run(app, options={})
|
||||||
options[:BindAddress] = options.delete(:Host) if options[:Host]
|
options[:BindAddress] = options.delete(:Host) if options[:Host]
|
||||||
server = ::WEBrick::HTTPServer.new(options)
|
@server = ::WEBrick::HTTPServer.new(options)
|
||||||
server.mount "/", Rack::Handler::WEBrick, app
|
@server.mount "/", Rack::Handler::WEBrick, app
|
||||||
trap(:INT) { server.shutdown }
|
yield @server if block_given?
|
||||||
trap(:TERM) { server.shutdown }
|
@server.start
|
||||||
yield server if block_given?
|
end
|
||||||
server.start
|
|
||||||
|
def self.shutdown
|
||||||
|
@server.shutdown
|
||||||
|
@server = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(server, app)
|
def initialize(server, app)
|
||||||
|
@ -27,7 +30,7 @@ module Rack
|
||||||
rack_input = StringIO.new(req.body.to_s)
|
rack_input = StringIO.new(req.body.to_s)
|
||||||
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
||||||
|
|
||||||
env.update({"rack.version" => [1,1],
|
env.update({"rack.version" => Rack::VERSION,
|
||||||
"rack.input" => rack_input,
|
"rack.input" => rack_input,
|
||||||
"rack.errors" => $stderr,
|
"rack.errors" => $stderr,
|
||||||
|
|
||||||
|
|
56
vendor/plugins/rack/lib/rack/lint.rb
vendored
56
vendor/plugins/rack/lib/rack/lint.rb
vendored
|
@ -7,6 +7,7 @@ module Rack
|
||||||
class Lint
|
class Lint
|
||||||
def initialize(app)
|
def initialize(app)
|
||||||
@app = app
|
@app = app
|
||||||
|
@content_length = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# :stopdoc:
|
# :stopdoc:
|
||||||
|
@ -51,15 +52,16 @@ module Rack
|
||||||
check_headers headers
|
check_headers headers
|
||||||
## and the *body*.
|
## and the *body*.
|
||||||
check_content_type status, headers
|
check_content_type status, headers
|
||||||
check_content_length status, headers, env
|
check_content_length status, headers
|
||||||
|
@head_request = env["REQUEST_METHOD"] == "HEAD"
|
||||||
[status, headers, self]
|
[status, headers, self]
|
||||||
end
|
end
|
||||||
|
|
||||||
## == The Environment
|
## == The Environment
|
||||||
def check_env(env)
|
def check_env(env)
|
||||||
## The environment must be an true instance of Hash (no
|
## The environment must be an instance of Hash that includes
|
||||||
## subclassing allowed) that includes CGI-like headers.
|
## CGI-like headers. The application is free to modify the
|
||||||
## The application is free to modify the environment.
|
## environment.
|
||||||
assert("env #{env.inspect} is not a Hash, but #{env.class}") {
|
assert("env #{env.inspect} is not a Hash, but #{env.class}") {
|
||||||
env.kind_of? Hash
|
env.kind_of? Hash
|
||||||
}
|
}
|
||||||
|
@ -288,10 +290,6 @@ module Rack
|
||||||
@input = input
|
@input = input
|
||||||
end
|
end
|
||||||
|
|
||||||
def size
|
|
||||||
@input.size
|
|
||||||
end
|
|
||||||
|
|
||||||
## * +gets+ must be called without arguments and return a string,
|
## * +gets+ must be called without arguments and return a string,
|
||||||
## or +nil+ on EOF.
|
## or +nil+ on EOF.
|
||||||
def gets(*args)
|
def gets(*args)
|
||||||
|
@ -481,7 +479,7 @@ module Rack
|
||||||
end
|
end
|
||||||
|
|
||||||
## === The Content-Length
|
## === The Content-Length
|
||||||
def check_content_length(status, headers, env)
|
def check_content_length(status, headers)
|
||||||
headers.each { |key, value|
|
headers.each { |key, value|
|
||||||
if key.downcase == 'content-length'
|
if key.downcase == 'content-length'
|
||||||
## There must not be a <tt>Content-Length</tt> header when the
|
## There must not be a <tt>Content-Length</tt> header when the
|
||||||
|
@ -489,49 +487,43 @@ module Rack
|
||||||
assert("Content-Length header found in #{status} response, not allowed") {
|
assert("Content-Length header found in #{status} response, not allowed") {
|
||||||
not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
|
not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
|
||||||
}
|
}
|
||||||
|
@content_length = value
|
||||||
bytes = 0
|
end
|
||||||
string_body = true
|
}
|
||||||
|
|
||||||
if @body.respond_to?(:to_ary)
|
|
||||||
@body.each { |part|
|
|
||||||
unless part.kind_of?(String)
|
|
||||||
string_body = false
|
|
||||||
break
|
|
||||||
end
|
end
|
||||||
|
|
||||||
bytes += Rack::Utils.bytesize(part)
|
def verify_content_length(bytes)
|
||||||
}
|
if @head_request
|
||||||
|
|
||||||
if env["REQUEST_METHOD"] == "HEAD"
|
|
||||||
assert("Response body was given for HEAD request, but should be empty") {
|
assert("Response body was given for HEAD request, but should be empty") {
|
||||||
bytes == 0
|
bytes == 0
|
||||||
}
|
}
|
||||||
else
|
elsif @content_length
|
||||||
if string_body
|
assert("Content-Length header was #{@content_length}, but should be #{bytes}") {
|
||||||
assert("Content-Length header was #{value}, but should be #{bytes}") {
|
@content_length == bytes.to_s
|
||||||
value == bytes.to_s
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
return
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
## === The Body
|
## === The Body
|
||||||
def each
|
def each
|
||||||
@closed = false
|
@closed = false
|
||||||
|
bytes = 0
|
||||||
|
|
||||||
## The Body must respond to +each+
|
## The Body must respond to +each+
|
||||||
|
assert("Response body must respond to each") do
|
||||||
|
@body.respond_to?(:each)
|
||||||
|
end
|
||||||
|
|
||||||
@body.each { |part|
|
@body.each { |part|
|
||||||
## and must only yield String values.
|
## and must only yield String values.
|
||||||
assert("Body yielded non-string value #{part.inspect}") {
|
assert("Body yielded non-string value #{part.inspect}") {
|
||||||
part.kind_of? String
|
part.kind_of? String
|
||||||
}
|
}
|
||||||
|
bytes += Rack::Utils.bytesize(part)
|
||||||
yield part
|
yield part
|
||||||
}
|
}
|
||||||
|
verify_content_length(bytes)
|
||||||
|
|
||||||
##
|
##
|
||||||
## The Body itself should not be an instance of String, as this will
|
## The Body itself should not be an instance of String, as this will
|
||||||
## break in Ruby 1.9.
|
## break in Ruby 1.9.
|
||||||
|
|
2
vendor/plugins/rack/lib/rack/mime.rb
vendored
2
vendor/plugins/rack/lib/rack/mime.rb
vendored
|
@ -87,6 +87,7 @@ module Rack
|
||||||
".gif" => "image/gif",
|
".gif" => "image/gif",
|
||||||
".gz" => "application/x-gzip",
|
".gz" => "application/x-gzip",
|
||||||
".h" => "text/x-c",
|
".h" => "text/x-c",
|
||||||
|
".htc" => "text/x-component",
|
||||||
".hh" => "text/x-c",
|
".hh" => "text/x-c",
|
||||||
".htm" => "text/html",
|
".htm" => "text/html",
|
||||||
".html" => "text/html",
|
".html" => "text/html",
|
||||||
|
@ -186,6 +187,7 @@ module Rack
|
||||||
".vrml" => "model/vrml",
|
".vrml" => "model/vrml",
|
||||||
".war" => "application/java-archive",
|
".war" => "application/java-archive",
|
||||||
".wav" => "audio/x-wav",
|
".wav" => "audio/x-wav",
|
||||||
|
".webm" => "video/webm",
|
||||||
".wma" => "audio/x-ms-wma",
|
".wma" => "audio/x-ms-wma",
|
||||||
".wmv" => "video/x-ms-wmv",
|
".wmv" => "video/x-ms-wmv",
|
||||||
".wmx" => "video/x-ms-wmx",
|
".wmx" => "video/x-ms-wmx",
|
||||||
|
|
3
vendor/plugins/rack/lib/rack/mock.rb
vendored
3
vendor/plugins/rack/lib/rack/mock.rb
vendored
|
@ -1,5 +1,6 @@
|
||||||
require 'uri'
|
require 'uri'
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
|
require 'rack'
|
||||||
require 'rack/lint'
|
require 'rack/lint'
|
||||||
require 'rack/utils'
|
require 'rack/utils'
|
||||||
require 'rack/response'
|
require 'rack/response'
|
||||||
|
@ -40,7 +41,7 @@ module Rack
|
||||||
end
|
end
|
||||||
|
|
||||||
DEFAULT_ENV = {
|
DEFAULT_ENV = {
|
||||||
"rack.version" => [1,1],
|
"rack.version" => Rack::VERSION,
|
||||||
"rack.input" => StringIO.new,
|
"rack.input" => StringIO.new,
|
||||||
"rack.errors" => StringIO.new,
|
"rack.errors" => StringIO.new,
|
||||||
"rack.multithread" => true,
|
"rack.multithread" => true,
|
||||||
|
|
4
vendor/plugins/rack/lib/rack/recursive.rb
vendored
4
vendor/plugins/rack/lib/rack/recursive.rb
vendored
|
@ -35,6 +35,10 @@ module Rack
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
|
dup._call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
def _call(env)
|
||||||
@script_name = env["SCRIPT_NAME"]
|
@script_name = env["SCRIPT_NAME"]
|
||||||
@app.call(env.merge('rack.recursive.include' => method(:include)))
|
@app.call(env.merge('rack.recursive.include' => method(:include)))
|
||||||
rescue ForwardRequest => req
|
rescue ForwardRequest => req
|
||||||
|
|
8
vendor/plugins/rack/lib/rack/request.rb
vendored
8
vendor/plugins/rack/lib/rack/request.rb
vendored
|
@ -80,11 +80,13 @@ module Rack
|
||||||
def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end
|
def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end
|
||||||
def path_info=(s); @env["PATH_INFO"] = s.to_s end
|
def path_info=(s); @env["PATH_INFO"] = s.to_s end
|
||||||
|
|
||||||
|
def delete?; request_method == "DELETE" end
|
||||||
def get?; request_method == "GET" end
|
def get?; request_method == "GET" end
|
||||||
|
def head?; request_method == "HEAD" end
|
||||||
|
def options?; request_method == "OPTIONS" end
|
||||||
def post?; request_method == "POST" end
|
def post?; request_method == "POST" end
|
||||||
def put?; request_method == "PUT" end
|
def put?; request_method == "PUT" end
|
||||||
def delete?; request_method == "DELETE" end
|
def trace?; request_method == "TRACE" end
|
||||||
def head?; request_method == "HEAD" end
|
|
||||||
|
|
||||||
# The set of form-data media-types. Requests that do not indicate
|
# The set of form-data media-types. Requests that do not indicate
|
||||||
# one of the media types presents in this list will not be eligible
|
# one of the media types presents in this list will not be eligible
|
||||||
|
@ -253,7 +255,7 @@ module Rack
|
||||||
|
|
||||||
def ip
|
def ip
|
||||||
if addr = @env['HTTP_X_FORWARDED_FOR']
|
if addr = @env['HTTP_X_FORWARDED_FOR']
|
||||||
addr.split(',').last.strip
|
(addr.split(',').grep(/\d\./).first || @env['REMOTE_ADDR']).to_s.strip
|
||||||
else
|
else
|
||||||
@env['REMOTE_ADDR']
|
@env['REMOTE_ADDR']
|
||||||
end
|
end
|
||||||
|
|
1
vendor/plugins/rack/lib/rack/response.rb
vendored
1
vendor/plugins/rack/lib/rack/response.rb
vendored
|
@ -1,5 +1,6 @@
|
||||||
require 'rack/request'
|
require 'rack/request'
|
||||||
require 'rack/utils'
|
require 'rack/utils'
|
||||||
|
require 'time'
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
# Rack::Response provides a convenient interface to create a Rack
|
# Rack::Response provides a convenient interface to create a Rack
|
||||||
|
|
17
vendor/plugins/rack/lib/rack/rewindable_input.rb
vendored
17
vendor/plugins/rack/lib/rack/rewindable_input.rb
vendored
|
@ -1,4 +1,6 @@
|
||||||
|
# -*- encoding: binary -*-
|
||||||
require 'tempfile'
|
require 'tempfile'
|
||||||
|
require 'rack/utils'
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
# Class which can make any IO object rewindable, including non-rewindable ones. It does
|
# Class which can make any IO object rewindable, including non-rewindable ones. It does
|
||||||
|
@ -74,8 +76,9 @@ module Rack
|
||||||
@rewindable_io.chmod(0000)
|
@rewindable_io.chmod(0000)
|
||||||
@rewindable_io.set_encoding(Encoding::BINARY) if @rewindable_io.respond_to?(:set_encoding)
|
@rewindable_io.set_encoding(Encoding::BINARY) if @rewindable_io.respond_to?(:set_encoding)
|
||||||
@rewindable_io.binmode
|
@rewindable_io.binmode
|
||||||
if filesystem_has_posix_semantics? && !tempfile_unlink_contains_bug?
|
if filesystem_has_posix_semantics?
|
||||||
@rewindable_io.unlink
|
@rewindable_io.unlink
|
||||||
|
raise 'Unlink failed. IO closed.' if @rewindable_io.closed?
|
||||||
@unlinked = true
|
@unlinked = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -84,7 +87,7 @@ module Rack
|
||||||
entire_buffer_written_out = false
|
entire_buffer_written_out = false
|
||||||
while !entire_buffer_written_out
|
while !entire_buffer_written_out
|
||||||
written = @rewindable_io.write(buffer)
|
written = @rewindable_io.write(buffer)
|
||||||
entire_buffer_written_out = written == buffer.size
|
entire_buffer_written_out = written == Rack::Utils.bytesize(buffer)
|
||||||
if !entire_buffer_written_out
|
if !entire_buffer_written_out
|
||||||
buffer.slice!(0 .. written - 1)
|
buffer.slice!(0 .. written - 1)
|
||||||
end
|
end
|
||||||
|
@ -96,15 +99,5 @@ module Rack
|
||||||
def filesystem_has_posix_semantics?
|
def filesystem_has_posix_semantics?
|
||||||
RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/
|
RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/
|
||||||
end
|
end
|
||||||
|
|
||||||
def tempfile_unlink_contains_bug?
|
|
||||||
# The tempfile library as included in Ruby 1.9.1-p152 and later
|
|
||||||
# contains a bug: unlinking an open Tempfile object also closes
|
|
||||||
# it, which breaks our expected POSIX semantics. This problem
|
|
||||||
# has been fixed in Ruby 1.9.2, but the Ruby team chose not to
|
|
||||||
# include the bug fix in later versions of the 1.9.1 series.
|
|
||||||
ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
|
|
||||||
ruby_engine == "ruby" && RUBY_VERSION == "1.9.1" && RUBY_PATCHLEVEL >= 152
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
12
vendor/plugins/rack/lib/rack/sendfile.rb
vendored
12
vendor/plugins/rack/lib/rack/sendfile.rb
vendored
|
@ -2,8 +2,10 @@ require 'rack/file'
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
class File #:nodoc:
|
class File #:nodoc:
|
||||||
|
unless instance_methods(false).include?('to_path')
|
||||||
alias :to_path :path
|
alias :to_path :path
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# = Sendfile
|
# = Sendfile
|
||||||
#
|
#
|
||||||
|
@ -11,7 +13,7 @@ module Rack
|
||||||
# served from a file and replaces it with a server specific X-Sendfile
|
# served from a file and replaces it with a server specific X-Sendfile
|
||||||
# header. The web server is then responsible for writing the file contents
|
# header. The web server is then responsible for writing the file contents
|
||||||
# to the client. This can dramatically reduce the amount of work required
|
# to the client. This can dramatically reduce the amount of work required
|
||||||
# by the Ruby backend and takes advantage of the web servers optimized file
|
# by the Ruby backend and takes advantage of the web server's optimized file
|
||||||
# delivery code.
|
# delivery code.
|
||||||
#
|
#
|
||||||
# In order to take advantage of this middleware, the response body must
|
# In order to take advantage of this middleware, the response body must
|
||||||
|
@ -31,19 +33,19 @@ module Rack
|
||||||
# a private "/files/" area, enable X-Accel-Redirect, and pass the special
|
# a private "/files/" area, enable X-Accel-Redirect, and pass the special
|
||||||
# X-Sendfile-Type and X-Accel-Mapping headers to the backend:
|
# X-Sendfile-Type and X-Accel-Mapping headers to the backend:
|
||||||
#
|
#
|
||||||
# location /files/ {
|
# location ~ /files/(.*) {
|
||||||
# internal;
|
# internal;
|
||||||
# alias /var/www/;
|
# alias /var/www/$1;
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# location / {
|
# location / {
|
||||||
# proxy_redirect false;
|
# proxy_redirect off;
|
||||||
#
|
#
|
||||||
# proxy_set_header Host $host;
|
# proxy_set_header Host $host;
|
||||||
# proxy_set_header X-Real-IP $remote_addr;
|
# proxy_set_header X-Real-IP $remote_addr;
|
||||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
#
|
#
|
||||||
# proxy_set_header X-Sendfile-Type X-Accel-Redirect
|
# proxy_set_header X-Sendfile-Type X-Accel-Redirect;
|
||||||
# proxy_set_header X-Accel-Mapping /files/=/var/www/;
|
# proxy_set_header X-Accel-Mapping /files/=/var/www/;
|
||||||
#
|
#
|
||||||
# proxy_pass http://127.0.0.1:8080/;
|
# proxy_pass http://127.0.0.1:8080/;
|
||||||
|
|
83
vendor/plugins/rack/lib/rack/server.rb
vendored
83
vendor/plugins/rack/lib/rack/server.rb
vendored
|
@ -57,7 +57,7 @@ module Rack
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.on("-P", "--pid FILE", "file to store PID (default: rack.pid)") { |f|
|
opts.on("-P", "--pid FILE", "file to store PID (default: rack.pid)") { |f|
|
||||||
options[:pid] = ::File.expand_path(f)
|
options[:pid] = f
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.separator ""
|
opts.separator ""
|
||||||
|
@ -74,17 +74,66 @@ module Rack
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
opt_parser.parse! args
|
opt_parser.parse! args
|
||||||
options[:rack_file] = args.last if args.last
|
options[:config] = args.last if args.last
|
||||||
options
|
options
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.start
|
# Start a new rack server (like running rackup). This will parse ARGV and
|
||||||
new.start
|
# provide standard ARGV rackup options, defaulting to load 'config.ru'.
|
||||||
|
#
|
||||||
|
# Providing an options hash will prevent ARGV parsing and will not include
|
||||||
|
# any default options.
|
||||||
|
#
|
||||||
|
# This method can be used to very easily launch a CGI application, for
|
||||||
|
# example:
|
||||||
|
#
|
||||||
|
# Rack::Server.start(
|
||||||
|
# :app => lambda do |e|
|
||||||
|
# [200, {'Content-Type' => 'text/html'}, ['hello world']]
|
||||||
|
# end,
|
||||||
|
# :server => 'cgi'
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# Further options available here are documented on Rack::Server#initialize
|
||||||
|
def self.start(options = nil)
|
||||||
|
new(options).start
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_accessor :options
|
attr_writer :options
|
||||||
|
|
||||||
|
# Options may include:
|
||||||
|
# * :app
|
||||||
|
# a rack application to run (overrides :config)
|
||||||
|
# * :config
|
||||||
|
# a rackup configuration file path to load (.ru)
|
||||||
|
# * :environment
|
||||||
|
# this selects the middleware that will be wrapped around
|
||||||
|
# your application. Default options available are:
|
||||||
|
# - development: CommonLogger, ShowExceptions, and Lint
|
||||||
|
# - deployment: CommonLogger
|
||||||
|
# - none: no extra middleware
|
||||||
|
# note: when the server is a cgi server, CommonLogger is not included.
|
||||||
|
# * :server
|
||||||
|
# choose a specific Rack::Handler, e.g. cgi, fcgi, webrick
|
||||||
|
# * :daemonize
|
||||||
|
# if true, the server will daemonize itself (fork, detach, etc)
|
||||||
|
# * :pid
|
||||||
|
# path to write a pid file after daemonize
|
||||||
|
# * :Host
|
||||||
|
# the host address to bind to (used by supporting Rack::Handler)
|
||||||
|
# * :Port
|
||||||
|
# the port to bind to (used by supporting Rack::Handler)
|
||||||
|
# * :AccessLog
|
||||||
|
# webrick acess log options (or supporting Rack::Handler)
|
||||||
|
# * :debug
|
||||||
|
# turn on debug output ($DEBUG = true)
|
||||||
|
# * :warn
|
||||||
|
# turn on warnings ($-w = true)
|
||||||
|
# * :include
|
||||||
|
# add given paths to $LOAD_PATH
|
||||||
|
# * :require
|
||||||
|
# require the given libraries
|
||||||
def initialize(options = nil)
|
def initialize(options = nil)
|
||||||
@options = options
|
@options = options
|
||||||
end
|
end
|
||||||
|
@ -100,17 +149,17 @@ module Rack
|
||||||
:Port => 9292,
|
:Port => 9292,
|
||||||
:Host => "0.0.0.0",
|
:Host => "0.0.0.0",
|
||||||
:AccessLog => [],
|
:AccessLog => [],
|
||||||
:rack_file => ::File.expand_path("config.ru")
|
:config => "config.ru"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def app
|
def app
|
||||||
@app ||= begin
|
@app ||= begin
|
||||||
if !::File.exist? options[:rack_file]
|
if !::File.exist? options[:config]
|
||||||
abort "configuration #{options[:rack_file]} not found"
|
abort "configuration #{options[:config]} not found"
|
||||||
end
|
end
|
||||||
|
|
||||||
app, options = Rack::Builder.parse_file(self.options[:rack_file], opt_parser)
|
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
|
||||||
self.options.merge! options
|
self.options.merge! options
|
||||||
app
|
app
|
||||||
end
|
end
|
||||||
|
@ -119,7 +168,7 @@ module Rack
|
||||||
def self.middleware
|
def self.middleware
|
||||||
@middleware ||= begin
|
@middleware ||= begin
|
||||||
m = Hash.new {|h,k| h[k] = []}
|
m = Hash.new {|h,k| h[k] = []}
|
||||||
m["deployment"].concat [lambda {|server| server.server =~ /CGI/ ? nil : [Rack::CommonLogger, $stderr] }]
|
m["deployment"].concat [lambda {|server| server.server.name =~ /CGI/ ? nil : [Rack::CommonLogger, $stderr] }]
|
||||||
m["development"].concat m["deployment"] + [[Rack::ShowExceptions], [Rack::Lint]]
|
m["development"].concat m["deployment"] + [[Rack::ShowExceptions], [Rack::Lint]]
|
||||||
m
|
m
|
||||||
end
|
end
|
||||||
|
@ -143,7 +192,7 @@ module Rack
|
||||||
end
|
end
|
||||||
|
|
||||||
if includes = options[:include]
|
if includes = options[:include]
|
||||||
$LOAD_PATH.unshift *includes
|
$LOAD_PATH.unshift(*includes)
|
||||||
end
|
end
|
||||||
|
|
||||||
if library = options[:require]
|
if library = options[:require]
|
||||||
|
@ -152,11 +201,20 @@ module Rack
|
||||||
|
|
||||||
daemonize_app if options[:daemonize]
|
daemonize_app if options[:daemonize]
|
||||||
write_pid if options[:pid]
|
write_pid if options[:pid]
|
||||||
|
|
||||||
|
trap(:INT) do
|
||||||
|
if server.respond_to?(:shutdown)
|
||||||
|
server.shutdown
|
||||||
|
else
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
server.run wrapped_app, options
|
server.run wrapped_app, options
|
||||||
end
|
end
|
||||||
|
|
||||||
def server
|
def server
|
||||||
@_server ||= Rack::Handler.get(options[:server]) || Rack::Handler.default
|
@_server ||= Rack::Handler.get(options[:server]) || Rack::Handler.default(options)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -168,6 +226,7 @@ module Rack
|
||||||
args.clear if ENV.include?("REQUEST_METHOD")
|
args.clear if ENV.include?("REQUEST_METHOD")
|
||||||
|
|
||||||
options.merge! opt_parser.parse! args
|
options.merge! opt_parser.parse! args
|
||||||
|
ENV["RACK_ENV"] = options[:environment]
|
||||||
options
|
options
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ module Rack
|
||||||
@mutex = Mutex.new
|
@mutex = Mutex.new
|
||||||
mserv = @default_options[:memcache_server]
|
mserv = @default_options[:memcache_server]
|
||||||
mopts = @default_options.
|
mopts = @default_options.
|
||||||
reject{|k,v| MemCache::DEFAULT_OPTIONS.include? k }
|
reject{|k,v| !MemCache::DEFAULT_OPTIONS.include? k }
|
||||||
@pool = MemCache.new mserv, mopts
|
@pool = MemCache.new mserv, mopts
|
||||||
unless @pool.active? and @pool.servers.any?{|c| c.alive? }
|
unless @pool.active? and @pool.servers.any?{|c| c.alive? }
|
||||||
raise 'No memcache servers'
|
raise 'No memcache servers'
|
||||||
|
|
13
vendor/plugins/rack/lib/rack/urlmap.rb
vendored
13
vendor/plugins/rack/lib/rack/urlmap.rb
vendored
|
@ -35,21 +35,20 @@ module Rack
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
path = env["PATH_INFO"].to_s
|
path = env["PATH_INFO"]
|
||||||
script_name = env['SCRIPT_NAME']
|
script_name = env['SCRIPT_NAME']
|
||||||
hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT')
|
hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT')
|
||||||
@mapping.each { |host, location, match, app|
|
@mapping.each { |host, location, match, app|
|
||||||
next unless (hHost == host || sName == host \
|
next unless (hHost == host || sName == host \
|
||||||
|| (host.nil? && (hHost == sName || hHost == sName+':'+sPort)))
|
|| (host.nil? && (hHost == sName || hHost == sName+':'+sPort)))
|
||||||
next unless path =~ match && rest = $1
|
next unless path.to_s =~ match && rest = $1
|
||||||
next unless rest.empty? || rest[0] == ?/
|
next unless rest.empty? || rest[0] == ?/
|
||||||
|
env.merge!('SCRIPT_NAME' => (script_name + location), 'PATH_INFO' => rest)
|
||||||
return app.call(
|
return app.call(env)
|
||||||
env.merge(
|
|
||||||
'SCRIPT_NAME' => (script_name + location),
|
|
||||||
'PATH_INFO' => rest))
|
|
||||||
}
|
}
|
||||||
[404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]]
|
[404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]]
|
||||||
|
ensure
|
||||||
|
env.merge! 'PATH_INFO' => path, 'SCRIPT_NAME' => script_name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
99
vendor/plugins/rack/lib/rack/utils.rb
vendored
99
vendor/plugins/rack/lib/rack/utils.rb
vendored
|
@ -1,5 +1,6 @@
|
||||||
# -*- encoding: binary -*-
|
# -*- encoding: binary -*-
|
||||||
|
|
||||||
|
require 'fileutils'
|
||||||
require 'set'
|
require 'set'
|
||||||
require 'tempfile'
|
require 'tempfile'
|
||||||
|
|
||||||
|
@ -38,9 +39,6 @@ module Rack
|
||||||
|
|
||||||
(qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
|
(qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
|
||||||
k, v = p.split('=', 2).map { |x| unescape(x) }
|
k, v = p.split('=', 2).map { |x| unescape(x) }
|
||||||
if v =~ /^("|')(.*)\1$/
|
|
||||||
v = $2.gsub('\\'+$1, $1)
|
|
||||||
end
|
|
||||||
if cur = params[k]
|
if cur = params[k]
|
||||||
if cur.class == Array
|
if cur.class == Array
|
||||||
params[k] << v
|
params[k] << v
|
||||||
|
@ -69,9 +67,6 @@ module Rack
|
||||||
module_function :parse_nested_query
|
module_function :parse_nested_query
|
||||||
|
|
||||||
def normalize_params(params, name, v = nil)
|
def normalize_params(params, name, v = nil)
|
||||||
if v and v =~ /^("|')(.*)\1$/
|
|
||||||
v = $2.gsub('\\'+$1, $1)
|
|
||||||
end
|
|
||||||
name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
|
name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
|
||||||
k = $1 || ''
|
k = $1 || ''
|
||||||
after = $' || ''
|
after = $' || ''
|
||||||
|
@ -133,13 +128,18 @@ module Rack
|
||||||
end
|
end
|
||||||
module_function :build_nested_query
|
module_function :build_nested_query
|
||||||
|
|
||||||
|
ESCAPE_HTML = {
|
||||||
|
"&" => "&",
|
||||||
|
"<" => "<",
|
||||||
|
">" => ">",
|
||||||
|
"'" => "'",
|
||||||
|
'"' => """,
|
||||||
|
}
|
||||||
|
ESCAPE_HTML_PATTERN = Regexp.union(ESCAPE_HTML.keys)
|
||||||
|
|
||||||
# Escape ampersands, brackets and quotes to their HTML/XML entities.
|
# Escape ampersands, brackets and quotes to their HTML/XML entities.
|
||||||
def escape_html(string)
|
def escape_html(string)
|
||||||
string.to_s.gsub("&", "&").
|
string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
|
||||||
gsub("<", "<").
|
|
||||||
gsub(">", ">").
|
|
||||||
gsub("'", "'").
|
|
||||||
gsub('"', """)
|
|
||||||
end
|
end
|
||||||
module_function :escape_html
|
module_function :escape_html
|
||||||
|
|
||||||
|
@ -180,8 +180,8 @@ module Rack
|
||||||
path = "; path=" + value[:path] if value[:path]
|
path = "; path=" + value[:path] if value[:path]
|
||||||
# According to RFC 2109, we need dashes here.
|
# According to RFC 2109, we need dashes here.
|
||||||
# N.B.: cgi.rb uses spaces...
|
# N.B.: cgi.rb uses spaces...
|
||||||
expires = "; expires=" + value[:expires].clone.gmtime.
|
expires = "; expires=" +
|
||||||
strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires]
|
rfc2822(value[:expires].clone.gmtime) if value[:expires]
|
||||||
secure = "; secure" if value[:secure]
|
secure = "; secure" if value[:secure]
|
||||||
httponly = "; HttpOnly" if value[:httponly]
|
httponly = "; HttpOnly" if value[:httponly]
|
||||||
value = value[:value]
|
value = value[:value]
|
||||||
|
@ -192,12 +192,12 @@ module Rack
|
||||||
"#{domain}#{path}#{expires}#{secure}#{httponly}"
|
"#{domain}#{path}#{expires}#{secure}#{httponly}"
|
||||||
|
|
||||||
case header["Set-Cookie"]
|
case header["Set-Cookie"]
|
||||||
when Array
|
when nil, ''
|
||||||
header["Set-Cookie"] << cookie
|
|
||||||
when String
|
|
||||||
header["Set-Cookie"] = [header["Set-Cookie"], cookie]
|
|
||||||
when nil
|
|
||||||
header["Set-Cookie"] = cookie
|
header["Set-Cookie"] = cookie
|
||||||
|
when String
|
||||||
|
header["Set-Cookie"] = [header["Set-Cookie"], cookie].join("\n")
|
||||||
|
when Array
|
||||||
|
header["Set-Cookie"] = (header["Set-Cookie"] + [cookie]).join("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
nil
|
nil
|
||||||
|
@ -205,14 +205,25 @@ module Rack
|
||||||
module_function :set_cookie_header!
|
module_function :set_cookie_header!
|
||||||
|
|
||||||
def delete_cookie_header!(header, key, value = {})
|
def delete_cookie_header!(header, key, value = {})
|
||||||
unless Array === header["Set-Cookie"]
|
case header["Set-Cookie"]
|
||||||
header["Set-Cookie"] = [header["Set-Cookie"]].compact
|
when nil, ''
|
||||||
|
cookies = []
|
||||||
|
when String
|
||||||
|
cookies = header["Set-Cookie"].split("\n")
|
||||||
|
when Array
|
||||||
|
cookies = header["Set-Cookie"]
|
||||||
end
|
end
|
||||||
|
|
||||||
header["Set-Cookie"].reject! { |cookie|
|
cookies.reject! { |cookie|
|
||||||
|
if value[:domain]
|
||||||
|
cookie =~ /\A#{escape(key)}=.*domain=#{value[:domain]}/
|
||||||
|
else
|
||||||
cookie =~ /\A#{escape(key)}=/
|
cookie =~ /\A#{escape(key)}=/
|
||||||
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header["Set-Cookie"] = cookies.join("\n")
|
||||||
|
|
||||||
set_cookie_header!(header, key,
|
set_cookie_header!(header, key,
|
||||||
{:value => '', :path => nil, :domain => nil,
|
{:value => '', :path => nil, :domain => nil,
|
||||||
:expires => Time.at(0) }.merge(value))
|
:expires => Time.at(0) }.merge(value))
|
||||||
|
@ -234,6 +245,22 @@ module Rack
|
||||||
end
|
end
|
||||||
module_function :bytesize
|
module_function :bytesize
|
||||||
|
|
||||||
|
# Modified version of stdlib time.rb Time#rfc2822 to use '%d-%b-%Y' instead
|
||||||
|
# of '% %b %Y'.
|
||||||
|
# It assumes that the time is in GMT to comply to the RFC 2109.
|
||||||
|
#
|
||||||
|
# NOTE: I'm not sure the RFC says it requires GMT, but is ambigous enough
|
||||||
|
# that I'm certain someone implemented only that option.
|
||||||
|
# Do not use %a and %b from Time.strptime, it would use localized names for
|
||||||
|
# weekday and month.
|
||||||
|
#
|
||||||
|
def rfc2822(time)
|
||||||
|
wday = Time::RFC2822_DAY_NAME[time.wday]
|
||||||
|
mon = Time::RFC2822_MONTH_NAME[time.mon - 1]
|
||||||
|
time.strftime("#{wday}, %d-#{mon}-%Y %T GMT")
|
||||||
|
end
|
||||||
|
module_function :rfc2822
|
||||||
|
|
||||||
# Context allows the use of a compatible middleware at different points
|
# Context allows the use of a compatible middleware at different points
|
||||||
# in a request handling stack. A compatible middleware must define
|
# in a request handling stack. A compatible middleware must define
|
||||||
# #context which should take the arguments env and app. The first of which
|
# #context which should take the arguments env and app. The first of which
|
||||||
|
@ -291,7 +318,8 @@ module Rack
|
||||||
end
|
end
|
||||||
|
|
||||||
def [](k)
|
def [](k)
|
||||||
super(@names[k] ||= @names[k.downcase])
|
super(@names[k]) if @names[k]
|
||||||
|
super(@names[k.downcase])
|
||||||
end
|
end
|
||||||
|
|
||||||
def []=(k, v)
|
def []=(k, v)
|
||||||
|
@ -478,11 +506,31 @@ module Rack
|
||||||
head = buf.slice!(0, i+2) # First \r\n
|
head = buf.slice!(0, i+2) # First \r\n
|
||||||
buf.slice!(0, 2) # Second \r\n
|
buf.slice!(0, 2) # Second \r\n
|
||||||
|
|
||||||
filename = head[/Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;\s]*))/ni, 1]
|
token = /[^\s()<>,;:\\"\/\[\]?=]+/
|
||||||
|
condisp = /Content-Disposition:\s*#{token}\s*/i
|
||||||
|
dispparm = /;\s*(#{token})=("(?:\\"|[^"])*"|#{token})*/
|
||||||
|
|
||||||
|
rfc2183 = /^#{condisp}(#{dispparm})+$/i
|
||||||
|
broken_quoted = /^#{condisp}.*;\sfilename="(.*?)"(?:\s*$|\s*;\s*#{token}=)/i
|
||||||
|
broken_unquoted = /^#{condisp}.*;\sfilename=(#{token})/i
|
||||||
|
|
||||||
|
if head =~ rfc2183
|
||||||
|
filename = Hash[head.scan(dispparm)]['filename']
|
||||||
|
filename = $1 if filename and filename =~ /^"(.*)"$/
|
||||||
|
elsif head =~ broken_quoted
|
||||||
|
filename = $1
|
||||||
|
elsif head =~ broken_unquoted
|
||||||
|
filename = $1
|
||||||
|
end
|
||||||
|
|
||||||
|
if filename && filename !~ /\\[^\\"]/
|
||||||
|
filename = Utils.unescape(filename).gsub(/\\(.)/, '\1')
|
||||||
|
end
|
||||||
|
|
||||||
content_type = head[/Content-Type: (.*)#{EOL}/ni, 1]
|
content_type = head[/Content-Type: (.*)#{EOL}/ni, 1]
|
||||||
name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1]
|
name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1]
|
||||||
|
|
||||||
if content_type || filename
|
if filename
|
||||||
body = Tempfile.new("RackMultipart")
|
body = Tempfile.new("RackMultipart")
|
||||||
body.binmode if body.respond_to?(:binmode)
|
body.binmode if body.respond_to?(:binmode)
|
||||||
end
|
end
|
||||||
|
@ -519,8 +567,7 @@ module Rack
|
||||||
# This handles the full Windows paths given by Internet Explorer
|
# This handles the full Windows paths given by Internet Explorer
|
||||||
# (and perhaps other broken user agents) without affecting
|
# (and perhaps other broken user agents) without affecting
|
||||||
# those which give the lone filename.
|
# those which give the lone filename.
|
||||||
filename =~ /^(?:.*[:\\\/])?(.*)/m
|
filename = filename.split(/[\/\\]/).last
|
||||||
filename = $1
|
|
||||||
|
|
||||||
data = {:filename => filename, :type => content_type,
|
data = {:filename => filename, :type => content_type,
|
||||||
:name => name, :tempfile => body, :head => head}
|
:name => name, :tempfile => body, :head => head}
|
||||||
|
|
12
vendor/plugins/rack/rack.gemspec
vendored
12
vendor/plugins/rack/rack.gemspec
vendored
|
@ -1,6 +1,6 @@
|
||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
s.name = "rack"
|
s.name = "rack"
|
||||||
s.version = "1.1.0"
|
s.version = "1.2.0"
|
||||||
s.platform = Gem::Platform::RUBY
|
s.platform = Gem::Platform::RUBY
|
||||||
s.summary = "a modular Ruby webserver interface"
|
s.summary = "a modular Ruby webserver interface"
|
||||||
|
|
||||||
|
@ -14,23 +14,23 @@ middleware) into a single method call.
|
||||||
Also see http://rack.rubyforge.org.
|
Also see http://rack.rubyforge.org.
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
s.files = Dir['{bin/*,contrib/*,example/*,lib/**/*}'] +
|
s.files = Dir['{bin/*,contrib/*,example/*,lib/**/*,spec/**/*}'] +
|
||||||
%w(COPYING KNOWN-ISSUES rack.gemspec RDOX README SPEC)
|
%w(COPYING KNOWN-ISSUES rack.gemspec README SPEC)
|
||||||
s.bindir = 'bin'
|
s.bindir = 'bin'
|
||||||
s.executables << 'rackup'
|
s.executables << 'rackup'
|
||||||
s.require_path = 'lib'
|
s.require_path = 'lib'
|
||||||
s.has_rdoc = true
|
s.has_rdoc = true
|
||||||
s.extra_rdoc_files = ['README', 'SPEC', 'KNOWN-ISSUES']
|
s.extra_rdoc_files = ['README', 'SPEC', 'KNOWN-ISSUES']
|
||||||
s.test_files = Dir['test/{test,spec}_*.rb']
|
s.test_files = Dir['spec/spec_*.rb']
|
||||||
|
|
||||||
s.author = 'Christian Neukirchen'
|
s.author = 'Christian Neukirchen'
|
||||||
s.email = 'chneukirchen@gmail.com'
|
s.email = 'chneukirchen@gmail.com'
|
||||||
s.homepage = 'http://rack.rubyforge.org'
|
s.homepage = 'http://rack.rubyforge.org'
|
||||||
s.rubyforge_project = 'rack'
|
s.rubyforge_project = 'rack'
|
||||||
|
|
||||||
s.add_development_dependency 'test-spec'
|
s.add_development_dependency 'bacon'
|
||||||
|
s.add_development_dependency 'rake'
|
||||||
|
|
||||||
s.add_development_dependency 'camping'
|
|
||||||
s.add_development_dependency 'fcgi'
|
s.add_development_dependency 'fcgi'
|
||||||
s.add_development_dependency 'memcache-client'
|
s.add_development_dependency 'memcache-client'
|
||||||
s.add_development_dependency 'mongrel'
|
s.add_development_dependency 'mongrel'
|
||||||
|
|
9
vendor/plugins/rack/test/cgi/lighttpd.conf → vendor/plugins/rack/spec/cgi/lighttpd.conf
vendored
Normal file → Executable file
9
vendor/plugins/rack/test/cgi/lighttpd.conf → vendor/plugins/rack/spec/cgi/lighttpd.conf
vendored
Normal file → Executable file
|
@ -1,6 +1,6 @@
|
||||||
server.modules = ("mod_fastcgi", "mod_cgi")
|
server.modules = ("mod_fastcgi", "mod_cgi")
|
||||||
server.document-root = "."
|
server.document-root = "."
|
||||||
server.errorlog = "lighttpd.errors"
|
server.errorlog = var.CWD + "/lighttpd.errors"
|
||||||
server.port = 9203
|
server.port = 9203
|
||||||
|
|
||||||
server.event-handler = "select"
|
server.event-handler = "select"
|
||||||
|
@ -9,7 +9,8 @@ cgi.assign = ("/test" => "",
|
||||||
# ".ru" => ""
|
# ".ru" => ""
|
||||||
)
|
)
|
||||||
|
|
||||||
fastcgi.server = ("test.fcgi" => ("localhost" =>
|
fastcgi.server = (
|
||||||
|
"test.fcgi" => ("localhost" =>
|
||||||
("min-procs" => 1,
|
("min-procs" => 1,
|
||||||
"socket" => "/tmp/rack-test-fcgi",
|
"socket" => "/tmp/rack-test-fcgi",
|
||||||
"bin-path" => "test.fcgi")),
|
"bin-path" => "test.fcgi")),
|
||||||
|
@ -17,4 +18,8 @@ fastcgi.server = ("test.fcgi" => ("localhost" =>
|
||||||
("min-procs" => 1,
|
("min-procs" => 1,
|
||||||
"socket" => "/tmp/rack-test-ru-fcgi",
|
"socket" => "/tmp/rack-test-ru-fcgi",
|
||||||
"bin-path" => "test.ru")),
|
"bin-path" => "test.ru")),
|
||||||
|
"sample_rackup.ru" => ("localhost" =>
|
||||||
|
("min-procs" => 1,
|
||||||
|
"socket" => "/tmp/rack-test-rackup-fcgi",
|
||||||
|
"bin-path" => CWD + "/rackup_stub.rb sample_rackup.ru")),
|
||||||
)
|
)
|
6
vendor/plugins/rack/spec/cgi/rackup_stub.rb
vendored
Executable file
6
vendor/plugins/rack/spec/cgi/rackup_stub.rb
vendored
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
# -*- ruby -*-
|
||||||
|
|
||||||
|
$:.unshift '../../lib'
|
||||||
|
require 'rack'
|
||||||
|
Rack::Server.start
|
5
vendor/plugins/rack/spec/cgi/sample_rackup.ru
vendored
Executable file
5
vendor/plugins/rack/spec/cgi/sample_rackup.ru
vendored
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- ruby -*-
|
||||||
|
|
||||||
|
require '../testrequest'
|
||||||
|
|
||||||
|
run TestRequest.new
|
5
vendor/plugins/rack/spec/cgi/test.ru
vendored
Executable file
5
vendor/plugins/rack/spec/cgi/test.ru
vendored
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
#!../../bin/rackup
|
||||||
|
# -*- ruby -*-
|
||||||
|
|
||||||
|
require '../testrequest'
|
||||||
|
run TestRequest.new
|
7
vendor/plugins/rack/spec/multipart/filename_and_modification_param
vendored
Normal file
7
vendor/plugins/rack/spec/multipart/filename_and_modification_param
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
--AaB03x
|
||||||
|
Content-Type: image/jpeg
|
||||||
|
Content-Disposition: attachment; name="files"; filename=genome.jpeg; modification-date="Wed, 12 Feb 1997 16:29:51 -0500";
|
||||||
|
Content-Description: a complete map of the human genome
|
||||||
|
|
||||||
|
contents
|
||||||
|
--AaB03x--
|
6
vendor/plugins/rack/spec/multipart/filename_with_escaped_quotes
vendored
Normal file
6
vendor/plugins/rack/spec/multipart/filename_with_escaped_quotes
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
--AaB03x
|
||||||
|
Content-Disposition: form-data; name="files"; filename="escape \"quotes"
|
||||||
|
Content-Type: application/octet-stream
|
||||||
|
|
||||||
|
contents
|
||||||
|
--AaB03x--
|
7
vendor/plugins/rack/spec/multipart/filename_with_escaped_quotes_and_modification_param
vendored
Normal file
7
vendor/plugins/rack/spec/multipart/filename_with_escaped_quotes_and_modification_param
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
--AaB03x
|
||||||
|
Content-Type: image/jpeg
|
||||||
|
Content-Disposition: attachment; name="files"; filename=""human" genome.jpeg"; modification-date="Wed, 12 Feb 1997 16:29:51 -0500";
|
||||||
|
Content-Description: a complete map of the human genome
|
||||||
|
|
||||||
|
contents
|
||||||
|
--AaB03x--
|
6
vendor/plugins/rack/spec/multipart/filename_with_percent_escaped_quotes
vendored
Normal file
6
vendor/plugins/rack/spec/multipart/filename_with_percent_escaped_quotes
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
--AaB03x
|
||||||
|
Content-Disposition: form-data; name="files"; filename="escape %22quotes"
|
||||||
|
Content-Type: application/octet-stream
|
||||||
|
|
||||||
|
contents
|
||||||
|
--AaB03x--
|
6
vendor/plugins/rack/spec/multipart/filename_with_unescaped_quotes
vendored
Normal file
6
vendor/plugins/rack/spec/multipart/filename_with_unescaped_quotes
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
--AaB03x
|
||||||
|
Content-Disposition: form-data; name="files"; filename="escape "quotes"
|
||||||
|
Content-Type: application/octet-stream
|
||||||
|
|
||||||
|
contents
|
||||||
|
--AaB03x--
|
|
@ -1,10 +1,7 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/auth/basic'
|
require 'rack/auth/basic'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
context 'Rack::Auth::Basic' do
|
describe Rack::Auth::Basic do
|
||||||
|
|
||||||
def realm
|
def realm
|
||||||
'WallysWorld'
|
'WallysWorld'
|
||||||
end
|
end
|
||||||
|
@ -19,7 +16,7 @@ context 'Rack::Auth::Basic' do
|
||||||
app
|
app
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
before do
|
||||||
@request = Rack::MockRequest.new(protected_app)
|
@request = Rack::MockRequest.new(protected_app)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -39,26 +36,26 @@ context 'Rack::Auth::Basic' do
|
||||||
response.body.should.be.empty
|
response.body.should.be.empty
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should challenge correctly when no credentials are specified' do
|
should 'challenge correctly when no credentials are specified' do
|
||||||
request do |response|
|
request do |response|
|
||||||
assert_basic_auth_challenge response
|
assert_basic_auth_challenge response
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should rechallenge if incorrect credentials are specified' do
|
should 'rechallenge if incorrect credentials are specified' do
|
||||||
request_with_basic_auth 'joe', 'password' do |response|
|
request_with_basic_auth 'joe', 'password' do |response|
|
||||||
assert_basic_auth_challenge response
|
assert_basic_auth_challenge response
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should return application output if correct credentials are specified' do
|
should 'return application output if correct credentials are specified' do
|
||||||
request_with_basic_auth 'Boss', 'password' do |response|
|
request_with_basic_auth 'Boss', 'password' do |response|
|
||||||
response.status.should.equal 200
|
response.status.should.equal 200
|
||||||
response.body.to_s.should.equal 'Hi Boss'
|
response.body.to_s.should.equal 'Hi Boss'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should return 400 Bad Request if different auth scheme used' do
|
should 'return 400 Bad Request if different auth scheme used' do
|
||||||
request 'HTTP_AUTHORIZATION' => 'Digest params' do |response|
|
request 'HTTP_AUTHORIZATION' => 'Digest params' do |response|
|
||||||
response.should.be.a.client_error
|
response.should.be.a.client_error
|
||||||
response.status.should.equal 400
|
response.status.should.equal 400
|
||||||
|
@ -66,8 +63,8 @@ context 'Rack::Auth::Basic' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'realm as optional constructor arg' do
|
it 'takes realm as optional constructor arg' do
|
||||||
app = Rack::Auth::Basic.new(unprotected_app, realm) { true }
|
app = Rack::Auth::Basic.new(unprotected_app, realm) { true }
|
||||||
assert_equal realm, app.realm
|
realm.should == app.realm
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,10 +1,7 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/auth/digest/md5'
|
require 'rack/auth/digest/md5'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
context 'Rack::Auth::Digest::MD5' do
|
describe Rack::Auth::Digest::MD5 do
|
||||||
|
|
||||||
def realm
|
def realm
|
||||||
'WallysWorld'
|
'WallysWorld'
|
||||||
end
|
end
|
||||||
|
@ -45,7 +42,7 @@ context 'Rack::Auth::Digest::MD5' do
|
||||||
Rack::MethodOverride.new(protected_app)
|
Rack::MethodOverride.new(protected_app)
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
before do
|
||||||
@request = Rack::MockRequest.new(protected_app)
|
@request = Rack::MockRequest.new(protected_app)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -117,20 +114,20 @@ context 'Rack::Auth::Digest::MD5' do
|
||||||
response.should.not.include 'WWW-Authenticate'
|
response.should.not.include 'WWW-Authenticate'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should challenge when no credentials are specified' do
|
should 'challenge when no credentials are specified' do
|
||||||
request 'GET', '/' do |response|
|
request 'GET', '/' do |response|
|
||||||
assert_digest_auth_challenge response
|
assert_digest_auth_challenge response
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should return application output if correct credentials given' do
|
should 'return application output if correct credentials given' do
|
||||||
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password' do |response|
|
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password' do |response|
|
||||||
response.status.should.equal 200
|
response.status.should.equal 200
|
||||||
response.body.to_s.should.equal 'Hi Alice'
|
response.body.to_s.should.equal 'Hi Alice'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should return application output if correct credentials given (hashed passwords)' do
|
should 'return application output if correct credentials given (hashed passwords)' do
|
||||||
@request = Rack::MockRequest.new(protected_app_with_hashed_passwords)
|
@request = Rack::MockRequest.new(protected_app_with_hashed_passwords)
|
||||||
|
|
||||||
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password' do |response|
|
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password' do |response|
|
||||||
|
@ -139,19 +136,19 @@ context 'Rack::Auth::Digest::MD5' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should rechallenge if incorrect username given' do
|
should 'rechallenge if incorrect username given' do
|
||||||
request_with_digest_auth 'GET', '/', 'Bob', 'correct-password' do |response|
|
request_with_digest_auth 'GET', '/', 'Bob', 'correct-password' do |response|
|
||||||
assert_digest_auth_challenge response
|
assert_digest_auth_challenge response
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should rechallenge if incorrect password given' do
|
should 'rechallenge if incorrect password given' do
|
||||||
request_with_digest_auth 'GET', '/', 'Alice', 'wrong-password' do |response|
|
request_with_digest_auth 'GET', '/', 'Alice', 'wrong-password' do |response|
|
||||||
assert_digest_auth_challenge response
|
assert_digest_auth_challenge response
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should rechallenge with stale parameter if nonce is stale' do
|
should 'rechallenge with stale parameter if nonce is stale' do
|
||||||
begin
|
begin
|
||||||
Rack::Auth::Digest::Nonce.time_limit = 1
|
Rack::Auth::Digest::Nonce.time_limit = 1
|
||||||
|
|
||||||
|
@ -164,39 +161,39 @@ context 'Rack::Auth::Digest::MD5' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should return 400 Bad Request if incorrect qop given' do
|
should 'return 400 Bad Request if incorrect qop given' do
|
||||||
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', 'qop' => 'auth-int' do |response|
|
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', 'qop' => 'auth-int' do |response|
|
||||||
assert_bad_request response
|
assert_bad_request response
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should return 400 Bad Request if incorrect uri given' do
|
should 'return 400 Bad Request if incorrect uri given' do
|
||||||
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', 'uri' => '/foo' do |response|
|
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', 'uri' => '/foo' do |response|
|
||||||
assert_bad_request response
|
assert_bad_request response
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should return 400 Bad Request if different auth scheme used' do
|
should 'return 400 Bad Request if different auth scheme used' do
|
||||||
request 'GET', '/', 'HTTP_AUTHORIZATION' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' do |response|
|
request 'GET', '/', 'HTTP_AUTHORIZATION' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' do |response|
|
||||||
assert_bad_request response
|
assert_bad_request response
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should not require credentials for unprotected path' do
|
should 'not require credentials for unprotected path' do
|
||||||
@request = Rack::MockRequest.new(partially_protected_app)
|
@request = Rack::MockRequest.new(partially_protected_app)
|
||||||
request 'GET', '/' do |response|
|
request 'GET', '/' do |response|
|
||||||
response.should.be.ok
|
response.should.be.ok
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should challenge when no credentials are specified for protected path' do
|
should 'challenge when no credentials are specified for protected path' do
|
||||||
@request = Rack::MockRequest.new(partially_protected_app)
|
@request = Rack::MockRequest.new(partially_protected_app)
|
||||||
request 'GET', '/protected' do |response|
|
request 'GET', '/protected' do |response|
|
||||||
assert_digest_auth_challenge response
|
assert_digest_auth_challenge response
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should return application output if correct credentials given for protected path' do
|
should 'return application output if correct credentials given for protected path' do
|
||||||
@request = Rack::MockRequest.new(partially_protected_app)
|
@request = Rack::MockRequest.new(partially_protected_app)
|
||||||
request_with_digest_auth 'GET', '/protected', 'Alice', 'correct-password' do |response|
|
request_with_digest_auth 'GET', '/protected', 'Alice', 'correct-password' do |response|
|
||||||
response.status.should.equal 200
|
response.status.should.equal 200
|
||||||
|
@ -204,14 +201,14 @@ context 'Rack::Auth::Digest::MD5' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should return application output if correct credentials given for POST' do
|
should 'return application output if correct credentials given for POST' do
|
||||||
request_with_digest_auth 'POST', '/', 'Alice', 'correct-password' do |response|
|
request_with_digest_auth 'POST', '/', 'Alice', 'correct-password' do |response|
|
||||||
response.status.should.equal 200
|
response.status.should.equal 200
|
||||||
response.body.to_s.should.equal 'Hi Alice'
|
response.body.to_s.should.equal 'Hi Alice'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should return application output if correct credentials given for PUT (using method override of POST)' do
|
should 'return application output if correct credentials given for PUT (using method override of POST)' do
|
||||||
@request = Rack::MockRequest.new(protected_app_with_method_override)
|
@request = Rack::MockRequest.new(protected_app_with_method_override)
|
||||||
request_with_digest_auth 'POST', '/', 'Alice', 'correct-password', :input => "_method=put" do |response|
|
request_with_digest_auth 'POST', '/', 'Alice', 'correct-password', :input => "_method=put" do |response|
|
||||||
response.status.should.equal 200
|
response.status.should.equal 200
|
||||||
|
@ -219,8 +216,8 @@ context 'Rack::Auth::Digest::MD5' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'realm as optional constructor arg' do
|
it 'takes realm as optional constructor arg' do
|
||||||
app = Rack::Auth::Digest::MD5.new(unprotected_app, realm) { true }
|
app = Rack::Auth::Digest::MD5.new(unprotected_app, realm) { true }
|
||||||
assert_equal realm, app.realm
|
realm.should == app.realm
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,12 +1,51 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/builder'
|
require 'rack/builder'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
require 'rack/showexceptions'
|
require 'rack/showexceptions'
|
||||||
require 'rack/auth/basic'
|
require 'rack/urlmap'
|
||||||
|
|
||||||
context "Rack::Builder" do
|
class NothingMiddleware
|
||||||
specify "chains apps by default" do
|
def initialize(app)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
def call(env)
|
||||||
|
@@env = env
|
||||||
|
response = @app.call(env)
|
||||||
|
response
|
||||||
|
end
|
||||||
|
def self.env
|
||||||
|
@@env
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe Rack::Builder do
|
||||||
|
it "supports mapping" do
|
||||||
|
app = Rack::Builder.new do
|
||||||
|
map '/' do |outer_env|
|
||||||
|
run lambda { |inner_env| [200, {}, ['root']] }
|
||||||
|
end
|
||||||
|
map '/sub' do
|
||||||
|
run lambda { |inner_env| [200, {}, ['sub']] }
|
||||||
|
end
|
||||||
|
end.to_app
|
||||||
|
Rack::MockRequest.new(app).get("/").body.to_s.should.equal 'root'
|
||||||
|
Rack::MockRequest.new(app).get("/sub").body.to_s.should.equal 'sub'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't dupe env even when mapping" do
|
||||||
|
app = Rack::Builder.new do
|
||||||
|
use NothingMiddleware
|
||||||
|
map '/' do |outer_env|
|
||||||
|
run lambda { |inner_env|
|
||||||
|
inner_env['new_key'] = 'new_value'
|
||||||
|
[200, {}, ['root']]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end.to_app
|
||||||
|
Rack::MockRequest.new(app).get("/").body.to_s.should.equal 'root'
|
||||||
|
NothingMiddleware.env['new_key'].should.equal 'new_value'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "chains apps by default" do
|
||||||
app = Rack::Builder.new do
|
app = Rack::Builder.new do
|
||||||
use Rack::ShowExceptions
|
use Rack::ShowExceptions
|
||||||
run lambda { |env| raise "bzzzt" }
|
run lambda { |env| raise "bzzzt" }
|
||||||
|
@ -17,7 +56,7 @@ context "Rack::Builder" do
|
||||||
Rack::MockRequest.new(app).get("/").should.be.server_error
|
Rack::MockRequest.new(app).get("/").should.be.server_error
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "has implicit #to_app" do
|
it "has implicit #to_app" do
|
||||||
app = Rack::Builder.new do
|
app = Rack::Builder.new do
|
||||||
use Rack::ShowExceptions
|
use Rack::ShowExceptions
|
||||||
run lambda { |env| raise "bzzzt" }
|
run lambda { |env| raise "bzzzt" }
|
||||||
|
@ -28,7 +67,7 @@ context "Rack::Builder" do
|
||||||
Rack::MockRequest.new(app).get("/").should.be.server_error
|
Rack::MockRequest.new(app).get("/").should.be.server_error
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "supports blocks on use" do
|
it "supports blocks on use" do
|
||||||
app = Rack::Builder.new do
|
app = Rack::Builder.new do
|
||||||
use Rack::ShowExceptions
|
use Rack::ShowExceptions
|
||||||
use Rack::Auth::Basic do |username, password|
|
use Rack::Auth::Basic do |username, password|
|
||||||
|
@ -49,7 +88,7 @@ context "Rack::Builder" do
|
||||||
response.body.to_s.should.equal 'Hi Boss'
|
response.body.to_s.should.equal 'Hi Boss'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "has explicit #to_app" do
|
it "has explicit #to_app" do
|
||||||
app = Rack::Builder.app do
|
app = Rack::Builder.app do
|
||||||
use Rack::ShowExceptions
|
use Rack::ShowExceptions
|
||||||
run lambda { |env| raise "bzzzt" }
|
run lambda { |env| raise "bzzzt" }
|
||||||
|
@ -60,7 +99,7 @@ context "Rack::Builder" do
|
||||||
Rack::MockRequest.new(app).get("/").should.be.server_error
|
Rack::MockRequest.new(app).get("/").should.be.server_error
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "apps are initialized once" do
|
should "initialize apps once" do
|
||||||
app = Rack::Builder.new do
|
app = Rack::Builder.new do
|
||||||
class AppClass
|
class AppClass
|
||||||
def initialize
|
def initialize
|
|
@ -1,12 +1,9 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/cascade'
|
require 'rack/cascade'
|
||||||
|
require 'rack/file'
|
||||||
|
require 'rack/urlmap'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
require 'rack/urlmap'
|
describe Rack::Cascade do
|
||||||
require 'rack/file'
|
|
||||||
|
|
||||||
context "Rack::Cascade" do
|
|
||||||
docroot = File.expand_path(File.dirname(__FILE__))
|
docroot = File.expand_path(File.dirname(__FILE__))
|
||||||
app1 = Rack::File.new(docroot)
|
app1 = Rack::File.new(docroot)
|
||||||
|
|
||||||
|
@ -15,7 +12,7 @@ context "Rack::Cascade" do
|
||||||
app3 = Rack::URLMap.new("/foo" => lambda { |env|
|
app3 = Rack::URLMap.new("/foo" => lambda { |env|
|
||||||
[200, { "Content-Type" => "text/plain"}, [""]]})
|
[200, { "Content-Type" => "text/plain"}, [""]]})
|
||||||
|
|
||||||
specify "should dispatch onward on 404 by default" do
|
should "dispatch onward on 404 by default" do
|
||||||
cascade = Rack::Cascade.new([app1, app2, app3])
|
cascade = Rack::Cascade.new([app1, app2, app3])
|
||||||
Rack::MockRequest.new(cascade).get("/cgi/test").should.be.ok
|
Rack::MockRequest.new(cascade).get("/cgi/test").should.be.ok
|
||||||
Rack::MockRequest.new(cascade).get("/foo").should.be.ok
|
Rack::MockRequest.new(cascade).get("/foo").should.be.ok
|
||||||
|
@ -23,16 +20,16 @@ context "Rack::Cascade" do
|
||||||
Rack::MockRequest.new(cascade).get("/cgi/../bla").should.be.forbidden
|
Rack::MockRequest.new(cascade).get("/cgi/../bla").should.be.forbidden
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should dispatch onward on whatever is passed" do
|
should "dispatch onward on whatever is passed" do
|
||||||
cascade = Rack::Cascade.new([app1, app2, app3], [404, 403])
|
cascade = Rack::Cascade.new([app1, app2, app3], [404, 403])
|
||||||
Rack::MockRequest.new(cascade).get("/cgi/../bla").should.be.not_found
|
Rack::MockRequest.new(cascade).get("/cgi/../bla").should.be.not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should return 404 if empty" do
|
should "return 404 if empty" do
|
||||||
Rack::MockRequest.new(Rack::Cascade.new([])).get('/').should.be.not_found
|
Rack::MockRequest.new(Rack::Cascade.new([])).get('/').should.be.not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should append new app" do
|
should "append new app" do
|
||||||
cascade = Rack::Cascade.new([], [404, 403])
|
cascade = Rack::Cascade.new([], [404, 403])
|
||||||
Rack::MockRequest.new(cascade).get('/').should.be.not_found
|
Rack::MockRequest.new(cascade).get('/').should.be.not_found
|
||||||
cascade << app2
|
cascade << app2
|
|
@ -1,53 +1,55 @@
|
||||||
require 'test/spec'
|
require File.expand_path('../testrequest', __FILE__)
|
||||||
require 'testrequest'
|
require 'rack/handler/cgi'
|
||||||
|
|
||||||
context "Rack::Handler::CGI" do
|
describe Rack::Handler::CGI do
|
||||||
include TestRequest::Helpers
|
extend TestRequest::Helpers
|
||||||
|
|
||||||
setup do
|
|
||||||
@host = '0.0.0.0'
|
@host = '0.0.0.0'
|
||||||
@port = 9203
|
@port = 9203
|
||||||
end
|
|
||||||
|
|
||||||
# Keep this first.
|
# Keep this first.
|
||||||
specify "startup" do
|
|
||||||
$pid = fork {
|
$pid = fork {
|
||||||
Dir.chdir(File.join(File.dirname(__FILE__), "..", "test", "cgi"))
|
ENV['RACK_ENV'] = 'deployment'
|
||||||
|
ENV['RUBYLIB'] = [
|
||||||
|
File.expand_path('../../lib', __FILE__),
|
||||||
|
ENV['RUBYLIB'],
|
||||||
|
].compact.join(':')
|
||||||
|
|
||||||
|
Dir.chdir(File.expand_path("../cgi", __FILE__)) do
|
||||||
exec "lighttpd -D -f lighttpd.conf"
|
exec "lighttpd -D -f lighttpd.conf"
|
||||||
|
end
|
||||||
}
|
}
|
||||||
end
|
|
||||||
|
|
||||||
specify "should respond" do
|
should "respond" do
|
||||||
sleep 1
|
sleep 1
|
||||||
lambda {
|
|
||||||
GET("/test")
|
GET("/test")
|
||||||
}.should.not.raise
|
response.should.not.be.nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be a lighttpd" do
|
should "be a lighttpd" do
|
||||||
GET("/test")
|
GET("/test")
|
||||||
status.should.be 200
|
status.should.equal 200
|
||||||
response["SERVER_SOFTWARE"].should =~ /lighttpd/
|
response["SERVER_SOFTWARE"].should =~ /lighttpd/
|
||||||
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
||||||
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
||||||
response["SERVER_PORT"].should.equal @port.to_s
|
response["SERVER_PORT"].should.equal @port.to_s
|
||||||
response["SERVER_NAME"].should =~ @host
|
response["SERVER_NAME"].should.equal @host
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have rack headers" do
|
should "have rack headers" do
|
||||||
GET("/test")
|
GET("/test")
|
||||||
response["rack.version"].should.equal [1,1]
|
response["rack.version"].should.equal([1,1])
|
||||||
response["rack.multithread"].should.be false
|
response["rack.multithread"].should.be.false
|
||||||
response["rack.multiprocess"].should.be true
|
response["rack.multiprocess"].should.be.true
|
||||||
response["rack.run_once"].should.be true
|
response["rack.run_once"].should.be.true
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have CGI headers on GET" do
|
should "have CGI headers on GET" do
|
||||||
GET("/test")
|
GET("/test")
|
||||||
response["REQUEST_METHOD"].should.equal "GET"
|
response["REQUEST_METHOD"].should.equal "GET"
|
||||||
response["SCRIPT_NAME"].should.equal "/test"
|
response["SCRIPT_NAME"].should.equal "/test"
|
||||||
response["REQUEST_PATH"].should.equal "/"
|
response["REQUEST_PATH"].should.equal "/"
|
||||||
response["PATH_INFO"].should.equal ""
|
response["PATH_INFO"].should.be.nil
|
||||||
response["QUERY_STRING"].should.equal ""
|
response["QUERY_STRING"].should.equal ""
|
||||||
response["test.postdata"].should.equal ""
|
response["test.postdata"].should.equal ""
|
||||||
|
|
||||||
|
@ -59,7 +61,7 @@ context "Rack::Handler::CGI" do
|
||||||
response["QUERY_STRING"].should.equal "quux=1"
|
response["QUERY_STRING"].should.equal "quux=1"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have CGI headers on POST" do
|
should "have CGI headers on POST" do
|
||||||
POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
||||||
status.should.equal 200
|
status.should.equal 200
|
||||||
response["REQUEST_METHOD"].should.equal "POST"
|
response["REQUEST_METHOD"].should.equal "POST"
|
||||||
|
@ -70,20 +72,20 @@ context "Rack::Handler::CGI" do
|
||||||
response["test.postdata"].should.equal "rack-form-data=23"
|
response["test.postdata"].should.equal "rack-form-data=23"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should support HTTP auth" do
|
should "support HTTP auth" do
|
||||||
GET("/test", {:user => "ruth", :passwd => "secret"})
|
GET("/test", {:user => "ruth", :passwd => "secret"})
|
||||||
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should set status" do
|
should "set status" do
|
||||||
GET("/test?secret")
|
GET("/test?secret")
|
||||||
status.should.equal 403
|
status.should.equal 403
|
||||||
response["rack.url_scheme"].should.equal "http"
|
response["rack.url_scheme"].should.equal "http"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Keep this last.
|
# Keep this last.
|
||||||
specify "shutdown" do
|
should "shutdown" do
|
||||||
Process.kill 15, $pid
|
Process.kill 15, $pid
|
||||||
Process.wait($pid).should.equal $pid
|
Process.wait($pid).should == $pid
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,15 +1,13 @@
|
||||||
require 'rack/mock'
|
|
||||||
require 'rack/chunked'
|
require 'rack/chunked'
|
||||||
require 'rack/utils'
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::Chunked" do
|
|
||||||
|
|
||||||
|
describe Rack::Chunked do
|
||||||
before do
|
before do
|
||||||
@env = Rack::MockRequest.
|
@env = Rack::MockRequest.
|
||||||
env_for('/', 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => 'GET')
|
env_for('/', 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => 'GET')
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'chunks responses with no Content-Length' do
|
should 'chunk responses with no Content-Length' do
|
||||||
app = lambda { |env| [200, {}, ['Hello', ' ', 'World!']] }
|
app = lambda { |env| [200, {}, ['Hello', ' ', 'World!']] }
|
||||||
response = Rack::MockResponse.new(*Rack::Chunked.new(app).call(@env))
|
response = Rack::MockResponse.new(*Rack::Chunked.new(app).call(@env))
|
||||||
response.headers.should.not.include 'Content-Length'
|
response.headers.should.not.include 'Content-Length'
|
||||||
|
@ -17,7 +15,7 @@ context "Rack::Chunked" do
|
||||||
response.body.should.equal "5\r\nHello\r\n1\r\n \r\n6\r\nWorld!\r\n0\r\n\r\n"
|
response.body.should.equal "5\r\nHello\r\n1\r\n \r\n6\r\nWorld!\r\n0\r\n\r\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'chunks empty bodies properly' do
|
should 'chunks empty bodies properly' do
|
||||||
app = lambda { |env| [200, {}, []] }
|
app = lambda { |env| [200, {}, []] }
|
||||||
response = Rack::MockResponse.new(*Rack::Chunked.new(app).call(@env))
|
response = Rack::MockResponse.new(*Rack::Chunked.new(app).call(@env))
|
||||||
response.headers.should.not.include 'Content-Length'
|
response.headers.should.not.include 'Content-Length'
|
||||||
|
@ -25,7 +23,7 @@ context "Rack::Chunked" do
|
||||||
response.body.should.equal "0\r\n\r\n"
|
response.body.should.equal "0\r\n\r\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'does not modify response when Content-Length header present' do
|
should 'not modify response when Content-Length header present' do
|
||||||
app = lambda { |env| [200, {'Content-Length'=>'12'}, ['Hello', ' ', 'World!']] }
|
app = lambda { |env| [200, {'Content-Length'=>'12'}, ['Hello', ' ', 'World!']] }
|
||||||
status, headers, body = Rack::Chunked.new(app).call(@env)
|
status, headers, body = Rack::Chunked.new(app).call(@env)
|
||||||
status.should.equal 200
|
status.should.equal 200
|
||||||
|
@ -34,7 +32,7 @@ context "Rack::Chunked" do
|
||||||
body.join.should.equal 'Hello World!'
|
body.join.should.equal 'Hello World!'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'does not modify response when client is HTTP/1.0' do
|
should 'not modify response when client is HTTP/1.0' do
|
||||||
app = lambda { |env| [200, {}, ['Hello', ' ', 'World!']] }
|
app = lambda { |env| [200, {}, ['Hello', ' ', 'World!']] }
|
||||||
@env['HTTP_VERSION'] = 'HTTP/1.0'
|
@env['HTTP_VERSION'] = 'HTTP/1.0'
|
||||||
status, headers, body = Rack::Chunked.new(app).call(@env)
|
status, headers, body = Rack::Chunked.new(app).call(@env)
|
||||||
|
@ -43,7 +41,7 @@ context "Rack::Chunked" do
|
||||||
body.join.should.equal 'Hello World!'
|
body.join.should.equal 'Hello World!'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'does not modify response when Transfer-Encoding header already present' do
|
should 'not modify response when Transfer-Encoding header already present' do
|
||||||
app = lambda { |env| [200, {'Transfer-Encoding' => 'identity'}, ['Hello', ' ', 'World!']] }
|
app = lambda { |env| [200, {'Transfer-Encoding' => 'identity'}, ['Hello', ' ', 'World!']] }
|
||||||
status, headers, body = Rack::Chunked.new(app).call(@env)
|
status, headers, body = Rack::Chunked.new(app).call(@env)
|
||||||
status.should.equal 200
|
status.should.equal 200
|
||||||
|
@ -52,7 +50,7 @@ context "Rack::Chunked" do
|
||||||
end
|
end
|
||||||
|
|
||||||
[100, 204, 304].each do |status_code|
|
[100, 204, 304].each do |status_code|
|
||||||
specify "does not modify response when status code is #{status_code}" do
|
should "not modify response when status code is #{status_code}" do
|
||||||
app = lambda { |env| [status_code, {}, []] }
|
app = lambda { |env| [status_code, {}, []] }
|
||||||
status, headers, body = Rack::Chunked.new(app).call(@env)
|
status, headers, body = Rack::Chunked.new(app).call(@env)
|
||||||
status.should.equal status_code
|
status.should.equal status_code
|
|
@ -1,11 +1,10 @@
|
||||||
require 'test/spec'
|
|
||||||
require 'stringio'
|
|
||||||
|
|
||||||
require 'rack/commonlogger'
|
require 'rack/commonlogger'
|
||||||
require 'rack/lobster'
|
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::CommonLogger" do
|
describe Rack::CommonLogger do
|
||||||
|
obj = 'foobar'
|
||||||
|
length = obj.size
|
||||||
|
|
||||||
app = lambda { |env|
|
app = lambda { |env|
|
||||||
[200,
|
[200,
|
||||||
{"Content-Type" => "text/html", "Content-Length" => length.to_s},
|
{"Content-Type" => "text/html", "Content-Length" => length.to_s},
|
||||||
|
@ -19,28 +18,28 @@ context "Rack::CommonLogger" do
|
||||||
{"Content-Type" => "text/html", "Content-Length" => "0"},
|
{"Content-Type" => "text/html", "Content-Length" => "0"},
|
||||||
[]]}
|
[]]}
|
||||||
|
|
||||||
specify "should log to rack.errors by default" do
|
should "log to rack.errors by default" do
|
||||||
res = Rack::MockRequest.new(Rack::CommonLogger.new(app)).get("/")
|
res = Rack::MockRequest.new(Rack::CommonLogger.new(app)).get("/")
|
||||||
|
|
||||||
res.errors.should.not.be.empty
|
res.errors.should.not.be.empty
|
||||||
res.errors.should =~ /"GET \/ " 200 #{length} /
|
res.errors.should =~ /"GET \/ " 200 #{length} /
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should log to anything with +write+" do
|
should "log to anything with +write+" do
|
||||||
log = StringIO.new
|
log = StringIO.new
|
||||||
res = Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
|
res = Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
|
||||||
|
|
||||||
log.string.should =~ /"GET \/ " 200 #{length} /
|
log.string.should =~ /"GET \/ " 200 #{length} /
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should log - content length if header is missing" do
|
should "log - content length if header is missing" do
|
||||||
res = Rack::MockRequest.new(Rack::CommonLogger.new(app_without_length)).get("/")
|
res = Rack::MockRequest.new(Rack::CommonLogger.new(app_without_length)).get("/")
|
||||||
|
|
||||||
res.errors.should.not.be.empty
|
res.errors.should.not.be.empty
|
||||||
res.errors.should =~ /"GET \/ " 200 - /
|
res.errors.should =~ /"GET \/ " 200 - /
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should log - content length if header is zero" do
|
should "log - content length if header is zero" do
|
||||||
res = Rack::MockRequest.new(Rack::CommonLogger.new(app_with_zero_length)).get("/")
|
res = Rack::MockRequest.new(Rack::CommonLogger.new(app_with_zero_length)).get("/")
|
||||||
|
|
||||||
res.errors.should.not.be.empty
|
res.errors.should.not.be.empty
|
||||||
|
@ -48,10 +47,6 @@ context "Rack::CommonLogger" do
|
||||||
end
|
end
|
||||||
|
|
||||||
def length
|
def length
|
||||||
self.class.length
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.length
|
|
||||||
123
|
123
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
require 'test/spec'
|
|
||||||
require 'time'
|
require 'time'
|
||||||
|
|
||||||
require 'rack/mock'
|
|
||||||
require 'rack/conditionalget'
|
require 'rack/conditionalget'
|
||||||
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::ConditionalGet" do
|
describe Rack::ConditionalGet do
|
||||||
specify "should set a 304 status and truncate body when If-Modified-Since hits" do
|
should "set a 304 status and truncate body when If-Modified-Since hits" do
|
||||||
timestamp = Time.now.httpdate
|
timestamp = Time.now.httpdate
|
||||||
app = Rack::ConditionalGet.new(lambda { |env|
|
app = Rack::ConditionalGet.new(lambda { |env|
|
||||||
[200, {'Last-Modified'=>timestamp}, ['TEST']] })
|
[200, {'Last-Modified'=>timestamp}, ['TEST']] })
|
||||||
|
@ -17,7 +15,7 @@ context "Rack::ConditionalGet" do
|
||||||
response.body.should.be.empty
|
response.body.should.be.empty
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should set a 304 status and truncate body when If-None-Match hits" do
|
should "set a 304 status and truncate body when If-None-Match hits" do
|
||||||
app = Rack::ConditionalGet.new(lambda { |env|
|
app = Rack::ConditionalGet.new(lambda { |env|
|
||||||
[200, {'Etag'=>'1234'}, ['TEST']] })
|
[200, {'Etag'=>'1234'}, ['TEST']] })
|
||||||
|
|
||||||
|
@ -28,7 +26,7 @@ context "Rack::ConditionalGet" do
|
||||||
response.body.should.be.empty
|
response.body.should.be.empty
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should not affect non-GET/HEAD requests" do
|
should "not affect non-GET/HEAD requests" do
|
||||||
app = Rack::ConditionalGet.new(lambda { |env|
|
app = Rack::ConditionalGet.new(lambda { |env|
|
||||||
[200, {'Etag'=>'1234'}, ['TEST']] })
|
[200, {'Etag'=>'1234'}, ['TEST']] })
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
require 'test/spec'
|
|
||||||
require 'rack/mock'
|
|
||||||
require 'rack/builder'
|
require 'rack/builder'
|
||||||
require 'rack/content_length'
|
|
||||||
require 'rack/config'
|
require 'rack/config'
|
||||||
|
require 'rack/content_length'
|
||||||
|
require 'rack/lint'
|
||||||
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::Config" do
|
describe Rack::Config do
|
||||||
|
should "accept a block that modifies the environment" do
|
||||||
specify "should accept a block that modifies the environment" do
|
|
||||||
app = Rack::Builder.new do
|
app = Rack::Builder.new do
|
||||||
use Rack::Lint
|
use Rack::Lint
|
||||||
use Rack::ContentLength
|
use Rack::ContentLength
|
||||||
|
@ -17,8 +16,8 @@ context "Rack::Config" do
|
||||||
[200, {'Content-Type' => 'text/plain'}, [env['greeting'] || '']]
|
[200, {'Content-Type' => 'text/plain'}, [env['greeting'] || '']]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
response = Rack::MockRequest.new(app).get('/')
|
response = Rack::MockRequest.new(app).get('/')
|
||||||
response.body.should.equal('hello')
|
response.body.should.equal('hello')
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
|
@ -1,20 +1,19 @@
|
||||||
require 'rack/mock'
|
|
||||||
require 'rack/content_length'
|
require 'rack/content_length'
|
||||||
|
|
||||||
context "Rack::ContentLength" do
|
describe Rack::ContentLength do
|
||||||
specify "sets Content-Length on String bodies if none is set" do
|
should "set Content-Length on String bodies if none is set" do
|
||||||
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
||||||
response = Rack::ContentLength.new(app).call({})
|
response = Rack::ContentLength.new(app).call({})
|
||||||
response[1]['Content-Length'].should.equal '13'
|
response[1]['Content-Length'].should.equal '13'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "sets Content-Length on Array bodies if none is set" do
|
should "set Content-Length on Array bodies if none is set" do
|
||||||
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
||||||
response = Rack::ContentLength.new(app).call({})
|
response = Rack::ContentLength.new(app).call({})
|
||||||
response[1]['Content-Length'].should.equal '13'
|
response[1]['Content-Length'].should.equal '13'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does not set Content-Length on variable length bodies" do
|
should "not set Content-Length on variable length bodies" do
|
||||||
body = lambda { "Hello World!" }
|
body = lambda { "Hello World!" }
|
||||||
def body.each ; yield call ; end
|
def body.each ; yield call ; end
|
||||||
|
|
||||||
|
@ -23,19 +22,19 @@ context "Rack::ContentLength" do
|
||||||
response[1]['Content-Length'].should.be.nil
|
response[1]['Content-Length'].should.be.nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does not change Content-Length if it is already set" do
|
should "not change Content-Length if it is already set" do
|
||||||
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Content-Length' => '1'}, "Hello, World!"] }
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Content-Length' => '1'}, "Hello, World!"] }
|
||||||
response = Rack::ContentLength.new(app).call({})
|
response = Rack::ContentLength.new(app).call({})
|
||||||
response[1]['Content-Length'].should.equal '1'
|
response[1]['Content-Length'].should.equal '1'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does not set Content-Length on 304 responses" do
|
should "not set Content-Length on 304 responses" do
|
||||||
app = lambda { |env| [304, {'Content-Type' => 'text/plain'}, []] }
|
app = lambda { |env| [304, {'Content-Type' => 'text/plain'}, []] }
|
||||||
response = Rack::ContentLength.new(app).call({})
|
response = Rack::ContentLength.new(app).call({})
|
||||||
response[1]['Content-Length'].should.equal nil
|
response[1]['Content-Length'].should.equal nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does not set Content-Length when Transfer-Encoding is chunked" do
|
should "not set Content-Length when Transfer-Encoding is chunked" do
|
||||||
app = lambda { |env| [200, {'Transfer-Encoding' => 'chunked'}, []] }
|
app = lambda { |env| [200, {'Transfer-Encoding' => 'chunked'}, []] }
|
||||||
response = Rack::ContentLength.new(app).call({})
|
response = Rack::ContentLength.new(app).call({})
|
||||||
response[1]['Content-Length'].should.equal nil
|
response[1]['Content-Length'].should.equal nil
|
|
@ -1,27 +1,26 @@
|
||||||
require 'rack/mock'
|
|
||||||
require 'rack/content_type'
|
require 'rack/content_type'
|
||||||
|
|
||||||
context "Rack::ContentType" do
|
describe Rack::ContentType do
|
||||||
specify "sets Content-Type to default text/html if none is set" do
|
should "set Content-Type to default text/html if none is set" do
|
||||||
app = lambda { |env| [200, {}, "Hello, World!"] }
|
app = lambda { |env| [200, {}, "Hello, World!"] }
|
||||||
status, headers, body = Rack::ContentType.new(app).call({})
|
status, headers, body = Rack::ContentType.new(app).call({})
|
||||||
headers['Content-Type'].should.equal 'text/html'
|
headers['Content-Type'].should.equal 'text/html'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "sets Content-Type to chosen default if none is set" do
|
should "set Content-Type to chosen default if none is set" do
|
||||||
app = lambda { |env| [200, {}, "Hello, World!"] }
|
app = lambda { |env| [200, {}, "Hello, World!"] }
|
||||||
status, headers, body =
|
status, headers, body =
|
||||||
Rack::ContentType.new(app, 'application/octet-stream').call({})
|
Rack::ContentType.new(app, 'application/octet-stream').call({})
|
||||||
headers['Content-Type'].should.equal 'application/octet-stream'
|
headers['Content-Type'].should.equal 'application/octet-stream'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does not change Content-Type if it is already set" do
|
should "not change Content-Type if it is already set" do
|
||||||
app = lambda { |env| [200, {'Content-Type' => 'foo/bar'}, "Hello, World!"] }
|
app = lambda { |env| [200, {'Content-Type' => 'foo/bar'}, "Hello, World!"] }
|
||||||
status, headers, body = Rack::ContentType.new(app).call({})
|
status, headers, body = Rack::ContentType.new(app).call({})
|
||||||
headers['Content-Type'].should.equal 'foo/bar'
|
headers['Content-Type'].should.equal 'foo/bar'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "case insensitive detection of Content-Type" do
|
should "detect Content-Type case insensitive" do
|
||||||
app = lambda { |env| [200, {'CONTENT-Type' => 'foo/bar'}, "Hello, World!"] }
|
app = lambda { |env| [200, {'CONTENT-Type' => 'foo/bar'}, "Hello, World!"] }
|
||||||
status, headers, body = Rack::ContentType.new(app).call({})
|
status, headers, body = Rack::ContentType.new(app).call({})
|
||||||
headers.to_a.select { |k,v| k.downcase == "content-type" }.
|
headers.to_a.select { |k,v| k.downcase == "content-type" }.
|
|
@ -1,11 +1,9 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/mock'
|
|
||||||
require 'rack/deflater'
|
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
require 'time' # for Time#httpdate
|
require 'time' # for Time#httpdate
|
||||||
|
require 'rack/deflater'
|
||||||
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::Deflater" do
|
describe Rack::Deflater do
|
||||||
def build_response(status, body, accept_encoding, headers = {})
|
def build_response(status, body, accept_encoding, headers = {})
|
||||||
body = [body] if body.respond_to? :to_str
|
body = [body] if body.respond_to? :to_str
|
||||||
app = lambda { |env| [status, {}, body] }
|
app = lambda { |env| [status, {}, body] }
|
||||||
|
@ -15,7 +13,7 @@ context "Rack::Deflater" do
|
||||||
return response
|
return response
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be able to deflate bodies that respond to each" do
|
should "be able to deflate bodies that respond to each" do
|
||||||
body = Object.new
|
body = Object.new
|
||||||
class << body; def each; yield("foo"); yield("bar"); end; end
|
class << body; def each; yield("foo"); yield("bar"); end; end
|
||||||
|
|
||||||
|
@ -32,7 +30,7 @@ context "Rack::Deflater" do
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: This is really just a special case of the above...
|
# TODO: This is really just a special case of the above...
|
||||||
specify "should be able to deflate String bodies" do
|
should "be able to deflate String bodies" do
|
||||||
response = build_response(200, "Hello world!", "deflate")
|
response = build_response(200, "Hello world!", "deflate")
|
||||||
|
|
||||||
response[0].should.equal(200)
|
response[0].should.equal(200)
|
||||||
|
@ -45,7 +43,7 @@ context "Rack::Deflater" do
|
||||||
buf.should.equal("\363H\315\311\311W(\317/\312IQ\004\000")
|
buf.should.equal("\363H\315\311\311W(\317/\312IQ\004\000")
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be able to gzip bodies that respond to each" do
|
should "be able to gzip bodies that respond to each" do
|
||||||
body = Object.new
|
body = Object.new
|
||||||
class << body; def each; yield("foo"); yield("bar"); end; end
|
class << body; def each; yield("foo"); yield("bar"); end; end
|
||||||
|
|
||||||
|
@ -65,7 +63,7 @@ context "Rack::Deflater" do
|
||||||
gz.close
|
gz.close
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be able to fallback to no deflation" do
|
should "be able to fallback to no deflation" do
|
||||||
response = build_response(200, "Hello world!", "superzip")
|
response = build_response(200, "Hello world!", "superzip")
|
||||||
|
|
||||||
response[0].should.equal(200)
|
response[0].should.equal(200)
|
||||||
|
@ -73,7 +71,7 @@ context "Rack::Deflater" do
|
||||||
response[2].should.equal(["Hello world!"])
|
response[2].should.equal(["Hello world!"])
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be able to skip when there is no response entity body" do
|
should "be able to skip when there is no response entity body" do
|
||||||
response = build_response(304, [], "gzip")
|
response = build_response(304, [], "gzip")
|
||||||
|
|
||||||
response[0].should.equal(304)
|
response[0].should.equal(304)
|
||||||
|
@ -81,7 +79,7 @@ context "Rack::Deflater" do
|
||||||
response[2].should.equal([])
|
response[2].should.equal([])
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should handle the lack of an acceptable encoding" do
|
should "handle the lack of an acceptable encoding" do
|
||||||
response1 = build_response(200, "Hello world!", "identity;q=0", "PATH_INFO" => "/")
|
response1 = build_response(200, "Hello world!", "identity;q=0", "PATH_INFO" => "/")
|
||||||
response1[0].should.equal(406)
|
response1[0].should.equal(406)
|
||||||
response1[1].should.equal({"Content-Type" => "text/plain", "Content-Length" => "71"})
|
response1[1].should.equal({"Content-Type" => "text/plain", "Content-Length" => "71"})
|
||||||
|
@ -93,7 +91,7 @@ context "Rack::Deflater" do
|
||||||
response2[2].should.equal(["An acceptable encoding for the requested resource /foo/bar could not be found."])
|
response2[2].should.equal(["An acceptable encoding for the requested resource /foo/bar could not be found."])
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should handle gzip response with Last-Modified header" do
|
should "handle gzip response with Last-Modified header" do
|
||||||
last_modified = Time.now.httpdate
|
last_modified = Time.now.httpdate
|
||||||
|
|
||||||
app = lambda { |env| [200, { "Last-Modified" => last_modified }, ["Hello World!"]] }
|
app = lambda { |env| [200, { "Last-Modified" => last_modified }, ["Hello World!"]] }
|
||||||
|
@ -115,7 +113,7 @@ context "Rack::Deflater" do
|
||||||
gz.close
|
gz.close
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should do nothing when no-transform Cache-Control directive present" do
|
should "do nothing when no-transform Cache-Control directive present" do
|
||||||
app = lambda { |env| [200, {'Cache-Control' => 'no-transform'}, ['Hello World!']] }
|
app = lambda { |env| [200, {'Cache-Control' => 'no-transform'}, ['Hello World!']] }
|
||||||
request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => "gzip")
|
request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => "gzip")
|
||||||
response = Rack::Deflater.new(app).call(request)
|
response = Rack::Deflater.new(app).call(request)
|
|
@ -1,16 +1,12 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/directory'
|
require 'rack/directory'
|
||||||
require 'rack/lint'
|
|
||||||
|
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::Directory" do
|
describe Rack::Directory do
|
||||||
DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT
|
DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT
|
||||||
FILE_CATCH = proc{|env| [200, {'Content-Type'=>'text/plain', "Content-Length" => "7"}, ['passed!']] }
|
FILE_CATCH = proc{|env| [200, {'Content-Type'=>'text/plain', "Content-Length" => "7"}, ['passed!']] }
|
||||||
app = Rack::Directory.new DOCROOT, FILE_CATCH
|
app = Rack::Directory.new DOCROOT, FILE_CATCH
|
||||||
|
|
||||||
specify "serves directory indices" do
|
should "serve directory indices" do
|
||||||
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
||||||
get("/cgi/")
|
get("/cgi/")
|
||||||
|
|
||||||
|
@ -18,7 +14,7 @@ context "Rack::Directory" do
|
||||||
res.should =~ /<html><head>/
|
res.should =~ /<html><head>/
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "passes to app if file found" do
|
should "pass to app if file found" do
|
||||||
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
||||||
get("/cgi/test")
|
get("/cgi/test")
|
||||||
|
|
||||||
|
@ -26,7 +22,7 @@ context "Rack::Directory" do
|
||||||
res.should =~ /passed!/
|
res.should =~ /passed!/
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "serves uri with URL encoded filenames" do
|
should "serve uri with URL encoded filenames" do
|
||||||
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
||||||
get("/%63%67%69/") # "/cgi/test"
|
get("/%63%67%69/") # "/cgi/test"
|
||||||
|
|
||||||
|
@ -40,7 +36,7 @@ context "Rack::Directory" do
|
||||||
res.should =~ /passed!/
|
res.should =~ /passed!/
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does not allow directory traversal" do
|
should "not allow directory traversal" do
|
||||||
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
||||||
get("/cgi/../test")
|
get("/cgi/../test")
|
||||||
|
|
||||||
|
@ -52,7 +48,7 @@ context "Rack::Directory" do
|
||||||
res.should.be.forbidden
|
res.should.be.forbidden
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "404s if it can't find the file" do
|
should "404 if it can't find the file" do
|
||||||
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
||||||
get("/cgi/blubb")
|
get("/cgi/blubb")
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
require 'test/spec'
|
|
||||||
require 'rack/mock'
|
|
||||||
require 'rack/etag'
|
require 'rack/etag'
|
||||||
|
|
||||||
context "Rack::ETag" do
|
describe Rack::ETag do
|
||||||
specify "sets ETag if none is set" do
|
should "set ETag if none is set" do
|
||||||
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
||||||
response = Rack::ETag.new(app).call({})
|
response = Rack::ETag.new(app).call({})
|
||||||
response[1]['ETag'].should.equal "\"65a8e27d8879283831b664bd8b7f0ad4\""
|
response[1]['ETag'].should.equal "\"65a8e27d8879283831b664bd8b7f0ad4\""
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does not change ETag if it is already set" do
|
should "not change ETag if it is already set" do
|
||||||
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'ETag' => '"abc"'}, ["Hello, World!"]] }
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'ETag' => '"abc"'}, ["Hello, World!"]] }
|
||||||
response = Rack::ETag.new(app).call({})
|
response = Rack::ETag.new(app).call({})
|
||||||
response[1]['ETag'].should.equal "\"abc\""
|
response[1]['ETag'].should.equal "\"abc\""
|
|
@ -1,48 +1,55 @@
|
||||||
require 'test/spec'
|
require File.expand_path('../testrequest', __FILE__)
|
||||||
require 'testrequest'
|
require 'rack/handler/fastcgi'
|
||||||
|
|
||||||
context "Rack::Handler::FastCGI" do
|
describe Rack::Handler::FastCGI do
|
||||||
include TestRequest::Helpers
|
extend TestRequest::Helpers
|
||||||
|
|
||||||
setup do
|
|
||||||
@host = '0.0.0.0'
|
@host = '0.0.0.0'
|
||||||
@port = 9203
|
@port = 9203
|
||||||
end
|
|
||||||
|
|
||||||
# Keep this first.
|
# Keep this first.
|
||||||
specify "startup" do
|
|
||||||
$pid = fork {
|
$pid = fork {
|
||||||
Dir.chdir(File.join(File.dirname(__FILE__), "..", "test", "cgi"))
|
ENV['RACK_ENV'] = 'deployment'
|
||||||
|
ENV['RUBYLIB'] = [
|
||||||
|
File.expand_path('../../lib', __FILE__),
|
||||||
|
ENV['RUBYLIB'],
|
||||||
|
].compact.join(':')
|
||||||
|
|
||||||
|
Dir.chdir(File.expand_path("../cgi", __FILE__)) do
|
||||||
exec "lighttpd -D -f lighttpd.conf"
|
exec "lighttpd -D -f lighttpd.conf"
|
||||||
|
end
|
||||||
}
|
}
|
||||||
end
|
|
||||||
|
|
||||||
specify "should respond" do
|
should "respond" do
|
||||||
sleep 1
|
sleep 1
|
||||||
lambda {
|
GET("/test")
|
||||||
GET("/test.fcgi")
|
response.should.not.be.nil
|
||||||
}.should.not.raise
|
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be a lighttpd" do
|
should "respond via rackup server" do
|
||||||
|
GET("/sample_rackup.ru")
|
||||||
|
status.should.equal 200
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be a lighttpd" do
|
||||||
GET("/test.fcgi")
|
GET("/test.fcgi")
|
||||||
status.should.be 200
|
status.should.equal 200
|
||||||
response["SERVER_SOFTWARE"].should =~ /lighttpd/
|
response["SERVER_SOFTWARE"].should =~ /lighttpd/
|
||||||
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
||||||
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
||||||
response["SERVER_PORT"].should.equal @port.to_s
|
response["SERVER_PORT"].should.equal @port.to_s
|
||||||
response["SERVER_NAME"].should =~ @host
|
response["SERVER_NAME"].should.equal @host
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have rack headers" do
|
should "have rack headers" do
|
||||||
GET("/test.fcgi")
|
GET("/test.fcgi")
|
||||||
response["rack.version"].should.equal [1,1]
|
response["rack.version"].should.equal [1,1]
|
||||||
response["rack.multithread"].should.be false
|
response["rack.multithread"].should.be.false
|
||||||
response["rack.multiprocess"].should.be true
|
response["rack.multiprocess"].should.be.true
|
||||||
response["rack.run_once"].should.be false
|
response["rack.run_once"].should.be.false
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have CGI headers on GET" do
|
should "have CGI headers on GET" do
|
||||||
GET("/test.fcgi")
|
GET("/test.fcgi")
|
||||||
response["REQUEST_METHOD"].should.equal "GET"
|
response["REQUEST_METHOD"].should.equal "GET"
|
||||||
response["SCRIPT_NAME"].should.equal "/test.fcgi"
|
response["SCRIPT_NAME"].should.equal "/test.fcgi"
|
||||||
|
@ -59,7 +66,7 @@ context "Rack::Handler::FastCGI" do
|
||||||
response["QUERY_STRING"].should.equal "quux=1"
|
response["QUERY_STRING"].should.equal "quux=1"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have CGI headers on POST" do
|
should "have CGI headers on POST" do
|
||||||
POST("/test.fcgi", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
POST("/test.fcgi", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
||||||
status.should.equal 200
|
status.should.equal 200
|
||||||
response["REQUEST_METHOD"].should.equal "POST"
|
response["REQUEST_METHOD"].should.equal "POST"
|
||||||
|
@ -70,19 +77,19 @@ context "Rack::Handler::FastCGI" do
|
||||||
response["test.postdata"].should.equal "rack-form-data=23"
|
response["test.postdata"].should.equal "rack-form-data=23"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should support HTTP auth" do
|
should "support HTTP auth" do
|
||||||
GET("/test.fcgi", {:user => "ruth", :passwd => "secret"})
|
GET("/test.fcgi", {:user => "ruth", :passwd => "secret"})
|
||||||
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should set status" do
|
should "set status" do
|
||||||
GET("/test.fcgi?secret")
|
GET("/test.fcgi?secret")
|
||||||
status.should.equal 403
|
status.should.equal 403
|
||||||
response["rack.url_scheme"].should.equal "http"
|
response["rack.url_scheme"].should.equal "http"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Keep this last.
|
# Keep this last.
|
||||||
specify "shutdown" do
|
should "shutdown" do
|
||||||
Process.kill 15, $pid
|
Process.kill 15, $pid
|
||||||
Process.wait($pid).should.equal $pid
|
Process.wait($pid).should.equal $pid
|
||||||
end
|
end
|
|
@ -1,14 +1,10 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/file'
|
require 'rack/file'
|
||||||
require 'rack/lint'
|
|
||||||
|
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::File" do
|
describe Rack::File do
|
||||||
DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT
|
DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT
|
||||||
|
|
||||||
specify "serves files" do
|
should "serve files" do
|
||||||
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
||||||
get("/cgi/test")
|
get("/cgi/test")
|
||||||
|
|
||||||
|
@ -16,7 +12,7 @@ context "Rack::File" do
|
||||||
res.should =~ /ruby/
|
res.should =~ /ruby/
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "sets Last-Modified header" do
|
should "set Last-Modified header" do
|
||||||
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
||||||
get("/cgi/test")
|
get("/cgi/test")
|
||||||
|
|
||||||
|
@ -26,7 +22,7 @@ context "Rack::File" do
|
||||||
res["Last-Modified"].should.equal File.mtime(path).httpdate
|
res["Last-Modified"].should.equal File.mtime(path).httpdate
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "serves files with URL encoded filenames" do
|
should "serve files with URL encoded filenames" do
|
||||||
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
||||||
get("/cgi/%74%65%73%74") # "/cgi/test"
|
get("/cgi/%74%65%73%74") # "/cgi/test"
|
||||||
|
|
||||||
|
@ -34,35 +30,35 @@ context "Rack::File" do
|
||||||
res.should =~ /ruby/
|
res.should =~ /ruby/
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does not allow directory traversal" do
|
should "not allow directory traversal" do
|
||||||
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
||||||
get("/cgi/../test")
|
get("/cgi/../test")
|
||||||
|
|
||||||
res.should.be.forbidden
|
res.should.be.forbidden
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does not allow directory traversal with encoded periods" do
|
should "not allow directory traversal with encoded periods" do
|
||||||
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
||||||
get("/%2E%2E/README")
|
get("/%2E%2E/README")
|
||||||
|
|
||||||
res.should.be.forbidden
|
res.should.be.forbidden
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "404s if it can't find the file" do
|
should "404 if it can't find the file" do
|
||||||
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
||||||
get("/cgi/blubb")
|
get("/cgi/blubb")
|
||||||
|
|
||||||
res.should.be.not_found
|
res.should.be.not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "detects SystemCallErrors" do
|
should "detect SystemCallErrors" do
|
||||||
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
||||||
get("/cgi")
|
get("/cgi")
|
||||||
|
|
||||||
res.should.be.not_found
|
res.should.be.not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "returns bodies that respond to #to_path" do
|
should "return bodies that respond to #to_path" do
|
||||||
env = Rack::MockRequest.env_for("/cgi/test")
|
env = Rack::MockRequest.env_for("/cgi/test")
|
||||||
status, headers, body = Rack::File.new(DOCROOT).call(env)
|
status, headers, body = Rack::File.new(DOCROOT).call(env)
|
||||||
|
|
|
@ -1,43 +1,41 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/handler'
|
require 'rack/handler'
|
||||||
|
|
||||||
class Rack::Handler::Lobster; end
|
class Rack::Handler::Lobster; end
|
||||||
class RockLobster; end
|
class RockLobster; end
|
||||||
|
|
||||||
context "Rack::Handler" do
|
describe Rack::Handler do
|
||||||
specify "has registered default handlers" do
|
it "has registered default handlers" do
|
||||||
Rack::Handler.get('cgi').should.equal Rack::Handler::CGI
|
Rack::Handler.get('cgi').should.equal Rack::Handler::CGI
|
||||||
Rack::Handler.get('fastcgi').should.equal Rack::Handler::FastCGI
|
Rack::Handler.get('fastcgi').should.equal Rack::Handler::FastCGI
|
||||||
Rack::Handler.get('mongrel').should.equal Rack::Handler::Mongrel
|
Rack::Handler.get('mongrel').should.equal Rack::Handler::Mongrel
|
||||||
Rack::Handler.get('webrick').should.equal Rack::Handler::WEBrick
|
Rack::Handler.get('webrick').should.equal Rack::Handler::WEBrick
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "handler that doesn't exist should raise a NameError" do
|
should "raise NameError if handler doesn't exist" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Handler.get('boom')
|
Rack::Handler.get('boom')
|
||||||
}.should.raise(NameError)
|
}.should.raise(NameError)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should get unregistered, but already required, handler by name" do
|
should "get unregistered, but already required, handler by name" do
|
||||||
Rack::Handler.get('Lobster').should.equal Rack::Handler::Lobster
|
Rack::Handler.get('Lobster').should.equal Rack::Handler::Lobster
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should register custom handler" do
|
should "register custom handler" do
|
||||||
Rack::Handler.register('rock_lobster', 'RockLobster')
|
Rack::Handler.register('rock_lobster', 'RockLobster')
|
||||||
Rack::Handler.get('rock_lobster').should.equal RockLobster
|
Rack::Handler.get('rock_lobster').should.equal RockLobster
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should not need registration for properly coded handlers even if not already required" do
|
should "not need registration for properly coded handlers even if not already required" do
|
||||||
begin
|
begin
|
||||||
$:.push "test/unregistered_handler"
|
$LOAD_PATH.push File.expand_path('../unregistered_handler', __FILE__)
|
||||||
Rack::Handler.get('Unregistered').should.equal Rack::Handler::Unregistered
|
Rack::Handler.get('Unregistered').should.equal Rack::Handler::Unregistered
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Handler.get('UnRegistered')
|
Rack::Handler.get('UnRegistered')
|
||||||
}.should.raise(NameError)
|
}.should.raise(NameError)
|
||||||
Rack::Handler.get('UnregisteredLongOne').should.equal Rack::Handler::UnregisteredLongOne
|
Rack::Handler.get('UnregisteredLongOne').should.equal Rack::Handler::UnregisteredLongOne
|
||||||
ensure
|
ensure
|
||||||
$:.delete "test/unregistered_handler"
|
$LOAD_PATH.delete File.expand_path('../unregistered_handler', __FILE__)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,7 +1,7 @@
|
||||||
require 'rack/head'
|
require 'rack/head'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::Head" do
|
describe Rack::Head do
|
||||||
def test_response(headers = {})
|
def test_response(headers = {})
|
||||||
app = lambda { |env| [200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]] }
|
app = lambda { |env| [200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]] }
|
||||||
request = Rack::MockRequest.env_for("/", headers)
|
request = Rack::MockRequest.env_for("/", headers)
|
||||||
|
@ -10,7 +10,7 @@ context "Rack::Head" do
|
||||||
return response
|
return response
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "passes GET, POST, PUT, DELETE, OPTIONS, TRACE requests" do
|
should "pass GET, POST, PUT, DELETE, OPTIONS, TRACE requests" do
|
||||||
%w[GET POST PUT DELETE OPTIONS TRACE].each do |type|
|
%w[GET POST PUT DELETE OPTIONS TRACE].each do |type|
|
||||||
resp = test_response("REQUEST_METHOD" => type)
|
resp = test_response("REQUEST_METHOD" => type)
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ context "Rack::Head" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "removes body from HEAD requests" do
|
should "remove body from HEAD requests" do
|
||||||
resp = test_response("REQUEST_METHOD" => "HEAD")
|
resp = test_response("REQUEST_METHOD" => "HEAD")
|
||||||
|
|
||||||
resp[0].should.equal(200)
|
resp[0].should.equal(200)
|
|
@ -1,15 +1,13 @@
|
||||||
require 'test/spec'
|
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
|
|
||||||
require 'rack/lint'
|
require 'rack/lint'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::Lint" do
|
describe Rack::Lint do
|
||||||
def env(*args)
|
def env(*args)
|
||||||
Rack::MockRequest.env_for("/", *args)
|
Rack::MockRequest.env_for("/", *args)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "passes valid request" do
|
should "pass valid request" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Lint.new(lambda { |env|
|
Rack::Lint.new(lambda { |env|
|
||||||
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]]
|
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]]
|
||||||
|
@ -17,12 +15,12 @@ context "Rack::Lint" do
|
||||||
}.should.not.raise
|
}.should.not.raise
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "notices fatal errors" do
|
should "notice fatal errors" do
|
||||||
lambda { Rack::Lint.new(nil).call }.should.raise(Rack::Lint::LintError).
|
lambda { Rack::Lint.new(nil).call }.should.raise(Rack::Lint::LintError).
|
||||||
message.should.match(/No env given/)
|
message.should.match(/No env given/)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "notices environment errors" do
|
should "notice environment errors" do
|
||||||
lambda { Rack::Lint.new(nil).call 5 }.should.raise(Rack::Lint::LintError).
|
lambda { Rack::Lint.new(nil).call 5 }.should.raise(Rack::Lint::LintError).
|
||||||
message.should.match(/not a Hash/)
|
message.should.match(/not a Hash/)
|
||||||
|
|
||||||
|
@ -110,7 +108,7 @@ context "Rack::Lint" do
|
||||||
message.should.match(/cannot be .* make it ''/)
|
message.should.match(/cannot be .* make it ''/)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "notices input errors" do
|
should "notice input errors" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Lint.new(nil).call(env("rack.input" => ""))
|
Rack::Lint.new(nil).call(env("rack.input" => ""))
|
||||||
}.should.raise(Rack::Lint::LintError).
|
}.should.raise(Rack::Lint::LintError).
|
||||||
|
@ -139,14 +137,14 @@ context "Rack::Lint" do
|
||||||
message.should.match(/does not have ASCII-8BIT as its external encoding/)
|
message.should.match(/does not have ASCII-8BIT as its external encoding/)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "notices error errors" do
|
should "notice error errors" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Lint.new(nil).call(env("rack.errors" => ""))
|
Rack::Lint.new(nil).call(env("rack.errors" => ""))
|
||||||
}.should.raise(Rack::Lint::LintError).
|
}.should.raise(Rack::Lint::LintError).
|
||||||
message.should.match(/does not respond to #puts/)
|
message.should.match(/does not respond to #puts/)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "notices status errors" do
|
should "notice status errors" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Lint.new(lambda { |env|
|
Rack::Lint.new(lambda { |env|
|
||||||
["cc", {}, ""]
|
["cc", {}, ""]
|
||||||
|
@ -162,7 +160,7 @@ context "Rack::Lint" do
|
||||||
message.should.match(/must be >=100 seen as integer/)
|
message.should.match(/must be >=100 seen as integer/)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "notices header errors" do
|
should "notice header errors" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Lint.new(lambda { |env|
|
Rack::Lint.new(lambda { |env|
|
||||||
[200, Object.new, []]
|
[200, Object.new, []]
|
||||||
|
@ -235,7 +233,7 @@ context "Rack::Lint" do
|
||||||
}.should.not.raise(Rack::Lint::LintError)
|
}.should.not.raise(Rack::Lint::LintError)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "notices content-type errors" do
|
should "notice content-type errors" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Lint.new(lambda { |env|
|
Rack::Lint.new(lambda { |env|
|
||||||
[200, {"Content-length" => "0"}, []]
|
[200, {"Content-length" => "0"}, []]
|
||||||
|
@ -253,7 +251,7 @@ context "Rack::Lint" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "notices content-length errors" do
|
should "notice content-length errors" do
|
||||||
[100, 101, 204, 304].each do |status|
|
[100, 101, 204, 304].each do |status|
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Lint.new(lambda { |env|
|
Rack::Lint.new(lambda { |env|
|
||||||
|
@ -266,12 +264,12 @@ context "Rack::Lint" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Lint.new(lambda { |env|
|
Rack::Lint.new(lambda { |env|
|
||||||
[200, {"Content-type" => "text/plain", "Content-Length" => "1"}, []]
|
[200, {"Content-type" => "text/plain", "Content-Length" => "1"}, []]
|
||||||
}).call(env({}))
|
}).call(env({}))[2].each { }
|
||||||
}.should.raise(Rack::Lint::LintError).
|
}.should.raise(Rack::Lint::LintError).
|
||||||
message.should.match(/Content-Length header was 1, but should be 0/)
|
message.should.match(/Content-Length header was 1, but should be 0/)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "notices body errors" do
|
should "notice body errors" do
|
||||||
lambda {
|
lambda {
|
||||||
status, header, body = Rack::Lint.new(lambda { |env|
|
status, header, body = Rack::Lint.new(lambda { |env|
|
||||||
[200, {"Content-type" => "text/plain","Content-length" => "3"}, [1,2,3]]
|
[200, {"Content-type" => "text/plain","Content-length" => "3"}, [1,2,3]]
|
||||||
|
@ -281,7 +279,7 @@ context "Rack::Lint" do
|
||||||
message.should.match(/yielded non-string/)
|
message.should.match(/yielded non-string/)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "notices input handling errors" do
|
should "notice input handling errors" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Lint.new(lambda { |env|
|
Rack::Lint.new(lambda { |env|
|
||||||
env["rack.input"].gets("\r\n")
|
env["rack.input"].gets("\r\n")
|
||||||
|
@ -425,7 +423,7 @@ context "Rack::Lint" do
|
||||||
message.should.match(/close must not be called/)
|
message.should.match(/close must not be called/)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "notices error handling errors" do
|
should "notice error handling errors" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Lint.new(lambda { |env|
|
Rack::Lint.new(lambda { |env|
|
||||||
env["rack.errors"].write(42)
|
env["rack.errors"].write(42)
|
||||||
|
@ -443,7 +441,7 @@ context "Rack::Lint" do
|
||||||
message.should.match(/close must not be called/)
|
message.should.match(/close must not be called/)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "notices HEAD errors" do
|
should "notice HEAD errors" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Lint.new(lambda { |env|
|
Rack::Lint.new(lambda { |env|
|
||||||
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, []]
|
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, []]
|
||||||
|
@ -453,12 +451,12 @@ context "Rack::Lint" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::Lint.new(lambda { |env|
|
Rack::Lint.new(lambda { |env|
|
||||||
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]]
|
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]]
|
||||||
}).call(env({"REQUEST_METHOD" => "HEAD"}))
|
}).call(env({"REQUEST_METHOD" => "HEAD"}))[2].each { }
|
||||||
}.should.raise(Rack::Lint::LintError).
|
}.should.raise(Rack::Lint::LintError).
|
||||||
message.should.match(/body was given for HEAD/)
|
message.should.match(/body was given for HEAD/)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "passes valid read calls" do
|
should "pass valid read calls" do
|
||||||
hello_str = "hello world"
|
hello_str = "hello world"
|
||||||
hello_str.force_encoding("ASCII-8BIT") if hello_str.respond_to? :force_encoding
|
hello_str.force_encoding("ASCII-8BIT") if hello_str.respond_to? :force_encoding
|
||||||
lambda {
|
lambda {
|
||||||
|
@ -505,19 +503,8 @@ context "Rack::Lint" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "Rack::Lint::InputWrapper" do
|
describe "Rack::Lint::InputWrapper" do
|
||||||
specify "delegates :size to underlying IO object" do
|
should "delegate :rewind to underlying IO object" do
|
||||||
class IOMock
|
|
||||||
def size
|
|
||||||
101
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
wrapper = Rack::Lint::InputWrapper.new(IOMock.new)
|
|
||||||
wrapper.size.should == 101
|
|
||||||
end
|
|
||||||
|
|
||||||
specify "delegates :rewind to underlying IO object" do
|
|
||||||
io = StringIO.new("123")
|
io = StringIO.new("123")
|
||||||
wrapper = Rack::Lint::InputWrapper.new(io)
|
wrapper = Rack::Lint::InputWrapper.new(io)
|
||||||
wrapper.read.should.equal "123"
|
wrapper.read.should.equal "123"
|
|
@ -1,29 +1,27 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/lobster'
|
require 'rack/lobster'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::Lobster::LambdaLobster" do
|
describe Rack::Lobster::LambdaLobster do
|
||||||
specify "should be a single lambda" do
|
should "be a single lambda" do
|
||||||
Rack::Lobster::LambdaLobster.should.be.kind_of Proc
|
Rack::Lobster::LambdaLobster.should.be.kind_of Proc
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should look like a lobster" do
|
should "look like a lobster" do
|
||||||
res = Rack::MockRequest.new(Rack::Lobster::LambdaLobster).get("/")
|
res = Rack::MockRequest.new(Rack::Lobster::LambdaLobster).get("/")
|
||||||
res.should.be.ok
|
res.should.be.ok
|
||||||
res.body.should.include "(,(,,(,,,("
|
res.body.should.include "(,(,,(,,,("
|
||||||
res.body.should.include "?flip"
|
res.body.should.include "?flip"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be flippable" do
|
should "be flippable" do
|
||||||
res = Rack::MockRequest.new(Rack::Lobster::LambdaLobster).get("/?flip")
|
res = Rack::MockRequest.new(Rack::Lobster::LambdaLobster).get("/?flip")
|
||||||
res.should.be.ok
|
res.should.be.ok
|
||||||
res.body.should.include "(,,,(,,(,("
|
res.body.should.include "(,,,(,,(,("
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "Rack::Lobster" do
|
describe Rack::Lobster do
|
||||||
specify "should look like a lobster" do
|
should "look like a lobster" do
|
||||||
res = Rack::MockRequest.new(Rack::Lobster.new).get("/")
|
res = Rack::MockRequest.new(Rack::Lobster.new).get("/")
|
||||||
res.should.be.ok
|
res.should.be.ok
|
||||||
res.body.should.include "(,(,,(,,,("
|
res.body.should.include "(,(,,(,,,("
|
||||||
|
@ -31,13 +29,13 @@ context "Rack::Lobster" do
|
||||||
res.body.should.include "crash"
|
res.body.should.include "crash"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be flippable" do
|
should "be flippable" do
|
||||||
res = Rack::MockRequest.new(Rack::Lobster.new).get("/?flip=left")
|
res = Rack::MockRequest.new(Rack::Lobster.new).get("/?flip=left")
|
||||||
res.should.be.ok
|
res.should.be.ok
|
||||||
res.body.should.include "(,,,(,,(,("
|
res.body.should.include "(,,,(,,(,("
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should provide crashing for testing purposes" do
|
should "provide crashing for testing purposes" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::MockRequest.new(Rack::Lobster.new).get("/?flip=crash")
|
Rack::MockRequest.new(Rack::Lobster.new).get("/?flip=crash")
|
||||||
}.should.raise
|
}.should.raise
|
|
@ -1,10 +1,7 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/mock'
|
|
||||||
require 'rack/lock'
|
require 'rack/lock'
|
||||||
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::Lock" do
|
class Lock
|
||||||
class Lock
|
|
||||||
attr_reader :synchronized
|
attr_reader :synchronized
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
|
@ -15,23 +12,24 @@ context "Rack::Lock" do
|
||||||
@synchronized = true
|
@synchronized = true
|
||||||
yield
|
yield
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should call synchronize on lock" do
|
describe Rack::Lock do
|
||||||
|
should "call synchronize on lock" do
|
||||||
lock = Lock.new
|
lock = Lock.new
|
||||||
env = Rack::MockRequest.env_for("/")
|
env = Rack::MockRequest.env_for("/")
|
||||||
app = Rack::Lock.new(lambda { |env| }, lock)
|
app = Rack::Lock.new(lambda { |inner_env| }, lock)
|
||||||
lock.synchronized.should.equal false
|
lock.synchronized.should.equal false
|
||||||
app.call(env)
|
app.call(env)
|
||||||
lock.synchronized.should.equal true
|
lock.synchronized.should.equal true
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should set multithread flag to false" do
|
should "set multithread flag to false" do
|
||||||
app = Rack::Lock.new(lambda { |env| env['rack.multithread'] })
|
app = Rack::Lock.new(lambda { |env| env['rack.multithread'] })
|
||||||
app.call(Rack::MockRequest.env_for("/")).should.equal false
|
app.call(Rack::MockRequest.env_for("/")).should.equal false
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should reset original multithread flag when exiting lock" do
|
should "reset original multithread flag when exiting lock" do
|
||||||
app = Rack::Lock.new(lambda { |env| env })
|
app = Rack::Lock.new(lambda { |env| env })
|
||||||
app.call(Rack::MockRequest.env_for("/"))['rack.multithread'].should.equal true
|
app.call(Rack::MockRequest.env_for("/"))['rack.multithread'].should.equal true
|
||||||
end
|
end
|
|
@ -1,9 +1,8 @@
|
||||||
require 'rack/logger'
|
|
||||||
require 'rack/lint'
|
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
|
require 'rack/logger'
|
||||||
|
|
||||||
context "Rack::Logger" do
|
describe Rack::Logger do
|
||||||
specify "logs to rack.errors" do
|
should "log to rack.errors" do
|
||||||
app = lambda { |env|
|
app = lambda { |env|
|
||||||
log = env['rack.logger']
|
log = env['rack.logger']
|
||||||
log.debug("Created logger")
|
log.debug("Created logger")
|
||||||
|
@ -14,8 +13,8 @@ context "Rack::Logger" do
|
||||||
}
|
}
|
||||||
|
|
||||||
errors = StringIO.new
|
errors = StringIO.new
|
||||||
Rack::Logger.new(app).call({'rack.errors' => errors})
|
Rack::Logger.new(app).call('rack.errors' => errors)
|
||||||
errors.string.should.match "INFO -- : Program started"
|
errors.string.should.match(/INFO -- : Program started/)
|
||||||
errors.string.should.match "WARN -- : Nothing to do"
|
errors.string.should.match(/WARN -- : Nothing to do/)
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,58 +1,56 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/mock'
|
|
||||||
require 'rack/methodoverride'
|
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
|
require 'rack/methodoverride'
|
||||||
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::MethodOverride" do
|
describe Rack::MethodOverride do
|
||||||
specify "should not affect GET requests" do
|
should "not affect GET requests" do
|
||||||
env = Rack::MockRequest.env_for("/?_method=delete", :method => "GET")
|
env = Rack::MockRequest.env_for("/?_method=delete", :method => "GET")
|
||||||
app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) })
|
app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
|
||||||
req = app.call(env)
|
req = app.call(env)
|
||||||
|
|
||||||
req.env["REQUEST_METHOD"].should.equal "GET"
|
req.env["REQUEST_METHOD"].should.equal "GET"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "_method parameter should modify REQUEST_METHOD for POST requests" do
|
should "modify REQUEST_METHOD for POST requests when _method parameter is set" do
|
||||||
env = Rack::MockRequest.env_for("/", :method => "POST", :input => "_method=put")
|
env = Rack::MockRequest.env_for("/", :method => "POST", :input => "_method=put")
|
||||||
app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) })
|
app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
|
||||||
req = app.call(env)
|
req = app.call(env)
|
||||||
|
|
||||||
req.env["REQUEST_METHOD"].should.equal "PUT"
|
req.env["REQUEST_METHOD"].should.equal "PUT"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "X-HTTP-Method-Override header should modify REQUEST_METHOD for POST requests" do
|
should "modify REQUEST_METHOD for POST requests when X-HTTP-Method-Override is set" do
|
||||||
env = Rack::MockRequest.env_for("/",
|
env = Rack::MockRequest.env_for("/",
|
||||||
:method => "POST",
|
:method => "POST",
|
||||||
"HTTP_X_HTTP_METHOD_OVERRIDE" => "PUT"
|
"HTTP_X_HTTP_METHOD_OVERRIDE" => "PUT"
|
||||||
)
|
)
|
||||||
app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) })
|
app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
|
||||||
req = app.call(env)
|
req = app.call(env)
|
||||||
|
|
||||||
req.env["REQUEST_METHOD"].should.equal "PUT"
|
req.env["REQUEST_METHOD"].should.equal "PUT"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should not modify REQUEST_METHOD if the method is unknown" do
|
should "not modify REQUEST_METHOD if the method is unknown" do
|
||||||
env = Rack::MockRequest.env_for("/", :method => "POST", :input => "_method=foo")
|
env = Rack::MockRequest.env_for("/", :method => "POST", :input => "_method=foo")
|
||||||
app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) })
|
app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
|
||||||
req = app.call(env)
|
req = app.call(env)
|
||||||
|
|
||||||
req.env["REQUEST_METHOD"].should.equal "POST"
|
req.env["REQUEST_METHOD"].should.equal "POST"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should not modify REQUEST_METHOD when _method is nil" do
|
should "not modify REQUEST_METHOD when _method is nil" do
|
||||||
env = Rack::MockRequest.env_for("/", :method => "POST", :input => "foo=bar")
|
env = Rack::MockRequest.env_for("/", :method => "POST", :input => "foo=bar")
|
||||||
app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) })
|
app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
|
||||||
req = app.call(env)
|
req = app.call(env)
|
||||||
|
|
||||||
req.env["REQUEST_METHOD"].should.equal "POST"
|
req.env["REQUEST_METHOD"].should.equal "POST"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should store the original REQUEST_METHOD prior to overriding" do
|
should "store the original REQUEST_METHOD prior to overriding" do
|
||||||
env = Rack::MockRequest.env_for("/",
|
env = Rack::MockRequest.env_for("/",
|
||||||
:method => "POST",
|
:method => "POST",
|
||||||
:input => "_method=options")
|
:input => "_method=options")
|
||||||
app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) })
|
app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
|
||||||
req = app.call(env)
|
req = app.call(env)
|
||||||
|
|
||||||
req.env["rack.methodoverride.original_method"].should.equal "POST"
|
req.env["rack.methodoverride.original_method"].should.equal "POST"
|
|
@ -1,7 +1,5 @@
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
require 'rack/request'
|
|
||||||
require 'rack/response'
|
|
||||||
|
|
||||||
app = lambda { |env|
|
app = lambda { |env|
|
||||||
req = Rack::Request.new(env)
|
req = Rack::Request.new(env)
|
||||||
|
@ -17,19 +15,19 @@ app = lambda { |env|
|
||||||
"Content-Type" => "text/yaml").finish
|
"Content-Type" => "text/yaml").finish
|
||||||
}
|
}
|
||||||
|
|
||||||
context "Rack::MockRequest" do
|
describe Rack::MockRequest do
|
||||||
specify "should return a MockResponse" do
|
should "return a MockResponse" do
|
||||||
res = Rack::MockRequest.new(app).get("")
|
res = Rack::MockRequest.new(app).get("")
|
||||||
res.should.be.kind_of Rack::MockResponse
|
res.should.be.kind_of Rack::MockResponse
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be able to only return the environment" do
|
should "be able to only return the environment" do
|
||||||
env = Rack::MockRequest.env_for("")
|
env = Rack::MockRequest.env_for("")
|
||||||
env.should.be.kind_of Hash
|
env.should.be.kind_of Hash
|
||||||
env.should.include "rack.version"
|
env.should.include "rack.version"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should provide sensible defaults" do
|
should "provide sensible defaults" do
|
||||||
res = Rack::MockRequest.new(app).request
|
res = Rack::MockRequest.new(app).request
|
||||||
|
|
||||||
env = YAML.load(res.body)
|
env = YAML.load(res.body)
|
||||||
|
@ -43,7 +41,7 @@ context "Rack::MockRequest" do
|
||||||
env["mock.postdata"].should.be.empty
|
env["mock.postdata"].should.be.empty
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should allow GET/POST/PUT/DELETE" do
|
should "allow GET/POST/PUT/DELETE" do
|
||||||
res = Rack::MockRequest.new(app).get("", :input => "foo")
|
res = Rack::MockRequest.new(app).get("", :input => "foo")
|
||||||
env = YAML.load(res.body)
|
env = YAML.load(res.body)
|
||||||
env["REQUEST_METHOD"].should.equal "GET"
|
env["REQUEST_METHOD"].should.equal "GET"
|
||||||
|
@ -64,12 +62,12 @@ context "Rack::MockRequest" do
|
||||||
should.equal "OPTIONS"
|
should.equal "OPTIONS"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should set content length" do
|
should "set content length" do
|
||||||
env = Rack::MockRequest.env_for("/", :input => "foo")
|
env = Rack::MockRequest.env_for("/", :input => "foo")
|
||||||
env["CONTENT_LENGTH"].should.equal "3"
|
env["CONTENT_LENGTH"].should.equal "3"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should allow posting" do
|
should "allow posting" do
|
||||||
res = Rack::MockRequest.new(app).get("", :input => "foo")
|
res = Rack::MockRequest.new(app).get("", :input => "foo")
|
||||||
env = YAML.load(res.body)
|
env = YAML.load(res.body)
|
||||||
env["mock.postdata"].should.equal "foo"
|
env["mock.postdata"].should.equal "foo"
|
||||||
|
@ -79,7 +77,7 @@ context "Rack::MockRequest" do
|
||||||
env["mock.postdata"].should.equal "foo"
|
env["mock.postdata"].should.equal "foo"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should use all parts of an URL" do
|
should "use all parts of an URL" do
|
||||||
res = Rack::MockRequest.new(app).
|
res = Rack::MockRequest.new(app).
|
||||||
get("https://bla.example.org:9292/meh/foo?bar")
|
get("https://bla.example.org:9292/meh/foo?bar")
|
||||||
res.should.be.kind_of Rack::MockResponse
|
res.should.be.kind_of Rack::MockResponse
|
||||||
|
@ -93,7 +91,7 @@ context "Rack::MockRequest" do
|
||||||
env["rack.url_scheme"].should.equal "https"
|
env["rack.url_scheme"].should.equal "https"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should set SSL port and HTTP flag on when using https" do
|
should "set SSL port and HTTP flag on when using https" do
|
||||||
res = Rack::MockRequest.new(app).
|
res = Rack::MockRequest.new(app).
|
||||||
get("https://example.org/foo")
|
get("https://example.org/foo")
|
||||||
res.should.be.kind_of Rack::MockResponse
|
res.should.be.kind_of Rack::MockResponse
|
||||||
|
@ -108,7 +106,7 @@ context "Rack::MockRequest" do
|
||||||
env["HTTPS"].should.equal "on"
|
env["HTTPS"].should.equal "on"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should prepend slash to uri path" do
|
should "prepend slash to uri path" do
|
||||||
res = Rack::MockRequest.new(app).
|
res = Rack::MockRequest.new(app).
|
||||||
get("foo")
|
get("foo")
|
||||||
res.should.be.kind_of Rack::MockResponse
|
res.should.be.kind_of Rack::MockResponse
|
||||||
|
@ -122,33 +120,33 @@ context "Rack::MockRequest" do
|
||||||
env["rack.url_scheme"].should.equal "http"
|
env["rack.url_scheme"].should.equal "http"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should properly convert method name to an uppercase string" do
|
should "properly convert method name to an uppercase string" do
|
||||||
res = Rack::MockRequest.new(app).request(:get)
|
res = Rack::MockRequest.new(app).request(:get)
|
||||||
env = YAML.load(res.body)
|
env = YAML.load(res.body)
|
||||||
env["REQUEST_METHOD"].should.equal "GET"
|
env["REQUEST_METHOD"].should.equal "GET"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should accept params and build query string for GET requests" do
|
should "accept params and build query string for GET requests" do
|
||||||
res = Rack::MockRequest.new(app).get("/foo?baz=2", :params => {:foo => {:bar => "1"}})
|
res = Rack::MockRequest.new(app).get("/foo?baz=2", :params => {:foo => {:bar => "1"}})
|
||||||
env = YAML.load(res.body)
|
env = YAML.load(res.body)
|
||||||
env["REQUEST_METHOD"].should.equal "GET"
|
env["REQUEST_METHOD"].should.equal "GET"
|
||||||
env["QUERY_STRING"].should.match "baz=2"
|
env["QUERY_STRING"].should.include "baz=2"
|
||||||
env["QUERY_STRING"].should.match "foo[bar]=1"
|
env["QUERY_STRING"].should.include "foo[bar]=1"
|
||||||
env["PATH_INFO"].should.equal "/foo"
|
env["PATH_INFO"].should.equal "/foo"
|
||||||
env["mock.postdata"].should.equal ""
|
env["mock.postdata"].should.equal ""
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should accept raw input in params for GET requests" do
|
should "accept raw input in params for GET requests" do
|
||||||
res = Rack::MockRequest.new(app).get("/foo?baz=2", :params => "foo[bar]=1")
|
res = Rack::MockRequest.new(app).get("/foo?baz=2", :params => "foo[bar]=1")
|
||||||
env = YAML.load(res.body)
|
env = YAML.load(res.body)
|
||||||
env["REQUEST_METHOD"].should.equal "GET"
|
env["REQUEST_METHOD"].should.equal "GET"
|
||||||
env["QUERY_STRING"].should.match "baz=2"
|
env["QUERY_STRING"].should.include "baz=2"
|
||||||
env["QUERY_STRING"].should.match "foo[bar]=1"
|
env["QUERY_STRING"].should.include "foo[bar]=1"
|
||||||
env["PATH_INFO"].should.equal "/foo"
|
env["PATH_INFO"].should.equal "/foo"
|
||||||
env["mock.postdata"].should.equal ""
|
env["mock.postdata"].should.equal ""
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should accept params and build url encoded params for POST requests" do
|
should "accept params and build url encoded params for POST requests" do
|
||||||
res = Rack::MockRequest.new(app).post("/foo", :params => {:foo => {:bar => "1"}})
|
res = Rack::MockRequest.new(app).post("/foo", :params => {:foo => {:bar => "1"}})
|
||||||
env = YAML.load(res.body)
|
env = YAML.load(res.body)
|
||||||
env["REQUEST_METHOD"].should.equal "POST"
|
env["REQUEST_METHOD"].should.equal "POST"
|
||||||
|
@ -158,7 +156,7 @@ context "Rack::MockRequest" do
|
||||||
env["mock.postdata"].should.equal "foo[bar]=1"
|
env["mock.postdata"].should.equal "foo[bar]=1"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should accept raw input in params for POST requests" do
|
should "accept raw input in params for POST requests" do
|
||||||
res = Rack::MockRequest.new(app).post("/foo", :params => "foo[bar]=1")
|
res = Rack::MockRequest.new(app).post("/foo", :params => "foo[bar]=1")
|
||||||
env = YAML.load(res.body)
|
env = YAML.load(res.body)
|
||||||
env["REQUEST_METHOD"].should.equal "POST"
|
env["REQUEST_METHOD"].should.equal "POST"
|
||||||
|
@ -168,7 +166,7 @@ context "Rack::MockRequest" do
|
||||||
env["mock.postdata"].should.equal "foo[bar]=1"
|
env["mock.postdata"].should.equal "foo[bar]=1"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should accept params and build multipart encoded params for POST requests" do
|
should "accept params and build multipart encoded params for POST requests" do
|
||||||
files = Rack::Utils::Multipart::UploadedFile.new(File.join(File.dirname(__FILE__), "multipart", "file1.txt"))
|
files = Rack::Utils::Multipart::UploadedFile.new(File.join(File.dirname(__FILE__), "multipart", "file1.txt"))
|
||||||
res = Rack::MockRequest.new(app).post("/foo", :params => { "submit-name" => "Larry", "files" => files })
|
res = Rack::MockRequest.new(app).post("/foo", :params => { "submit-name" => "Larry", "files" => files })
|
||||||
env = YAML.load(res.body)
|
env = YAML.load(res.body)
|
||||||
|
@ -179,7 +177,7 @@ context "Rack::MockRequest" do
|
||||||
env["mock.postdata"].length.should.equal 206
|
env["mock.postdata"].length.should.equal 206
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should behave valid according to the Rack spec" do
|
should "behave valid according to the Rack spec" do
|
||||||
lambda {
|
lambda {
|
||||||
res = Rack::MockRequest.new(app).
|
res = Rack::MockRequest.new(app).
|
||||||
get("https://bla.example.org:9292/meh/foo?bar", :lint => true)
|
get("https://bla.example.org:9292/meh/foo?bar", :lint => true)
|
||||||
|
@ -187,8 +185,8 @@ context "Rack::MockRequest" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "Rack::MockResponse" do
|
describe Rack::MockResponse do
|
||||||
specify "should provide access to the HTTP status" do
|
should "provide access to the HTTP status" do
|
||||||
res = Rack::MockRequest.new(app).get("")
|
res = Rack::MockRequest.new(app).get("")
|
||||||
res.should.be.successful
|
res.should.be.successful
|
||||||
res.should.be.ok
|
res.should.be.ok
|
||||||
|
@ -209,18 +207,18 @@ context "Rack::MockResponse" do
|
||||||
res.should.be.empty
|
res.should.be.empty
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should provide access to the HTTP headers" do
|
should "provide access to the HTTP headers" do
|
||||||
res = Rack::MockRequest.new(app).get("")
|
res = Rack::MockRequest.new(app).get("")
|
||||||
res.should.include "Content-Type"
|
res.should.include "Content-Type"
|
||||||
res.headers["Content-Type"].should.equal "text/yaml"
|
res.headers["Content-Type"].should.equal "text/yaml"
|
||||||
res.original_headers["Content-Type"].should.equal "text/yaml"
|
res.original_headers["Content-Type"].should.equal "text/yaml"
|
||||||
res["Content-Type"].should.equal "text/yaml"
|
res["Content-Type"].should.equal "text/yaml"
|
||||||
res.content_type.should.equal "text/yaml"
|
res.content_type.should.equal "text/yaml"
|
||||||
res.content_length.should.be 414 # needs change often.
|
res.content_length.should.be > 0
|
||||||
res.location.should.be.nil
|
res.location.should.be.nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should provide access to the HTTP body" do
|
should "provide access to the HTTP body" do
|
||||||
res = Rack::MockRequest.new(app).get("")
|
res = Rack::MockRequest.new(app).get("")
|
||||||
res.body.should =~ /rack/
|
res.body.should =~ /rack/
|
||||||
res.should =~ /rack/
|
res.should =~ /rack/
|
||||||
|
@ -228,14 +226,14 @@ context "Rack::MockResponse" do
|
||||||
res.should.satisfy { |r| r.match(/rack/) }
|
res.should.satisfy { |r| r.match(/rack/) }
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should provide access to the Rack errors" do
|
should "provide access to the Rack errors" do
|
||||||
res = Rack::MockRequest.new(app).get("/?error=foo", :lint => true)
|
res = Rack::MockRequest.new(app).get("/?error=foo", :lint => true)
|
||||||
res.should.be.ok
|
res.should.be.ok
|
||||||
res.errors.should.not.be.empty
|
res.errors.should.not.be.empty
|
||||||
res.errors.should.include "foo"
|
res.errors.should.include "foo"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should optionally make Rack errors fatal" do
|
should "optionally make Rack errors fatal" do
|
||||||
lambda {
|
lambda {
|
||||||
Rack::MockRequest.new(app).get("/?error=foo", :fatal => true)
|
Rack::MockRequest.new(app).get("/?error=foo", :fatal => true)
|
||||||
}.should.raise(Rack::MockRequest::FatalWarning)
|
}.should.raise(Rack::MockRequest::FatalWarning)
|
|
@ -1,37 +1,32 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
require 'rack'
|
||||||
require 'rack/handler/mongrel'
|
require 'rack/handler/mongrel'
|
||||||
require 'rack/urlmap'
|
require File.expand_path('../testrequest', __FILE__)
|
||||||
require 'rack/lint'
|
|
||||||
require 'testrequest'
|
|
||||||
require 'timeout'
|
require 'timeout'
|
||||||
|
|
||||||
Thread.abort_on_exception = true
|
Thread.abort_on_exception = true
|
||||||
$tcp_defer_accept_opts = nil
|
$tcp_defer_accept_opts = nil
|
||||||
$tcp_cork_opts = nil
|
$tcp_cork_opts = nil
|
||||||
|
|
||||||
context "Rack::Handler::Mongrel" do
|
describe Rack::Handler::Mongrel do
|
||||||
include TestRequest::Helpers
|
extend TestRequest::Helpers
|
||||||
|
|
||||||
setup do
|
@server = Mongrel::HttpServer.new(@host='0.0.0.0', @port=9201)
|
||||||
server = Mongrel::HttpServer.new(@host='0.0.0.0', @port=9201)
|
@server.register('/test',
|
||||||
server.register('/test',
|
|
||||||
Rack::Handler::Mongrel.new(Rack::Lint.new(TestRequest.new)))
|
Rack::Handler::Mongrel.new(Rack::Lint.new(TestRequest.new)))
|
||||||
server.register('/stream',
|
@server.register('/stream',
|
||||||
Rack::Handler::Mongrel.new(Rack::Lint.new(StreamingRequest)))
|
Rack::Handler::Mongrel.new(Rack::Lint.new(StreamingRequest)))
|
||||||
@acc = server.run
|
@acc = @server.run
|
||||||
end
|
|
||||||
|
|
||||||
specify "should respond" do
|
should "respond" do
|
||||||
lambda {
|
lambda {
|
||||||
GET("/test")
|
GET("/test")
|
||||||
}.should.not.raise
|
}.should.not.raise
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be a Mongrel" do
|
should "be a Mongrel" do
|
||||||
GET("/test")
|
GET("/test")
|
||||||
status.should.be 200
|
status.should.equal 200
|
||||||
response["SERVER_SOFTWARE"].should =~ /Mongrel/
|
response["SERVER_SOFTWARE"].should =~ /Mongrel/
|
||||||
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
||||||
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
||||||
|
@ -39,15 +34,15 @@ context "Rack::Handler::Mongrel" do
|
||||||
response["SERVER_NAME"].should.equal "0.0.0.0"
|
response["SERVER_NAME"].should.equal "0.0.0.0"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have rack headers" do
|
should "have rack headers" do
|
||||||
GET("/test")
|
GET("/test")
|
||||||
response["rack.version"].should.equal [1,1]
|
response["rack.version"].should.equal [1,1]
|
||||||
response["rack.multithread"].should.be true
|
response["rack.multithread"].should.be.true
|
||||||
response["rack.multiprocess"].should.be false
|
response["rack.multiprocess"].should.be.false
|
||||||
response["rack.run_once"].should.be false
|
response["rack.run_once"].should.be.false
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have CGI headers on GET" do
|
should "have CGI headers on GET" do
|
||||||
GET("/test")
|
GET("/test")
|
||||||
response["REQUEST_METHOD"].should.equal "GET"
|
response["REQUEST_METHOD"].should.equal "GET"
|
||||||
response["SCRIPT_NAME"].should.equal "/test"
|
response["SCRIPT_NAME"].should.equal "/test"
|
||||||
|
@ -64,7 +59,7 @@ context "Rack::Handler::Mongrel" do
|
||||||
response["QUERY_STRING"].should.equal "quux=1"
|
response["QUERY_STRING"].should.equal "quux=1"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have CGI headers on POST" do
|
should "have CGI headers on POST" do
|
||||||
POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
||||||
status.should.equal 200
|
status.should.equal 200
|
||||||
response["REQUEST_METHOD"].should.equal "POST"
|
response["REQUEST_METHOD"].should.equal "POST"
|
||||||
|
@ -75,18 +70,18 @@ context "Rack::Handler::Mongrel" do
|
||||||
response["test.postdata"].should.equal "rack-form-data=23"
|
response["test.postdata"].should.equal "rack-form-data=23"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should support HTTP auth" do
|
should "support HTTP auth" do
|
||||||
GET("/test", {:user => "ruth", :passwd => "secret"})
|
GET("/test", {:user => "ruth", :passwd => "secret"})
|
||||||
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should set status" do
|
should "set status" do
|
||||||
GET("/test?secret")
|
GET("/test?secret")
|
||||||
status.should.equal 403
|
status.should.equal 403
|
||||||
response["rack.url_scheme"].should.equal "http"
|
response["rack.url_scheme"].should.equal "http"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should provide a .run" do
|
should "provide a .run" do
|
||||||
block_ran = false
|
block_ran = false
|
||||||
Thread.new {
|
Thread.new {
|
||||||
Rack::Handler::Mongrel.run(lambda {}, {:Port => 9211}) { |server|
|
Rack::Handler::Mongrel.run(lambda {}, {:Port => 9211}) { |server|
|
||||||
|
@ -95,16 +90,16 @@ context "Rack::Handler::Mongrel" do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sleep 1
|
sleep 1
|
||||||
block_ran.should.be true
|
block_ran.should.be.true
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should provide a .run that maps a hash" do
|
should "provide a .run that maps a hash" do
|
||||||
block_ran = false
|
block_ran = false
|
||||||
Thread.new {
|
Thread.new {
|
||||||
map = {'/'=>lambda{},'/foo'=>lambda{}}
|
map = {'/'=>lambda{},'/foo'=>lambda{}}
|
||||||
Rack::Handler::Mongrel.run(map, :map => true, :Port => 9221) { |server|
|
Rack::Handler::Mongrel.run(map, :map => true, :Port => 9221) { |server|
|
||||||
server.should.be.kind_of Mongrel::HttpServer
|
server.should.be.kind_of Mongrel::HttpServer
|
||||||
server.classifier.uris.size.should.be 2
|
server.classifier.uris.size.should.equal 2
|
||||||
server.classifier.uris.should.not.include '/arf'
|
server.classifier.uris.should.not.include '/arf'
|
||||||
server.classifier.uris.should.include '/'
|
server.classifier.uris.should.include '/'
|
||||||
server.classifier.uris.should.include '/foo'
|
server.classifier.uris.should.include '/foo'
|
||||||
|
@ -112,16 +107,16 @@ context "Rack::Handler::Mongrel" do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sleep 1
|
sleep 1
|
||||||
block_ran.should.be true
|
block_ran.should.be.true
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should provide a .run that maps a urlmap" do
|
should "provide a .run that maps a urlmap" do
|
||||||
block_ran = false
|
block_ran = false
|
||||||
Thread.new {
|
Thread.new {
|
||||||
map = Rack::URLMap.new({'/'=>lambda{},'/bar'=>lambda{}})
|
map = Rack::URLMap.new({'/'=>lambda{},'/bar'=>lambda{}})
|
||||||
Rack::Handler::Mongrel.run(map, {:map => true, :Port => 9231}) { |server|
|
Rack::Handler::Mongrel.run(map, {:map => true, :Port => 9231}) { |server|
|
||||||
server.should.be.kind_of Mongrel::HttpServer
|
server.should.be.kind_of Mongrel::HttpServer
|
||||||
server.classifier.uris.size.should.be 2
|
server.classifier.uris.size.should.equal 2
|
||||||
server.classifier.uris.should.not.include '/arf'
|
server.classifier.uris.should.not.include '/arf'
|
||||||
server.classifier.uris.should.include '/'
|
server.classifier.uris.should.include '/'
|
||||||
server.classifier.uris.should.include '/bar'
|
server.classifier.uris.should.include '/bar'
|
||||||
|
@ -129,10 +124,10 @@ context "Rack::Handler::Mongrel" do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sleep 1
|
sleep 1
|
||||||
block_ran.should.be true
|
block_ran.should.be.true
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should provide a .run that maps a urlmap restricting by host" do
|
should "provide a .run that maps a urlmap restricting by host" do
|
||||||
block_ran = false
|
block_ran = false
|
||||||
Thread.new {
|
Thread.new {
|
||||||
map = Rack::URLMap.new({
|
map = Rack::URLMap.new({
|
||||||
|
@ -148,22 +143,22 @@ context "Rack::Handler::Mongrel" do
|
||||||
Rack::Handler::Mongrel.run(map, opt) { |server|
|
Rack::Handler::Mongrel.run(map, opt) { |server|
|
||||||
server.should.be.kind_of Mongrel::HttpServer
|
server.should.be.kind_of Mongrel::HttpServer
|
||||||
server.classifier.uris.should.include '/'
|
server.classifier.uris.should.include '/'
|
||||||
server.classifier.handler_map['/'].size.should.be 2
|
server.classifier.handler_map['/'].size.should.equal 2
|
||||||
server.classifier.uris.should.include '/foo'
|
server.classifier.uris.should.include '/foo'
|
||||||
server.classifier.handler_map['/foo'].size.should.be 1
|
server.classifier.handler_map['/foo'].size.should.equal 1
|
||||||
server.classifier.uris.should.include '/bar'
|
server.classifier.uris.should.include '/bar'
|
||||||
server.classifier.handler_map['/bar'].size.should.be 2
|
server.classifier.handler_map['/bar'].size.should.equal 2
|
||||||
server.classifier.uris.should.not.include '/qux'
|
server.classifier.uris.should.not.include '/qux'
|
||||||
server.classifier.uris.should.not.include '/arf'
|
server.classifier.uris.should.not.include '/arf'
|
||||||
server.classifier.uris.size.should.be 3
|
server.classifier.uris.size.should.equal 3
|
||||||
block_ran = true
|
block_ran = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sleep 1
|
sleep 1
|
||||||
block_ran.should.be true
|
block_ran.should.be.true
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should stream #each part of the response" do
|
should "stream #each part of the response" do
|
||||||
body = ''
|
body = ''
|
||||||
begin
|
begin
|
||||||
Timeout.timeout(1) do
|
Timeout.timeout(1) do
|
||||||
|
@ -179,11 +174,10 @@ context "Rack::Handler::Mongrel" do
|
||||||
body.should.not.be.empty
|
body.should.not.be.empty
|
||||||
end
|
end
|
||||||
|
|
||||||
teardown do
|
|
||||||
@acc.raise Mongrel::StopServer
|
@acc.raise Mongrel::StopServer
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue LoadError
|
rescue LoadError => ex
|
||||||
$stderr.puts "Skipping Rack::Handler::Mongrel tests (Mongrel is required). `gem install mongrel` and try again."
|
warn ex
|
||||||
|
warn "Skipping Rack::Handler::Mongrel tests (Mongrel is required). `gem install mongrel` and try again."
|
||||||
end
|
end
|
|
@ -1,13 +1,12 @@
|
||||||
require 'rack/nulllogger'
|
require 'rack/nulllogger'
|
||||||
require 'rack/lint'
|
|
||||||
require 'rack/mock'
|
|
||||||
|
|
||||||
context "Rack::NullLogger" do
|
describe Rack::NullLogger do
|
||||||
specify "acks as a nop logger" do
|
should "act as a noop logger" do
|
||||||
app = lambda { |env|
|
app = lambda { |env|
|
||||||
env['rack.logger'].warn "b00m"
|
env['rack.logger'].warn "b00m"
|
||||||
[200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]]
|
[200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]]
|
||||||
}
|
}
|
||||||
Rack::NullLogger.new(app).call({})
|
logger = Rack::NullLogger.new(app)
|
||||||
|
lambda{ logger.call({}) }.should.not.raise
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,19 +1,13 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/recursive'
|
require 'rack/recursive'
|
||||||
require 'rack/urlmap'
|
|
||||||
require 'rack/response'
|
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::Recursive" do
|
describe Rack::Recursive do
|
||||||
setup do
|
|
||||||
|
|
||||||
@app1 = lambda { |env|
|
@app1 = lambda { |env|
|
||||||
res = Rack::Response.new
|
res = Rack::Response.new
|
||||||
res["X-Path-Info"] = env["PATH_INFO"]
|
res["X-Path-Info"] = env["PATH_INFO"]
|
||||||
res["X-Query-String"] = env["QUERY_STRING"]
|
res["X-Query-String"] = env["QUERY_STRING"]
|
||||||
res.finish do |res|
|
res.finish do |inner_res|
|
||||||
res.write "App1"
|
inner_res.write "App1"
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,9 +29,7 @@ context "Rack::Recursive" do
|
||||||
raise Rack::ForwardRequest.new("http://example.org/app1/quux?meh")
|
raise Rack::ForwardRequest.new("http://example.org/app1/quux?meh")
|
||||||
}
|
}
|
||||||
|
|
||||||
end
|
should "allow for subrequests" do
|
||||||
|
|
||||||
specify "should allow for subrequests" do
|
|
||||||
res = Rack::MockRequest.new(Rack::Recursive.new(
|
res = Rack::MockRequest.new(Rack::Recursive.new(
|
||||||
Rack::URLMap.new("/app1" => @app1,
|
Rack::URLMap.new("/app1" => @app1,
|
||||||
"/app2" => @app2))).
|
"/app2" => @app2))).
|
||||||
|
@ -47,7 +39,7 @@ context "Rack::Recursive" do
|
||||||
res.body.should.equal "App2App1"
|
res.body.should.equal "App2App1"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should raise error on requests not below the app" do
|
should "raise error on requests not below the app" do
|
||||||
app = Rack::URLMap.new("/app1" => @app1,
|
app = Rack::URLMap.new("/app1" => @app1,
|
||||||
"/app" => Rack::Recursive.new(
|
"/app" => Rack::Recursive.new(
|
||||||
Rack::URLMap.new("/1" => @app1,
|
Rack::URLMap.new("/1" => @app1,
|
||||||
|
@ -59,7 +51,7 @@ context "Rack::Recursive" do
|
||||||
message.should =~ /can only include below/
|
message.should =~ /can only include below/
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should support forwarding" do
|
should "support forwarding" do
|
||||||
app = Rack::Recursive.new(Rack::URLMap.new("/app1" => @app1,
|
app = Rack::Recursive.new(Rack::URLMap.new("/app1" => @app1,
|
||||||
"/app3" => @app3,
|
"/app3" => @app3,
|
||||||
"/app4" => @app4))
|
"/app4" => @app4))
|
|
@ -1,11 +1,10 @@
|
||||||
require 'test/spec'
|
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
|
require 'cgi'
|
||||||
require 'rack/request'
|
require 'rack/request'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::Request" do
|
describe Rack::Request do
|
||||||
specify "wraps the rack variables" do
|
should "wrap the rack variables" do
|
||||||
req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/"))
|
req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/"))
|
||||||
|
|
||||||
req.body.should.respond_to? :gets
|
req.body.should.respond_to? :gets
|
||||||
|
@ -29,7 +28,7 @@ context "Rack::Request" do
|
||||||
req.content_type.should.be.nil
|
req.content_type.should.be.nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can figure out the correct host" do
|
should "figure out the correct host" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
|
||||||
req.host.should.equal "www2.example.org"
|
req.host.should.equal "www2.example.org"
|
||||||
|
@ -53,7 +52,7 @@ context "Rack::Request" do
|
||||||
req.host.should.equal ""
|
req.host.should.equal ""
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can parse the query string" do
|
should "parse the query string" do
|
||||||
req = Rack::Request.new(Rack::MockRequest.env_for("/?foo=bar&quux=bla"))
|
req = Rack::Request.new(Rack::MockRequest.env_for("/?foo=bar&quux=bla"))
|
||||||
req.query_string.should.equal "foo=bar&quux=bla"
|
req.query_string.should.equal "foo=bar&quux=bla"
|
||||||
req.GET.should.equal "foo" => "bar", "quux" => "bla"
|
req.GET.should.equal "foo" => "bar", "quux" => "bla"
|
||||||
|
@ -61,12 +60,12 @@ context "Rack::Request" do
|
||||||
req.params.should.equal "foo" => "bar", "quux" => "bla"
|
req.params.should.equal "foo" => "bar", "quux" => "bla"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "raises if rack.input is missing" do
|
should "raise if rack.input is missing" do
|
||||||
req = Rack::Request.new({})
|
req = Rack::Request.new({})
|
||||||
lambda { req.POST }.should.raise(RuntimeError)
|
lambda { req.POST }.should.raise(RuntimeError)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can parse POST data when method is POST and no Content-Type given" do
|
should "parse POST data when method is POST and no Content-Type given" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("/?foo=quux",
|
Rack::MockRequest.env_for("/?foo=quux",
|
||||||
"REQUEST_METHOD" => 'POST',
|
"REQUEST_METHOD" => 'POST',
|
||||||
|
@ -79,7 +78,7 @@ context "Rack::Request" do
|
||||||
req.params.should.equal "foo" => "bar", "quux" => "bla"
|
req.params.should.equal "foo" => "bar", "quux" => "bla"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can parse POST data with explicit content type regardless of method" do
|
should "parse POST data with explicit content type regardless of method" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("/",
|
Rack::MockRequest.env_for("/",
|
||||||
"CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
|
"CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
|
||||||
|
@ -91,7 +90,7 @@ context "Rack::Request" do
|
||||||
req.params.should.equal "foo" => "bar", "quux" => "bla"
|
req.params.should.equal "foo" => "bar", "quux" => "bla"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does not parse POST data when media type is not form-data" do
|
should "not parse POST data when media type is not form-data" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("/?foo=quux",
|
Rack::MockRequest.env_for("/?foo=quux",
|
||||||
"REQUEST_METHOD" => 'POST',
|
"REQUEST_METHOD" => 'POST',
|
||||||
|
@ -105,7 +104,7 @@ context "Rack::Request" do
|
||||||
req.body.read.should.equal "foo=bar&quux=bla"
|
req.body.read.should.equal "foo=bar&quux=bla"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can parse POST data on PUT when media type is form-data" do
|
should "parse POST data on PUT when media type is form-data" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("/?foo=quux",
|
Rack::MockRequest.env_for("/?foo=quux",
|
||||||
"REQUEST_METHOD" => 'PUT',
|
"REQUEST_METHOD" => 'PUT',
|
||||||
|
@ -115,7 +114,7 @@ context "Rack::Request" do
|
||||||
req.body.read.should.equal "foo=bar&quux=bla"
|
req.body.read.should.equal "foo=bar&quux=bla"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "rewinds input after parsing POST data" do
|
should "rewind input after parsing POST data" do
|
||||||
input = StringIO.new("foo=bar&quux=bla")
|
input = StringIO.new("foo=bar&quux=bla")
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("/",
|
Rack::MockRequest.env_for("/",
|
||||||
|
@ -125,21 +124,21 @@ context "Rack::Request" do
|
||||||
input.read.should.equal "foo=bar&quux=bla"
|
input.read.should.equal "foo=bar&quux=bla"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "cleans up Safari's ajax POST body" do
|
should "clean up Safari's ajax POST body" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("/",
|
Rack::MockRequest.env_for("/",
|
||||||
'REQUEST_METHOD' => 'POST', :input => "foo=bar&quux=bla\0")
|
'REQUEST_METHOD' => 'POST', :input => "foo=bar&quux=bla\0")
|
||||||
req.POST.should.equal "foo" => "bar", "quux" => "bla"
|
req.POST.should.equal "foo" => "bar", "quux" => "bla"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can get value by key from params with #[]" do
|
should "get value by key from params with #[]" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("?foo=quux")
|
Rack::MockRequest.env_for("?foo=quux")
|
||||||
req['foo'].should.equal 'quux'
|
req['foo'].should.equal 'quux'
|
||||||
req[:foo].should.equal 'quux'
|
req[:foo].should.equal 'quux'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can set value to key on params with #[]=" do
|
should "set value to key on params with #[]=" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("?foo=duh")
|
Rack::MockRequest.env_for("?foo=duh")
|
||||||
req['foo'].should.equal 'duh'
|
req['foo'].should.equal 'duh'
|
||||||
|
@ -157,7 +156,7 @@ context "Rack::Request" do
|
||||||
req[:foo].should.equal 'jaz'
|
req[:foo].should.equal 'jaz'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "values_at answers values by keys in order given" do
|
should "return values for the keys in the order given from values_at" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("?foo=baz&wun=der&bar=ful")
|
Rack::MockRequest.env_for("?foo=baz&wun=der&bar=ful")
|
||||||
req.values_at('foo').should.equal ['baz']
|
req.values_at('foo').should.equal ['baz']
|
||||||
|
@ -165,7 +164,7 @@ context "Rack::Request" do
|
||||||
req.values_at('bar', 'foo', 'wun').should.equal ['ful', 'baz', 'der']
|
req.values_at('bar', 'foo', 'wun').should.equal ['ful', 'baz', 'der']
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "referrer should be extracted correct" do
|
should "extract referrer correctly" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("/", "HTTP_REFERER" => "/some/path")
|
Rack::MockRequest.env_for("/", "HTTP_REFERER" => "/some/path")
|
||||||
req.referer.should.equal "/some/path"
|
req.referer.should.equal "/some/path"
|
||||||
|
@ -175,7 +174,7 @@ context "Rack::Request" do
|
||||||
req.referer.should.equal "/"
|
req.referer.should.equal "/"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "user agent should be extracted correct" do
|
should "extract user agent correctly" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("/", "HTTP_USER_AGENT" => "Mozilla/4.0 (compatible)")
|
Rack::MockRequest.env_for("/", "HTTP_USER_AGENT" => "Mozilla/4.0 (compatible)")
|
||||||
req.user_agent.should.equal "Mozilla/4.0 (compatible)"
|
req.user_agent.should.equal "Mozilla/4.0 (compatible)"
|
||||||
|
@ -185,7 +184,7 @@ context "Rack::Request" do
|
||||||
req.user_agent.should.equal nil
|
req.user_agent.should.equal nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can cache, but invalidates the cache" do
|
should "cache, but invalidates the cache" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("/?foo=quux",
|
Rack::MockRequest.env_for("/?foo=quux",
|
||||||
"CONTENT_TYPE" => "application/x-www-form-urlencoded",
|
"CONTENT_TYPE" => "application/x-www-form-urlencoded",
|
||||||
|
@ -203,7 +202,7 @@ context "Rack::Request" do
|
||||||
req.POST.should.equal "foo" => "bla", "quux" => "bar"
|
req.POST.should.equal "foo" => "bla", "quux" => "bar"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can figure out if called via XHR" do
|
should "figure out if called via XHR" do
|
||||||
req = Rack::Request.new(Rack::MockRequest.env_for(""))
|
req = Rack::Request.new(Rack::MockRequest.env_for(""))
|
||||||
req.should.not.be.xhr
|
req.should.not.be.xhr
|
||||||
|
|
||||||
|
@ -212,7 +211,7 @@ context "Rack::Request" do
|
||||||
req.should.be.xhr
|
req.should.be.xhr
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can parse cookies" do
|
should "parse cookies" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
|
Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
|
||||||
req.cookies.should.equal "foo" => "bar", "quux" => "h&m"
|
req.cookies.should.equal "foo" => "bar", "quux" => "h&m"
|
||||||
|
@ -221,13 +220,13 @@ context "Rack::Request" do
|
||||||
req.cookies.should.equal({})
|
req.cookies.should.equal({})
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "parses cookies according to RFC 2109" do
|
should "parse cookies according to RFC 2109" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for('', 'HTTP_COOKIE' => 'foo=bar;foo=car')
|
Rack::MockRequest.env_for('', 'HTTP_COOKIE' => 'foo=bar;foo=car')
|
||||||
req.cookies.should.equal 'foo' => 'bar'
|
req.cookies.should.equal 'foo' => 'bar'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "provides setters" do
|
should "provide setters" do
|
||||||
req = Rack::Request.new(e=Rack::MockRequest.env_for(""))
|
req = Rack::Request.new(e=Rack::MockRequest.env_for(""))
|
||||||
req.script_name.should.equal ""
|
req.script_name.should.equal ""
|
||||||
req.script_name = "/foo"
|
req.script_name = "/foo"
|
||||||
|
@ -240,12 +239,12 @@ context "Rack::Request" do
|
||||||
e["PATH_INFO"].should.equal "/foo"
|
e["PATH_INFO"].should.equal "/foo"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "provides the original env" do
|
should "provide the original env" do
|
||||||
req = Rack::Request.new(e=Rack::MockRequest.env_for(""))
|
req = Rack::Request.new(e = Rack::MockRequest.env_for(""))
|
||||||
req.env.should.be e
|
req.env.should == e
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can restore the URL" do
|
should "restore the URL" do
|
||||||
Rack::Request.new(Rack::MockRequest.env_for("")).url.
|
Rack::Request.new(Rack::MockRequest.env_for("")).url.
|
||||||
should.equal "http://example.org/"
|
should.equal "http://example.org/"
|
||||||
Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).url.
|
Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).url.
|
||||||
|
@ -263,7 +262,7 @@ context "Rack::Request" do
|
||||||
should.equal "https://example.com:8080/foo?foo"
|
should.equal "https://example.com:8080/foo?foo"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can restore the full path" do
|
should "restore the full path" do
|
||||||
Rack::Request.new(Rack::MockRequest.env_for("")).fullpath.
|
Rack::Request.new(Rack::MockRequest.env_for("")).fullpath.
|
||||||
should.equal "/"
|
should.equal "/"
|
||||||
Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).fullpath.
|
Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).fullpath.
|
||||||
|
@ -281,7 +280,7 @@ context "Rack::Request" do
|
||||||
should.equal "/foo?foo"
|
should.equal "/foo?foo"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can handle multiple media type parameters" do
|
should "handle multiple media type parameters" do
|
||||||
req = Rack::Request.new \
|
req = Rack::Request.new \
|
||||||
Rack::MockRequest.env_for("/",
|
Rack::MockRequest.env_for("/",
|
||||||
"CONTENT_TYPE" => 'text/plain; foo=BAR,baz=bizzle dizzle;BLING=bam')
|
"CONTENT_TYPE" => 'text/plain; foo=BAR,baz=bizzle dizzle;BLING=bam')
|
||||||
|
@ -295,7 +294,7 @@ context "Rack::Request" do
|
||||||
req.media_type_params['bling'].should.equal 'bam'
|
req.media_type_params['bling'].should.equal 'bam'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can parse multipart form data" do
|
should "parse multipart form data" do
|
||||||
# Adapted from RFC 1867.
|
# Adapted from RFC 1867.
|
||||||
input = <<EOF
|
input = <<EOF
|
||||||
--AaB03x\r
|
--AaB03x\r
|
||||||
|
@ -334,7 +333,7 @@ EOF
|
||||||
f[:tempfile].size.should.equal 76
|
f[:tempfile].size.should.equal 76
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can parse big multipart form data" do
|
should "parse big multipart form data" do
|
||||||
input = <<EOF
|
input = <<EOF
|
||||||
--AaB03x\r
|
--AaB03x\r
|
||||||
content-disposition: form-data; name="huge"; filename="huge"\r
|
content-disposition: form-data; name="huge"; filename="huge"\r
|
||||||
|
@ -356,7 +355,7 @@ EOF
|
||||||
req.POST["mean"][:tempfile].read.should.equal "--AaB03xha"
|
req.POST["mean"][:tempfile].read.should.equal "--AaB03xha"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can detect invalid multipart form data" do
|
should "detect invalid multipart form data" do
|
||||||
input = <<EOF
|
input = <<EOF
|
||||||
--AaB03x\r
|
--AaB03x\r
|
||||||
content-disposition: form-data; name="huge"; filename="huge"\r
|
content-disposition: form-data; name="huge"; filename="huge"\r
|
||||||
|
@ -395,7 +394,8 @@ EOF
|
||||||
lambda { req.POST }.should.raise(EOFError)
|
lambda { req.POST }.should.raise(EOFError)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "shouldn't try to interpret binary as utf8" do
|
should "not try to interpret binary as utf8" do
|
||||||
|
if /regexp/.respond_to?(:kcode) # < 1.9
|
||||||
begin
|
begin
|
||||||
original_kcode = $KCODE
|
original_kcode = $KCODE
|
||||||
$KCODE='UTF8'
|
$KCODE='UTF8'
|
||||||
|
@ -419,10 +419,27 @@ EOF
|
||||||
ensure
|
ensure
|
||||||
$KCODE = original_kcode
|
$KCODE = original_kcode
|
||||||
end
|
end
|
||||||
|
else # >= 1.9
|
||||||
|
input = <<EOF
|
||||||
|
--AaB03x\r
|
||||||
|
content-disposition: form-data; name="fileupload"; filename="junk.a"\r
|
||||||
|
content-type: application/octet-stream\r
|
||||||
|
\r
|
||||||
|
#{[0x36,0xCF,0x0A,0xF8].pack('c*')}\r
|
||||||
|
--AaB03x--\r
|
||||||
|
EOF
|
||||||
|
|
||||||
|
req = Rack::Request.new Rack::MockRequest.env_for("/",
|
||||||
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
||||||
|
"CONTENT_LENGTH" => input.size,
|
||||||
|
:input => input)
|
||||||
|
|
||||||
|
lambda{req.POST}.should.not.raise(EOFError)
|
||||||
|
req.POST["fileupload"][:tempfile].size.should.equal 4
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
should "work around buggy 1.8.* Tempfile equality" do
|
||||||
specify "should work around buggy 1.8.* Tempfile equality" do
|
|
||||||
input = <<EOF
|
input = <<EOF
|
||||||
--AaB03x\r
|
--AaB03x\r
|
||||||
content-disposition: form-data; name="huge"; filename="huge"\r
|
content-disposition: form-data; name="huge"; filename="huge"\r
|
||||||
|
@ -440,11 +457,11 @@ EOF
|
||||||
"CONTENT_LENGTH" => input.size,
|
"CONTENT_LENGTH" => input.size,
|
||||||
:input => rack_input)
|
:input => rack_input)
|
||||||
|
|
||||||
lambda {req.POST}.should.not.raise
|
lambda{ req.POST }.should.not.raise
|
||||||
lambda {req.POST}.should.blaming("input re-processed!").not.raise
|
lambda{ req.POST }.should.not.raise("input re-processed!")
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does conform to the Rack spec" do
|
should "conform to the Rack spec" do
|
||||||
app = lambda { |env|
|
app = lambda { |env|
|
||||||
content = Rack::Request.new(env).POST["file"].inspect
|
content = Rack::Request.new(env).POST["file"].inspect
|
||||||
size = content.respond_to?(:bytesize) ? content.bytesize : content.size
|
size = content.respond_to?(:bytesize) ? content.bytesize : content.size
|
||||||
|
@ -472,7 +489,7 @@ EOF
|
||||||
res.should.be.ok
|
res.should.be.ok
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should parse Accept-Encoding correctly" do
|
should "parse Accept-Encoding correctly" do
|
||||||
parser = lambda do |x|
|
parser = lambda do |x|
|
||||||
Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding
|
Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding
|
||||||
end
|
end
|
||||||
|
@ -488,7 +505,7 @@ EOF
|
||||||
lambda { parser.call("gzip ; q=1.0") }.should.raise(RuntimeError)
|
lambda { parser.call("gzip ; q=1.0") }.should.raise(RuntimeError)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'should provide ip information' do
|
should 'provide ip information' do
|
||||||
app = lambda { |env|
|
app = lambda { |env|
|
||||||
request = Rack::Request.new(env)
|
request = Rack::Request.new(env)
|
||||||
response = Rack::Response.new
|
response = Rack::Response.new
|
||||||
|
@ -510,7 +527,13 @@ EOF
|
||||||
'REMOTE_ADDR' => '123.123.123.123',
|
'REMOTE_ADDR' => '123.123.123.123',
|
||||||
'HTTP_X_FORWARDED_FOR' => '234.234.234.234,212.212.212.212'
|
'HTTP_X_FORWARDED_FOR' => '234.234.234.234,212.212.212.212'
|
||||||
|
|
||||||
res.body.should.equal '212.212.212.212'
|
res.body.should.equal '234.234.234.234'
|
||||||
|
|
||||||
|
res = mock.get '/',
|
||||||
|
'REMOTE_ADDR' => '123.123.123.123',
|
||||||
|
'HTTP_X_FORWARDED_FOR' => 'unknown,234.234.234.234,212.212.212.212'
|
||||||
|
|
||||||
|
res.body.should.equal '234.234.234.234'
|
||||||
end
|
end
|
||||||
|
|
||||||
class MyRequest < Rack::Request
|
class MyRequest < Rack::Request
|
||||||
|
@ -519,7 +542,7 @@ EOF
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should allow subclass request to be instantiated after parent request" do
|
should "allow subclass request to be instantiated after parent request" do
|
||||||
env = Rack::MockRequest.env_for("/?foo=bar")
|
env = Rack::MockRequest.env_for("/?foo=bar")
|
||||||
|
|
||||||
req1 = Rack::Request.new(env)
|
req1 = Rack::Request.new(env)
|
||||||
|
@ -531,7 +554,7 @@ EOF
|
||||||
req2.params.should.equal :foo => "bar"
|
req2.params.should.equal :foo => "bar"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should allow parent request to be instantiated after subclass request" do
|
should "allow parent request to be instantiated after subclass request" do
|
||||||
env = Rack::MockRequest.env_for("/?foo=bar")
|
env = Rack::MockRequest.env_for("/?foo=bar")
|
||||||
|
|
||||||
req1 = MyRequest.new(env)
|
req1 = MyRequest.new(env)
|
||||||
|
@ -542,4 +565,16 @@ EOF
|
||||||
req2.GET.should.equal "foo" => "bar"
|
req2.GET.should.equal "foo" => "bar"
|
||||||
req2.params.should.equal "foo" => "bar"
|
req2.params.should.equal "foo" => "bar"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
(0x20...0x7E).collect { |a|
|
||||||
|
b = a.chr
|
||||||
|
c = CGI.escape(b)
|
||||||
|
should "not strip '#{a}' => '#{c}' => '#{b}' escaped character from parameters when accessed as string" do
|
||||||
|
url = "/?foo=#{c}bar#{c}"
|
||||||
|
env = Rack::MockRequest.env_for(url)
|
||||||
|
req2 = Rack::Request.new(env)
|
||||||
|
req2.GET.should.equal "foo" => "#{b}bar#{b}"
|
||||||
|
req2.params.should.equal "foo" => "#{b}bar#{b}"
|
||||||
|
end
|
||||||
|
}
|
||||||
end
|
end
|
|
@ -1,10 +1,8 @@
|
||||||
require 'test/spec'
|
|
||||||
require 'set'
|
require 'set'
|
||||||
|
|
||||||
require 'rack/response'
|
require 'rack/response'
|
||||||
|
|
||||||
context "Rack::Response" do
|
describe Rack::Response do
|
||||||
specify "has sensible default values" do
|
should "have sensible default values" do
|
||||||
response = Rack::Response.new
|
response = Rack::Response.new
|
||||||
status, header, body = response.finish
|
status, header, body = response.finish
|
||||||
status.should.equal 200
|
status.should.equal 200
|
||||||
|
@ -22,7 +20,7 @@ context "Rack::Response" do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can be written to" do
|
it "can be written to" do
|
||||||
response = Rack::Response.new
|
response = Rack::Response.new
|
||||||
|
|
||||||
status, header, body = response.finish do
|
status, header, body = response.finish do
|
||||||
|
@ -37,25 +35,32 @@ context "Rack::Response" do
|
||||||
parts.should.equal ["foo", "bar", "baz"]
|
parts.should.equal ["foo", "bar", "baz"]
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can set and read headers" do
|
it "can set and read headers" do
|
||||||
response = Rack::Response.new
|
response = Rack::Response.new
|
||||||
response["Content-Type"].should.equal "text/html"
|
response["Content-Type"].should.equal "text/html"
|
||||||
response["Content-Type"] = "text/plain"
|
response["Content-Type"] = "text/plain"
|
||||||
response["Content-Type"].should.equal "text/plain"
|
response["Content-Type"].should.equal "text/plain"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can set cookies" do
|
it "can set cookies" do
|
||||||
response = Rack::Response.new
|
response = Rack::Response.new
|
||||||
|
|
||||||
response.set_cookie "foo", "bar"
|
response.set_cookie "foo", "bar"
|
||||||
response["Set-Cookie"].should.equal "foo=bar"
|
response["Set-Cookie"].should.equal "foo=bar"
|
||||||
response.set_cookie "foo2", "bar2"
|
response.set_cookie "foo2", "bar2"
|
||||||
response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2"]
|
response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2"].join("\n")
|
||||||
response.set_cookie "foo3", "bar3"
|
response.set_cookie "foo3", "bar3"
|
||||||
response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2", "foo3=bar3"]
|
response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2", "foo3=bar3"].join("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "formats the Cookie expiration date accordingly to RFC 2109" do
|
it "can set cookies with the same name for multiple domains" do
|
||||||
|
response = Rack::Response.new
|
||||||
|
response.set_cookie "foo", {:value => "bar", :domain => "sample.example.com"}
|
||||||
|
response.set_cookie "foo", {:value => "bar", :domain => ".example.com"}
|
||||||
|
response["Set-Cookie"].should.equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"].join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "formats the Cookie expiration date accordingly to RFC 2109" do
|
||||||
response = Rack::Response.new
|
response = Rack::Response.new
|
||||||
|
|
||||||
response.set_cookie "foo", {:value => "bar", :expires => Time.now+10}
|
response.set_cookie "foo", {:value => "bar", :expires => Time.now+10}
|
||||||
|
@ -63,28 +68,42 @@ context "Rack::Response" do
|
||||||
/expires=..., \d\d-...-\d\d\d\d \d\d:\d\d:\d\d .../)
|
/expires=..., \d\d-...-\d\d\d\d \d\d:\d\d:\d\d .../)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can set secure cookies" do
|
it "can set secure cookies" do
|
||||||
response = Rack::Response.new
|
response = Rack::Response.new
|
||||||
response.set_cookie "foo", {:value => "bar", :secure => true}
|
response.set_cookie "foo", {:value => "bar", :secure => true}
|
||||||
response["Set-Cookie"].should.equal "foo=bar; secure"
|
response["Set-Cookie"].should.equal "foo=bar; secure"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can set http only cookies" do
|
it "can set http only cookies" do
|
||||||
response = Rack::Response.new
|
response = Rack::Response.new
|
||||||
response.set_cookie "foo", {:value => "bar", :httponly => true}
|
response.set_cookie "foo", {:value => "bar", :httponly => true}
|
||||||
response["Set-Cookie"].should.equal "foo=bar; HttpOnly"
|
response["Set-Cookie"].should.equal "foo=bar; HttpOnly"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can delete cookies" do
|
it "can delete cookies" do
|
||||||
response = Rack::Response.new
|
response = Rack::Response.new
|
||||||
response.set_cookie "foo", "bar"
|
response.set_cookie "foo", "bar"
|
||||||
response.set_cookie "foo2", "bar2"
|
response.set_cookie "foo2", "bar2"
|
||||||
response.delete_cookie "foo"
|
response.delete_cookie "foo"
|
||||||
response["Set-Cookie"].should.equal ["foo2=bar2",
|
response["Set-Cookie"].should.equal [
|
||||||
"foo=; expires=Thu, 01-Jan-1970 00:00:00 GMT"]
|
"foo2=bar2",
|
||||||
|
"foo=; expires=Thu, 01-Jan-1970 00:00:00 GMT"
|
||||||
|
].join("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can do redirects" do
|
it "can delete cookies with the same name from multiple domains" do
|
||||||
|
response = Rack::Response.new
|
||||||
|
response.set_cookie "foo", {:value => "bar", :domain => "sample.example.com"}
|
||||||
|
response.set_cookie "foo", {:value => "bar", :domain => ".example.com"}
|
||||||
|
response["Set-Cookie"].should.equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"].join("\n")
|
||||||
|
response.delete_cookie "foo", :domain => ".example.com"
|
||||||
|
response["Set-Cookie"].should.equal ["foo=bar; domain=sample.example.com", "foo=; domain=.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
|
||||||
|
response.delete_cookie "foo", :domain => "sample.example.com"
|
||||||
|
response["Set-Cookie"].should.equal ["foo=; domain=.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT",
|
||||||
|
"foo=; domain=sample.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can do redirects" do
|
||||||
response = Rack::Response.new
|
response = Rack::Response.new
|
||||||
response.redirect "/foo"
|
response.redirect "/foo"
|
||||||
status, header, body = response.finish
|
status, header, body = response.finish
|
||||||
|
@ -99,7 +118,7 @@ context "Rack::Response" do
|
||||||
status.should.equal 307
|
status.should.equal 307
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "has a useful constructor" do
|
it "has a useful constructor" do
|
||||||
r = Rack::Response.new("foo")
|
r = Rack::Response.new("foo")
|
||||||
status, header, body = r.finish
|
status, header, body = r.finish
|
||||||
str = ""; body.each { |part| str << part }
|
str = ""; body.each { |part| str << part }
|
||||||
|
@ -123,7 +142,7 @@ context "Rack::Response" do
|
||||||
r.status.should.equal 200
|
r.status.should.equal 200
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "has a constructor that can take a block" do
|
it "has a constructor that can take a block" do
|
||||||
r = Rack::Response.new { |res|
|
r = Rack::Response.new { |res|
|
||||||
res.status = 404
|
res.status = 404
|
||||||
res.write "foo"
|
res.write "foo"
|
||||||
|
@ -134,7 +153,7 @@ context "Rack::Response" do
|
||||||
status.should.equal 404
|
status.should.equal 404
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "doesn't return invalid responses" do
|
it "doesn't return invalid responses" do
|
||||||
r = Rack::Response.new(["foo", "bar"], 204)
|
r = Rack::Response.new(["foo", "bar"], 204)
|
||||||
status, header, body = r.finish
|
status, header, body = r.finish
|
||||||
str = ""; body.each { |part| str << part }
|
str = ""; body.each { |part| str << part }
|
||||||
|
@ -147,7 +166,7 @@ context "Rack::Response" do
|
||||||
message.should =~ /stringable or iterable required/
|
message.should =~ /stringable or iterable required/
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "knows if it's empty" do
|
it "knows if it's empty" do
|
||||||
r = Rack::Response.new
|
r = Rack::Response.new
|
||||||
r.should.be.empty
|
r.should.be.empty
|
||||||
r.write "foo"
|
r.write "foo"
|
||||||
|
@ -164,7 +183,7 @@ context "Rack::Response" do
|
||||||
r.should.not.be.empty
|
r.should.not.be.empty
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should provide access to the HTTP status" do
|
should "provide access to the HTTP status" do
|
||||||
res = Rack::Response.new
|
res = Rack::Response.new
|
||||||
res.status = 200
|
res.status = 200
|
||||||
res.should.be.successful
|
res.should.be.successful
|
||||||
|
@ -183,7 +202,7 @@ context "Rack::Response" do
|
||||||
res.should.be.redirect
|
res.should.be.redirect
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should provide access to the HTTP headers" do
|
should "provide access to the HTTP headers" do
|
||||||
res = Rack::Response.new
|
res = Rack::Response.new
|
||||||
res["Content-Type"] = "text/yaml"
|
res["Content-Type"] = "text/yaml"
|
||||||
|
|
||||||
|
@ -195,7 +214,7 @@ context "Rack::Response" do
|
||||||
res.location.should.be.nil
|
res.location.should.be.nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does not add or change Content-Length when #finish()ing" do
|
it "does not add or change Content-Length when #finish()ing" do
|
||||||
res = Rack::Response.new
|
res = Rack::Response.new
|
||||||
res.status = 200
|
res.status = 200
|
||||||
res.finish
|
res.finish
|
||||||
|
@ -208,7 +227,7 @@ context "Rack::Response" do
|
||||||
res.headers["Content-Length"].should.equal "10"
|
res.headers["Content-Length"].should.equal "10"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "updates Content-Length when body appended to using #write" do
|
it "updates Content-Length when body appended to using #write" do
|
||||||
res = Rack::Response.new
|
res = Rack::Response.new
|
||||||
res.status = 200
|
res.status = 200
|
||||||
res.headers["Content-Length"].should.be.nil
|
res.headers["Content-Length"].should.be.nil
|
118
vendor/plugins/rack/spec/spec_rewindable_input.rb
vendored
Normal file
118
vendor/plugins/rack/spec/spec_rewindable_input.rb
vendored
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
require 'stringio'
|
||||||
|
require 'rack/rewindable_input'
|
||||||
|
|
||||||
|
shared "a rewindable IO object" do
|
||||||
|
before do
|
||||||
|
@rio = Rack::RewindableInput.new(@io)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be able to handle to read()" do
|
||||||
|
@rio.read.should.equal "hello world"
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be able to handle to read(nil)" do
|
||||||
|
@rio.read(nil).should.equal "hello world"
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be able to handle to read(length)" do
|
||||||
|
@rio.read(1).should.equal "h"
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be able to handle to read(length, buffer)" do
|
||||||
|
buffer = ""
|
||||||
|
result = @rio.read(1, buffer)
|
||||||
|
result.should.equal "h"
|
||||||
|
result.object_id.should.equal buffer.object_id
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be able to handle to read(nil, buffer)" do
|
||||||
|
buffer = ""
|
||||||
|
result = @rio.read(nil, buffer)
|
||||||
|
result.should.equal "hello world"
|
||||||
|
result.object_id.should.equal buffer.object_id
|
||||||
|
end
|
||||||
|
|
||||||
|
should "rewind to the beginning when #rewind is called" do
|
||||||
|
@rio.read(1)
|
||||||
|
@rio.rewind
|
||||||
|
@rio.read.should.equal "hello world"
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be able to handle gets" do
|
||||||
|
@rio.gets.should == "hello world"
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be able to handle each" do
|
||||||
|
array = []
|
||||||
|
@rio.each do |data|
|
||||||
|
array << data
|
||||||
|
end
|
||||||
|
array.should.equal(["hello world"])
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not buffer into a Tempfile if no data has been read yet" do
|
||||||
|
@rio.instance_variable_get(:@rewindable_io).should.be.nil
|
||||||
|
end
|
||||||
|
|
||||||
|
should "buffer into a Tempfile when data has been consumed for the first time" do
|
||||||
|
@rio.read(1)
|
||||||
|
tempfile = @rio.instance_variable_get(:@rewindable_io)
|
||||||
|
tempfile.should.not.be.nil
|
||||||
|
@rio.read(1)
|
||||||
|
tempfile2 = @rio.instance_variable_get(:@rewindable_io)
|
||||||
|
tempfile2.path.should == tempfile.path
|
||||||
|
end
|
||||||
|
|
||||||
|
should "close the underlying tempfile upon calling #close" do
|
||||||
|
@rio.read(1)
|
||||||
|
tempfile = @rio.instance_variable_get(:@rewindable_io)
|
||||||
|
@rio.close
|
||||||
|
tempfile.should.be.closed
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be possible to call #close when no data has been buffered yet" do
|
||||||
|
lambda{ @rio.close }.should.not.raise
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be possible to call #close multiple times" do
|
||||||
|
lambda{
|
||||||
|
@rio.close
|
||||||
|
@rio.close
|
||||||
|
}.should.not.raise
|
||||||
|
end
|
||||||
|
|
||||||
|
@rio.close
|
||||||
|
@rio = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
describe Rack::RewindableInput do
|
||||||
|
describe "given an IO object that is already rewindable" do
|
||||||
|
before do
|
||||||
|
@io = StringIO.new("hello world")
|
||||||
|
end
|
||||||
|
|
||||||
|
behaves_like "a rewindable IO object"
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "given an IO object that is not rewindable" do
|
||||||
|
before do
|
||||||
|
@io = StringIO.new("hello world")
|
||||||
|
@io.instance_eval do
|
||||||
|
undef :rewind
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
behaves_like "a rewindable IO object"
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "given an IO object whose rewind method raises Errno::ESPIPE" do
|
||||||
|
before do
|
||||||
|
@io = StringIO.new("hello world")
|
||||||
|
def @io.rewind
|
||||||
|
raise Errno::ESPIPE, "You can't rewind this!"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
behaves_like "a rewindable IO object"
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,31 +1,35 @@
|
||||||
require 'test/spec'
|
|
||||||
require 'rack/mock'
|
|
||||||
require 'rack/runtime'
|
require 'rack/runtime'
|
||||||
|
|
||||||
context "Rack::Runtime" do
|
describe Rack::Runtime do
|
||||||
specify "sets X-Runtime is none is set" do
|
it "sets X-Runtime is none is set" do
|
||||||
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
||||||
response = Rack::Runtime.new(app).call({})
|
response = Rack::Runtime.new(app).call({})
|
||||||
response[1]['X-Runtime'].should =~ /[\d\.]+/
|
response[1]['X-Runtime'].should =~ /[\d\.]+/
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does not set the X-Runtime if it is already set" do
|
it "doesn't set the X-Runtime if it is already set" do
|
||||||
app = lambda { |env| [200, {'Content-Type' => 'text/plain', "X-Runtime" => "foobar"}, "Hello, World!"] }
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain', "X-Runtime" => "foobar"}, "Hello, World!"] }
|
||||||
response = Rack::Runtime.new(app).call({})
|
response = Rack::Runtime.new(app).call({})
|
||||||
response[1]['X-Runtime'].should == "foobar"
|
response[1]['X-Runtime'].should == "foobar"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should allow a suffix to be set" do
|
should "allow a suffix to be set" do
|
||||||
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
||||||
response = Rack::Runtime.new(app, "Test").call({})
|
response = Rack::Runtime.new(app, "Test").call({})
|
||||||
response[1]['X-Runtime-Test'].should =~ /[\d\.]+/
|
response[1]['X-Runtime-Test'].should =~ /[\d\.]+/
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should allow multiple timers to be set" do
|
should "allow multiple timers to be set" do
|
||||||
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
app = lambda { |env| sleep 0.1; [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
||||||
runtime1 = Rack::Runtime.new(app, "App")
|
runtime = Rack::Runtime.new(app, "App")
|
||||||
runtime2 = Rack::Runtime.new(runtime1, "All")
|
|
||||||
response = runtime2.call({})
|
# wrap many times to guarantee a measurable difference
|
||||||
|
100.times do |i|
|
||||||
|
runtime = Rack::Runtime.new(runtime, i.to_s)
|
||||||
|
end
|
||||||
|
runtime = Rack::Runtime.new(runtime, "All")
|
||||||
|
|
||||||
|
response = runtime.call({})
|
||||||
|
|
||||||
response[1]['X-Runtime-App'].should =~ /[\d\.]+/
|
response[1]['X-Runtime-App'].should =~ /[\d\.]+/
|
||||||
response[1]['X-Runtime-All'].should =~ /[\d\.]+/
|
response[1]['X-Runtime-All'].should =~ /[\d\.]+/
|
|
@ -1,14 +1,13 @@
|
||||||
require 'test/spec'
|
|
||||||
require 'rack/mock'
|
|
||||||
require 'rack/sendfile'
|
require 'rack/sendfile'
|
||||||
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::File" do
|
describe Rack::File do
|
||||||
specify "should respond to #to_path" do
|
should "respond to #to_path" do
|
||||||
Rack::File.new(Dir.pwd).should.respond_to :to_path
|
Rack::File.new(Dir.pwd).should.respond_to :to_path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "Rack::Sendfile" do
|
describe Rack::Sendfile do
|
||||||
def sendfile_body
|
def sendfile_body
|
||||||
res = ['Hello World']
|
res = ['Hello World']
|
||||||
def res.to_path ; "/tmp/hello.txt" ; end
|
def res.to_path ; "/tmp/hello.txt" ; end
|
||||||
|
@ -23,15 +22,13 @@ context "Rack::Sendfile" do
|
||||||
Rack::Sendfile.new(simple_app(body))
|
Rack::Sendfile.new(simple_app(body))
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
|
||||||
@request = Rack::MockRequest.new(sendfile_app)
|
@request = Rack::MockRequest.new(sendfile_app)
|
||||||
end
|
|
||||||
|
|
||||||
def request(headers={})
|
def request(headers={})
|
||||||
yield @request.get('/', headers)
|
yield @request.get('/', headers)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "does nothing when no X-Sendfile-Type header present" do
|
it "does nothing when no X-Sendfile-Type header present" do
|
||||||
request do |response|
|
request do |response|
|
||||||
response.should.be.ok
|
response.should.be.ok
|
||||||
response.body.should.equal 'Hello World'
|
response.body.should.equal 'Hello World'
|
||||||
|
@ -39,7 +36,7 @@ context "Rack::Sendfile" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "sets X-Sendfile response header and discards body" do
|
it "sets X-Sendfile response header and discards body" do
|
||||||
request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
|
request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
|
||||||
response.should.be.ok
|
response.should.be.ok
|
||||||
response.body.should.be.empty
|
response.body.should.be.empty
|
||||||
|
@ -47,7 +44,7 @@ context "Rack::Sendfile" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "sets X-Lighttpd-Send-File response header and discards body" do
|
it "sets X-Lighttpd-Send-File response header and discards body" do
|
||||||
request 'HTTP_X_SENDFILE_TYPE' => 'X-Lighttpd-Send-File' do |response|
|
request 'HTTP_X_SENDFILE_TYPE' => 'X-Lighttpd-Send-File' do |response|
|
||||||
response.should.be.ok
|
response.should.be.ok
|
||||||
response.body.should.be.empty
|
response.body.should.be.empty
|
||||||
|
@ -55,7 +52,7 @@ context "Rack::Sendfile" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "sets X-Accel-Redirect response header and discards body" do
|
it "sets X-Accel-Redirect response header and discards body" do
|
||||||
headers = {
|
headers = {
|
||||||
'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect',
|
'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect',
|
||||||
'HTTP_X_ACCEL_MAPPING' => '/tmp/=/foo/bar/'
|
'HTTP_X_ACCEL_MAPPING' => '/tmp/=/foo/bar/'
|
||||||
|
@ -67,7 +64,7 @@ context "Rack::Sendfile" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'writes to rack.error when no X-Accel-Mapping is specified' do
|
it 'writes to rack.error when no X-Accel-Mapping is specified' do
|
||||||
request 'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect' do |response|
|
request 'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect' do |response|
|
||||||
response.should.be.ok
|
response.should.be.ok
|
||||||
response.body.should.equal 'Hello World'
|
response.body.should.equal 'Hello World'
|
||||||
|
@ -76,7 +73,7 @@ context "Rack::Sendfile" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify 'does nothing when body does not respond to #to_path' do
|
it 'does nothing when body does not respond to #to_path' do
|
||||||
@request = Rack::MockRequest.new(sendfile_app(['Not a file...']))
|
@request = Rack::MockRequest.new(sendfile_app(['Not a file...']))
|
||||||
request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
|
request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
|
||||||
response.body.should.equal 'Not a file...'
|
response.body.should.equal 'Not a file...'
|
|
@ -1,23 +1,20 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/session/cookie'
|
require 'rack/session/cookie'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
require 'rack/response'
|
|
||||||
|
|
||||||
context "Rack::Session::Cookie" do
|
describe Rack::Session::Cookie do
|
||||||
incrementor = lambda { |env|
|
incrementor = lambda do |env|
|
||||||
env["rack.session"]["counter"] ||= 0
|
env["rack.session"]["counter"] ||= 0
|
||||||
env["rack.session"]["counter"] += 1
|
env["rack.session"]["counter"] += 1
|
||||||
Rack::Response.new(env["rack.session"].inspect).to_a
|
Rack::Response.new(env["rack.session"].inspect).to_a
|
||||||
}
|
end
|
||||||
|
|
||||||
specify "creates a new cookie" do
|
it "creates a new cookie" do
|
||||||
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/")
|
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/")
|
||||||
res["Set-Cookie"].should.match("rack.session=")
|
res["Set-Cookie"].should.include("rack.session=")
|
||||||
res.body.should.equal '{"counter"=>1}'
|
res.body.should.equal '{"counter"=>1}'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "loads from a cookie" do
|
it "loads from a cookie" do
|
||||||
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/")
|
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/")
|
||||||
cookie = res["Set-Cookie"]
|
cookie = res["Set-Cookie"]
|
||||||
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
|
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
|
||||||
|
@ -29,34 +26,25 @@ context "Rack::Session::Cookie" do
|
||||||
res.body.should.equal '{"counter"=>3}'
|
res.body.should.equal '{"counter"=>3}'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "survives broken cookies" do
|
it "survives broken cookies" do
|
||||||
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
|
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
|
||||||
get("/", "HTTP_COOKIE" => "rack.session=blarghfasel")
|
get("/", "HTTP_COOKIE" => "rack.session=blarghfasel")
|
||||||
res.body.should.equal '{"counter"=>1}'
|
res.body.should.equal '{"counter"=>1}'
|
||||||
end
|
end
|
||||||
|
|
||||||
bigcookie = lambda { |env|
|
bigcookie = lambda do |env|
|
||||||
env["rack.session"]["cookie"] = "big" * 3000
|
env["rack.session"]["cookie"] = "big" * 3000
|
||||||
Rack::Response.new(env["rack.session"].inspect).to_a
|
Rack::Response.new(env["rack.session"].inspect).to_a
|
||||||
}
|
end
|
||||||
|
|
||||||
specify "barks on too big cookies" do
|
it "barks on too big cookies" do
|
||||||
lambda {
|
lambda{
|
||||||
Rack::MockRequest.new(Rack::Session::Cookie.new(bigcookie)).
|
Rack::MockRequest.new(Rack::Session::Cookie.new(bigcookie)).
|
||||||
get("/", :fatal => true)
|
get("/", :fatal => true)
|
||||||
}.should.raise(Rack::MockRequest::FatalWarning)
|
}.should.raise(Rack::MockRequest::FatalWarning)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "creates a new cookie with integrity hash" do
|
it "loads from a cookie wih integrity hash" do
|
||||||
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).get("/")
|
|
||||||
if RUBY_VERSION < "1.9"
|
|
||||||
res["Set-Cookie"].should.match("rack.session=BAh7BiIMY291bnRlcmkG%0A--1439b4d37b9d4b04c603848382f712d6fcd31088")
|
|
||||||
else
|
|
||||||
res["Set-Cookie"].should.match("rack.session=BAh7BkkiDGNvdW50ZXIGOg1lbmNvZGluZyINVVMtQVNDSUlpBg%3D%3D%0A--d7a6637b94d2728194a96c18484e1f7ed9074a83")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
specify "loads from a cookie wih integrity hash" do
|
|
||||||
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).get("/")
|
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).get("/")
|
||||||
cookie = res["Set-Cookie"]
|
cookie = res["Set-Cookie"]
|
||||||
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).
|
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).
|
||||||
|
@ -68,7 +56,7 @@ context "Rack::Session::Cookie" do
|
||||||
res.body.should.equal '{"counter"=>3}'
|
res.body.should.equal '{"counter"=>3}'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "ignores tampered with session cookies" do
|
it "ignores tampered with session cookies" do
|
||||||
app = Rack::Session::Cookie.new(incrementor, :secret => 'test')
|
app = Rack::Session::Cookie.new(incrementor, :secret => 'test')
|
||||||
response1 = Rack::MockRequest.new(app).get("/")
|
response1 = Rack::MockRequest.new(app).get("/")
|
||||||
_, digest = response1["Set-Cookie"].split("--")
|
_, digest = response1["Set-Cookie"].split("--")
|
|
@ -1,12 +1,9 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
require 'rack/session/memcache'
|
require 'rack/session/memcache'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
require 'rack/response'
|
|
||||||
require 'thread'
|
require 'thread'
|
||||||
|
|
||||||
context "Rack::Session::Memcache" do
|
describe Rack::Session::Memcache do
|
||||||
session_key = Rack::Session::Memcache::DEFAULT_OPTIONS[:key]
|
session_key = Rack::Session::Memcache::DEFAULT_OPTIONS[:key]
|
||||||
session_match = /#{session_key}=([0-9a-fA-F]+);/
|
session_match = /#{session_key}=([0-9a-fA-F]+);/
|
||||||
incrementor = lambda do |env|
|
incrementor = lambda do |env|
|
||||||
|
@ -27,30 +24,36 @@ begin
|
||||||
incrementor.call(env)
|
incrementor.call(env)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "faults on no connection" do
|
it "faults on no connection" do
|
||||||
if RUBY_VERSION < "1.9"
|
if RUBY_VERSION < "1.9"
|
||||||
lambda do
|
lambda{
|
||||||
Rack::Session::Memcache.new incrementor, :memcache_server => 'nosuchserver'
|
Rack::Session::Memcache.new(incrementor, :memcache_server => 'nosuchserver')
|
||||||
end.should.raise
|
}.should.raise
|
||||||
else
|
else
|
||||||
lambda do
|
lambda{
|
||||||
Rack::Session::Memcache.new incrementor, :memcache_server => 'nosuchserver'
|
Rack::Session::Memcache.new(incrementor, :memcache_server => 'nosuchserver')
|
||||||
end.should.raise ArgumentError
|
}.should.raise ArgumentError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "connect to existing server" do
|
it "connects to existing server" do
|
||||||
test_pool = MemCache.new incrementor, :namespace => 'test:rack:session'
|
test_pool = MemCache.new(incrementor, :namespace => 'test:rack:session')
|
||||||
|
test_pool.namespace.should.equal 'test:rack:session'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "creates a new cookie" do
|
it "passes options to MemCache" do
|
||||||
|
pool = Rack::Session::Memcache.new(incrementor, :namespace => 'test:rack:session')
|
||||||
|
pool.pool.namespace.should.equal 'test:rack:session'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates a new cookie" do
|
||||||
pool = Rack::Session::Memcache.new(incrementor)
|
pool = Rack::Session::Memcache.new(incrementor)
|
||||||
res = Rack::MockRequest.new(pool).get("/")
|
res = Rack::MockRequest.new(pool).get("/")
|
||||||
res["Set-Cookie"].should.match("#{session_key}=")
|
res["Set-Cookie"].should.include("#{session_key}=")
|
||||||
res.body.should.equal '{"counter"=>1}'
|
res.body.should.equal '{"counter"=>1}'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "determines session from a cookie" do
|
it "determines session from a cookie" do
|
||||||
pool = Rack::Session::Memcache.new(incrementor)
|
pool = Rack::Session::Memcache.new(incrementor)
|
||||||
req = Rack::MockRequest.new(pool)
|
req = Rack::MockRequest.new(pool)
|
||||||
res = req.get("/")
|
res = req.get("/")
|
||||||
|
@ -61,7 +64,7 @@ begin
|
||||||
body.should.equal '{"counter"=>3}'
|
body.should.equal '{"counter"=>3}'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "survives nonexistant cookies" do
|
it "survives nonexistant cookies" do
|
||||||
bad_cookie = "rack.session=blarghfasel"
|
bad_cookie = "rack.session=blarghfasel"
|
||||||
pool = Rack::Session::Memcache.new(incrementor)
|
pool = Rack::Session::Memcache.new(incrementor)
|
||||||
res = Rack::MockRequest.new(pool).
|
res = Rack::MockRequest.new(pool).
|
||||||
|
@ -71,7 +74,7 @@ begin
|
||||||
cookie.should.not.match(/#{bad_cookie}/)
|
cookie.should.not.match(/#{bad_cookie}/)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "maintains freshness" do
|
it "maintains freshness" do
|
||||||
pool = Rack::Session::Memcache.new(incrementor, :expire_after => 3)
|
pool = Rack::Session::Memcache.new(incrementor, :expire_after => 3)
|
||||||
res = Rack::MockRequest.new(pool).get('/')
|
res = Rack::MockRequest.new(pool).get('/')
|
||||||
res.body.should.include '"counter"=>1'
|
res.body.should.include '"counter"=>1'
|
||||||
|
@ -86,7 +89,7 @@ begin
|
||||||
res.body.should.include '"counter"=>1'
|
res.body.should.include '"counter"=>1'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "deletes cookies with :drop option" do
|
it "deletes cookies with :drop option" do
|
||||||
pool = Rack::Session::Memcache.new(incrementor)
|
pool = Rack::Session::Memcache.new(incrementor)
|
||||||
req = Rack::MockRequest.new(pool)
|
req = Rack::MockRequest.new(pool)
|
||||||
drop = Rack::Utils::Context.new(pool, drop_session)
|
drop = Rack::Utils::Context.new(pool, drop_session)
|
||||||
|
@ -109,7 +112,7 @@ begin
|
||||||
res3.body.should.equal '{"counter"=>1}'
|
res3.body.should.equal '{"counter"=>1}'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "provides new session id with :renew option" do
|
it "provides new session id with :renew option" do
|
||||||
pool = Rack::Session::Memcache.new(incrementor)
|
pool = Rack::Session::Memcache.new(incrementor)
|
||||||
req = Rack::MockRequest.new(pool)
|
req = Rack::MockRequest.new(pool)
|
||||||
renew = Rack::Utils::Context.new(pool, renew_session)
|
renew = Rack::Utils::Context.new(pool, renew_session)
|
||||||
|
@ -134,7 +137,7 @@ begin
|
||||||
res3.body.should.equal '{"counter"=>4}'
|
res3.body.should.equal '{"counter"=>4}'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "omits cookie with :defer option" do
|
it "omits cookie with :defer option" do
|
||||||
pool = Rack::Session::Memcache.new(incrementor)
|
pool = Rack::Session::Memcache.new(incrementor)
|
||||||
req = Rack::MockRequest.new(pool)
|
req = Rack::MockRequest.new(pool)
|
||||||
defer = Rack::Utils::Context.new(pool, defer_session)
|
defer = Rack::Utils::Context.new(pool, defer_session)
|
||||||
|
@ -157,7 +160,7 @@ begin
|
||||||
res3.body.should.equal '{"counter"=>4}'
|
res3.body.should.equal '{"counter"=>4}'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "deep hashes are correctly updated" do
|
it "updates deep hashes correctly" do
|
||||||
store = nil
|
store = nil
|
||||||
hash_check = proc do |env|
|
hash_check = proc do |env|
|
||||||
session = env['rack.session']
|
session = env['rack.session']
|
||||||
|
@ -183,8 +186,11 @@ begin
|
||||||
end
|
end
|
||||||
|
|
||||||
# anyone know how to do this better?
|
# anyone know how to do this better?
|
||||||
specify "multithread: should cleanly merge sessions" do
|
it "cleanly merges sessions when multithreaded" do
|
||||||
next unless $DEBUG
|
unless $DEBUG
|
||||||
|
1.should.equal 1 # fake assertion to appease the mighty bacon
|
||||||
|
next
|
||||||
|
end
|
||||||
warn 'Running multithread test for Session::Memcache'
|
warn 'Running multithread test for Session::Memcache'
|
||||||
pool = Rack::Session::Memcache.new(incrementor)
|
pool = Rack::Session::Memcache.new(incrementor)
|
||||||
req = Rack::MockRequest.new(pool)
|
req = Rack::MockRequest.new(pool)
|
||||||
|
@ -215,8 +221,8 @@ begin
|
||||||
end
|
end
|
||||||
|
|
||||||
session = pool.pool.get(session_id)
|
session = pool.pool.get(session_id)
|
||||||
session.size.should.be tnum+1 # counter
|
session.size.should.equal tnum+1 # counter
|
||||||
session['counter'].should.be 2 # meeeh
|
session['counter'].should.equal 2 # meeeh
|
||||||
|
|
||||||
tnum = rand(7).to_i+5
|
tnum = rand(7).to_i+5
|
||||||
r = Array.new(tnum) do |i|
|
r = Array.new(tnum) do |i|
|
|
@ -1,39 +1,40 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/session/pool'
|
|
||||||
require 'rack/mock'
|
|
||||||
require 'rack/response'
|
|
||||||
require 'thread'
|
require 'thread'
|
||||||
|
require 'rack/mock'
|
||||||
|
require 'rack/session/pool'
|
||||||
|
|
||||||
context "Rack::Session::Pool" do
|
describe Rack::Session::Pool do
|
||||||
session_key = Rack::Session::Pool::DEFAULT_OPTIONS[:key]
|
session_key = Rack::Session::Pool::DEFAULT_OPTIONS[:key]
|
||||||
session_match = /#{session_key}=[0-9a-fA-F]+;/
|
session_match = /#{session_key}=[0-9a-fA-F]+;/
|
||||||
|
|
||||||
incrementor = lambda do |env|
|
incrementor = lambda do |env|
|
||||||
env["rack.session"]["counter"] ||= 0
|
env["rack.session"]["counter"] ||= 0
|
||||||
env["rack.session"]["counter"] += 1
|
env["rack.session"]["counter"] += 1
|
||||||
Rack::Response.new(env["rack.session"].inspect).to_a
|
Rack::Response.new(env["rack.session"].inspect).to_a
|
||||||
end
|
end
|
||||||
drop_session = proc do |env|
|
|
||||||
|
drop_session = lambda do |env|
|
||||||
env['rack.session.options'][:drop] = true
|
env['rack.session.options'][:drop] = true
|
||||||
incrementor.call(env)
|
incrementor.call(env)
|
||||||
end
|
end
|
||||||
renew_session = proc do |env|
|
|
||||||
|
renew_session = lambda do |env|
|
||||||
env['rack.session.options'][:renew] = true
|
env['rack.session.options'][:renew] = true
|
||||||
incrementor.call(env)
|
incrementor.call(env)
|
||||||
end
|
end
|
||||||
defer_session = proc do |env|
|
|
||||||
|
defer_session = lambda do |env|
|
||||||
env['rack.session.options'][:defer] = true
|
env['rack.session.options'][:defer] = true
|
||||||
incrementor.call(env)
|
incrementor.call(env)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "creates a new cookie" do
|
it "creates a new cookie" do
|
||||||
pool = Rack::Session::Pool.new(incrementor)
|
pool = Rack::Session::Pool.new(incrementor)
|
||||||
res = Rack::MockRequest.new(pool).get("/")
|
res = Rack::MockRequest.new(pool).get("/")
|
||||||
res["Set-Cookie"].should.match session_match
|
res["Set-Cookie"].should.match session_match
|
||||||
res.body.should.equal '{"counter"=>1}'
|
res.body.should.equal '{"counter"=>1}'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "determines session from a cookie" do
|
it "determines session from a cookie" do
|
||||||
pool = Rack::Session::Pool.new(incrementor)
|
pool = Rack::Session::Pool.new(incrementor)
|
||||||
req = Rack::MockRequest.new(pool)
|
req = Rack::MockRequest.new(pool)
|
||||||
cookie = req.get("/")["Set-Cookie"]
|
cookie = req.get("/")["Set-Cookie"]
|
||||||
|
@ -43,14 +44,14 @@ context "Rack::Session::Pool" do
|
||||||
body.should.equal '{"counter"=>3}'
|
body.should.equal '{"counter"=>3}'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "survives nonexistant cookies" do
|
it "survives nonexistant cookies" do
|
||||||
pool = Rack::Session::Pool.new(incrementor)
|
pool = Rack::Session::Pool.new(incrementor)
|
||||||
res = Rack::MockRequest.new(pool).
|
res = Rack::MockRequest.new(pool).
|
||||||
get("/", "HTTP_COOKIE" => "#{session_key}=blarghfasel")
|
get("/", "HTTP_COOKIE" => "#{session_key}=blarghfasel")
|
||||||
res.body.should.equal '{"counter"=>1}'
|
res.body.should.equal '{"counter"=>1}'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "deletes cookies with :drop option" do
|
it "deletes cookies with :drop option" do
|
||||||
pool = Rack::Session::Pool.new(incrementor)
|
pool = Rack::Session::Pool.new(incrementor)
|
||||||
req = Rack::MockRequest.new(pool)
|
req = Rack::MockRequest.new(pool)
|
||||||
drop = Rack::Utils::Context.new(pool, drop_session)
|
drop = Rack::Utils::Context.new(pool, drop_session)
|
||||||
|
@ -59,25 +60,25 @@ context "Rack::Session::Pool" do
|
||||||
res0 = req.get("/")
|
res0 = req.get("/")
|
||||||
session = (cookie = res0["Set-Cookie"])[session_match]
|
session = (cookie = res0["Set-Cookie"])[session_match]
|
||||||
res0.body.should.equal '{"counter"=>1}'
|
res0.body.should.equal '{"counter"=>1}'
|
||||||
pool.pool.size.should.be 1
|
pool.pool.size.should.equal 1
|
||||||
|
|
||||||
res1 = req.get("/", "HTTP_COOKIE" => cookie)
|
res1 = req.get("/", "HTTP_COOKIE" => cookie)
|
||||||
res1["Set-Cookie"][session_match].should.equal session
|
res1["Set-Cookie"][session_match].should.equal session
|
||||||
res1.body.should.equal '{"counter"=>2}'
|
res1.body.should.equal '{"counter"=>2}'
|
||||||
pool.pool.size.should.be 1
|
pool.pool.size.should.equal 1
|
||||||
|
|
||||||
res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
|
res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
|
||||||
res2["Set-Cookie"].should.equal nil
|
res2["Set-Cookie"].should.equal nil
|
||||||
res2.body.should.equal '{"counter"=>3}'
|
res2.body.should.equal '{"counter"=>3}'
|
||||||
pool.pool.size.should.be 0
|
pool.pool.size.should.equal 0
|
||||||
|
|
||||||
res3 = req.get("/", "HTTP_COOKIE" => cookie)
|
res3 = req.get("/", "HTTP_COOKIE" => cookie)
|
||||||
res3["Set-Cookie"][session_match].should.not.equal session
|
res3["Set-Cookie"][session_match].should.not.equal session
|
||||||
res3.body.should.equal '{"counter"=>1}'
|
res3.body.should.equal '{"counter"=>1}'
|
||||||
pool.pool.size.should.be 1
|
pool.pool.size.should.equal 1
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "provides new session id with :renew option" do
|
it "provides new session id with :renew option" do
|
||||||
pool = Rack::Session::Pool.new(incrementor)
|
pool = Rack::Session::Pool.new(incrementor)
|
||||||
req = Rack::MockRequest.new(pool)
|
req = Rack::MockRequest.new(pool)
|
||||||
renew = Rack::Utils::Context.new(pool, renew_session)
|
renew = Rack::Utils::Context.new(pool, renew_session)
|
||||||
|
@ -86,27 +87,27 @@ context "Rack::Session::Pool" do
|
||||||
res0 = req.get("/")
|
res0 = req.get("/")
|
||||||
session = (cookie = res0["Set-Cookie"])[session_match]
|
session = (cookie = res0["Set-Cookie"])[session_match]
|
||||||
res0.body.should.equal '{"counter"=>1}'
|
res0.body.should.equal '{"counter"=>1}'
|
||||||
pool.pool.size.should.be 1
|
pool.pool.size.should.equal 1
|
||||||
|
|
||||||
res1 = req.get("/", "HTTP_COOKIE" => cookie)
|
res1 = req.get("/", "HTTP_COOKIE" => cookie)
|
||||||
res1["Set-Cookie"][session_match].should.equal session
|
res1["Set-Cookie"][session_match].should.equal session
|
||||||
res1.body.should.equal '{"counter"=>2}'
|
res1.body.should.equal '{"counter"=>2}'
|
||||||
pool.pool.size.should.be 1
|
pool.pool.size.should.equal 1
|
||||||
|
|
||||||
res2 = rreq.get("/", "HTTP_COOKIE" => cookie)
|
res2 = rreq.get("/", "HTTP_COOKIE" => cookie)
|
||||||
new_cookie = res2["Set-Cookie"]
|
new_cookie = res2["Set-Cookie"]
|
||||||
new_session = new_cookie[session_match]
|
new_session = new_cookie[session_match]
|
||||||
new_session.should.not.equal session
|
new_session.should.not.equal session
|
||||||
res2.body.should.equal '{"counter"=>3}'
|
res2.body.should.equal '{"counter"=>3}'
|
||||||
pool.pool.size.should.be 1
|
pool.pool.size.should.equal 1
|
||||||
|
|
||||||
res3 = req.get("/", "HTTP_COOKIE" => new_cookie)
|
res3 = req.get("/", "HTTP_COOKIE" => new_cookie)
|
||||||
res3["Set-Cookie"][session_match].should.equal new_session
|
res3["Set-Cookie"][session_match].should.equal new_session
|
||||||
res3.body.should.equal '{"counter"=>4}'
|
res3.body.should.equal '{"counter"=>4}'
|
||||||
pool.pool.size.should.be 1
|
pool.pool.size.should.equal 1
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "omits cookie with :defer option" do
|
it "omits cookie with :defer option" do
|
||||||
pool = Rack::Session::Pool.new(incrementor)
|
pool = Rack::Session::Pool.new(incrementor)
|
||||||
req = Rack::MockRequest.new(pool)
|
req = Rack::MockRequest.new(pool)
|
||||||
defer = Rack::Utils::Context.new(pool, defer_session)
|
defer = Rack::Utils::Context.new(pool, defer_session)
|
||||||
|
@ -115,27 +116,31 @@ context "Rack::Session::Pool" do
|
||||||
res0 = req.get("/")
|
res0 = req.get("/")
|
||||||
session = (cookie = res0["Set-Cookie"])[session_match]
|
session = (cookie = res0["Set-Cookie"])[session_match]
|
||||||
res0.body.should.equal '{"counter"=>1}'
|
res0.body.should.equal '{"counter"=>1}'
|
||||||
pool.pool.size.should.be 1
|
pool.pool.size.should.equal 1
|
||||||
|
|
||||||
res1 = req.get("/", "HTTP_COOKIE" => cookie)
|
res1 = req.get("/", "HTTP_COOKIE" => cookie)
|
||||||
res1["Set-Cookie"][session_match].should.equal session
|
res1["Set-Cookie"][session_match].should.equal session
|
||||||
res1.body.should.equal '{"counter"=>2}'
|
res1.body.should.equal '{"counter"=>2}'
|
||||||
pool.pool.size.should.be 1
|
pool.pool.size.should.equal 1
|
||||||
|
|
||||||
res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
|
res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
|
||||||
res2["Set-Cookie"].should.equal nil
|
res2["Set-Cookie"].should.equal nil
|
||||||
res2.body.should.equal '{"counter"=>3}'
|
res2.body.should.equal '{"counter"=>3}'
|
||||||
pool.pool.size.should.be 1
|
pool.pool.size.should.equal 1
|
||||||
|
|
||||||
res3 = req.get("/", "HTTP_COOKIE" => cookie)
|
res3 = req.get("/", "HTTP_COOKIE" => cookie)
|
||||||
res3["Set-Cookie"][session_match].should.equal session
|
res3["Set-Cookie"][session_match].should.equal session
|
||||||
res3.body.should.equal '{"counter"=>4}'
|
res3.body.should.equal '{"counter"=>4}'
|
||||||
pool.pool.size.should.be 1
|
pool.pool.size.should.equal 1
|
||||||
end
|
end
|
||||||
|
|
||||||
# anyone know how to do this better?
|
# anyone know how to do this better?
|
||||||
specify "multithread: should merge sessions" do
|
it "should merge sessions when multithreaded" do
|
||||||
next unless $DEBUG
|
unless $DEBUG
|
||||||
|
1.should.equal 1
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
warn 'Running multithread tests for Session::Pool'
|
warn 'Running multithread tests for Session::Pool'
|
||||||
pool = Rack::Session::Pool.new(incrementor)
|
pool = Rack::Session::Pool.new(incrementor)
|
||||||
req = Rack::MockRequest.new(pool)
|
req = Rack::MockRequest.new(pool)
|
||||||
|
@ -166,7 +171,7 @@ context "Rack::Session::Pool" do
|
||||||
end
|
end
|
||||||
|
|
||||||
session = pool.pool[sess_id]
|
session = pool.pool[sess_id]
|
||||||
session.size.should.be tnum+1 # counter
|
session.size.should.equal tnum+1 # counter
|
||||||
session['counter'].should.be 2 # meeeh
|
session['counter'].should.equal 2 # meeeh
|
||||||
end
|
end
|
||||||
end
|
end
|
23
vendor/plugins/rack/spec/spec_showexceptions.rb
vendored
Normal file
23
vendor/plugins/rack/spec/spec_showexceptions.rb
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
require 'rack/showexceptions'
|
||||||
|
require 'rack/mock'
|
||||||
|
|
||||||
|
describe Rack::ShowExceptions do
|
||||||
|
it "catches exceptions" do
|
||||||
|
res = nil
|
||||||
|
|
||||||
|
req = Rack::MockRequest.new(
|
||||||
|
Rack::ShowExceptions.new(
|
||||||
|
lambda{|env| raise RuntimeError }
|
||||||
|
))
|
||||||
|
|
||||||
|
lambda{
|
||||||
|
res = req.get("/")
|
||||||
|
}.should.not.raise
|
||||||
|
|
||||||
|
res.should.be.a.server_error
|
||||||
|
res.status.should.equal 500
|
||||||
|
|
||||||
|
res.should =~ /RuntimeError/
|
||||||
|
res.should =~ /ShowExceptions/
|
||||||
|
end
|
||||||
|
end
|
79
vendor/plugins/rack/spec/spec_showstatus.rb
vendored
Normal file
79
vendor/plugins/rack/spec/spec_showstatus.rb
vendored
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
require 'rack/showstatus'
|
||||||
|
require 'rack/mock'
|
||||||
|
|
||||||
|
describe Rack::ShowStatus do
|
||||||
|
should "provide a default status message" do
|
||||||
|
req = Rack::MockRequest.new(
|
||||||
|
Rack::ShowStatus.new(lambda{|env|
|
||||||
|
[404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []]
|
||||||
|
}))
|
||||||
|
|
||||||
|
res = req.get("/", :lint => true)
|
||||||
|
res.should.be.not_found
|
||||||
|
res.should.be.not.empty
|
||||||
|
|
||||||
|
res["Content-Type"].should.equal("text/html")
|
||||||
|
res.should =~ /404/
|
||||||
|
res.should =~ /Not Found/
|
||||||
|
end
|
||||||
|
|
||||||
|
should "let the app provide additional information" do
|
||||||
|
req = Rack::MockRequest.new(
|
||||||
|
Rack::ShowStatus.new(
|
||||||
|
lambda{|env|
|
||||||
|
env["rack.showstatus.detail"] = "gone too meta."
|
||||||
|
[404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []]
|
||||||
|
}))
|
||||||
|
|
||||||
|
res = req.get("/", :lint => true)
|
||||||
|
res.should.be.not_found
|
||||||
|
res.should.be.not.empty
|
||||||
|
|
||||||
|
res["Content-Type"].should.equal("text/html")
|
||||||
|
res.should =~ /404/
|
||||||
|
res.should =~ /Not Found/
|
||||||
|
res.should =~ /too meta/
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not replace existing messages" do
|
||||||
|
req = Rack::MockRequest.new(
|
||||||
|
Rack::ShowStatus.new(
|
||||||
|
lambda{|env|
|
||||||
|
[404, {"Content-Type" => "text/plain", "Content-Length" => "4"}, ["foo!"]]
|
||||||
|
}))
|
||||||
|
|
||||||
|
res = req.get("/", :lint => true)
|
||||||
|
res.should.be.not_found
|
||||||
|
|
||||||
|
res.body.should == "foo!"
|
||||||
|
end
|
||||||
|
|
||||||
|
should "pass on original headers" do
|
||||||
|
headers = {"WWW-Authenticate" => "Basic blah"}
|
||||||
|
|
||||||
|
req = Rack::MockRequest.new(
|
||||||
|
Rack::ShowStatus.new(lambda{|env| [401, headers, []] }))
|
||||||
|
res = req.get("/", :lint => true)
|
||||||
|
|
||||||
|
res["WWW-Authenticate"].should.equal("Basic blah")
|
||||||
|
end
|
||||||
|
|
||||||
|
should "replace existing messages if there is detail" do
|
||||||
|
req = Rack::MockRequest.new(
|
||||||
|
Rack::ShowStatus.new(
|
||||||
|
lambda{|env|
|
||||||
|
env["rack.showstatus.detail"] = "gone too meta."
|
||||||
|
[404, {"Content-Type" => "text/plain", "Content-Length" => "4"}, ["foo!"]]
|
||||||
|
}))
|
||||||
|
|
||||||
|
res = req.get("/", :lint => true)
|
||||||
|
res.should.be.not_found
|
||||||
|
res.should.be.not.empty
|
||||||
|
|
||||||
|
res["Content-Type"].should.equal("text/html")
|
||||||
|
res["Content-Length"].should.not.equal("4")
|
||||||
|
res.should =~ /404/
|
||||||
|
res.should =~ /too meta/
|
||||||
|
res.body.should.not =~ /foo/
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,3 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/static'
|
require 'rack/static'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
|
@ -9,26 +7,24 @@ class DummyApp
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "Rack::Static" do
|
describe Rack::Static do
|
||||||
root = File.expand_path(File.dirname(__FILE__))
|
root = File.expand_path(File.dirname(__FILE__))
|
||||||
OPTIONS = {:urls => ["/cgi"], :root => root}
|
OPTIONS = {:urls => ["/cgi"], :root => root}
|
||||||
|
|
||||||
setup do
|
|
||||||
@request = Rack::MockRequest.new(Rack::Static.new(DummyApp.new, OPTIONS))
|
@request = Rack::MockRequest.new(Rack::Static.new(DummyApp.new, OPTIONS))
|
||||||
end
|
|
||||||
|
|
||||||
specify "serves files" do
|
it "serves files" do
|
||||||
res = @request.get("/cgi/test")
|
res = @request.get("/cgi/test")
|
||||||
res.should.be.ok
|
res.should.be.ok
|
||||||
res.body.should =~ /ruby/
|
res.body.should =~ /ruby/
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "404s if url root is known but it can't find the file" do
|
it "404s if url root is known but it can't find the file" do
|
||||||
res = @request.get("/cgi/foo")
|
res = @request.get("/cgi/foo")
|
||||||
res.should.be.not_found
|
res.should.be.not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "calls down the chain if url root is not known" do
|
it "calls down the chain if url root is not known" do
|
||||||
res = @request.get("/something/else")
|
res = @request.get("/something/else")
|
||||||
res.should.be.ok
|
res.should.be.ok
|
||||||
res.body.should == "Hello World"
|
res.body.should == "Hello World"
|
|
@ -1,34 +1,31 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
require 'rack/handler/thin'
|
require 'rack/handler/thin'
|
||||||
require 'testrequest'
|
require File.expand_path('../testrequest', __FILE__)
|
||||||
require 'timeout'
|
require 'timeout'
|
||||||
|
|
||||||
context "Rack::Handler::Thin" do
|
describe Rack::Handler::Thin do
|
||||||
include TestRequest::Helpers
|
extend TestRequest::Helpers
|
||||||
|
|
||||||
setup do
|
|
||||||
@app = Rack::Lint.new(TestRequest.new)
|
@app = Rack::Lint.new(TestRequest.new)
|
||||||
@server = nil
|
@server = nil
|
||||||
Thin::Logging.silent = true
|
Thin::Logging.silent = true
|
||||||
|
|
||||||
@thread = Thread.new do
|
@thread = Thread.new do
|
||||||
Rack::Handler::Thin.run(@app, :Host => @host='0.0.0.0', :Port => @port=9204) do |server|
|
Rack::Handler::Thin.run(@app, :Host => @host='0.0.0.0', :Port => @port=9204) do |server|
|
||||||
@server = server
|
@server = server
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Thread.pass until @server && @server.running?
|
Thread.pass until @server && @server.running?
|
||||||
|
|
||||||
|
should "respond" do
|
||||||
|
GET("/")
|
||||||
|
response.should.not.be.nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should respond" do
|
should "be a Thin" do
|
||||||
lambda {
|
|
||||||
GET("/")
|
GET("/")
|
||||||
}.should.not.raise
|
status.should.equal 200
|
||||||
end
|
|
||||||
|
|
||||||
specify "should be a Thin" do
|
|
||||||
GET("/")
|
|
||||||
status.should.be 200
|
|
||||||
response["SERVER_SOFTWARE"].should =~ /thin/
|
response["SERVER_SOFTWARE"].should =~ /thin/
|
||||||
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
||||||
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
||||||
|
@ -36,15 +33,15 @@ context "Rack::Handler::Thin" do
|
||||||
response["SERVER_NAME"].should.equal "0.0.0.0"
|
response["SERVER_NAME"].should.equal "0.0.0.0"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have rack headers" do
|
should "have rack headers" do
|
||||||
GET("/")
|
GET("/")
|
||||||
response["rack.version"].should.equal [0,3]
|
response["rack.version"].should.equal [1,0]
|
||||||
response["rack.multithread"].should.be false
|
response["rack.multithread"].should.equal false
|
||||||
response["rack.multiprocess"].should.be false
|
response["rack.multiprocess"].should.equal false
|
||||||
response["rack.run_once"].should.be false
|
response["rack.run_once"].should.equal false
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have CGI headers on GET" do
|
should "have CGI headers on GET" do
|
||||||
GET("/")
|
GET("/")
|
||||||
response["REQUEST_METHOD"].should.equal "GET"
|
response["REQUEST_METHOD"].should.equal "GET"
|
||||||
response["REQUEST_PATH"].should.equal "/"
|
response["REQUEST_PATH"].should.equal "/"
|
||||||
|
@ -59,7 +56,7 @@ context "Rack::Handler::Thin" do
|
||||||
response["QUERY_STRING"].should.equal "quux=1"
|
response["QUERY_STRING"].should.equal "quux=1"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have CGI headers on POST" do
|
should "have CGI headers on POST" do
|
||||||
POST("/", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
POST("/", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
||||||
status.should.equal 200
|
status.should.equal 200
|
||||||
response["REQUEST_METHOD"].should.equal "POST"
|
response["REQUEST_METHOD"].should.equal "POST"
|
||||||
|
@ -69,21 +66,19 @@ context "Rack::Handler::Thin" do
|
||||||
response["test.postdata"].should.equal "rack-form-data=23"
|
response["test.postdata"].should.equal "rack-form-data=23"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should support HTTP auth" do
|
should "support HTTP auth" do
|
||||||
GET("/test", {:user => "ruth", :passwd => "secret"})
|
GET("/test", {:user => "ruth", :passwd => "secret"})
|
||||||
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should set status" do
|
should "set status" do
|
||||||
GET("/test?secret")
|
GET("/test?secret")
|
||||||
status.should.equal 403
|
status.should.equal 403
|
||||||
response["rack.url_scheme"].should.equal "http"
|
response["rack.url_scheme"].should.equal "http"
|
||||||
end
|
end
|
||||||
|
|
||||||
teardown do
|
|
||||||
@server.stop!
|
@server.stop!
|
||||||
@thread.kill
|
@thread.kill
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue LoadError
|
rescue LoadError
|
|
@ -1,10 +1,8 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/urlmap'
|
require 'rack/urlmap'
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::URLMap" do
|
describe Rack::URLMap do
|
||||||
specify "dispatches paths correctly" do
|
it "dispatches paths correctly" do
|
||||||
app = lambda { |env|
|
app = lambda { |env|
|
||||||
[200, {
|
[200, {
|
||||||
'X-ScriptName' => env['SCRIPT_NAME'],
|
'X-ScriptName' => env['SCRIPT_NAME'],
|
||||||
|
@ -67,7 +65,7 @@ context "Rack::URLMap" do
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
specify "dispatches hosts correctly" do
|
it "dispatches hosts correctly" do
|
||||||
map = Rack::URLMap.new("http://foo.org/" => lambda { |env|
|
map = Rack::URLMap.new("http://foo.org/" => lambda { |env|
|
||||||
[200,
|
[200,
|
||||||
{ "Content-Type" => "text/plain",
|
{ "Content-Type" => "text/plain",
|
||||||
|
@ -125,7 +123,7 @@ context "Rack::URLMap" do
|
||||||
res["X-Position"].should.equal "default.org"
|
res["X-Position"].should.equal "default.org"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be nestable" do
|
should "be nestable" do
|
||||||
map = Rack::URLMap.new("/foo" =>
|
map = Rack::URLMap.new("/foo" =>
|
||||||
Rack::URLMap.new("/bar" =>
|
Rack::URLMap.new("/bar" =>
|
||||||
Rack::URLMap.new("/quux" => lambda { |env|
|
Rack::URLMap.new("/quux" => lambda { |env|
|
||||||
|
@ -147,7 +145,7 @@ context "Rack::URLMap" do
|
||||||
res["X-ScriptName"].should.equal "/foo/bar/quux"
|
res["X-ScriptName"].should.equal "/foo/bar/quux"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should route root apps correctly" do
|
should "route root apps correctly" do
|
||||||
map = Rack::URLMap.new("/" => lambda { |env|
|
map = Rack::URLMap.new("/" => lambda { |env|
|
||||||
[200,
|
[200,
|
||||||
{ "Content-Type" => "text/plain",
|
{ "Content-Type" => "text/plain",
|
||||||
|
@ -189,7 +187,7 @@ context "Rack::URLMap" do
|
||||||
res["X-ScriptName"].should.equal ""
|
res["X-ScriptName"].should.equal ""
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should not squeeze slashes" do
|
should "not squeeze slashes" do
|
||||||
map = Rack::URLMap.new("/" => lambda { |env|
|
map = Rack::URLMap.new("/" => lambda { |env|
|
||||||
[200,
|
[200,
|
||||||
{ "Content-Type" => "text/plain",
|
{ "Content-Type" => "text/plain",
|
|
@ -1,18 +1,15 @@
|
||||||
require 'test/spec'
|
|
||||||
|
|
||||||
require 'rack/utils'
|
require 'rack/utils'
|
||||||
require 'rack/lint'
|
|
||||||
require 'rack/mock'
|
require 'rack/mock'
|
||||||
|
|
||||||
context "Rack::Utils" do
|
describe Rack::Utils do
|
||||||
specify "should escape correctly" do
|
should "escape correctly" do
|
||||||
Rack::Utils.escape("fo<o>bar").should.equal "fo%3Co%3Ebar"
|
Rack::Utils.escape("fo<o>bar").should.equal "fo%3Co%3Ebar"
|
||||||
Rack::Utils.escape("a space").should.equal "a+space"
|
Rack::Utils.escape("a space").should.equal "a+space"
|
||||||
Rack::Utils.escape("q1!2\"'w$5&7/z8)?\\").
|
Rack::Utils.escape("q1!2\"'w$5&7/z8)?\\").
|
||||||
should.equal "q1%212%22%27w%245%267%2Fz8%29%3F%5C"
|
should.equal "q1%212%22%27w%245%267%2Fz8%29%3F%5C"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should escape correctly for multibyte characters" do
|
should "escape correctly for multibyte characters" do
|
||||||
matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsumoto
|
matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsumoto
|
||||||
matz_name.force_encoding("UTF-8") if matz_name.respond_to? :force_encoding
|
matz_name.force_encoding("UTF-8") if matz_name.respond_to? :force_encoding
|
||||||
Rack::Utils.escape(matz_name).should.equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8'
|
Rack::Utils.escape(matz_name).should.equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8'
|
||||||
|
@ -21,7 +18,7 @@ context "Rack::Utils" do
|
||||||
Rack::Utils.escape(matz_name_sep).should.equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
|
Rack::Utils.escape(matz_name_sep).should.equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should unescape correctly" do
|
should "unescape correctly" do
|
||||||
Rack::Utils.unescape("fo%3Co%3Ebar").should.equal "fo<o>bar"
|
Rack::Utils.unescape("fo%3Co%3Ebar").should.equal "fo<o>bar"
|
||||||
Rack::Utils.unescape("a+space").should.equal "a space"
|
Rack::Utils.unescape("a+space").should.equal "a space"
|
||||||
Rack::Utils.unescape("a%20space").should.equal "a space"
|
Rack::Utils.unescape("a%20space").should.equal "a space"
|
||||||
|
@ -29,11 +26,11 @@ context "Rack::Utils" do
|
||||||
should.equal "q1!2\"'w$5&7/z8)?\\"
|
should.equal "q1!2\"'w$5&7/z8)?\\"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should parse query strings correctly" do
|
should "parse query strings correctly" do
|
||||||
Rack::Utils.parse_query("foo=bar").
|
Rack::Utils.parse_query("foo=bar").
|
||||||
should.equal "foo" => "bar"
|
should.equal "foo" => "bar"
|
||||||
Rack::Utils.parse_query("foo=\"bar\"").
|
Rack::Utils.parse_query("foo=\"bar\"").
|
||||||
should.equal "foo" => "bar"
|
should.equal "foo" => "\"bar\""
|
||||||
Rack::Utils.parse_query("foo=bar&foo=quux").
|
Rack::Utils.parse_query("foo=bar&foo=quux").
|
||||||
should.equal "foo" => ["bar", "quux"]
|
should.equal "foo" => ["bar", "quux"]
|
||||||
Rack::Utils.parse_query("foo=1&bar=2").
|
Rack::Utils.parse_query("foo=1&bar=2").
|
||||||
|
@ -43,7 +40,7 @@ context "Rack::Utils" do
|
||||||
Rack::Utils.parse_query("foo%3Dbaz=bar").should.equal "foo=baz" => "bar"
|
Rack::Utils.parse_query("foo%3Dbaz=bar").should.equal "foo=baz" => "bar"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should parse nested query strings correctly" do
|
should "parse nested query strings correctly" do
|
||||||
Rack::Utils.parse_nested_query("foo").
|
Rack::Utils.parse_nested_query("foo").
|
||||||
should.equal "foo" => nil
|
should.equal "foo" => nil
|
||||||
Rack::Utils.parse_nested_query("foo=").
|
Rack::Utils.parse_nested_query("foo=").
|
||||||
|
@ -51,7 +48,7 @@ context "Rack::Utils" do
|
||||||
Rack::Utils.parse_nested_query("foo=bar").
|
Rack::Utils.parse_nested_query("foo=bar").
|
||||||
should.equal "foo" => "bar"
|
should.equal "foo" => "bar"
|
||||||
Rack::Utils.parse_nested_query("foo=\"bar\"").
|
Rack::Utils.parse_nested_query("foo=\"bar\"").
|
||||||
should.equal "foo" => "bar"
|
should.equal "foo" => "\"bar\""
|
||||||
|
|
||||||
Rack::Utils.parse_nested_query("foo=bar&foo=quux").
|
Rack::Utils.parse_nested_query("foo=bar&foo=quux").
|
||||||
should.equal "foo" => "quux"
|
should.equal "foo" => "quux"
|
||||||
|
@ -121,7 +118,7 @@ context "Rack::Utils" do
|
||||||
message.should.equal "expected Array (got String) for param `y'"
|
message.should.equal "expected Array (got String) for param `y'"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should build query strings correctly" do
|
should "build query strings correctly" do
|
||||||
Rack::Utils.build_query("foo" => "bar").should.equal "foo=bar"
|
Rack::Utils.build_query("foo" => "bar").should.equal "foo=bar"
|
||||||
Rack::Utils.build_query("foo" => ["bar", "quux"]).
|
Rack::Utils.build_query("foo" => ["bar", "quux"]).
|
||||||
should.equal "foo=bar&foo=quux"
|
should.equal "foo=bar&foo=quux"
|
||||||
|
@ -131,7 +128,7 @@ context "Rack::Utils" do
|
||||||
should.equal "my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F"
|
should.equal "my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should build nested query strings correctly" do
|
should "build nested query strings correctly" do
|
||||||
Rack::Utils.build_nested_query("foo" => nil).should.equal "foo"
|
Rack::Utils.build_nested_query("foo" => nil).should.equal "foo"
|
||||||
Rack::Utils.build_nested_query("foo" => "").should.equal "foo="
|
Rack::Utils.build_nested_query("foo" => "").should.equal "foo="
|
||||||
Rack::Utils.build_nested_query("foo" => "bar").should.equal "foo=bar"
|
Rack::Utils.build_nested_query("foo" => "bar").should.equal "foo=bar"
|
||||||
|
@ -178,7 +175,7 @@ context "Rack::Utils" do
|
||||||
message.should.equal "value must be a Hash"
|
message.should.equal "value must be a Hash"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should figure out which encodings are acceptable" do
|
should "figure out which encodings are acceptable" do
|
||||||
helper = lambda do |a, b|
|
helper = lambda do |a, b|
|
||||||
request = Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => a))
|
request = Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => a))
|
||||||
Rack::Utils.select_best_encoding(a, b)
|
Rack::Utils.select_best_encoding(a, b)
|
||||||
|
@ -201,43 +198,43 @@ context "Rack::Utils" do
|
||||||
helper.call(%w(foo bar baz identity), [["*", 0], ["identity", 0.1]]).should.equal("identity")
|
helper.call(%w(foo bar baz identity), [["*", 0], ["identity", 0.1]]).should.equal("identity")
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should return the bytesize of String" do
|
should "return the bytesize of String" do
|
||||||
Rack::Utils.bytesize("FOO\xE2\x82\xAC").should.equal 6
|
Rack::Utils.bytesize("FOO\xE2\x82\xAC").should.equal 6
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should return status code for integer" do
|
should "return status code for integer" do
|
||||||
Rack::Utils.status_code(200).should.equal 200
|
Rack::Utils.status_code(200).should.equal 200
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should return status code for string" do
|
should "return status code for string" do
|
||||||
Rack::Utils.status_code("200").should.equal 200
|
Rack::Utils.status_code("200").should.equal 200
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should return status code for symbol" do
|
should "return status code for symbol" do
|
||||||
Rack::Utils.status_code(:ok).should.equal 200
|
Rack::Utils.status_code(:ok).should.equal 200
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "Rack::Utils::HeaderHash" do
|
describe Rack::Utils::HeaderHash do
|
||||||
specify "should retain header case" do
|
should "retain header case" do
|
||||||
h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
|
h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
|
||||||
h['ETag'] = 'Boo!'
|
h['ETag'] = 'Boo!'
|
||||||
h.to_hash.should.equal "Content-MD5" => "d5ff4e2a0 ...", "ETag" => 'Boo!'
|
h.to_hash.should.equal "Content-MD5" => "d5ff4e2a0 ...", "ETag" => 'Boo!'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should check existence of keys case insensitively" do
|
should "check existence of keys case insensitively" do
|
||||||
h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
|
h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
|
||||||
h.should.include 'content-md5'
|
h.should.include 'content-md5'
|
||||||
h.should.not.include 'ETag'
|
h.should.not.include 'ETag'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should merge case-insensitively" do
|
should "merge case-insensitively" do
|
||||||
h = Rack::Utils::HeaderHash.new("ETag" => 'HELLO', "content-length" => '123')
|
h = Rack::Utils::HeaderHash.new("ETag" => 'HELLO', "content-length" => '123')
|
||||||
merged = h.merge("Etag" => 'WORLD', 'Content-Length' => '321', "Foo" => 'BAR')
|
merged = h.merge("Etag" => 'WORLD', 'Content-Length' => '321', "Foo" => 'BAR')
|
||||||
merged.should.equal "Etag"=>'WORLD', "Content-Length"=>'321', "Foo"=>'BAR'
|
merged.should.equal "Etag"=>'WORLD', "Content-Length"=>'321', "Foo"=>'BAR'
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should overwrite case insensitively and assume the new key's case" do
|
should "overwrite case insensitively and assume the new key's case" do
|
||||||
h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
|
h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
|
||||||
h["foo-bar"] = "bizzle"
|
h["foo-bar"] = "bizzle"
|
||||||
h["FOO-BAR"].should.equal "bizzle"
|
h["FOO-BAR"].should.equal "bizzle"
|
||||||
|
@ -245,55 +242,55 @@ context "Rack::Utils::HeaderHash" do
|
||||||
h.to_hash.should.equal "foo-bar" => "bizzle"
|
h.to_hash.should.equal "foo-bar" => "bizzle"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be converted to real Hash" do
|
should "be converted to real Hash" do
|
||||||
h = Rack::Utils::HeaderHash.new("foo" => "bar")
|
h = Rack::Utils::HeaderHash.new("foo" => "bar")
|
||||||
h.to_hash.should.be.instance_of Hash
|
h.to_hash.should.be.instance_of Hash
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should convert Array values to Strings when converting to Hash" do
|
should "convert Array values to Strings when converting to Hash" do
|
||||||
h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
|
h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
|
||||||
h.to_hash.should.equal({ "foo" => "bar\nbaz" })
|
h.to_hash.should.equal({ "foo" => "bar\nbaz" })
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should replace hashes correctly" do
|
should "replace hashes correctly" do
|
||||||
h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
|
h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
|
||||||
j = {"foo" => "bar"}
|
j = {"foo" => "bar"}
|
||||||
h.replace(j)
|
h.replace(j)
|
||||||
h["foo"].should.equal "bar"
|
h["foo"].should.equal "bar"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be able to delete the given key case-sensitively" do
|
should "be able to delete the given key case-sensitively" do
|
||||||
h = Rack::Utils::HeaderHash.new("foo" => "bar")
|
h = Rack::Utils::HeaderHash.new("foo" => "bar")
|
||||||
h.delete("foo")
|
h.delete("foo")
|
||||||
h["foo"].should.be.nil
|
h["foo"].should.be.nil
|
||||||
h["FOO"].should.be.nil
|
h["FOO"].should.be.nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be able to delete the given key case-insensitively" do
|
should "be able to delete the given key case-insensitively" do
|
||||||
h = Rack::Utils::HeaderHash.new("foo" => "bar")
|
h = Rack::Utils::HeaderHash.new("foo" => "bar")
|
||||||
h.delete("FOO")
|
h.delete("FOO")
|
||||||
h["foo"].should.be.nil
|
h["foo"].should.be.nil
|
||||||
h["FOO"].should.be.nil
|
h["FOO"].should.be.nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should return the deleted value when #delete is called on an existing key" do
|
should "return the deleted value when #delete is called on an existing key" do
|
||||||
h = Rack::Utils::HeaderHash.new("foo" => "bar")
|
h = Rack::Utils::HeaderHash.new("foo" => "bar")
|
||||||
h.delete("Foo").should.equal("bar")
|
h.delete("Foo").should.equal("bar")
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should return nil when #delete is called on a non-existant key" do
|
should "return nil when #delete is called on a non-existant key" do
|
||||||
h = Rack::Utils::HeaderHash.new("foo" => "bar")
|
h = Rack::Utils::HeaderHash.new("foo" => "bar")
|
||||||
h.delete("Hello").should.be.nil
|
h.delete("Hello").should.be.nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should avoid unnecessary object creation if possible" do
|
should "avoid unnecessary object creation if possible" do
|
||||||
a = Rack::Utils::HeaderHash.new("foo" => "bar")
|
a = Rack::Utils::HeaderHash.new("foo" => "bar")
|
||||||
b = Rack::Utils::HeaderHash.new(a)
|
b = Rack::Utils::HeaderHash.new(a)
|
||||||
b.object_id.should.equal(a.object_id)
|
b.object_id.should.equal(a.object_id)
|
||||||
b.should.equal(a)
|
b.should.equal(a)
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should convert Array values to Strings when responding to #each" do
|
should "convert Array values to Strings when responding to #each" do
|
||||||
h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
|
h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
|
||||||
h.each do |k,v|
|
h.each do |k,v|
|
||||||
k.should.equal("foo")
|
k.should.equal("foo")
|
||||||
|
@ -303,7 +300,7 @@ context "Rack::Utils::HeaderHash" do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context "Rack::Utils::Context" do
|
describe Rack::Utils::Context do
|
||||||
class ContextTest
|
class ContextTest
|
||||||
attr_reader :app
|
attr_reader :app
|
||||||
def initialize app; @app=app; end
|
def initialize app; @app=app; end
|
||||||
|
@ -316,7 +313,7 @@ context "Rack::Utils::Context" do
|
||||||
test_target4 = proc{|e| [200,{'Content-Type'=>'text/plain', 'Content-Length'=>'0'},['']] }
|
test_target4 = proc{|e| [200,{'Content-Type'=>'text/plain', 'Content-Length'=>'0'},['']] }
|
||||||
test_app = ContextTest.new test_target4
|
test_app = ContextTest.new test_target4
|
||||||
|
|
||||||
specify "should set context correctly" do
|
should "set context correctly" do
|
||||||
test_app.app.should.equal test_target4
|
test_app.app.should.equal test_target4
|
||||||
c1 = Rack::Utils::Context.new(test_app, test_target1)
|
c1 = Rack::Utils::Context.new(test_app, test_target1)
|
||||||
c1.for.should.equal test_app
|
c1.for.should.equal test_app
|
||||||
|
@ -326,7 +323,7 @@ context "Rack::Utils::Context" do
|
||||||
c2.app.should.equal test_target2
|
c2.app.should.equal test_target2
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should alter app on recontexting" do
|
should "alter app on recontexting" do
|
||||||
c1 = Rack::Utils::Context.new(test_app, test_target1)
|
c1 = Rack::Utils::Context.new(test_app, test_target1)
|
||||||
c2 = c1.recontext(test_target2)
|
c2 = c1.recontext(test_target2)
|
||||||
c2.for.should.equal test_app
|
c2.for.should.equal test_app
|
||||||
|
@ -336,7 +333,7 @@ context "Rack::Utils::Context" do
|
||||||
c3.app.should.equal test_target3
|
c3.app.should.equal test_target3
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should run different apps" do
|
should "run different apps" do
|
||||||
c1 = Rack::Utils::Context.new test_app, test_target1
|
c1 = Rack::Utils::Context.new test_app, test_target1
|
||||||
c2 = c1.recontext test_target2
|
c2 = c1.recontext test_target2
|
||||||
c3 = c2.recontext test_target3
|
c3 = c2.recontext test_target3
|
||||||
|
@ -350,21 +347,37 @@ context "Rack::Utils::Context" do
|
||||||
r3 = c3.call(:misc_symbol)
|
r3 = c3.call(:misc_symbol)
|
||||||
r3.should.be.nil
|
r3.should.be.nil
|
||||||
r4 = Rack::MockRequest.new(a4).get('/')
|
r4 = Rack::MockRequest.new(a4).get('/')
|
||||||
r4.status.should.be 200
|
r4.status.should.equal 200
|
||||||
r5 = Rack::MockRequest.new(a5).get('/')
|
r5 = Rack::MockRequest.new(a5).get('/')
|
||||||
r5.status.should.be 200
|
r5.status.should.equal 200
|
||||||
r4.body.should.equal r5.body
|
r4.body.should.equal r5.body
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "Rack::Utils::Multipart" do
|
describe Rack::Utils::Multipart do
|
||||||
specify "should return nil if content type is not multipart" do
|
def multipart_fixture(name)
|
||||||
|
file = multipart_file(name)
|
||||||
|
data = File.open(file, 'rb') { |io| io.read }
|
||||||
|
|
||||||
|
type = "multipart/form-data; boundary=AaB03x"
|
||||||
|
length = data.respond_to?(:bytesize) ? data.bytesize : data.size
|
||||||
|
|
||||||
|
{ "CONTENT_TYPE" => type,
|
||||||
|
"CONTENT_LENGTH" => length.to_s,
|
||||||
|
:input => StringIO.new(data) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def multipart_file(name)
|
||||||
|
File.join(File.dirname(__FILE__), "multipart", name.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "return nil if content type is not multipart" do
|
||||||
env = Rack::MockRequest.env_for("/",
|
env = Rack::MockRequest.env_for("/",
|
||||||
"CONTENT_TYPE" => 'application/x-www-form-urlencoded')
|
"CONTENT_TYPE" => 'application/x-www-form-urlencoded')
|
||||||
Rack::Utils::Multipart.parse_multipart(env).should.equal nil
|
Rack::Utils::Multipart.parse_multipart(env).should.equal nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should parse multipart upload with text file" do
|
should "parse multipart upload with text file" do
|
||||||
env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
|
||||||
params = Rack::Utils::Multipart.parse_multipart(env)
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
||||||
params["submit-name"].should.equal "Larry"
|
params["submit-name"].should.equal "Larry"
|
||||||
|
@ -377,7 +390,7 @@ context "Rack::Utils::Multipart" do
|
||||||
params["files"][:tempfile].read.should.equal "contents"
|
params["files"][:tempfile].read.should.equal "contents"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should parse multipart upload with nested parameters" do
|
should "parse multipart upload with nested parameters" do
|
||||||
env = Rack::MockRequest.env_for("/", multipart_fixture(:nested))
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:nested))
|
||||||
params = Rack::Utils::Multipart.parse_multipart(env)
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
||||||
params["foo"]["submit-name"].should.equal "Larry"
|
params["foo"]["submit-name"].should.equal "Larry"
|
||||||
|
@ -390,7 +403,7 @@ context "Rack::Utils::Multipart" do
|
||||||
params["foo"]["files"][:tempfile].read.should.equal "contents"
|
params["foo"]["files"][:tempfile].read.should.equal "contents"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should parse multipart upload with binary file" do
|
should "parse multipart upload with binary file" do
|
||||||
env = Rack::MockRequest.env_for("/", multipart_fixture(:binary))
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:binary))
|
||||||
params = Rack::Utils::Multipart.parse_multipart(env)
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
||||||
params["submit-name"].should.equal "Larry"
|
params["submit-name"].should.equal "Larry"
|
||||||
|
@ -403,7 +416,7 @@ context "Rack::Utils::Multipart" do
|
||||||
params["files"][:tempfile].read.length.should.equal 26473
|
params["files"][:tempfile].read.length.should.equal 26473
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should parse multipart upload with empty file" do
|
should "parse multipart upload with empty file" do
|
||||||
env = Rack::MockRequest.env_for("/", multipart_fixture(:empty))
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:empty))
|
||||||
params = Rack::Utils::Multipart.parse_multipart(env)
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
||||||
params["submit-name"].should.equal "Larry"
|
params["submit-name"].should.equal "Larry"
|
||||||
|
@ -416,7 +429,7 @@ context "Rack::Utils::Multipart" do
|
||||||
params["files"][:tempfile].read.should.equal ""
|
params["files"][:tempfile].read.should.equal ""
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should parse multipart upload with filename with semicolons" do
|
should "parse multipart upload with filename with semicolons" do
|
||||||
env = Rack::MockRequest.env_for("/", multipart_fixture(:semicolon))
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:semicolon))
|
||||||
params = Rack::Utils::Multipart.parse_multipart(env)
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
||||||
params["files"][:type].should.equal "text/plain"
|
params["files"][:type].should.equal "text/plain"
|
||||||
|
@ -428,7 +441,7 @@ context "Rack::Utils::Multipart" do
|
||||||
params["files"][:tempfile].read.should.equal "contents"
|
params["files"][:tempfile].read.should.equal "contents"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should not include file params if no file was selected" do
|
should "not include file params if no file was selected" do
|
||||||
env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
|
||||||
params = Rack::Utils::Multipart.parse_multipart(env)
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
||||||
params["submit-name"].should.equal "Larry"
|
params["submit-name"].should.equal "Larry"
|
||||||
|
@ -436,7 +449,7 @@ context "Rack::Utils::Multipart" do
|
||||||
params.keys.should.not.include "files"
|
params.keys.should.not.include "files"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should parse IE multipart upload and clean up filename" do
|
should "parse IE multipart upload and clean up filename" do
|
||||||
env = Rack::MockRequest.env_for("/", multipart_fixture(:ie))
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:ie))
|
||||||
params = Rack::Utils::Multipart.parse_multipart(env)
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
||||||
params["files"][:type].should.equal "text/plain"
|
params["files"][:type].should.equal "text/plain"
|
||||||
|
@ -449,7 +462,76 @@ context "Rack::Utils::Multipart" do
|
||||||
params["files"][:tempfile].read.should.equal "contents"
|
params["files"][:tempfile].read.should.equal "contents"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "rewinds input after parsing upload" do
|
should "parse filename and modification param" do
|
||||||
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_and_modification_param))
|
||||||
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
||||||
|
params["files"][:type].should.equal "image/jpeg"
|
||||||
|
params["files"][:filename].should.equal "genome.jpeg"
|
||||||
|
params["files"][:head].should.equal "Content-Type: image/jpeg\r\n" +
|
||||||
|
"Content-Disposition: attachment; " +
|
||||||
|
"name=\"files\"; " +
|
||||||
|
"filename=genome.jpeg; " +
|
||||||
|
"modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\";\r\n" +
|
||||||
|
"Content-Description: a complete map of the human genome\r\n"
|
||||||
|
params["files"][:name].should.equal "files"
|
||||||
|
params["files"][:tempfile].read.should.equal "contents"
|
||||||
|
end
|
||||||
|
|
||||||
|
should "parse filename with escaped quotes" do
|
||||||
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_escaped_quotes))
|
||||||
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
||||||
|
params["files"][:type].should.equal "application/octet-stream"
|
||||||
|
params["files"][:filename].should.equal "escape \"quotes"
|
||||||
|
params["files"][:head].should.equal "Content-Disposition: form-data; " +
|
||||||
|
"name=\"files\"; " +
|
||||||
|
"filename=\"escape \\\"quotes\"\r\n" +
|
||||||
|
"Content-Type: application/octet-stream\r\n"
|
||||||
|
params["files"][:name].should.equal "files"
|
||||||
|
params["files"][:tempfile].read.should.equal "contents"
|
||||||
|
end
|
||||||
|
|
||||||
|
should "parse filename with percent escaped quotes" do
|
||||||
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_percent_escaped_quotes))
|
||||||
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
||||||
|
params["files"][:type].should.equal "application/octet-stream"
|
||||||
|
params["files"][:filename].should.equal "escape \"quotes"
|
||||||
|
params["files"][:head].should.equal "Content-Disposition: form-data; " +
|
||||||
|
"name=\"files\"; " +
|
||||||
|
"filename=\"escape %22quotes\"\r\n" +
|
||||||
|
"Content-Type: application/octet-stream\r\n"
|
||||||
|
params["files"][:name].should.equal "files"
|
||||||
|
params["files"][:tempfile].read.should.equal "contents"
|
||||||
|
end
|
||||||
|
|
||||||
|
should "parse filename with unescaped quotes" do
|
||||||
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_quotes))
|
||||||
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
||||||
|
params["files"][:type].should.equal "application/octet-stream"
|
||||||
|
params["files"][:filename].should.equal "escape \"quotes"
|
||||||
|
params["files"][:head].should.equal "Content-Disposition: form-data; " +
|
||||||
|
"name=\"files\"; " +
|
||||||
|
"filename=\"escape \"quotes\"\r\n" +
|
||||||
|
"Content-Type: application/octet-stream\r\n"
|
||||||
|
params["files"][:name].should.equal "files"
|
||||||
|
params["files"][:tempfile].read.should.equal "contents"
|
||||||
|
end
|
||||||
|
|
||||||
|
should "parse filename with escaped quotes and modification param" do
|
||||||
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_escaped_quotes_and_modification_param))
|
||||||
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
||||||
|
params["files"][:type].should.equal "image/jpeg"
|
||||||
|
params["files"][:filename].should.equal "\"human\" genome.jpeg"
|
||||||
|
params["files"][:head].should.equal "Content-Type: image/jpeg\r\n" +
|
||||||
|
"Content-Disposition: attachment; " +
|
||||||
|
"name=\"files\"; " +
|
||||||
|
"filename=\"\"human\" genome.jpeg\"; " +
|
||||||
|
"modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\";\r\n" +
|
||||||
|
"Content-Description: a complete map of the human genome\r\n"
|
||||||
|
params["files"][:name].should.equal "files"
|
||||||
|
params["files"][:tempfile].read.should.equal "contents"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "rewinds input after parsing upload" do
|
||||||
options = multipart_fixture(:text)
|
options = multipart_fixture(:text)
|
||||||
input = options[:input]
|
input = options[:input]
|
||||||
env = Rack::MockRequest.env_for("/", options)
|
env = Rack::MockRequest.env_for("/", options)
|
||||||
|
@ -459,7 +541,7 @@ context "Rack::Utils::Multipart" do
|
||||||
input.read.length.should.equal 197
|
input.read.length.should.equal 197
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "builds multipart body" do
|
it "builds multipart body" do
|
||||||
files = Rack::Utils::Multipart::UploadedFile.new(multipart_file("file1.txt"))
|
files = Rack::Utils::Multipart::UploadedFile.new(multipart_file("file1.txt"))
|
||||||
data = Rack::Utils::Multipart.build_multipart("submit-name" => "Larry", "files" => files)
|
data = Rack::Utils::Multipart.build_multipart("submit-name" => "Larry", "files" => files)
|
||||||
|
|
||||||
|
@ -475,7 +557,7 @@ context "Rack::Utils::Multipart" do
|
||||||
params["files"][:tempfile].read.should.equal "contents"
|
params["files"][:tempfile].read.should.equal "contents"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "builds nested multipart body" do
|
it "builds nested multipart body" do
|
||||||
files = Rack::Utils::Multipart::UploadedFile.new(multipart_file("file1.txt"))
|
files = Rack::Utils::Multipart::UploadedFile.new(multipart_file("file1.txt"))
|
||||||
data = Rack::Utils::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => files}])
|
data = Rack::Utils::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => files}])
|
||||||
|
|
||||||
|
@ -491,7 +573,7 @@ context "Rack::Utils::Multipart" do
|
||||||
params["people"][0]["files"][:tempfile].read.should.equal "contents"
|
params["people"][0]["files"][:tempfile].read.should.equal "contents"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "can parse fields that end at the end of the buffer" do
|
it "can parse fields that end at the end of the buffer" do
|
||||||
input = File.read(multipart_file("bad_robots"))
|
input = File.read(multipart_file("bad_robots"))
|
||||||
|
|
||||||
req = Rack::Request.new Rack::MockRequest.env_for("/",
|
req = Rack::Request.new Rack::MockRequest.env_for("/",
|
||||||
|
@ -503,7 +585,7 @@ context "Rack::Utils::Multipart" do
|
||||||
req.POST['addresses'].should.not.equal nil
|
req.POST['addresses'].should.not.equal nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "builds complete params with the chunk size of 16384 slicing exactly on boundary" do
|
it "builds complete params with the chunk size of 16384 slicing exactly on boundary" do
|
||||||
data = File.open(multipart_file("fail_16384_nofile")) { |f| f.read }.gsub(/\n/, "\r\n")
|
data = File.open(multipart_file("fail_16384_nofile")) { |f| f.read }.gsub(/\n/, "\r\n")
|
||||||
options = {
|
options = {
|
||||||
"CONTENT_TYPE" => "multipart/form-data; boundary=----WebKitFormBoundaryWsY0GnpbI5U7ztzo",
|
"CONTENT_TYPE" => "multipart/form-data; boundary=----WebKitFormBoundaryWsY0GnpbI5U7ztzo",
|
||||||
|
@ -522,31 +604,14 @@ context "Rack::Utils::Multipart" do
|
||||||
params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"]["ba_unit_id"].should.equal "1017"
|
params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"]["ba_unit_id"].should.equal "1017"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should return nil if no UploadedFiles were used" do
|
should "return nil if no UploadedFiles were used" do
|
||||||
data = Rack::Utils::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => "contents"}])
|
data = Rack::Utils::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => "contents"}])
|
||||||
data.should.equal nil
|
data.should.equal nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should raise ArgumentError if params is not a Hash" do
|
should "raise ArgumentError if params is not a Hash" do
|
||||||
lambda { Rack::Utils::Multipart.build_multipart("foo=bar") }.
|
lambda { Rack::Utils::Multipart.build_multipart("foo=bar") }.
|
||||||
should.raise(ArgumentError).
|
should.raise(ArgumentError).
|
||||||
message.should.equal "value must be a Hash"
|
message.should.equal "value must be a Hash"
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
def multipart_fixture(name)
|
|
||||||
file = multipart_file(name)
|
|
||||||
data = File.open(file, 'rb') { |io| io.read }
|
|
||||||
|
|
||||||
type = "multipart/form-data; boundary=AaB03x"
|
|
||||||
length = data.respond_to?(:bytesize) ? data.bytesize : data.size
|
|
||||||
|
|
||||||
{ "CONTENT_TYPE" => type,
|
|
||||||
"CONTENT_LENGTH" => length.to_s,
|
|
||||||
:input => StringIO.new(data) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def multipart_file(name)
|
|
||||||
File.join(File.dirname(__FILE__), "multipart", name.to_s)
|
|
||||||
end
|
|
||||||
end
|
end
|
|
@ -1,16 +1,11 @@
|
||||||
require 'test/spec'
|
require 'rack/mock'
|
||||||
|
require File.expand_path('../testrequest', __FILE__)
|
||||||
require 'rack/handler/webrick'
|
|
||||||
require 'rack/lint'
|
|
||||||
require 'rack/response'
|
|
||||||
require 'testrequest'
|
|
||||||
|
|
||||||
Thread.abort_on_exception = true
|
Thread.abort_on_exception = true
|
||||||
|
|
||||||
context "Rack::Handler::WEBrick" do
|
describe Rack::Handler::WEBrick do
|
||||||
include TestRequest::Helpers
|
extend TestRequest::Helpers
|
||||||
|
|
||||||
setup do
|
|
||||||
@server = WEBrick::HTTPServer.new(:Host => @host='0.0.0.0',
|
@server = WEBrick::HTTPServer.new(:Host => @host='0.0.0.0',
|
||||||
:Port => @port=9202,
|
:Port => @port=9202,
|
||||||
:Logger => WEBrick::Log.new(nil, WEBrick::BasicLog::WARN),
|
:Logger => WEBrick::Log.new(nil, WEBrick::BasicLog::WARN),
|
||||||
|
@ -19,17 +14,16 @@ context "Rack::Handler::WEBrick" do
|
||||||
Rack::Lint.new(TestRequest.new)
|
Rack::Lint.new(TestRequest.new)
|
||||||
Thread.new { @server.start }
|
Thread.new { @server.start }
|
||||||
trap(:INT) { @server.shutdown }
|
trap(:INT) { @server.shutdown }
|
||||||
end
|
|
||||||
|
|
||||||
specify "should respond" do
|
should "respond" do
|
||||||
lambda {
|
lambda {
|
||||||
GET("/test")
|
GET("/test")
|
||||||
}.should.not.raise
|
}.should.not.raise
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be a WEBrick" do
|
should "be a WEBrick" do
|
||||||
GET("/test")
|
GET("/test")
|
||||||
status.should.be 200
|
status.should.equal 200
|
||||||
response["SERVER_SOFTWARE"].should =~ /WEBrick/
|
response["SERVER_SOFTWARE"].should =~ /WEBrick/
|
||||||
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
||||||
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
||||||
|
@ -37,15 +31,15 @@ context "Rack::Handler::WEBrick" do
|
||||||
response["SERVER_NAME"].should.equal "0.0.0.0"
|
response["SERVER_NAME"].should.equal "0.0.0.0"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have rack headers" do
|
should "have rack headers" do
|
||||||
GET("/test")
|
GET("/test")
|
||||||
response["rack.version"].should.equal [1,1]
|
response["rack.version"].should.equal [1,1]
|
||||||
response["rack.multithread"].should.be true
|
response["rack.multithread"].should.be.true
|
||||||
response["rack.multiprocess"].should.be false
|
response["rack.multiprocess"].should.be.false
|
||||||
response["rack.run_once"].should.be false
|
response["rack.run_once"].should.be.false
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have CGI headers on GET" do
|
should "have CGI headers on GET" do
|
||||||
GET("/test")
|
GET("/test")
|
||||||
response["REQUEST_METHOD"].should.equal "GET"
|
response["REQUEST_METHOD"].should.equal "GET"
|
||||||
response["SCRIPT_NAME"].should.equal "/test"
|
response["SCRIPT_NAME"].should.equal "/test"
|
||||||
|
@ -69,7 +63,7 @@ context "Rack::Handler::WEBrick" do
|
||||||
response["QUERY_STRING"].should.equal "quux=1"
|
response["QUERY_STRING"].should.equal "quux=1"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should have CGI headers on POST" do
|
should "have CGI headers on POST" do
|
||||||
POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
||||||
status.should.equal 200
|
status.should.equal 200
|
||||||
response["REQUEST_METHOD"].should.equal "POST"
|
response["REQUEST_METHOD"].should.equal "POST"
|
||||||
|
@ -80,18 +74,18 @@ context "Rack::Handler::WEBrick" do
|
||||||
response["test.postdata"].should.equal "rack-form-data=23"
|
response["test.postdata"].should.equal "rack-form-data=23"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should support HTTP auth" do
|
should "support HTTP auth" do
|
||||||
GET("/test", {:user => "ruth", :passwd => "secret"})
|
GET("/test", {:user => "ruth", :passwd => "secret"})
|
||||||
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should set status" do
|
should "set status" do
|
||||||
GET("/test?secret")
|
GET("/test?secret")
|
||||||
status.should.equal 403
|
status.should.equal 403
|
||||||
response["rack.url_scheme"].should.equal "http"
|
response["rack.url_scheme"].should.equal "http"
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should correctly set cookies" do
|
should "correctly set cookies" do
|
||||||
@server.mount "/cookie-test", Rack::Handler::WEBrick,
|
@server.mount "/cookie-test", Rack::Handler::WEBrick,
|
||||||
Rack::Lint.new(lambda { |req|
|
Rack::Lint.new(lambda { |req|
|
||||||
res = Rack::Response.new
|
res = Rack::Response.new
|
||||||
|
@ -107,7 +101,7 @@ context "Rack::Handler::WEBrick" do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should provide a .run" do
|
should "provide a .run" do
|
||||||
block_ran = false
|
block_ran = false
|
||||||
catch(:done) {
|
catch(:done) {
|
||||||
Rack::Handler::WEBrick.run(lambda {},
|
Rack::Handler::WEBrick.run(lambda {},
|
||||||
|
@ -120,11 +114,9 @@ context "Rack::Handler::WEBrick" do
|
||||||
throw :done
|
throw :done
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
block_ran.should.be true
|
block_ran.should.be.true
|
||||||
@s.shutdown
|
@s.shutdown
|
||||||
end
|
end
|
||||||
|
|
||||||
teardown do
|
|
||||||
@server.shutdown
|
@server.shutdown
|
||||||
end
|
|
||||||
end
|
end
|
|
@ -2,10 +2,15 @@ require 'yaml'
|
||||||
require 'net/http'
|
require 'net/http'
|
||||||
|
|
||||||
class TestRequest
|
class TestRequest
|
||||||
|
NOSERIALIZE = [Method, Proc]
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
status = env["QUERY_STRING"] =~ /secret/ ? 403 : 200
|
status = env["QUERY_STRING"] =~ /secret/ ? 403 : 200
|
||||||
env["test.postdata"] = env["rack.input"].read
|
env["test.postdata"] = env["rack.input"].read
|
||||||
body = env.to_yaml
|
minienv = env.dup
|
||||||
|
# This may in the future want to replace with a dummy value instead.
|
||||||
|
minienv.delete_if { |k,v| NOSERIALIZE.any? { |c| v.kind_of?(c) } }
|
||||||
|
body = minienv.to_yaml
|
||||||
size = body.respond_to?(:bytesize) ? body.bytesize : body.size
|
size = body.respond_to?(:bytesize) ? body.bytesize : body.size
|
||||||
[status, {"Content-Type" => "text/yaml", "Content-Length" => size.to_s}, [body]]
|
[status, {"Content-Type" => "text/yaml", "Content-Length" => size.to_s}, [body]]
|
||||||
end
|
end
|
||||||
|
@ -35,7 +40,7 @@ class TestRequest
|
||||||
@status = response.code.to_i
|
@status = response.code.to_i
|
||||||
begin
|
begin
|
||||||
@response = YAML.load(response.body)
|
@response = YAML.load(response.body)
|
||||||
rescue ArgumentError
|
rescue TypeError, ArgumentError
|
||||||
@response = nil
|
@response = nil
|
||||||
end
|
end
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue