diff --git a/lib/rack/handler.rb b/lib/rack/handler.rb index df17b238d..22d547453 100644 --- a/lib/rack/handler.rb +++ b/lib/rack/handler.rb @@ -31,7 +31,7 @@ def self.get(server) # Select first available Rack handler given an `Array` of server names. # Raises `LoadError` if no handler was found. # - # > pick ['thin', 'webrick'] + # > pick ['puma', 'webrick'] # => Rack::Handler::WEBrick def self.pick(server_names) server_names = Array(server_names) @@ -45,17 +45,14 @@ def self.pick(server_names) raise LoadError, "Couldn't find handler for: #{server_names.join(', ')}." end - SERVER_NAMES = %w(puma thin falcon webrick).freeze + RACK_HANDLER = 'RACK_HANDLER' + + SERVER_NAMES = %w(puma falcon webrick).freeze private_constant :SERVER_NAMES def self.default - # Guess. - if ENV.include?("PHP_FCGI_CHILDREN") - Rack::Handler::FastCGI - elsif ENV.include?(REQUEST_METHOD) - Rack::Handler::CGI - elsif ENV.include?("RACK_HANDLER") - self.get(ENV["RACK_HANDLER"]) + if rack_handler = ENV[RACK_HANDLER] + self.get(rack_handler) else pick SERVER_NAMES end @@ -87,18 +84,7 @@ def self.register(server, klass) @handlers[server.to_s] = klass.to_s end - autoload :CGI, "rack/handler/cgi" - autoload :FastCGI, "rack/handler/fastcgi" autoload :WEBrick, "rack/handler/webrick" - autoload :LSWS, "rack/handler/lsws" - autoload :SCGI, "rack/handler/scgi" - autoload :Thin, "rack/handler/thin" - - register 'cgi', 'Rack::Handler::CGI' - register 'fastcgi', 'Rack::Handler::FastCGI' register 'webrick', 'Rack::Handler::WEBrick' - register 'lsws', 'Rack::Handler::LSWS' - register 'scgi', 'Rack::Handler::SCGI' - register 'thin', 'Rack::Handler::Thin' end end diff --git a/lib/rack/handler/cgi.rb b/lib/rack/handler/cgi.rb index 1c11ab360..48da2e2fc 100644 --- a/lib/rack/handler/cgi.rb +++ b/lib/rack/handler/cgi.rb @@ -55,5 +55,7 @@ def self.send_body(body) } end end + + register 'cgi', 'Rack::Handler::CGI' end end diff --git a/lib/rack/handler/fastcgi.rb b/lib/rack/handler/fastcgi.rb deleted file mode 100644 index 1df123e02..000000000 --- a/lib/rack/handler/fastcgi.rb +++ /dev/null @@ -1,100 +0,0 @@ -# frozen_string_literal: true - -require 'fcgi' -require 'socket' - -if defined? FCGI::Stream - class FCGI::Stream - alias _rack_read_without_buffer read - - def read(n, buffer = nil) - buf = _rack_read_without_buffer n - buffer.replace(buf.to_s) if buffer - buf - end - end -end - -module Rack - module Handler - class FastCGI - def self.run(app, **options) - if options[:File] - STDIN.reopen(UNIXServer.new(options[:File])) - elsif options[:Port] - STDIN.reopen(TCPServer.new(options[:Host], options[:Port])) - end - FCGI.each { |request| - serve request, app - } - end - - def self.valid_options - environment = ENV['RACK_ENV'] || 'development' - default_host = environment == 'development' ? 'localhost' : '0.0.0.0' - - { - "Host=HOST" => "Hostname to listen on (default: #{default_host})", - "Port=PORT" => "Port to listen on (default: 8080)", - "File=PATH" => "Creates a Domain socket at PATH instead of a TCP socket. Ignores Host and Port if set.", - } - end - - def self.serve(request, app) - env = request.env - env.delete "HTTP_CONTENT_LENGTH" - - env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/" - - rack_input = RewindableInput.new(request.in) - - env.update( - RACK_VERSION => Rack::VERSION, - RACK_INPUT => rack_input, - RACK_ERRORS => request.err, - RACK_MULTITHREAD => false, - RACK_MULTIPROCESS => true, - RACK_RUNONCE => false, - RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http" - ) - - env[QUERY_STRING] ||= "" - env[HTTP_VERSION] ||= env[SERVER_PROTOCOL] - env[REQUEST_PATH] ||= "/" - env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == "" - env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == "" - - begin - status, headers, body = app.call(env) - begin - send_headers request.out, status, headers - send_body request.out, body - ensure - body.close if body.respond_to? :close - end - ensure - rack_input.close - request.finish - end - end - - def self.send_headers(out, status, headers) - out.print "Status: #{status}\r\n" - headers.each { |k, vs| - vs.split("\n").each { |v| - out.print "#{k}: #{v}\r\n" - } - } - out.print "\r\n" - out.flush - end - - def self.send_body(out, body) - body.each { |part| - out.print part - out.flush - } - end - end - end -end diff --git a/lib/rack/handler/lsws.rb b/lib/rack/handler/lsws.rb deleted file mode 100644 index f12090bd6..000000000 --- a/lib/rack/handler/lsws.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -require 'lsapi' - -module Rack - module Handler - class LSWS - def self.run(app, **options) - while LSAPI.accept != nil - serve app - end - end - def self.serve(app) - env = ENV.to_hash - env.delete "HTTP_CONTENT_LENGTH" - env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/" - - rack_input = RewindableInput.new($stdin.read.to_s) - - env.update( - RACK_VERSION => Rack::VERSION, - RACK_INPUT => rack_input, - RACK_ERRORS => $stderr, - RACK_MULTITHREAD => false, - RACK_MULTIPROCESS => true, - RACK_RUNONCE => false, - RACK_URL_SCHEME => ["yes", "on", "1"].include?(ENV[HTTPS]) ? "https" : "http" - ) - - env[QUERY_STRING] ||= "" - env[HTTP_VERSION] ||= env[SERVER_PROTOCOL] - env[REQUEST_PATH] ||= "/" - status, headers, body = app.call(env) - begin - send_headers status, headers - send_body body - ensure - body.close if body.respond_to? :close - end - ensure - rack_input.close - end - def self.send_headers(status, headers) - print "Status: #{status}\r\n" - headers.each { |k, vs| - vs.split("\n").each { |v| - print "#{k}: #{v}\r\n" - } - } - print "\r\n" - STDOUT.flush - end - def self.send_body(body) - body.each { |part| - print part - STDOUT.flush - } - end - end - end -end diff --git a/lib/rack/handler/scgi.rb b/lib/rack/handler/scgi.rb deleted file mode 100644 index e3b8d3c6f..000000000 --- a/lib/rack/handler/scgi.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -require 'scgi' -require 'stringio' - -module Rack - module Handler - class SCGI < ::SCGI::Processor - attr_accessor :app - - def self.run(app, **options) - options[:Socket] = UNIXServer.new(options[:File]) if options[:File] - new(options.merge(app: app, - host: options[:Host], - port: options[:Port], - socket: options[:Socket])).listen - end - - def self.valid_options - environment = ENV['RACK_ENV'] || 'development' - default_host = environment == 'development' ? 'localhost' : '0.0.0.0' - - { - "Host=HOST" => "Hostname to listen on (default: #{default_host})", - "Port=PORT" => "Port to listen on (default: 8080)", - } - end - - def initialize(settings = {}) - @app = settings[:app] - super(settings) - end - - def process_request(request, input_body, socket) - env = Hash[request] - env.delete "HTTP_CONTENT_TYPE" - env.delete "HTTP_CONTENT_LENGTH" - env[REQUEST_PATH], env[QUERY_STRING] = env["REQUEST_URI"].split('?', 2) - env[HTTP_VERSION] ||= env[SERVER_PROTOCOL] - env[PATH_INFO] = env[REQUEST_PATH] - env[QUERY_STRING] ||= "" - env[SCRIPT_NAME] = "" - - rack_input = StringIO.new(input_body) - rack_input.set_encoding(Encoding::BINARY) - - env.update( - RACK_VERSION => Rack::VERSION, - RACK_INPUT => rack_input, - RACK_ERRORS => $stderr, - RACK_MULTITHREAD => true, - RACK_MULTIPROCESS => true, - RACK_RUNONCE => false, - RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http" - ) - - status, headers, body = app.call(env) - begin - socket.write("Status: #{status}\r\n") - headers.each do |k, vs| - vs.split("\n").each { |v| socket.write("#{k}: #{v}\r\n")} - end - socket.write("\r\n") - body.each {|s| socket.write(s)} - ensure - body.close if body.respond_to? :close - end - end - end - end -end diff --git a/lib/rack/handler/thin.rb b/lib/rack/handler/thin.rb deleted file mode 100644 index 393a6e986..000000000 --- a/lib/rack/handler/thin.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -require "thin" -require "thin/server" -require "thin/logging" -require "thin/backends/tcp_server" - -module Rack - module Handler - class Thin - def self.run(app, **options) - environment = ENV['RACK_ENV'] || 'development' - default_host = environment == 'development' ? 'localhost' : '0.0.0.0' - - host = options.delete(:Host) || default_host - port = options.delete(:Port) || 8080 - args = [host, port, app, options] - # Thin versions below 0.8.0 do not support additional options - args.pop if ::Thin::VERSION::MAJOR < 1 && ::Thin::VERSION::MINOR < 8 - server = ::Thin::Server.new(*args) - yield server if block_given? - server.start - end - - def self.valid_options - environment = ENV['RACK_ENV'] || 'development' - default_host = environment == 'development' ? 'localhost' : '0.0.0.0' - - { - "Host=HOST" => "Hostname to listen on (default: #{default_host})", - "Port=PORT" => "Port to listen on (default: 8080)", - } - end - end - end -end diff --git a/lib/rack/handler/webrick.rb b/lib/rack/handler/webrick.rb index d2f389758..1e88c1956 100644 --- a/lib/rack/handler/webrick.rb +++ b/lib/rack/handler/webrick.rb @@ -37,7 +37,7 @@ def self.run(app, **options) @server = ::WEBrick::HTTPServer.new(options) @server.mount "/", Rack::Handler::WEBrick, app - yield @server if block_given? + yield @server if block_given? @server.start end diff --git a/test/spec_server.rb b/test/spec_server.rb index 20992a0f9..a6968cfb9 100644 --- a/test/spec_server.rb +++ b/test/spec_server.rb @@ -8,6 +8,8 @@ require 'net/http' require 'net/https' +require 'rack/handler/cgi' + module Minitest::Spec::DSL alias :should :it end @@ -75,17 +77,6 @@ def with_stderr server.middleware['deployment'].flatten.must_include Rack::TempfileReaper end - it "support CGI" do - begin - o, ENV["REQUEST_METHOD"] = ENV["REQUEST_METHOD"], 'foo' - server = Rack::Server.new(app: 'foo') - server.server.name =~ /CGI/ - Rack::Server.logging_middleware.call(server).must_be_nil - ensure - ENV['REQUEST_METHOD'] = o - end - end - it "be quiet if said so" do server = Rack::Server.new(app: "FOO", quiet: true) Rack::Server.logging_middleware.call(server).must_be_nil