From 5153e9649ce5a3afa346b61e3854dd611dad62e8 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Mon, 1 Aug 2022 16:01:56 +1200 Subject: [PATCH] Extract rackup code + tests into separate gem. --- bin/rackup | 5 - lib/rack/handler.rb | 82 +-- lib/rack/handler/cgi.rb | 56 -- lib/rack/handler/webrick.rb | 128 ---- lib/rack/lobster.rb | 76 --- lib/rack/server.rb | 457 ------------- test/builder/line.ru | 3 - test/cgi/assets/folder/test.js | 1 - test/cgi/assets/fonts/font.eot | 1 - test/cgi/assets/images/image.png | 1 - test/cgi/assets/index.html | 1 - test/cgi/assets/javascripts/app.js | 1 - test/cgi/assets/stylesheets/app.css | 1 - test/cgi/rackup_stub.rb | 6 - test/cgi/sample_rackup.ru | 5 - test/cgi/test | 5 - test/cgi/test+directory/test+file | 1 - test/cgi/test.gz | Bin 187 -> 0 bytes test/cgi/test.ru | 5 - test/load/rack-test-a.rb | 0 test/load/rack-test-b.rb | 0 test/rackup/.gitignore | 1 - test/rackup/config.ru | 33 - .../rack/handler/registering_myself.rb | 10 - test/spec_handler.rb | 62 -- test/spec_lobster.rb | 64 -- test/spec_server.rb | 598 ------------------ test/spec_webrick.rb | 215 ------- test/test_request.rb | 81 --- .../rack/handler/unregistered.rb | 9 - .../rack/handler/unregistered_long_one.rb | 9 - 31 files changed, 9 insertions(+), 1908 deletions(-) delete mode 100755 bin/rackup delete mode 100644 lib/rack/handler/cgi.rb delete mode 100644 lib/rack/handler/webrick.rb delete mode 100644 lib/rack/lobster.rb delete mode 100644 lib/rack/server.rb delete mode 100644 test/builder/line.ru delete mode 100644 test/cgi/assets/folder/test.js delete mode 100644 test/cgi/assets/fonts/font.eot delete mode 100644 test/cgi/assets/images/image.png delete mode 100644 test/cgi/assets/index.html delete mode 100644 test/cgi/assets/javascripts/app.js delete mode 100644 test/cgi/assets/stylesheets/app.css delete mode 100755 test/cgi/rackup_stub.rb delete mode 100755 test/cgi/sample_rackup.ru delete mode 100755 test/cgi/test delete mode 100644 test/cgi/test+directory/test+file delete mode 100644 test/cgi/test.gz delete mode 100755 test/cgi/test.ru delete mode 100644 test/load/rack-test-a.rb delete mode 100644 test/load/rack-test-b.rb delete mode 100644 test/rackup/.gitignore delete mode 100644 test/rackup/config.ru delete mode 100644 test/registering_handler/rack/handler/registering_myself.rb delete mode 100644 test/spec_handler.rb delete mode 100644 test/spec_lobster.rb delete mode 100644 test/spec_server.rb delete mode 100644 test/spec_webrick.rb delete mode 100644 test/test_request.rb delete mode 100644 test/unregistered_handler/rack/handler/unregistered.rb delete mode 100644 test/unregistered_handler/rack/handler/unregistered_long_one.rb diff --git a/bin/rackup b/bin/rackup deleted file mode 100755 index 58988a0b3..000000000 --- a/bin/rackup +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -require "rack" -Rack::Server.start diff --git a/lib/rack/handler.rb b/lib/rack/handler.rb index e5843d3c0..70bc5f898 100644 --- a/lib/rack/handler.rb +++ b/lib/rack/handler.rb @@ -2,86 +2,22 @@ module Rack # *Handlers* connect web servers with Rack. - # - # Rack includes Handlers for WEBrick and CGI. - # - # Handlers usually are activated by calling MyHandler.run(myapp). - # A second optional hash can be passed to include server-specific - # configuration. module Handler @handlers = {} - def self.get(server) - return unless server - server = server.to_s - - unless @handlers.include? server - load_error = try_require('rack/handler', server) - end - - if klass = @handlers[server] - const_get(klass) - else - const_get(server, false) - end - - rescue NameError => name_error - raise load_error || name_error - end - - # Select first available Rack handler given an `Array` of server names. - # Raises `LoadError` if no handler was found. - # - # > pick ['puma', 'webrick'] - # => Rack::Handler::WEBrick - def self.pick(server_names) - server_names = Array(server_names) - server_names.each do |server_name| - begin - return get(server_name.to_s) - rescue LoadError, NameError - end + # Register a named handler class. + def self.register(name, klass) + if klass.is_a?(String) + warn "Calling Rack::Handler.register with a string is deprecated, use the class/module itself.", uplevel: 1 + + klass = self.const_get(klass, false) end - raise LoadError, "Couldn't find handler for: #{server_names.join(', ')}." - end - - RACK_HANDLER = 'RACK_HANDLER' - - SERVER_NAMES = %w(puma falcon webrick).freeze - private_constant :SERVER_NAMES - - def self.default - if rack_handler = ENV[RACK_HANDLER] - self.get(rack_handler) - else - pick SERVER_NAMES - end - end - - # Transforms server-name constants to their canonical form as filenames, - # then tries to require them but silences the LoadError if not found - # - # Naming convention: - # - # Foo # => 'foo' - # FooBar # => 'foo_bar.rb' - # FooBAR # => 'foobar.rb' - # FOObar # => 'foobar.rb' - # FOOBAR # => 'foobar.rb' - # FooBarBaz # => 'foo_bar_baz.rb' - def self.try_require(prefix, const_name) - file = const_name.gsub(/^[A-Z]+/) { |pre| pre.downcase }. - gsub(/[A-Z]+[^A-Z]/, '_\&').downcase - - require(::File.join(prefix, file)) - nil - rescue LoadError => error - error + @handlers[name] = klass end - def self.register(server, klass) - @handlers[server.to_s] = klass.to_s + def self.[](name) + @handlers[name] end end end diff --git a/lib/rack/handler/cgi.rb b/lib/rack/handler/cgi.rb deleted file mode 100644 index eecbaf036..000000000 --- a/lib/rack/handler/cgi.rb +++ /dev/null @@ -1,56 +0,0 @@ -# frozen_string_literal: true - -module Rack - module Handler - class CGI - def self.run(app, **options) - $stdin.binmode - serve app - end - - def self.serve(app) - env = ENV.to_hash - env.delete "HTTP_CONTENT_LENGTH" - - env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/" - - env.update( - RACK_INPUT => $stdin, - RACK_ERRORS => $stderr, - RACK_URL_SCHEME => ["yes", "on", "1"].include?(ENV[HTTPS]) ? "https" : "http" - ) - - env[QUERY_STRING] ||= "" - 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 - end - - def self.send_headers(status, headers) - $stdout.print "Status: #{status}\r\n" - headers.each { |k, vs| - vs.split("\n").each { |v| - $stdout.print "#{k}: #{v}\r\n" - } - } - $stdout.print "\r\n" - $stdout.flush - end - - def self.send_body(body) - body.each { |part| - $stdout.print part - $stdout.flush - } - end - end - - register 'cgi', 'Rack::Handler::CGI' - end -end diff --git a/lib/rack/handler/webrick.rb b/lib/rack/handler/webrick.rb deleted file mode 100644 index b85d02707..000000000 --- a/lib/rack/handler/webrick.rb +++ /dev/null @@ -1,128 +0,0 @@ -# frozen_string_literal: true - -require 'webrick' -require 'stringio' - -require_relative '../constants' -require_relative '../handler' -require_relative '../version' - -# This monkey patch allows for applications to perform their own chunking -# through WEBrick::HTTPResponse if rack is set to true. -class WEBrick::HTTPResponse - attr_accessor :rack - - alias _rack_setup_header setup_header - def setup_header - app_chunking = rack && @header['transfer-encoding'] == 'chunked' - - @chunked = app_chunking if app_chunking - - _rack_setup_header - - @chunked = false if app_chunking - end -end - -module Rack - module Handler - class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet - def self.run(app, **options) - environment = ENV['RACK_ENV'] || 'development' - default_host = environment == 'development' ? 'localhost' : nil - - if !options[:BindAddress] || options[:Host] - options[:BindAddress] = options.delete(:Host) || default_host - end - options[:Port] ||= 8080 - if options[:SSLEnable] - require 'webrick/https' - end - - @server = ::WEBrick::HTTPServer.new(options) - @server.mount "/", Rack::Handler::WEBrick, app - 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 - - def self.shutdown - if @server - @server.shutdown - @server = nil - end - end - - def initialize(server, app) - super server - @app = app - end - - def service(req, res) - res.rack = true - env = req.meta_vars - env.delete_if { |k, v| v.nil? } - - rack_input = StringIO.new(req.body.to_s) - rack_input.set_encoding(Encoding::BINARY) - - env.update( - RACK_INPUT => rack_input, - RACK_ERRORS => $stderr, - RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http", - RACK_IS_HIJACK => true, - ) - - env[QUERY_STRING] ||= "" - unless env[PATH_INFO] == "" - path, n = req.request_uri.path, env[SCRIPT_NAME].length - env[PATH_INFO] = path[n, path.length - n] - end - env[REQUEST_PATH] ||= [env[SCRIPT_NAME], env[PATH_INFO]].join - - status, headers, body = @app.call(env) - begin - res.status = status.to_i - io_lambda = nil - headers.each { |key, value| - if key == RACK_HIJACK - io_lambda = value - elsif key == "set-cookie" - res.cookies.concat(Array(value)) - else - # Since WEBrick won't accept repeated headers, - # merge the values per RFC 1945 section 4.2. - res[key] = Array(value).join(", ") - end - } - - if io_lambda - rd, wr = IO.pipe - res.body = rd - res.chunked = true - io_lambda.call wr - elsif body.respond_to?(:to_path) - res.body = ::File.open(body.to_path, 'rb') - else - body.each { |part| - res.body << part - } - end - ensure - body.close if body.respond_to? :close - end - end - end - - register 'webrick', WEBrick - end -end diff --git a/lib/rack/lobster.rb b/lib/rack/lobster.rb deleted file mode 100644 index ede7f909b..000000000 --- a/lib/rack/lobster.rb +++ /dev/null @@ -1,76 +0,0 @@ -# frozen_string_literal: true - -require 'zlib' - -require_relative 'constants' -require_relative 'request' -require_relative 'response' - -module Rack - # Paste has a Pony, Rack has a Lobster! - class Lobster - LobsterString = Zlib::Inflate.inflate("eJx9kEEOwyAMBO99xd7MAcytUhPlJyj2 - P6jy9i4k9EQyGAnBarEXeCBqSkntNXsi/ZCvC48zGQoZKikGrFMZvgS5ZHd+aGWVuWwhVF0 - t1drVmiR42HcWNz5w3QanT+2gIvTVCiE1lm1Y0eU4JGmIIbaKwextKn8rvW+p5PIwFl8ZWJ - I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0]) - - LambdaLobster = lambda { |env| - if env[QUERY_STRING].include?("flip") - lobster = LobsterString.split("\n"). - map { |line| line.ljust(42).reverse }. - join("\n") - href = "?" - else - lobster = LobsterString - href = "?flip" - end - - content = ["Lobstericious!", - "
", lobster, "
", - "flip!"] - length = content.inject(0) { |a, e| a + e.size }.to_s - [200, { CONTENT_TYPE => "text/html", CONTENT_LENGTH => length }, content] - } - - def call(env) - req = Request.new(env) - if req.GET["flip"] == "left" - lobster = LobsterString.split("\n").map do |line| - line.ljust(42).reverse. - gsub('\\', 'TEMP'). - gsub('/', '\\'). - gsub('TEMP', '/'). - gsub('{', '}'). - gsub('(', ')') - end.join("\n") - href = "?flip=right" - elsif req.GET["flip"] == "crash" - raise "Lobster crashed" - else - lobster = LobsterString - href = "?flip=left" - end - - res = Response.new - res.write "Lobstericious!" - res.write "
"
-      res.write lobster
-      res.write "
" - res.write "

flip!

" - res.write "

crash!

" - res.finish - end - - end -end - -if $0 == __FILE__ - # :nocov: - require_relative 'server' - require_relative 'show_exceptions' - require_relative 'lint' - Rack::Server.start( - app: Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)), Port: 9292 - ) - # :nocov: -end diff --git a/lib/rack/server.rb b/lib/rack/server.rb deleted file mode 100644 index cf361a944..000000000 --- a/lib/rack/server.rb +++ /dev/null @@ -1,457 +0,0 @@ -# frozen_string_literal: true - -require 'optparse' -require 'fileutils' - -require_relative 'version' -require_relative 'handler' -require_relative 'builder' -require_relative 'common_logger' -require_relative 'content_length' -require_relative 'show_exceptions' -require_relative 'lint' -require_relative 'tempfile_reaper' - -module Rack - - class Server - class Options - def parse!(args) - options = {} - opt_parser = OptionParser.new("", 24, ' ') do |opts| - opts.banner = "Usage: rackup [ruby options] [rack options] [rackup config]" - - opts.separator "" - opts.separator "Ruby options:" - - lineno = 1 - opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line| - eval line, TOPLEVEL_BINDING, "-e", lineno - lineno += 1 - } - - opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") { - options[:debug] = true - } - opts.on("-w", "--warn", "turn warnings on for your script") { - options[:warn] = true - } - opts.on("-q", "--quiet", "turn off logging") { - options[:quiet] = true - } - - opts.on("-I", "--include PATH", - "specify $LOAD_PATH (may be used more than once)") { |path| - (options[:include] ||= []).concat(path.split(":")) - } - - opts.on("-r", "--require LIBRARY", - "require the library, before executing your script") { |library| - (options[:require] ||= []) << library - } - - opts.separator "" - opts.separator "Rack options:" - opts.on("-b", "--builder BUILDER_LINE", "evaluate a BUILDER_LINE of code as a builder script") { |line| - options[:builder] = line - } - - opts.on("-s", "--server SERVER", "serve using SERVER (thin/puma/webrick)") { |s| - options[:server] = s - } - - opts.on("-o", "--host HOST", "listen on HOST (default: localhost)") { |host| - options[:Host] = host - } - - opts.on("-p", "--port PORT", "use PORT (default: 9292)") { |port| - options[:Port] = port - } - - opts.on("-O", "--option NAME[=VALUE]", "pass VALUE to the server as option NAME. If no VALUE, sets it to true. Run '#{$0} -s SERVER -h' to get a list of options for SERVER") { |name| - name, value = name.split('=', 2) - value = true if value.nil? - options[name.to_sym] = value - } - - opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development)") { |e| - options[:environment] = e - } - - opts.on("-D", "--daemonize", "run daemonized in the background") { |d| - options[:daemonize] ||= true - } - - opts.on("--daemonize-noclose", "run daemonized in the background without closing stdout/stderr") { - options[:daemonize] = :noclose - } - - opts.on("-P", "--pid FILE", "file to store PID") { |f| - options[:pid] = ::File.expand_path(f) - } - - opts.separator "" - opts.separator "Profiling options:" - - opts.on("--heap HEAPFILE", "Build the application, then dump the heap to HEAPFILE") do |e| - options[:heapfile] = e - end - - opts.on("--profile PROFILE", "Dump CPU or Memory profile to PROFILE (defaults to a tempfile)") do |e| - options[:profile_file] = e - end - - opts.on("--profile-mode MODE", "Profile mode (cpu|wall|object)") do |e| - unless %w[cpu wall object].include?(e) - raise OptionParser::InvalidOption, "unknown profile mode: #{e}" - end - options[:profile_mode] = e.to_sym - end - - opts.separator "" - opts.separator "Common options:" - - opts.on_tail("-h", "-?", "--help", "Show this message") do - puts opts - puts handler_opts(options) - - exit - end - - opts.on_tail("--version", "Show version") do - puts "Rack #{Rack.version} (Release: #{Rack.release})" - exit - end - end - - begin - opt_parser.parse! args - rescue OptionParser::InvalidOption => e - warn e.message - abort opt_parser.to_s - end - - options[:config] = args.last if args.last && !args.last.empty? - options - end - - def handler_opts(options) - info = [] - server = Rack::Handler.get(options[:server]) || Rack::Handler.default - if server && server.respond_to?(:valid_options) - info << "" - info << "Server-specific options for #{server.name}:" - - has_options = false - server.valid_options.each do |name, description| - next if /^(Host|Port)[^a-zA-Z]/.match?(name.to_s) # ignore handler's host and port options, we do our own. - info << sprintf(" -O %-21s %s", name, description) - has_options = true - end - return "" if !has_options - end - info.join("\n") - rescue NameError, LoadError - return "Warning: Could not find handler specified (#{options[:server] || 'default'}) to determine handler-specific options" - end - end - - # Start a new rack server (like running rackup). This will parse ARGV and - # 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 - - attr_writer :options - - # Options may include: - # * :app - # a rack application to run (overrides :config and :builder) - # * :builder - # a string to evaluate a Rack::Builder from - # * :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 truthy, the server will daemonize itself (fork, detach, etc) - # if :noclose, the server will not close STDOUT/STDERR - # * :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 access 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 - # - # Additional options for profiling app initialization include: - # * :heapfile - # location for ObjectSpace.dump_all to write the output to - # * :profile_file - # location for CPU/Memory (StackProf) profile output (defaults to a tempfile) - # * :profile_mode - # StackProf profile mode (cpu|wall|object) - def initialize(options = nil) - @ignore_options = [] - - if options - @use_default_options = false - @options = options - @app = options[:app] if options[:app] - else - @use_default_options = true - @options = parse_options(ARGV) - end - end - - def options - merged_options = @use_default_options ? default_options.merge(@options) : @options - merged_options.reject { |k, v| @ignore_options.include?(k) } - end - - def default_options - environment = ENV['RACK_ENV'] || 'development' - default_host = environment == 'development' ? 'localhost' : '0.0.0.0' - - { - environment: environment, - pid: nil, - Port: 9292, - Host: default_host, - AccessLog: [], - config: "config.ru" - } - end - - def app - @app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config - end - - class << self - def logging_middleware - lambda { |server| - /CGI/.match?(server.server.name) || server.options[:quiet] ? nil : [Rack::CommonLogger, $stderr] - } - end - - def default_middleware_by_environment - m = Hash.new {|h, k| h[k] = []} - m["deployment"] = [ - [Rack::ContentLength], - logging_middleware, - [Rack::TempfileReaper] - ] - m["development"] = [ - [Rack::ContentLength], - logging_middleware, - [Rack::ShowExceptions], - [Rack::Lint], - [Rack::TempfileReaper] - ] - - m - end - - def middleware - default_middleware_by_environment - end - end - - def middleware - self.class.middleware - end - - def start(&block) - if options[:warn] - $-w = true - end - - if includes = options[:include] - $LOAD_PATH.unshift(*includes) - end - - Array(options[:require]).each do |library| - require library - end - - if options[:debug] - $DEBUG = true - require 'pp' - p options[:server] - pp wrapped_app - pp app - end - - check_pid! if options[:pid] - - # Touch the wrapped app, so that the config.ru is loaded before - # daemonization (i.e. before chdir, etc). - handle_profiling(options[:heapfile], options[:profile_mode], options[:profile_file]) do - wrapped_app - end - - daemonize_app if options[:daemonize] - - write_pid if options[:pid] - - trap(:INT) do - if server.respond_to?(:shutdown) - server.shutdown - else - exit - end - end - - server.run(wrapped_app, **options, &block) - end - - def server - @_server ||= Rack::Handler.get(options[:server]) || Rack::Handler.default - end - - private - def build_app_and_options_from_config - if !::File.exist? options[:config] - abort "configuration #{options[:config]} not found" - end - - return Rack::Builder.parse_file(self.options[:config]) - end - - def handle_profiling(heapfile, profile_mode, filename) - if heapfile - require "objspace" - ObjectSpace.trace_object_allocations_start - yield - GC.start - ::File.open(heapfile, "w") { |f| ObjectSpace.dump_all(output: f) } - exit - end - - if profile_mode - require "stackprof" - require "tempfile" - - make_profile_name(filename) do |filename| - ::File.open(filename, "w") do |f| - StackProf.run(mode: profile_mode, out: f) do - yield - end - puts "Profile written to: #{filename}" - end - end - exit - end - - yield - end - - def make_profile_name(filename) - if filename - yield filename - else - ::Dir::Tmpname.create("profile.dump") do |tmpname, _, _| - yield tmpname - end - end - end - - def build_app_from_string - Rack::Builder.new_from_string(self.options[:builder]) - end - - def parse_options(args) - # Don't evaluate CGI ISINDEX parameters. - args.clear if ENV.include?(REQUEST_METHOD) - - @options = opt_parser.parse!(args) - @options[:config] = ::File.expand_path(options[:config]) - ENV["RACK_ENV"] = options[:environment] - @options - end - - def opt_parser - Options.new - end - - def build_app(app) - middleware[options[:environment]].reverse_each do |middleware| - middleware = middleware.call(self) if middleware.respond_to?(:call) - next unless middleware - klass, *args = middleware - app = klass.new(app, *args) - end - app - end - - def wrapped_app - @wrapped_app ||= build_app app - end - - def daemonize_app - # Cannot be covered as it forks - # :nocov: - Process.daemon(true, options[:daemonize] == :noclose) - # :nocov: - end - - def write_pid - ::File.open(options[:pid], ::File::CREAT | ::File::EXCL | ::File::WRONLY ){ |f| f.write("#{Process.pid}") } - at_exit { ::FileUtils.rm_f(options[:pid]) } - rescue Errno::EEXIST - check_pid! - retry - end - - def check_pid! - return unless ::File.exist?(options[:pid]) - - pid = ::File.read(options[:pid]).to_i - raise Errno::ESRCH if pid == 0 - - Process.kill(0, pid) - exit_with_pid(pid) - rescue Errno::ESRCH - ::File.delete(options[:pid]) - rescue Errno::EPERM - exit_with_pid(pid) - end - - def exit_with_pid(pid) - $stderr.puts "A server is already running (pid: #{pid}, file: #{options[:pid]})." - exit(1) - end - end - -end diff --git a/test/builder/line.ru b/test/builder/line.ru deleted file mode 100644 index 03a8e017c..000000000 --- a/test/builder/line.ru +++ /dev/null @@ -1,3 +0,0 @@ -# frozen_string_literal: true - -run lambda{ |env| [200, { 'content-type' => 'text/plain' }, [__LINE__.to_s]] } diff --git a/test/cgi/assets/folder/test.js b/test/cgi/assets/folder/test.js deleted file mode 100644 index 6874e45ae..000000000 --- a/test/cgi/assets/folder/test.js +++ /dev/null @@ -1 +0,0 @@ -### TestFile ### diff --git a/test/cgi/assets/fonts/font.eot b/test/cgi/assets/fonts/font.eot deleted file mode 100644 index 6874e45ae..000000000 --- a/test/cgi/assets/fonts/font.eot +++ /dev/null @@ -1 +0,0 @@ -### TestFile ### diff --git a/test/cgi/assets/images/image.png b/test/cgi/assets/images/image.png deleted file mode 100644 index 6874e45ae..000000000 --- a/test/cgi/assets/images/image.png +++ /dev/null @@ -1 +0,0 @@ -### TestFile ### diff --git a/test/cgi/assets/index.html b/test/cgi/assets/index.html deleted file mode 100644 index 6874e45ae..000000000 --- a/test/cgi/assets/index.html +++ /dev/null @@ -1 +0,0 @@ -### TestFile ### diff --git a/test/cgi/assets/javascripts/app.js b/test/cgi/assets/javascripts/app.js deleted file mode 100644 index 6874e45ae..000000000 --- a/test/cgi/assets/javascripts/app.js +++ /dev/null @@ -1 +0,0 @@ -### TestFile ### diff --git a/test/cgi/assets/stylesheets/app.css b/test/cgi/assets/stylesheets/app.css deleted file mode 100644 index 6874e45ae..000000000 --- a/test/cgi/assets/stylesheets/app.css +++ /dev/null @@ -1 +0,0 @@ -### TestFile ### diff --git a/test/cgi/rackup_stub.rb b/test/cgi/rackup_stub.rb deleted file mode 100755 index 5f0e4365e..000000000 --- a/test/cgi/rackup_stub.rb +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -$:.unshift '../../lib' -require 'rack' -Rack::Server.start diff --git a/test/cgi/sample_rackup.ru b/test/cgi/sample_rackup.ru deleted file mode 100755 index ec154da3a..000000000 --- a/test/cgi/sample_rackup.ru +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true - -require '../test_request' - -run Rack::Lint.new(TestRequest.new) diff --git a/test/cgi/test b/test/cgi/test deleted file mode 100755 index 546ad9061..000000000 --- a/test/cgi/test +++ /dev/null @@ -1,5 +0,0 @@ -***** DO NOT MODIFY THIS FILE! ***** -If you modify this file, tests will break!!! -The quick brown fox jumps over the ruby dog. -The quick brown fox jumps over the lazy dog. -***** DO NOT MODIFY THIS FILE! ***** diff --git a/test/cgi/test+directory/test+file b/test/cgi/test+directory/test+file deleted file mode 100644 index f4273fb83..000000000 --- a/test/cgi/test+directory/test+file +++ /dev/null @@ -1 +0,0 @@ -this file has plusses! diff --git a/test/cgi/test.gz b/test/cgi/test.gz deleted file mode 100644 index a23c856c8e9f2b68ace458f61f8343e6c7f0d131..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 187 zcmV;s07U;EiwFp0rqx;i16Y1NKx{d2H2_78K?}k#42AFg6?GG~f^_$?n>ZcpG`yG1 zMTyo7vsTexZ*`!TB;U(>ymV27iHjbo0J=*K{Zpj!$m0vhPM(oY)}aUPoROXb2(dJ> zEM@_jV7bLPWJi8r%!ND|Nh003exS4{u_ diff --git a/test/cgi/test.ru b/test/cgi/test.ru deleted file mode 100755 index d13f288fb..000000000 --- a/test/cgi/test.ru +++ /dev/null @@ -1,5 +0,0 @@ -#!../../bin/rackup -# frozen_string_literal: true - -require '../test_request' -run Rack::Lint.new(TestRequest.new) diff --git a/test/load/rack-test-a.rb b/test/load/rack-test-a.rb deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/load/rack-test-b.rb b/test/load/rack-test-b.rb deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/rackup/.gitignore b/test/rackup/.gitignore deleted file mode 100644 index 2f9d279a6..000000000 --- a/test/rackup/.gitignore +++ /dev/null @@ -1 +0,0 @@ -log_output diff --git a/test/rackup/config.ru b/test/rackup/config.ru deleted file mode 100644 index 267ffb506..000000000 --- a/test/rackup/config.ru +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -require_relative "../test_request" - -$stderr = File.open("#{File.dirname(__FILE__)}/log_output", "w") - -class EnvMiddleware - def initialize(app) - @app = app - end - - def call(env) - # provides a way to test that lint is present - if env["PATH_INFO"] == "/broken_lint" - return [200, {}, ["Broken Lint"]] - # provides a way to kill the process without knowing the pid - elsif env["PATH_INFO"] == "/die" - exit! - end - - env["test.$DEBUG"] = $DEBUG - env["test.$EVAL"] = BUKKIT if defined?(BUKKIT) - env["test.$VERBOSE"] = $VERBOSE - env["test.$LOAD_PATH"] = $LOAD_PATH - env["test.stderr"] = File.expand_path($stderr.path) - env["test.Ping"] = defined?(Ping) - env["test.pid"] = Process.pid - @app.call(env) - end -end - -use EnvMiddleware -run TestRequest.new diff --git a/test/registering_handler/rack/handler/registering_myself.rb b/test/registering_handler/rack/handler/registering_myself.rb deleted file mode 100644 index 21b605167..000000000 --- a/test/registering_handler/rack/handler/registering_myself.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -module Rack - module Handler - class RegisteringMyself - end - - register :registering_myself, RegisteringMyself - end -end diff --git a/test/spec_handler.rb b/test/spec_handler.rb deleted file mode 100644 index f307d1580..000000000 --- a/test/spec_handler.rb +++ /dev/null @@ -1,62 +0,0 @@ -# frozen_string_literal: true - -require_relative 'helper' - -separate_testing do - require_relative '../lib/rack/handler' -end - -class Rack::Handler::Lobster; end -class RockLobster; end - -describe Rack::Handler do - it "has registered default handlers" do - Rack::Handler.get('cgi').must_equal Rack::Handler::CGI - Rack::Handler.get('webrick').must_equal Rack::Handler::WEBrick - - begin - Rack::Handler.get('fastcgi').must_equal Rack::Handler::FastCGI - rescue LoadError - end - end - - it "raise LoadError if handler doesn't exist" do - lambda { - Rack::Handler.get('boom') - }.must_raise(LoadError) - - lambda { - Rack::Handler.get('Object') - }.must_raise(LoadError) - end - - it "get unregistered, but already required, handler by name" do - Rack::Handler.get('Lobster').must_equal Rack::Handler::Lobster - end - - it "register custom handler" do - Rack::Handler.register('rock_lobster', 'RockLobster') - Rack::Handler.get('rock_lobster').must_equal RockLobster - end - - it "not need registration for properly coded handlers even if not already required" do - begin - $LOAD_PATH.push File.expand_path('../unregistered_handler', __FILE__) - Rack::Handler.get('Unregistered').must_equal Rack::Handler::Unregistered - lambda { Rack::Handler.get('UnRegistered') }.must_raise LoadError - Rack::Handler.get('UnregisteredLongOne').must_equal Rack::Handler::UnregisteredLongOne - ensure - $LOAD_PATH.delete File.expand_path('../unregistered_handler', __FILE__) - end - end - - it "allow autoloaded handlers to be registered properly while being loaded" do - path = File.expand_path('../registering_handler', __FILE__) - begin - $LOAD_PATH.push path - Rack::Handler.get('registering_myself').must_equal Rack::Handler::RegisteringMyself - ensure - $LOAD_PATH.delete path - end - end -end diff --git a/test/spec_lobster.rb b/test/spec_lobster.rb deleted file mode 100644 index 0db9cd8ce..000000000 --- a/test/spec_lobster.rb +++ /dev/null @@ -1,64 +0,0 @@ -# frozen_string_literal: true - -require_relative 'helper' - -require_relative '../lib/rack/lobster' -separate_testing do - require_relative '../lib/rack/lint' - require_relative '../lib/rack/mock_request' -end - -module LobsterHelpers - def lobster - Rack::MockRequest.new Rack::Lint.new(Rack::Lobster.new) - end - - def lambda_lobster - Rack::MockRequest.new Rack::Lint.new(Rack::Lobster::LambdaLobster) - end -end - -describe Rack::Lobster::LambdaLobster do - include LobsterHelpers - - it "be a single lambda" do - Rack::Lobster::LambdaLobster.must_be_kind_of Proc - end - - it "look like a lobster" do - res = lambda_lobster.get("/") - res.must_be :ok? - res.body.must_include "(,(,,(,,,(" - res.body.must_include "?flip" - end - - it "be flippable" do - res = lambda_lobster.get("/?flip") - res.must_be :ok? - res.body.must_include "(,,,(,,(,(" - end -end - -describe Rack::Lobster do - include LobsterHelpers - - it "look like a lobster" do - res = lobster.get("/") - res.must_be :ok? - res.body.must_include "(,(,,(,,,(" - res.body.must_include "?flip" - res.body.must_include "crash" - end - - it "be flippable" do - res = lobster.get("/?flip=left") - res.must_be :ok? - res.body.must_include "),,,),,),)" - end - - it "provide crashing for testing purposes" do - lambda { - lobster.get("/?flip=crash") - }.must_raise RuntimeError - end -end diff --git a/test/spec_server.rb b/test/spec_server.rb deleted file mode 100644 index 7e4850b41..000000000 --- a/test/spec_server.rb +++ /dev/null @@ -1,598 +0,0 @@ -# frozen_string_literal: true - -require_relative 'helper' -require 'tempfile' -require 'socket' -require 'webrick' -require 'open-uri' -require 'net/http' -require 'net/https' - -begin - require 'stackprof' - require 'tmpdir' -rescue LoadError -else - test_profile = true -end - -separate_testing do - require_relative '../lib/rack/server' - require_relative '../lib/rack/lint' - require_relative '../lib/rack/mock_request' - require_relative '../lib/rack/show_exceptions' - require_relative '../lib/rack/tempfile_reaper' - require_relative '../lib/rack/handler' - require_relative '../lib/rack/handler/cgi' -end - -describe Rack::Server do - argv = Rack::Server::ARGV = [] - define_method(:argv) { argv } - - before { argv.clear } - - def app - lambda { |env| [200, { 'content-type' => 'text/plain' }, ['success']] } - end - - def with_stderr - old, $stderr = $stderr, StringIO.new - yield $stderr - ensure - $stderr = old - end - - it "overrides :config if :app is passed in" do - server = Rack::Server.new(app: "FOO") - server.app.must_equal "FOO" - end - - it "Options#parse parses -p and --port options into :Port" do - Rack::Server::Options.new.parse!(%w[-p 1234]).must_equal :Port => '1234' - Rack::Server::Options.new.parse!(%w[--port 1234]).must_equal :Port => '1234' - end - - it "Options#parse parses -D and --daemonize option into :daemonize" do - Rack::Server::Options.new.parse!(%w[-D]).must_equal :daemonize => true - Rack::Server::Options.new.parse!(%w[--daemonize]).must_equal :daemonize => true - end - - it "Options#parse parses --daemonize-noclose option into :daemonize => :noclose" do - Rack::Server::Options.new.parse!(%w[--daemonize-noclose]).must_equal :daemonize => :noclose - Rack::Server::Options.new.parse!(%w[-D --daemonize-noclose]).must_equal :daemonize => :noclose - Rack::Server::Options.new.parse!(%w[--daemonize-noclose -D]).must_equal :daemonize => :noclose - end - - it "Options#parse parses --profile option into :profile" do - Rack::Server::Options.new.parse!(%w[--profile foo]).must_equal :profile_file => 'foo' - end - - it "Options#parse parses --profile-mode option into :profile_mode" do - Rack::Server::Options.new.parse!(%w[--profile-mode cpu]).must_equal :profile_mode => :cpu - end - - it "Options#parse parses argument into :config" do - Rack::Server::Options.new.parse!(%w[foo]).must_equal :config => 'foo' - end - - it "Options#handler_opts doesn't include Host/Port options" do - tester = Object.new - def tester.valid_options - {'Host: ' => 'anything', 'Port: ' => 'anything'} - end - def tester.to_s - 'HPOT' - end - def tester.name - 'HPOT' - end - Rack::Handler.const_set(:HPOT, tester) - Rack::Handler.register(:host_port_option_tester, tester) - Rack::Server::Options.new.handler_opts(server: :host_port_option_tester).must_equal "" - end - - it "logging_middleware will include common logger except for CGI" do - c = Class.new(Rack::Server) - def c.middleware - Hash.new{[logging_middleware]} - end - - argv.replace(['-swebrick', '-b', 'run ->(env){[200, {}, []]}']) - c.new.send(:wrapped_app).must_be_kind_of Rack::CommonLogger - - argv.replace(['-scgi', '-b', 'run ->(env){[200, {}, []]}']) - c.new.send(:wrapped_app).must_be_kind_of Proc - end - - it "#app aborts when config.ru file does not exist" do - argv.replace(['-swebrick', 'non-existant.ru']) - c = Class.new(Rack::Server) do - alias abort raise - end - proc{c.new.app}.must_raise(RuntimeError).message.must_match(/\Aconfiguration .* not found\z/) - end - - it "#app returns app when config.ru file exists" do - argv.replace(['-swebrick', 'test/builder/line.ru']) - Rack::Server.new.app.must_be_kind_of Proc - end - - it "#start daemonizes if daemonize option is given" do - server = Rack::Server.new(daemonize: true, app: proc{}, server: :cgi) - def server.daemonize_app - throw :foo, :bar - end - catch(:foo){server.start}.must_equal :bar - end - - if test_profile - it "#profiles to temp file if :profile_mode option is given and :profile_file option is not given" do - server = Rack::Server.new(app: proc{[200, {}, []]}, server: :cgi, profile_mode: :cpu) - output = String.new - server.define_singleton_method(:puts){|str| output << str} - def server.exit - throw :foo, :bar - end - catch(:foo){server.start}.must_equal :bar - filename = output.split.last - File.file?(filename).must_equal true - File.size(filename).must_be :>, 0 - File.delete(filename) - end - - it "#profiles to given file if :profile_mode and :profile_file options are given" do - Dir.mktmpdir('test-rack-') do |dir| - filename = File.join(dir, 'profile') - server = Rack::Server.new(app: proc{[200, {}, []]}, server: :cgi, profile_mode: :cpu, profile_file: filename) - output = String.new - server.define_singleton_method(:puts){|str| output << str} - def server.exit - throw :foo, :bar - end - catch(:foo){server.start}.must_equal :bar - output.split.last.must_include 'profile' - File.file?(filename).must_equal true - File.size(filename).must_be :>, 0 - File.delete(filename) - end - end - end - - it "clears arguments if ENV['REQUEST_METHOD'] is set" do - begin - ENV['REQUEST_METHOD'] = 'GET' - argv.replace(%w[-scgi config.ru]) - Rack::Server.new - argv.must_be_empty - ensure - ENV.delete('REQUEST_METHOD') - end - end - - it "prefer to use :builder when it is passed in" do - server = Rack::Server.new(builder: "run lambda { |env| [200, {'content-type' => 'text/plain'}, ['success']] }") - Rack::MockRequest.new(server.app).get("/").body.to_s.must_equal 'success' - end - - it "allow subclasses to override middleware" do - server = Class.new(Rack::Server).class_eval { def middleware; Hash.new [] end; self } - server.middleware['deployment'].wont_equal [] - server.new(app: 'foo').middleware['deployment'].must_equal [] - end - - it "allow subclasses to override default middleware" do - server = Class.new(Rack::Server).instance_eval { def default_middleware_by_environment; Hash.new [] end; self } - server.middleware['deployment'].must_equal [] - server.new(app: 'foo').middleware['deployment'].must_equal [] - end - - it "only provide default middleware for development and deployment environments" do - Rack::Server.default_middleware_by_environment.keys.sort.must_equal %w(deployment development) - end - - it "always return an empty array for unknown environments" do - server = Rack::Server.new(app: 'foo') - server.middleware['production'].must_equal [] - end - - it "not include Rack::Lint in deployment environment" do - server = Rack::Server.new(app: 'foo') - server.middleware['deployment'].flatten.wont_include Rack::Lint - end - - it "not include Rack::ShowExceptions in deployment environment" do - server = Rack::Server.new(app: 'foo') - server.middleware['deployment'].flatten.wont_include Rack::ShowExceptions - end - - it "include Rack::TempfileReaper in deployment environment" do - server = Rack::Server.new(app: 'foo') - server.middleware['deployment'].flatten.must_include Rack::TempfileReaper - 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 - end - - it "use a full path to the pidfile" do - # avoids issues with daemonize chdir - opts = Rack::Server.new.send(:parse_options, %w[--pid testing.pid]) - opts[:pid].must_equal ::File.expand_path('testing.pid') - end - - it "get options from ARGV" do - argv.replace(['--debug', '-sthin', '--env', 'production', '-w', '-q', '-o', 'localhost', '-O', 'NAME=VALUE', '-ONAME2', '-D']) - server = Rack::Server.new - server.options[:debug].must_equal true - server.options[:server].must_equal 'thin' - server.options[:environment].must_equal 'production' - server.options[:warn].must_equal true - server.options[:quiet].must_equal true - server.options[:Host].must_equal 'localhost' - server.options[:NAME].must_equal 'VALUE' - server.options[:NAME2].must_equal true - server.options[:daemonize].must_equal true - end - - def test_options_server(*args) - argv.replace(args) - output = String.new - Class.new(Rack::Server) do - define_method(:opt_parser) do - Class.new(Rack::Server::Options) do - define_method(:puts) do |*args| - output << args.join("\n") << "\n" - end - alias warn puts - alias abort puts - define_method(:exit) do - output << "exited" - end - end.new - end - end.new - output - end - - it "support -h option to get help" do - test_options_server('-scgi', '-h').must_match(/\AUsage: rackup.*Ruby options:.*Rack options.*Profiling options.*Common options.*exited\z/m) - end - - it "support -h option to get handler-specific help" do - cgi = Rack::Handler.get('cgi') - begin - def cgi.valid_options; { "FOO=BAR" => "BAZ" } end - test_options_server('-scgi', '-h').must_match(/\AUsage: rackup.*Ruby options:.*Rack options.*Profiling options.*Common options.*Server-specific options for Rack::Handler::CGI.*-O +FOO=BAR +BAZ.*exited\z/m) - ensure - cgi.singleton_class.send(:remove_method, :valid_options) - end - end - - it "support -h option to display warning for invalid handler" do - test_options_server('-sbanana', '-h').must_match(/\AUsage: rackup.*Ruby options:.*Rack options.*Profiling options.*Common options.*Warning: Could not find handler specified \(banana\) to determine handler-specific options.*exited\z/m) - end - - it "support -v option to get version" do - test_options_server('-v').must_match(/\ARack \d\.\d \(Release: \d+\.\d+\.\d+\)\nexited\z/) - end - - it "warn for invalid --profile-mode option" do - test_options_server('--profile-mode', 'foo').must_match(/\Ainvalid option: --profile-mode unknown profile mode: foo.*Usage: rackup/m) - end - - it "warn for invalid options" do - test_options_server('--banana').must_match(/\Ainvalid option: --banana.*Usage: rackup/m) - end - - it "support -b option to specify inline rackup config" do - argv.replace(['-scgi', '-E', 'development', '-b', 'use Rack::ContentLength; run ->(env){[200, {}, []]}']) - server = Rack::Server.new - server.server.singleton_class.send(:remove_method, :run) - def (server.server).run(app, **) app end - s, h, b = server.start.call('rack.errors' => StringIO.new) - s.must_equal 500 - h['content-type'].must_equal 'text/plain' - b.join.must_include 'Rack::Lint::LintError' - end - - it "support -e option to evaluate ruby code" do - argv.replace(['-scgi', '-e', 'Object::XYZ = 2']) - begin - Rack::Server.new - Object::XYZ.must_equal 2 - ensure - Object.send(:remove_const, :XYZ) - end - end - - it "abort if config file does not exist" do - argv.replace(['-scgi']) - server = Rack::Server.new - def server.abort(s) throw :abort, s end - message = catch(:abort) do - server.start - end - message.must_match(/\Aconfiguration .*config\.ru not found/) - end - - it "support -I option to change the load path and -r to require" do - argv.replace(['-scgi', '-Ifoo/bar', '-Itest/load', '-rrack-test-a', '-rrack-test-b']) - begin - server = Rack::Server.new - server.server.singleton_class.send(:remove_method, :run) - def (server.server).run(*) end - def server.handle_profiling(*) end - def server.app(*) end - server.start - $LOAD_PATH.must_include('foo/bar') - $LOAD_PATH.must_include('test/load') - $LOADED_FEATURES.must_include(File.join(Dir.pwd, "test/load/rack-test-a.rb")) - $LOADED_FEATURES.must_include(File.join(Dir.pwd, "test/load/rack-test-b.rb")) - ensure - $LOAD_PATH.delete('foo/bar') - $LOAD_PATH.delete('test/load') - $LOADED_FEATURES.delete(File.join(Dir.pwd, "test/load/rack-test-a.rb")) - $LOADED_FEATURES.delete(File.join(Dir.pwd, "test/load/rack-test-b.rb")) - end - end - - it "support -w option to warn and -d option to debug" do - argv.replace(['-scgi', '-d', '-w']) - warn = $-w - debug = $DEBUG - begin - server = Rack::Server.new - server.server.singleton_class.send(:remove_method, :run) - def (server.server).run(*) end - def server.handle_profiling(*) end - def server.app(*) end - def server.p(*) end - def server.pp(*) end - def server.require(*) end - server.start - $-w.must_equal true - $DEBUG.must_equal true - ensure - $-w = warn - $DEBUG = debug - end - end - - if RUBY_ENGINE == "ruby" - it "support --heap option for heap profiling" do - begin - require 'objspace' - rescue LoadError - else - t = Tempfile.new - begin - argv.replace(['-scgi', '--heap', t.path, '-E', 'production', '-b', 'run ->(env){[200, {}, []]}']) - server = Rack::Server.new - server.server.singleton_class.send(:remove_method, :run) - def (server.server).run(*) end - def server.exit; throw :exit end - catch :exit do - server.start - end - File.file?(t.path).must_equal true - ensure - File.delete t.path - end - end - end - - it "support --profile-mode option for stackprof profiling" do - begin - require 'stackprof' - rescue LoadError - else - t = Tempfile.new - begin - argv.replace(['-scgi', '--profile', t.path, '--profile-mode', 'cpu', '-E', 'production', '-b', 'run ->(env){[200, {}, []]}']) - server = Rack::Server.new - def (server.server).run(*) end - def server.puts(*) end - def server.exit; throw :exit end - catch :exit do - server.start - end - File.file?(t.path).must_equal true - ensure - File.delete t.path - end - end - end - - it "support --profile-mode option for stackprof profiling without --profile option" do - begin - require 'stackprof' - rescue LoadError - else - begin - argv.replace(['-scgi', '--profile-mode', 'cpu', '-E', 'production', '-b', 'run ->(env){[200, {}, []]}']) - server = Rack::Server.new - def (server.server).run(*) end - filename = nil - server.define_singleton_method(:make_profile_name) do |fname, &block| - super(fname) do |fn| - filename = fn - block.call(filename) - end - end - def server.puts(*) end - def server.exit; throw :exit end - catch :exit do - server.start - end - File.file?(filename).must_equal true - ensure - File.delete filename - end - end - end - end - - it "support exit for INT signal when server does not respond to shutdown" do - argv.replace(['-scgi']) - server = Rack::Server.new - server.server.singleton_class.send(:remove_method, :run) - def (server.server).run(*) end - def server.handle_profiling(*) end - def server.app(*) end - exited = false - server.define_singleton_method(:exit) do - exited = true - end - server.start - exited.must_equal false - Process.kill(:INT, $$) - sleep 1 unless RUBY_ENGINE == 'ruby' - exited.must_equal true - end - - it "support support Server.start for starting" do - argv.replace(['-scgi']) - c = Class.new(Rack::Server) do - def start(*) [self.class, :started] end - end - c.start.must_equal [c, :started] - end - - - it "run a server" do - pidfile = Tempfile.open('pidfile') { |f| break f } - FileUtils.rm pidfile.path - server = Rack::Server.new( - app: app, - environment: 'none', - pid: pidfile.path, - Port: TCPServer.open('localhost', 0){|s| s.addr[1] }, - Host: 'localhost', - Logger: WEBrick::Log.new(nil, WEBrick::BasicLog::WARN), - AccessLog: [], - daemonize: false, - server: 'webrick' - ) - t = Thread.new { server.start { |s| Thread.current[:server] = s } } - t.join(0.01) until t[:server] && t[:server].status != :Stop - body = if URI.respond_to?(:open) - URI.open("http://localhost:#{server.options[:Port]}/") { |f| f.read } - else - open("http://localhost:#{server.options[:Port]}/") { |f| f.read } - end - body.must_equal 'success' - - Process.kill(:INT, $$) - t.join - open(pidfile.path) { |f| f.read.must_equal $$.to_s } - end - - it "run a secure server" do - pidfile = Tempfile.open('pidfile') { |f| break f } - FileUtils.rm pidfile.path - server = Rack::Server.new( - app: app, - environment: 'none', - pid: pidfile.path, - Port: TCPServer.open('localhost', 0){|s| s.addr[1] }, - Host: 'localhost', - Logger: WEBrick::Log.new(nil, WEBrick::BasicLog::WARN), - AccessLog: [], - daemonize: false, - server: 'webrick', - SSLEnable: true, - SSLCertName: [['CN', 'nobody'], ['DC', 'example']] - ) - t = Thread.new { server.start { |s| Thread.current[:server] = s } } - t.join(0.01) until t[:server] && t[:server].status != :Stop - - uri = URI.parse("https://localhost:#{server.options[:Port]}/") - - Net::HTTP.start("localhost", uri.port, use_ssl: true, - verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http| - - request = Net::HTTP::Get.new uri - - body = http.request(request).body - body.must_equal 'success' - end - - Process.kill(:INT, $$) - t.join - open(pidfile.path) { |f| f.read.must_equal $$.to_s } - end if RUBY_VERSION >= "2.6" && RUBY_ENGINE == "ruby" - - it "check pid file presence and running process" do - pidfile = Tempfile.open('pidfile') { |f| f.write($$); break f }.path - server = Rack::Server.new(pid: pidfile) - with_stderr do |err| - lambda { server.send(:check_pid!) }.must_raise SystemExit - err.rewind - output = err.read - output.must_match(/already running \(pid: #{$$}, file: #{pidfile}\)/) - end - end - - it "check pid file presence and dead process" do - dead_pid = `echo $$`.to_i - pidfile = Tempfile.open('pidfile') { |f| f.write(dead_pid); break f }.path - server = Rack::Server.new(pid: pidfile) - server.send(:check_pid!) - ::File.exist?(pidfile).must_equal false - end - - it "check pid file presence and exited process" do - pidfile = Tempfile.open('pidfile') { |f| break f }.path - ::File.delete(pidfile) - server = Rack::Server.new(pid: pidfile) - server.send(:check_pid!) - end - - it "check pid file presence and not owned process" do - owns_pid_1 = (Process.kill(0, 1) rescue nil) == 1 - skip "cannot test if pid 1 owner matches current process (eg. docker/lxc)" if owns_pid_1 - pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path - server = Rack::Server.new(pid: pidfile) - with_stderr do |err| - lambda { server.send(:check_pid!) }.must_raise SystemExit - err.rewind - output = err.read - output.must_match(/already running \(pid: 1, file: #{pidfile}\)/) - end - end - - it "rewrite pid file when it does not reference a running process" do - pidfile = Tempfile.open('pidfile') { |f| break f }.path - server = Rack::Server.new(pid: pidfile) - ::File.open(pidfile, 'w') { } - server.send(:write_pid) - ::File.read(pidfile).to_i.must_equal $$ - end - - it "not write pid file when it references a running process" do - pidfile = Tempfile.open('pidfile') { |f| break f }.path - ::File.delete(pidfile) - server = Rack::Server.new(pid: pidfile) - ::File.open(pidfile, 'w') { |f| f.write(1) } - with_stderr do |err| - lambda { server.send(:write_pid) }.must_raise SystemExit - err.rewind - output = err.read - output.must_match(/already running \(pid: 1, file: #{pidfile}\)/) - end - end - - it "inform the user about existing pidfiles with running processes" do - pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path - server = Rack::Server.new(pid: pidfile) - with_stderr do |err| - lambda { server.start }.must_raise SystemExit - err.rewind - output = err.read - output.must_match(/already running \(pid: 1, file: #{pidfile}\)/) - end - end - -end diff --git a/test/spec_webrick.rb b/test/spec_webrick.rb deleted file mode 100644 index 302d7cb20..000000000 --- a/test/spec_webrick.rb +++ /dev/null @@ -1,215 +0,0 @@ -# frozen_string_literal: true - -require_relative 'helper' -require 'thread' -require 'webrick' -require 'rack/handler/webrick' -require_relative 'test_request' - -separate_testing do - require_relative '../lib/rack/handler' - require_relative '../lib/rack/lint' - require_relative '../lib/rack/response' -end - -Thread.abort_on_exception = true - -describe Rack::Handler::WEBrick do - include TestRequest::Helpers - - before do - @server = WEBrick::HTTPServer.new(Host: @host = 'localhost', - Port: @port = 9202, - Logger: WEBrick::Log.new(nil, WEBrick::BasicLog::WARN), - AccessLog: []) - @server.mount "/test", Rack::Handler::WEBrick, - Rack::Lint.new(TestRequest.new) - @thread = Thread.new { @server.start } - trap(:INT) { @server.shutdown } - @status_thread = Thread.new do - seconds = 10 - wait_time = 0.1 - until is_running? || seconds <= 0 - seconds -= wait_time - sleep wait_time - end - raise "Server never reached status 'Running'" unless is_running? - end - end - - def is_running? - @server.status == :Running - end - - it "respond" do - GET("/test") - status.must_equal 200 - end - - it "be a WEBrick" do - GET("/test") - status.must_equal 200 - response["SERVER_SOFTWARE"].must_match(/WEBrick/) - response["SERVER_PROTOCOL"].must_equal "HTTP/1.1" - response["SERVER_PORT"].must_equal "9202" - response["SERVER_NAME"].must_equal "localhost" - end - - it "have CGI headers on GET" do - GET("/test") - response["REQUEST_METHOD"].must_equal "GET" - response["SCRIPT_NAME"].must_equal "/test" - response["REQUEST_PATH"].must_equal "/test" - response["PATH_INFO"].must_equal "" - response["QUERY_STRING"].must_equal "" - response["test.postdata"].must_equal "" - - GET("/test/foo?quux=1") - response["REQUEST_METHOD"].must_equal "GET" - response["SCRIPT_NAME"].must_equal "/test" - response["REQUEST_PATH"].must_equal "/test/foo" - response["PATH_INFO"].must_equal "/foo" - response["QUERY_STRING"].must_equal "quux=1" - - GET("/test/foo%25encoding?quux=1") - response["REQUEST_METHOD"].must_equal "GET" - response["SCRIPT_NAME"].must_equal "/test" - response["REQUEST_PATH"].must_equal "/test/foo%25encoding" - response["PATH_INFO"].must_equal "/foo%25encoding" - response["QUERY_STRING"].must_equal "quux=1" - end - - it "have CGI headers on POST" do - POST("/test", { "rack-form-data" => "23" }, { 'X-test-header' => '42' }) - status.must_equal 200 - response["REQUEST_METHOD"].must_equal "POST" - response["SCRIPT_NAME"].must_equal "/test" - response["REQUEST_PATH"].must_equal "/test" - response["PATH_INFO"].must_equal "" - response["QUERY_STRING"].must_equal "" - response["HTTP_X_TEST_HEADER"].must_equal "42" - response["test.postdata"].must_equal "rack-form-data=23" - end - - it "support HTTP auth" do - GET("/test", { user: "ruth", passwd: "secret" }) - response["HTTP_AUTHORIZATION"].must_equal "Basic cnV0aDpzZWNyZXQ=" - end - - it "set status" do - GET("/test?secret") - status.must_equal 403 - response["rack.url_scheme"].must_equal "http" - end - - it "correctly set cookies" do - @server.mount "/cookie-test", Rack::Handler::WEBrick, - Rack::Lint.new(lambda { |req| - res = Rack::Response.new - res.set_cookie "one", "1" - res.set_cookie "two", "2" - res.finish - }) - - Net::HTTP.start(@host, @port) { |http| - res = http.get("/cookie-test") - res.code.to_i.must_equal 200 - res.get_fields("set-cookie").must_equal ["one=1", "two=2"] - } - end - - it "provide a .run" do - queue = Queue.new - - t = Thread.new do - Rack::Handler::WEBrick.run(lambda {}, - Host: 'localhost', - Port: 9210, - Logger: WEBrick::Log.new(nil, WEBrick::BasicLog::WARN), - AccessLog: []) { |server| - assert_kind_of WEBrick::HTTPServer, server - queue.push(server) - } - end - - server = queue.pop - - # The server may not yet have started: wait for it - seconds = 10 - wait_time = 0.1 - until server.status == :Running || seconds <= 0 - seconds -= wait_time - sleep wait_time - end - - raise "Server never reached status 'Running'" unless server.status == :Running - - server.shutdown - t.join - end - - it "return repeated headers" do - @server.mount "/headers", Rack::Handler::WEBrick, - Rack::Lint.new(lambda { |req| - [ - 401, - { "content-type" => "text/plain", - "www-authenticate" => ["Bar realm=X", "Baz realm=Y"] }, - [""] - ] - }) - - Net::HTTP.start(@host, @port) { |http| - res = http.get("/headers") - res.code.to_i.must_equal 401 - res["www-authenticate"].must_equal "Bar realm=X, Baz realm=Y" - } - end - - it "support Rack partial hijack" do - io_lambda = lambda{ |io| - 5.times do - io.write "David\r\n" - end - io.close - } - - @server.mount "/partial", Rack::Handler::WEBrick, - Rack::Lint.new(lambda{ |req| - [ - 200, - { "rack.hijack" => io_lambda }, - [""] - ] - }) - - Net::HTTP.start(@host, @port){ |http| - res = http.get("/partial") - res.body.must_equal "David\r\nDavid\r\nDavid\r\nDavid\r\nDavid\r\n" - } - end - - it "produce correct HTTP semantics with and without app chunking" do - @server.mount "/chunked", Rack::Handler::WEBrick, - Rack::Lint.new(lambda{ |req| - [ - 200, - { "transfer-encoding" => "chunked" }, - ["7\r\nchunked\r\n0\r\n\r\n"] - ] - }) - - Net::HTTP.start(@host, @port){ |http| - res = http.get("/chunked") - res["transfer-encoding"].must_equal "chunked" - res["content-length"].must_be_nil - res.body.must_equal "chunked" - } - end - - after do - @status_thread.join - @server.shutdown - @thread.join - end -end diff --git a/test/test_request.rb b/test/test_request.rb deleted file mode 100644 index d40169aaf..000000000 --- a/test/test_request.rb +++ /dev/null @@ -1,81 +0,0 @@ -# frozen_string_literal: true - -require 'yaml' -require_relative 'psych_fix' -require 'net/http' -require 'rack/lint' - -class TestRequest - NOSERIALIZE = [Method, Proc, Rack::Lint::Wrapper::InputWrapper] - - def call(env) - status = env["QUERY_STRING"] =~ /secret/ ? 403 : 200 - env["test.postdata"] = env["rack.input"].read - 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.bytesize - [status, { "content-type" => "text/yaml", "content-length" => size.to_s }, [body]] - end - - module Helpers - attr_reader :status, :response - - ROOT = File.expand_path(File.dirname(__FILE__) + "/..") - ENV["RUBYOPT"] = "-I#{ROOT}/lib -rubygems" - - def root - ROOT - end - - def rackup - "#{ROOT}/bin/rackup" - end - - def GET(path, header = {}) - Net::HTTP.start(@host, @port) { |http| - user = header.delete(:user) - passwd = header.delete(:passwd) - - get = Net::HTTP::Get.new(path, header) - get.basic_auth user, passwd if user && passwd - http.request(get) { |response| - @status = response.code.to_i - begin - @response = YAML.unsafe_load(response.body) - rescue TypeError, ArgumentError - @response = nil - end - } - } - end - - def POST(path, formdata = {}, header = {}) - Net::HTTP.start(@host, @port) { |http| - user = header.delete(:user) - passwd = header.delete(:passwd) - - post = Net::HTTP::Post.new(path, header) - post.form_data = formdata - post.basic_auth user, passwd if user && passwd - http.request(post) { |response| - @status = response.code.to_i - @response = YAML.unsafe_load(response.body) - } - } - end - end -end - -class StreamingRequest - def self.call(env) - [200, { "content-type" => "text/plain" }, new] - end - - def each - yield "hello there!\n" - sleep 5 - yield "that is all.\n" - end -end diff --git a/test/unregistered_handler/rack/handler/unregistered.rb b/test/unregistered_handler/rack/handler/unregistered.rb deleted file mode 100644 index e98468cc6..000000000 --- a/test/unregistered_handler/rack/handler/unregistered.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module Rack - module Handler - # this class doesn't do anything, we're just seeing if we get it. - class Unregistered - end - end -end diff --git a/test/unregistered_handler/rack/handler/unregistered_long_one.rb b/test/unregistered_handler/rack/handler/unregistered_long_one.rb deleted file mode 100644 index 87c6c2543..000000000 --- a/test/unregistered_handler/rack/handler/unregistered_long_one.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module Rack - module Handler - # this class doesn't do anything, we're just seeing if we get it. - class UnregisteredLongOne - end - end -end