diff --git a/gems/passenger-v6-rack-v2.rb b/gems/passenger-v6-rack-v2.rb index 384c82c..4e81152 100644 --- a/gems/passenger-v6-rack-v2.rb +++ b/gems/passenger-v6-rack-v2.rb @@ -13,3 +13,5 @@ # export RACK_CONFORM_SERVER="passenger start" # export RACK_CONFORM_ENDPOINT="http://127.0.0.1:3000" + +::RACK_CONFORM_BROKEN = [:options_star] diff --git a/gems/webrick-rack-v2.rb b/gems/webrick-rack-v2.rb index 41fc7e1..15c1875 100644 --- a/gems/webrick-rack-v2.rb +++ b/gems/webrick-rack-v2.rb @@ -7,3 +7,5 @@ gem "rack", "~> 2.0" gem "webrick" + +::RACK_CONFORM_BROKEN = [:options_star] diff --git a/gems/webrick-rack-v3.rb b/gems/webrick-rack-v3.rb index 5a30a3e..d10e2fe 100644 --- a/gems/webrick-rack-v3.rb +++ b/gems/webrick-rack-v3.rb @@ -5,6 +5,9 @@ eval_gemfile "../gems.rb" -gem "rack", "~> 3.0.1" +gem "rack", "~> 3.2" gem "webrick" gem "rackup" + +# export RACK_CONFORM_SERVER="rackup -s webrick" +# export RACK_CONFORM_ENDPOINT="http://127.0.0.1:9292" diff --git a/lib/rack/conform.rb b/lib/rack/conform.rb index 11cbb4c..2e702b7 100644 --- a/lib/rack/conform.rb +++ b/lib/rack/conform.rb @@ -5,3 +5,15 @@ require_relative "conform/version" require_relative "conform/application" + +module Rack + module Conform + def self.broken?(feature) + if defined?(::RACK_CONFORM_BROKEN) + ::RACK_CONFORM_BROKEN.include?(feature) + else + false + end + end + end +end diff --git a/lib/rack/conform/application.rb b/lib/rack/conform/application.rb index a878295..bcb79e7 100644 --- a/lib/rack/conform/application.rb +++ b/lib/rack/conform/application.rb @@ -114,7 +114,7 @@ def test_middleware_body_itself(env) Middleware::BodyItself.new(self).call(env) end - def test_options_star(env) + def test_options(env) request_method = env["REQUEST_METHOD"] path_info = env["PATH_INFO"] @@ -129,7 +129,7 @@ def test_method_for(env) # Special case for OPTIONS * request: if request_method == "OPTIONS" - return :test_options_star + return :test_options end parts = path_info.split("/") diff --git a/readme.md b/readme.md index 9516979..401ad31 100644 --- a/readme.md +++ b/readme.md @@ -14,11 +14,15 @@ Rack has pretty decent support for validating applications do the right thing us ### Servers Tested - - Falcon (Rack 2 & 3) - - Puma (Rack 2) - - Passenger (Rack 2) - - Unicorn (Rack 2) - - Thin (Rack 2) +| Server | Rack 2 | Rack 3 | Broken Features | +|-----------|:------:|:------:|-------------------------| +| Falcon | ✓ | ✓ | | +| Pitchfork | ✓ | | | +| Passenger | ✓ | | `options_star` | +| Puma | ✓ | ✓ | | +| Thin | ✓ | | | +| Unicorn | ✓ | | | +| Webrick | ✓ | ✓ | `options_star` (Rack 2) | ## Usage @@ -66,6 +70,17 @@ export RACK_CONFORM_ENDPOINT="http://localhost:9292" bundle exec sus ``` +### Passenger + +``` bash +export BUNDLE_GEMFILE="gems/passenger-v6-rack-v2.rb" +bundle install +passenger start # Install passenger and then exit. +export RACK_CONFORM_SERVER="passenger start" +export RACK_CONFORM_ENDPOINT="http://127.0.0.1:3000" +bundle exec sus +``` + ### Starting A Server You can also start a server running the conform application for independent testing (e.g. using `curl`). diff --git a/test/rack/conform/options.rb b/test/rack/conform/options.rb new file mode 100644 index 0000000..8b6b252 --- /dev/null +++ b/test/rack/conform/options.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +require "rack/conform" + +require "client_context" +include ClientContext + +require "protocol/http/request" + +it "can handle OPTIONS / request" do + request = Protocol::HTTP::Request.new( + endpoint.scheme, endpoint.authority, "OPTIONS", "/", nil, Protocol::HTTP::Headers.new, nil + ) + + response = client.call(request) + expect(response.status).to be == 200 + expect(response.read).to be == "OPTIONS /" +ensure + response&.finish +end + +it "can handle OPTIONS * request" do + skip("Unsuppported by server!") if ::Rack::Conform.broken?(:options_star) + + request = Protocol::HTTP::Request.new( + endpoint.scheme, endpoint.authority, "OPTIONS", "*", nil, Protocol::HTTP::Headers.new, nil + ) + + response = client.call(request) + expect(response.status).to be == 200 + if ::Rack::RELEASE > "3.2" + expect(response.read).to be == "OPTIONS *" + else + expect(response.read).to be(:start_with?, "OPTIONS") + end +ensure + response&.finish +end diff --git a/test/rack/conform/options_star.rb b/test/rack/conform/options_star.rb deleted file mode 100644 index fa29f71..0000000 --- a/test/rack/conform/options_star.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -# Released under the MIT License. -# Copyright, 2024, by Samuel Williams. - -require "client_context" -include ClientContext - -require "protocol/http/request" - -it "can handle OPTIONS / request" do - request = Protocol::HTTP::Request.new( - endpoint.scheme, endpoint.authority, "OPTIONS", "/", nil, Protocol::HTTP::Headers.new, nil - ) - - response = client.call(request) - expect(response.status).to be == 200 - expect(response.read).to be == "OPTIONS /" -ensure - response&.finish -end