Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Draft Expectation Cascade

  • Loading branch information...
commit cfee6eefe8291d0aa3c70a12b3b2cc350ec09beb 1 parent 185fa26
@josh josh authored
View
1  lib/rack/contrib.rb
@@ -13,6 +13,7 @@ def self.release
autoload :CSSHTTPRequest, "rack/contrib/csshttprequest"
autoload :Deflect, "rack/contrib/deflect"
autoload :ETag, "rack/contrib/etag"
+ autoload :ExpectationCascade, "rack/contrib/expectation_cascade"
autoload :GarbageCollector, "rack/contrib/garbagecollector"
autoload :JSONP, "rack/contrib/jsonp"
autoload :LighttpdScriptNameFix, "rack/contrib/lighttpd_script_name_fix"
View
32 lib/rack/contrib/expectation_cascade.rb
@@ -0,0 +1,32 @@
+module Rack
+ class ExpectationCascade
+ Expect = "Expect".freeze
+ ContinueExpectation = "100-continue".freeze
+
+ ExpectationFailed = [417, {"Content-Type" => "text/html"}, []].freeze
+ NotFound = [404, {"Content-Type" => "text/html"}, []].freeze
+
+ attr_reader :apps
+
+ def initialize
+ @apps = []
+ yield self if block_given?
+ end
+
+ def call(env)
+ set_expectation = env[Expect] != ContinueExpectation
+ env[Expect] = ContinueExpectation if set_expectation
+ @apps.each do |app|
+ result = app.call(env)
+ return result unless result[0].to_i == 417
+ end
+ set_expectation ? NotFound : ExpectationFailed
+ ensure
+ env.delete(Expect) if set_expectation
+ end
+
+ def <<(app)
+ @apps << app
+ end
+ end
+end
View
72 test/spec_rack_expectation_cascade.rb
@@ -0,0 +1,72 @@
+require 'test/spec'
+require 'rack/mock'
+require 'rack/contrib/expectation_cascade'
+
+context "Rack::ExpectationCascade" do
+ specify "with no apps returns a 404 if no expectation header was set" do
+ app = Rack::ExpectationCascade.new
+ env = {}
+ response = app.call(env)
+ response[0].should.equal 404
+ env.should.equal({})
+ end
+
+ specify "with no apps returns a 417 if expectation header was set" do
+ app = Rack::ExpectationCascade.new
+ env = {"Expect" => "100-continue"}
+ response = app.call(env)
+ response[0].should.equal 417
+ env.should.equal({"Expect" => "100-continue"})
+ end
+
+ specify "returns first successful response" do
+ app = Rack::ExpectationCascade.new do |cascade|
+ cascade << lambda { |env| [417, {"Content-Type" => "text/plain"}, []] }
+ cascade << lambda { |env| [200, {"Content-Type" => "text/plain"}, ["OK"]] }
+ end
+ response = app.call({})
+ response[0].should.equal 200
+ response[2][0].should.equal "OK"
+ end
+
+ specify "expectation is set if it has not been already" do
+ app = Rack::ExpectationCascade.new do |cascade|
+ cascade << lambda { |env| [200, {"Content-Type" => "text/plain"}, ["Expect: #{env["Expect"]}"]] }
+ end
+ response = app.call({})
+ response[0].should.equal 200
+ response[2][0].should.equal "Expect: 100-continue"
+ end
+
+ specify "returns a 404 if no apps where matched and no expectation header was set" do
+ app = Rack::ExpectationCascade.new do |cascade|
+ cascade << lambda { |env| [417, {"Content-Type" => "text/plain"}, []] }
+ end
+ response = app.call({})
+ response[0].should.equal 404
+ response[2][0].should.equal nil
+ end
+
+ specify "returns a 417 if no apps where matched and a expectation header was set" do
+ app = Rack::ExpectationCascade.new do |cascade|
+ cascade << lambda { |env| [417, {"Content-Type" => "text/plain"}, []] }
+ end
+ response = app.call({"Expect" => "100-continue"})
+ response[0].should.equal 417
+ response[2][0].should.equal nil
+ end
+
+ specify "nests expectation cascades" do
+ app = Rack::ExpectationCascade.new do |c1|
+ c1 << Rack::ExpectationCascade.new do |c2|
+ c2 << lambda { |env| [417, {"Content-Type" => "text/plain"}, []] }
+ end
+ c1 << Rack::ExpectationCascade.new do |c2|
+ c2 << lambda { |env| [200, {"Content-Type" => "text/plain"}, ["OK"]] }
+ end
+ end
+ response = app.call({})
+ response[0].should.equal 200
+ response[2][0].should.equal "OK"
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.