rackup 0.2.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 23caa71b03397adf9344168de947fca289d1e4df6c577678e8b7fc8285c522e9
4
- data.tar.gz: e39027a50a3f54eb0928d6cef394f79cdd52c71da06854f2fcf5ba3a5722c083
3
+ metadata.gz: 92bf342afdd0c82df66b17a4d0a18102b82ff4f6fe0d6c0a9c6c448c1833b020
4
+ data.tar.gz: '0803347f74697ae828f519c5ec3bb3c9d52aa67605c1cc86c918e460ef3b2f22'
5
5
  SHA512:
6
- metadata.gz: be73868bc8995d73ae90f9e70bc6b8141ff5b0c26276cfcb8c010376cf3b7bdfc97d3836afad0524de61cee8c9cb910f16806becae671569fbb3484702c84e6c
7
- data.tar.gz: fdad77f1c5b70d027c67a893db852bb825631772854df4bfdfc08d3d5ab2a2c40212375bc318f276695ce659014b7f72a2c80d62b0c0c73a0f6069649f21c845
6
+ metadata.gz: ccc75df436ba2fba6a7971d0eb0db09714cf90364eeca96d380f3cc86b57845e5d4c38fb1bb9d91cce47207656926de42ebec03d2688dad292fc00c48f76dcf0
7
+ data.tar.gz: 074af927d0ed8d981ad74d02139e7493269d6406b3426675aab136d051e4d93e7355f98ca5ae4081458e35572efa8360db47fe657e6dce6ab57a7cf711bae626
@@ -1,25 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright, 2022, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
3
+ # Released under the MIT License.
4
+ # Copyright, 2022, by Samuel Williams.
22
5
 
23
6
  module Rackup
24
- VERSION = "0.2.3"
7
+ VERSION = "1.0.0"
25
8
  end
data/lib/rackup.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Released under the MIT License.
4
+ # Copyright, 2022, by Samuel Williams.
5
+
3
6
  require_relative 'rackup/handler'
4
7
  require_relative 'rackup/server'
5
8
  require_relative 'rackup/version'
6
9
 
7
10
  require_relative 'rackup/handler/webrick'
8
- require_relative 'rackup/handler/cgi'
11
+ require_relative 'rackup/handler/cgi'
@@ -1,7 +1,7 @@
1
- Released under the MIT license.
1
+ # MIT License
2
2
 
3
- Copyright, 2007-2021, by [Leah Neukirchen](https://leahneukirchen.org).
4
- Copyright, 2022, by [Samuel G. D. Williams](https://www.codeotaku.com).
3
+ Copyright, 2022, by Samuel Williams.
4
+ Copyright, 2022, by Jeremy Evans.
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  of this software and associated documentation files (the "Software"), to deal
@@ -10,13 +10,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
10
  copies of the Software, and to permit persons to whom the Software is
11
11
  furnished to do so, subject to the following conditions:
12
12
 
13
- The above copyright notice and this permission notice shall be included in
14
- all copies or substantial portions of the Software.
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
15
 
16
16
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
17
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
18
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
19
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
20
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
- THE SOFTWARE.
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
data/readme.md ADDED
@@ -0,0 +1,31 @@
1
+ # Rackup
2
+
3
+ `rackup` provides a command line interface for running a Rack-compatible application.
4
+
5
+ [![Development Status](https://github.com/rack/rackup/workflows/Test/badge.svg)](https://github.com/rack/rackup/actions?workflow=Test)
6
+
7
+ ## Installation
8
+
9
+ ``` bash
10
+ $ gem install rackup
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ In a directory with your `config.ru` simply run the command:
16
+
17
+ ``` bash
18
+ $ rackup
19
+ ```
20
+
21
+ Your application should now be available locally, typically `http://localhost:9292`.
22
+
23
+ ## Contributing
24
+
25
+ We welcome contributions to this project.
26
+
27
+ 1. Fork it.
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`).
30
+ 4. Push to the branch (`git push origin my-new-feature`).
31
+ 5. Create new Pull Request.
data/security.md ADDED
@@ -0,0 +1,3 @@
1
+ # Security Policy
2
+
3
+ Please see our main security policy: https://github.com/rack/rack/security/policy
metadata CHANGED
@@ -1,29 +1,30 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rackup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
- - Rack Contributors
7
+ - Samuel Williams
8
+ - Jeremy Evans
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2022-11-11 00:00:00.000000000 Z
12
+ date: 2023-01-18 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: rack
15
16
  requirement: !ruby/object:Gem::Requirement
16
17
  requirements:
17
- - - ">="
18
+ - - "<"
18
19
  - !ruby/object:Gem::Version
19
- version: 3.0.0.beta1
20
+ version: '3'
20
21
  type: :runtime
21
22
  prerelease: false
22
23
  version_requirements: !ruby/object:Gem::Requirement
23
24
  requirements:
24
- - - ">="
25
+ - - "<"
25
26
  - !ruby/object:Gem::Version
26
- version: 3.0.0.beta1
27
+ version: '3'
27
28
  - !ruby/object:Gem::Dependency
28
29
  name: webrick
29
30
  requirement: !ruby/object:Gem::Requirement
@@ -39,33 +40,33 @@ dependencies:
39
40
  - !ruby/object:Gem::Version
40
41
  version: '0'
41
42
  - !ruby/object:Gem::Dependency
42
- name: minitest
43
+ name: bundler
43
44
  requirement: !ruby/object:Gem::Requirement
44
45
  requirements:
45
- - - "~>"
46
+ - - ">="
46
47
  - !ruby/object:Gem::Version
47
- version: '5.0'
48
+ version: '0'
48
49
  type: :development
49
50
  prerelease: false
50
51
  version_requirements: !ruby/object:Gem::Requirement
51
52
  requirements:
52
- - - "~>"
53
+ - - ">="
53
54
  - !ruby/object:Gem::Version
54
- version: '5.0'
55
+ version: '0'
55
56
  - !ruby/object:Gem::Dependency
56
- name: minitest-sprint
57
+ name: minitest
57
58
  requirement: !ruby/object:Gem::Requirement
58
59
  requirements:
59
- - - ">="
60
+ - - "~>"
60
61
  - !ruby/object:Gem::Version
61
- version: '0'
62
+ version: '5.0'
62
63
  type: :development
63
64
  prerelease: false
64
65
  version_requirements: !ruby/object:Gem::Requirement
65
66
  requirements:
66
- - - ">="
67
+ - - "~>"
67
68
  - !ruby/object:Gem::Version
68
- version: '0'
69
+ version: '5.0'
69
70
  - !ruby/object:Gem::Dependency
70
71
  name: minitest-global_expectations
71
72
  requirement: !ruby/object:Gem::Requirement
@@ -81,7 +82,7 @@ dependencies:
81
82
  - !ruby/object:Gem::Version
82
83
  version: '0'
83
84
  - !ruby/object:Gem::Dependency
84
- name: bundler
85
+ name: minitest-sprint
85
86
  requirement: !ruby/object:Gem::Requirement
86
87
  requirements:
87
88
  - - ">="
@@ -110,22 +111,15 @@ dependencies:
110
111
  version: '0'
111
112
  description:
112
113
  email:
113
- executables:
114
- - rackup
114
+ executables: []
115
115
  extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
- - LICENSE.md
119
- - bin/rackup
120
- - lib/rack/handler.rb
121
- - lib/rack/server.rb
122
118
  - lib/rackup.rb
123
- - lib/rackup/handler.rb
124
- - lib/rackup/handler/cgi.rb
125
- - lib/rackup/handler/webrick.rb
126
- - lib/rackup/lobster.rb
127
- - lib/rackup/server.rb
128
119
  - lib/rackup/version.rb
120
+ - license.md
121
+ - readme.md
122
+ - security.md
129
123
  homepage: https://github.com/rack/rackup
130
124
  licenses:
131
125
  - MIT
@@ -145,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
139
  - !ruby/object:Gem::Version
146
140
  version: '0'
147
141
  requirements: []
148
- rubygems_version: 3.3.7
142
+ rubygems_version: 3.4.1
149
143
  signing_key:
150
144
  specification_version: 4
151
145
  summary: A general server command for Rack applications.
data/bin/rackup DELETED
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require_relative "../lib/rackup"
5
- Rackup::Server.start
data/lib/rack/handler.rb DELETED
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- warn "Rack::Handler is deprecated and replaced by Rackup::Handler"
4
- require_relative '../rackup/handler'
5
- module Rack
6
- Handler = ::Rackup::Handler
7
- end
data/lib/rack/server.rb DELETED
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- warn "Rack::Server is deprecated and replaced by Rackup::Server"
4
- require_relative '../rackup/server'
5
- module Rack
6
- Server = ::Rackup::Server
7
- end
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rackup
4
- module Handler
5
- class CGI
6
- include Rack
7
-
8
- def self.run(app, **options)
9
- $stdin.binmode
10
- serve app
11
- end
12
-
13
- def self.serve(app)
14
- env = ENV.to_hash
15
- env.delete "HTTP_CONTENT_LENGTH"
16
-
17
- env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/"
18
-
19
- env.update(
20
- RACK_INPUT => $stdin,
21
- RACK_ERRORS => $stderr,
22
- RACK_URL_SCHEME => ["yes", "on", "1"].include?(ENV[HTTPS]) ? "https" : "http"
23
- )
24
-
25
- env[QUERY_STRING] ||= ""
26
- env[REQUEST_PATH] ||= "/"
27
-
28
- status, headers, body = app.call(env)
29
- begin
30
- send_headers status, headers
31
- send_body body
32
- ensure
33
- body.close if body.respond_to? :close
34
- end
35
- end
36
-
37
- def self.send_headers(status, headers)
38
- $stdout.print "Status: #{status}\r\n"
39
- headers.each { |k, vs|
40
- vs.split("\n").each { |v|
41
- $stdout.print "#{k}: #{v}\r\n"
42
- }
43
- }
44
- $stdout.print "\r\n"
45
- $stdout.flush
46
- end
47
-
48
- def self.send_body(body)
49
- body.each { |part|
50
- $stdout.print part
51
- $stdout.flush
52
- }
53
- end
54
- end
55
-
56
- register :cgi, CGI
57
- end
58
- end
@@ -1,138 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'webrick'
4
- require 'stringio'
5
-
6
- require 'rack/constants'
7
- require_relative '../handler'
8
- require_relative '../version'
9
-
10
- # This monkey patch allows for applications to perform their own chunking
11
- # through WEBrick::HTTPResponse if rack is set to true.
12
- class WEBrick::HTTPResponse
13
- attr_accessor :rack
14
-
15
- alias _rack_setup_header setup_header
16
- def setup_header
17
- app_chunking = rack && @header['transfer-encoding'] == 'chunked'
18
-
19
- @chunked = app_chunking if app_chunking
20
-
21
- _rack_setup_header
22
-
23
- @chunked = false if app_chunking
24
- end
25
- end
26
-
27
- module Rackup
28
- module Handler
29
- class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet
30
- include Rack
31
-
32
- def self.run(app, **options)
33
- environment = ENV['RACK_ENV'] || 'development'
34
- default_host = environment == 'development' ? 'localhost' : nil
35
-
36
- if !options[:BindAddress] || options[:Host]
37
- options[:BindAddress] = options.delete(:Host) || default_host
38
- end
39
- options[:Port] ||= 8080
40
- if options[:SSLEnable]
41
- require 'webrick/https'
42
- end
43
-
44
- @server = ::WEBrick::HTTPServer.new(options)
45
- @server.mount "/", Rackup::Handler::WEBrick, app
46
- yield @server if block_given?
47
- @server.start
48
- end
49
-
50
- def self.valid_options
51
- environment = ENV['RACK_ENV'] || 'development'
52
- default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
53
-
54
- {
55
- "Host=HOST" => "Hostname to listen on (default: #{default_host})",
56
- "Port=PORT" => "Port to listen on (default: 8080)",
57
- }
58
- end
59
-
60
- def self.shutdown
61
- if @server
62
- @server.shutdown
63
- @server = nil
64
- end
65
- end
66
-
67
- def initialize(server, app)
68
- super server
69
- @app = app
70
- end
71
-
72
- def service(req, res)
73
- res.rack = true
74
- env = req.meta_vars
75
- env.delete_if { |k, v| v.nil? }
76
-
77
- rack_input = StringIO.new(req.body.to_s)
78
- rack_input.set_encoding(Encoding::BINARY)
79
-
80
- env.update(
81
- RACK_INPUT => rack_input,
82
- RACK_ERRORS => $stderr,
83
- RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http",
84
- RACK_IS_HIJACK => true,
85
- )
86
-
87
- env[QUERY_STRING] ||= ""
88
- unless env[PATH_INFO] == ""
89
- path, n = req.request_uri.path, env[SCRIPT_NAME].length
90
- env[PATH_INFO] = path[n, path.length - n]
91
- end
92
- env[REQUEST_PATH] ||= [env[SCRIPT_NAME], env[PATH_INFO]].join
93
-
94
- status, headers, body = @app.call(env)
95
- begin
96
- res.status = status
97
-
98
- if value = headers[RACK_HIJACK]
99
- io_lambda = value
100
- elsif !body.respond_to?(:to_path) && !body.respond_to?(:each)
101
- io_lambda = body
102
- end
103
-
104
- if value = headers.delete('set-cookie')
105
- res.cookies.concat(Array(value))
106
- end
107
-
108
- headers.each { |key, value|
109
- # Skip keys starting with rack., per Rack SPEC
110
- next if key.start_with?('rack.')
111
-
112
- # Since WEBrick won't accept repeated headers,
113
- # merge the values per RFC 1945 section 4.2.
114
- value = value.join(", ") if Array === value
115
- res[key] = value
116
- }
117
-
118
- if io_lambda
119
- rd, wr = IO.pipe
120
- res.body = rd
121
- res.chunked = true
122
- io_lambda.call wr
123
- elsif body.respond_to?(:to_path)
124
- res.body = ::File.open(body.to_path, 'rb')
125
- else
126
- body.each { |part|
127
- res.body << part
128
- }
129
- end
130
- ensure
131
- body.close if body.respond_to? :close
132
- end
133
- end
134
- end
135
-
136
- register :webrick, WEBrick
137
- end
138
- end
@@ -1,110 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rackup
4
- # *Handlers* connect web servers with Rack.
5
- #
6
- # Rackup includes Handlers for WEBrick and CGI.
7
- #
8
- # Handlers usually are activated by calling <tt>MyHandler.run(myapp)</tt>.
9
- # A second optional hash can be passed to include server-specific
10
- # configuration.
11
- module Handler
12
- @handlers = {}
13
-
14
- # Register a named handler class.
15
- def self.register(name, klass)
16
- if klass.is_a?(String)
17
- warn "Calling Rackup::Handler.register with a string is deprecated, use the class/module itself.", uplevel: 1
18
-
19
- klass = self.const_get(klass, false)
20
- end
21
-
22
- name = name.to_sym
23
-
24
- @handlers[name] = klass
25
- end
26
-
27
- def self.[](name)
28
- name = name.to_sym
29
-
30
- begin
31
- @handlers[name] || self.const_get(name, false)
32
- rescue NameError
33
- # Ignore.
34
- end
35
- end
36
-
37
- def self.get(name)
38
- return nil unless name
39
-
40
- name = name.to_sym
41
-
42
- if server = self[name]
43
- return server
44
- end
45
-
46
- begin
47
- require_handler("rackup/handler", name)
48
- rescue LoadError
49
- require_handler("rack/handler", name)
50
- end
51
-
52
- return self[name]
53
- end
54
-
55
- RACK_HANDLER = 'RACK_HANDLER'
56
- RACKUP_HANDLER = 'RACKUP_HANDLER'
57
-
58
- SERVER_NAMES = %i(puma falcon webrick).freeze
59
- private_constant :SERVER_NAMES
60
-
61
- # Select first available Rack handler given an `Array` of server names.
62
- # Raises `LoadError` if no handler was found.
63
- #
64
- # > pick ['puma', 'webrick']
65
- # => Rackup::Handler::WEBrick
66
- def self.pick(server_names)
67
- server_names = Array(server_names)
68
-
69
- server_names.each do |server_name|
70
- begin
71
- server = self.get(server_name)
72
- return server if server
73
- rescue LoadError
74
- # Ignore.
75
- end
76
- end
77
-
78
- raise LoadError, "Couldn't find handler for: #{server_names.join(', ')}."
79
- end
80
-
81
- def self.default
82
- if rack_handler = ENV[RACKUP_HANDLER]
83
- self.get(rack_handler)
84
- elsif rack_handler = ENV[RACK_HANDLER]
85
- warn "RACK_HANDLER is deprecated, use RACKUP_HANDLER."
86
- self.get(rack_handler)
87
- else
88
- pick SERVER_NAMES
89
- end
90
- end
91
-
92
- # Transforms server-name constants to their canonical form as filenames,
93
- # then tries to require them but silences the LoadError if not found
94
- #
95
- # Naming convention:
96
- #
97
- # Foo # => 'foo'
98
- # FooBar # => 'foo_bar.rb'
99
- # FooBAR # => 'foobar.rb'
100
- # FOObar # => 'foobar.rb'
101
- # FOOBAR # => 'foobar.rb'
102
- # FooBarBaz # => 'foo_bar_baz.rb'
103
- def self.require_handler(prefix, const_name)
104
- file = const_name.to_s.gsub(/^[A-Z]+/) { |pre| pre.downcase }.
105
- gsub(/[A-Z]+[^A-Z]/, '_\&').downcase
106
-
107
- require(::File.join(prefix, file))
108
- end
109
- end
110
- end
@@ -1,78 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'zlib'
4
-
5
- require 'rack/constants'
6
- require 'rack/request'
7
- require 'rack/response'
8
-
9
- module Rackup
10
- # Paste has a Pony, Rack has a Lobster!
11
- class Lobster
12
- include Rack
13
-
14
- LobsterString = Zlib::Inflate.inflate("eJx9kEEOwyAMBO99xd7MAcytUhPlJyj2
15
- P6jy9i4k9EQyGAnBarEXeCBqSkntNXsi/ZCvC48zGQoZKikGrFMZvgS5ZHd+aGWVuWwhVF0
16
- t1drVmiR42HcWNz5w3QanT+2gIvTVCiE1lm1Y0eU4JGmIIbaKwextKn8rvW+p5PIwFl8ZWJ
17
- I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0])
18
-
19
- LambdaLobster = lambda { |env|
20
- if env[QUERY_STRING].include?("flip")
21
- lobster = LobsterString.split("\n").
22
- map { |line| line.ljust(42).reverse }.
23
- join("\n")
24
- href = "?"
25
- else
26
- lobster = LobsterString
27
- href = "?flip"
28
- end
29
-
30
- content = ["<title>Lobstericious!</title>",
31
- "<pre>", lobster, "</pre>",
32
- "<a href='#{href}'>flip!</a>"]
33
- length = content.inject(0) { |a, e| a + e.size }.to_s
34
- [200, { CONTENT_TYPE => "text/html", CONTENT_LENGTH => length }, content]
35
- }
36
-
37
- def call(env)
38
- req = Request.new(env)
39
- if req.GET["flip"] == "left"
40
- lobster = LobsterString.split("\n").map do |line|
41
- line.ljust(42).reverse.
42
- gsub('\\', 'TEMP').
43
- gsub('/', '\\').
44
- gsub('TEMP', '/').
45
- gsub('{', '}').
46
- gsub('(', ')')
47
- end.join("\n")
48
- href = "?flip=right"
49
- elsif req.GET["flip"] == "crash"
50
- raise "Lobster crashed"
51
- else
52
- lobster = LobsterString
53
- href = "?flip=left"
54
- end
55
-
56
- res = Response.new
57
- res.write "<title>Lobstericious!</title>"
58
- res.write "<pre>"
59
- res.write lobster
60
- res.write "</pre>"
61
- res.write "<p><a href='#{href}'>flip!</a></p>"
62
- res.write "<p><a href='?flip=crash'>crash!</a></p>"
63
- res.finish
64
- end
65
-
66
- end
67
- end
68
-
69
- if $0 == __FILE__
70
- # :nocov:
71
- require_relative 'server'
72
- require_relative 'show_exceptions'
73
- require_relative 'lint'
74
- Rackup::Server.start(
75
- app: Rack::ShowExceptions.new(Rack::Lint.new(Rackup::Lobster.new)), Port: 9292
76
- )
77
- # :nocov:
78
- end
data/lib/rackup/server.rb DELETED
@@ -1,459 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'optparse'
4
- require 'fileutils'
5
-
6
- require 'rack/builder'
7
- require 'rack/common_logger'
8
- require 'rack/content_length'
9
- require 'rack/show_exceptions'
10
- require 'rack/lint'
11
- require 'rack/tempfile_reaper'
12
-
13
- require 'rack/version'
14
-
15
- require_relative 'version'
16
- require_relative 'handler'
17
-
18
- module Rackup
19
- class Server
20
- class Options
21
- def parse!(args)
22
- options = {}
23
- opt_parser = OptionParser.new("", 24, ' ') do |opts|
24
- opts.banner = "Usage: rackup [ruby options] [rack options] [rackup config]"
25
-
26
- opts.separator ""
27
- opts.separator "Ruby options:"
28
-
29
- lineno = 1
30
- opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line|
31
- eval line, TOPLEVEL_BINDING, "-e", lineno
32
- lineno += 1
33
- }
34
-
35
- opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") {
36
- options[:debug] = true
37
- }
38
- opts.on("-w", "--warn", "turn warnings on for your script") {
39
- options[:warn] = true
40
- }
41
- opts.on("-q", "--quiet", "turn off logging") {
42
- options[:quiet] = true
43
- }
44
-
45
- opts.on("-I", "--include PATH",
46
- "specify $LOAD_PATH (may be used more than once)") { |path|
47
- (options[:include] ||= []).concat(path.split(":"))
48
- }
49
-
50
- opts.on("-r", "--require LIBRARY",
51
- "require the library, before executing your script") { |library|
52
- (options[:require] ||= []) << library
53
- }
54
-
55
- opts.separator ""
56
- opts.separator "Rack options:"
57
- opts.on("-b", "--builder BUILDER_LINE", "evaluate a BUILDER_LINE of code as a builder script") { |line|
58
- options[:builder] = line
59
- }
60
-
61
- opts.on("-s", "--server SERVER", "serve using SERVER (thin/puma/webrick)") { |s|
62
- options[:server] = s
63
- }
64
-
65
- opts.on("-o", "--host HOST", "listen on HOST (default: localhost)") { |host|
66
- options[:Host] = host
67
- }
68
-
69
- opts.on("-p", "--port PORT", "use PORT (default: 9292)") { |port|
70
- options[:Port] = port
71
- }
72
-
73
- 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|
74
- name, value = name.split('=', 2)
75
- value = true if value.nil?
76
- options[name.to_sym] = value
77
- }
78
-
79
- opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development)") { |e|
80
- options[:environment] = e
81
- }
82
-
83
- opts.on("-D", "--daemonize", "run daemonized in the background") { |d|
84
- options[:daemonize] ||= true
85
- }
86
-
87
- opts.on("--daemonize-noclose", "run daemonized in the background without closing stdout/stderr") {
88
- options[:daemonize] = :noclose
89
- }
90
-
91
- opts.on("-P", "--pid FILE", "file to store PID") { |f|
92
- options[:pid] = ::File.expand_path(f)
93
- }
94
-
95
- opts.separator ""
96
- opts.separator "Profiling options:"
97
-
98
- opts.on("--heap HEAPFILE", "Build the application, then dump the heap to HEAPFILE") do |e|
99
- options[:heapfile] = e
100
- end
101
-
102
- opts.on("--profile PROFILE", "Dump CPU or Memory profile to PROFILE (defaults to a tempfile)") do |e|
103
- options[:profile_file] = e
104
- end
105
-
106
- opts.on("--profile-mode MODE", "Profile mode (cpu|wall|object)") do |e|
107
- unless %w[cpu wall object].include?(e)
108
- raise OptionParser::InvalidOption, "unknown profile mode: #{e}"
109
- end
110
- options[:profile_mode] = e.to_sym
111
- end
112
-
113
- opts.separator ""
114
- opts.separator "Common options:"
115
-
116
- opts.on_tail("-h", "-?", "--help", "Show this message") do
117
- puts opts
118
- puts handler_opts(options)
119
-
120
- exit
121
- end
122
-
123
- opts.on_tail("--version", "Show version") do
124
- puts "Rack #{Rack::RELEASE}"
125
- exit
126
- end
127
- end
128
-
129
- begin
130
- opt_parser.parse! args
131
- rescue OptionParser::InvalidOption => e
132
- warn e.message
133
- abort opt_parser.to_s
134
- end
135
-
136
- options[:config] = args.last if args.last && !args.last.empty?
137
- options
138
- end
139
-
140
- def handler_opts(options)
141
- info = []
142
- server = Rackup::Handler.get(options[:server]) || Rackup::Handler.default
143
- if server && server.respond_to?(:valid_options)
144
- info << ""
145
- info << "Server-specific options for #{server.name}:"
146
-
147
- has_options = false
148
- server.valid_options.each do |name, description|
149
- next if /^(Host|Port)[^a-zA-Z]/.match?(name.to_s) # ignore handler's host and port options, we do our own.
150
- info << sprintf(" -O %-21s %s", name, description)
151
- has_options = true
152
- end
153
- return "" if !has_options
154
- end
155
- info.join("\n")
156
- rescue NameError, LoadError
157
- return "Warning: Could not find handler specified (#{options[:server] || 'default'}) to determine handler-specific options"
158
- end
159
- end
160
-
161
- # Start a new rack server (like running rackup). This will parse ARGV and
162
- # provide standard ARGV rackup options, defaulting to load 'config.ru'.
163
- #
164
- # Providing an options hash will prevent ARGV parsing and will not include
165
- # any default options.
166
- #
167
- # This method can be used to very easily launch a CGI application, for
168
- # example:
169
- #
170
- # Rack::Server.start(
171
- # :app => lambda do |e|
172
- # [200, {'content-type' => 'text/html'}, ['hello world']]
173
- # end,
174
- # :server => 'cgi'
175
- # )
176
- #
177
- # Further options available here are documented on Rack::Server#initialize
178
- def self.start(options = nil)
179
- new(options).start
180
- end
181
-
182
- attr_writer :options
183
-
184
- # Options may include:
185
- # * :app
186
- # a rack application to run (overrides :config and :builder)
187
- # * :builder
188
- # a string to evaluate a Rack::Builder from
189
- # * :config
190
- # a rackup configuration file path to load (.ru)
191
- # * :environment
192
- # this selects the middleware that will be wrapped around
193
- # your application. Default options available are:
194
- # - development: CommonLogger, ShowExceptions, and Lint
195
- # - deployment: CommonLogger
196
- # - none: no extra middleware
197
- # note: when the server is a cgi server, CommonLogger is not included.
198
- # * :server
199
- # choose a specific Rackup::Handler, e.g. cgi, fcgi, webrick
200
- # * :daemonize
201
- # if truthy, the server will daemonize itself (fork, detach, etc)
202
- # if :noclose, the server will not close STDOUT/STDERR
203
- # * :pid
204
- # path to write a pid file after daemonize
205
- # * :Host
206
- # the host address to bind to (used by supporting Rackup::Handler)
207
- # * :Port
208
- # the port to bind to (used by supporting Rackup::Handler)
209
- # * :AccessLog
210
- # webrick access log options (or supporting Rackup::Handler)
211
- # * :debug
212
- # turn on debug output ($DEBUG = true)
213
- # * :warn
214
- # turn on warnings ($-w = true)
215
- # * :include
216
- # add given paths to $LOAD_PATH
217
- # * :require
218
- # require the given libraries
219
- #
220
- # Additional options for profiling app initialization include:
221
- # * :heapfile
222
- # location for ObjectSpace.dump_all to write the output to
223
- # * :profile_file
224
- # location for CPU/Memory (StackProf) profile output (defaults to a tempfile)
225
- # * :profile_mode
226
- # StackProf profile mode (cpu|wall|object)
227
- def initialize(options = nil)
228
- @ignore_options = []
229
-
230
- if options
231
- @use_default_options = false
232
- @options = options
233
- @app = options[:app] if options[:app]
234
- else
235
- @use_default_options = true
236
- @options = parse_options(ARGV)
237
- end
238
- end
239
-
240
- def options
241
- merged_options = @use_default_options ? default_options.merge(@options) : @options
242
- merged_options.reject { |k, v| @ignore_options.include?(k) }
243
- end
244
-
245
- def default_options
246
- environment = ENV['RACK_ENV'] || 'development'
247
- default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
248
-
249
- {
250
- environment: environment,
251
- pid: nil,
252
- Port: 9292,
253
- Host: default_host,
254
- AccessLog: [],
255
- config: "config.ru"
256
- }
257
- end
258
-
259
- def app
260
- @app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
261
- end
262
-
263
- class << self
264
- def logging_middleware
265
- lambda { |server|
266
- /CGI/.match?(server.server.name) || server.options[:quiet] ? nil : [Rack::CommonLogger, $stderr]
267
- }
268
- end
269
-
270
- def default_middleware_by_environment
271
- m = Hash.new {|h, k| h[k] = []}
272
- m["deployment"] = [
273
- [Rack::ContentLength],
274
- logging_middleware,
275
- [Rack::TempfileReaper]
276
- ]
277
- m["development"] = [
278
- [Rack::ContentLength],
279
- logging_middleware,
280
- [Rack::ShowExceptions],
281
- [Rack::Lint],
282
- [Rack::TempfileReaper]
283
- ]
284
-
285
- m
286
- end
287
-
288
- def middleware
289
- default_middleware_by_environment
290
- end
291
- end
292
-
293
- def middleware
294
- self.class.middleware
295
- end
296
-
297
- def start(&block)
298
- if options[:warn]
299
- $-w = true
300
- end
301
-
302
- if includes = options[:include]
303
- $LOAD_PATH.unshift(*includes)
304
- end
305
-
306
- Array(options[:require]).each do |library|
307
- require library
308
- end
309
-
310
- if options[:debug]
311
- $DEBUG = true
312
- require 'pp'
313
- p options[:server]
314
- pp wrapped_app
315
- pp app
316
- end
317
-
318
- check_pid! if options[:pid]
319
-
320
- # Touch the wrapped app, so that the config.ru is loaded before
321
- # daemonization (i.e. before chdir, etc).
322
- handle_profiling(options[:heapfile], options[:profile_mode], options[:profile_file]) do
323
- wrapped_app
324
- end
325
-
326
- daemonize_app if options[:daemonize]
327
-
328
- write_pid if options[:pid]
329
-
330
- trap(:INT) do
331
- if server.respond_to?(:shutdown)
332
- server.shutdown
333
- else
334
- exit
335
- end
336
- end
337
-
338
- server.run(wrapped_app, **options, &block)
339
- end
340
-
341
- def server
342
- @_server ||= Handler.get(options[:server]) || Handler.default
343
- end
344
-
345
- private
346
- def build_app_and_options_from_config
347
- if !::File.exist? options[:config]
348
- abort "configuration #{options[:config]} not found"
349
- end
350
-
351
- return Rack::Builder.parse_file(self.options[:config])
352
- end
353
-
354
- def handle_profiling(heapfile, profile_mode, filename)
355
- if heapfile
356
- require "objspace"
357
- ObjectSpace.trace_object_allocations_start
358
- yield
359
- GC.start
360
- ::File.open(heapfile, "w") { |f| ObjectSpace.dump_all(output: f) }
361
- exit
362
- end
363
-
364
- if profile_mode
365
- require "stackprof"
366
- require "tempfile"
367
-
368
- make_profile_name(filename) do |filename|
369
- ::File.open(filename, "w") do |f|
370
- StackProf.run(mode: profile_mode, out: f) do
371
- yield
372
- end
373
- puts "Profile written to: #{filename}"
374
- end
375
- end
376
- exit
377
- end
378
-
379
- yield
380
- end
381
-
382
- def make_profile_name(filename)
383
- if filename
384
- yield filename
385
- else
386
- ::Dir::Tmpname.create("profile.dump") do |tmpname, _, _|
387
- yield tmpname
388
- end
389
- end
390
- end
391
-
392
- def build_app_from_string
393
- Rack::Builder.new_from_string(self.options[:builder])
394
- end
395
-
396
- def parse_options(args)
397
- # Don't evaluate CGI ISINDEX parameters.
398
- args.clear if ENV.include?(Rack::REQUEST_METHOD)
399
-
400
- @options = opt_parser.parse!(args)
401
- @options[:config] = ::File.expand_path(options[:config])
402
- ENV["RACK_ENV"] = options[:environment]
403
- @options
404
- end
405
-
406
- def opt_parser
407
- Options.new
408
- end
409
-
410
- def build_app(app)
411
- middleware[options[:environment]].reverse_each do |middleware|
412
- middleware = middleware.call(self) if middleware.respond_to?(:call)
413
- next unless middleware
414
- klass, *args = middleware
415
- app = klass.new(app, *args)
416
- end
417
- app
418
- end
419
-
420
- def wrapped_app
421
- @wrapped_app ||= build_app app
422
- end
423
-
424
- def daemonize_app
425
- # Cannot be covered as it forks
426
- # :nocov:
427
- Process.daemon(true, options[:daemonize] == :noclose)
428
- # :nocov:
429
- end
430
-
431
- def write_pid
432
- ::File.open(options[:pid], ::File::CREAT | ::File::EXCL | ::File::WRONLY ){ |f| f.write("#{Process.pid}") }
433
- at_exit { ::FileUtils.rm_f(options[:pid]) }
434
- rescue Errno::EEXIST
435
- check_pid!
436
- retry
437
- end
438
-
439
- def check_pid!
440
- return unless ::File.exist?(options[:pid])
441
-
442
- pid = ::File.read(options[:pid]).to_i
443
- raise Errno::ESRCH if pid == 0
444
-
445
- Process.kill(0, pid)
446
- exit_with_pid(pid)
447
- rescue Errno::ESRCH
448
- ::File.delete(options[:pid])
449
- rescue Errno::EPERM
450
- exit_with_pid(pid)
451
- end
452
-
453
- def exit_with_pid(pid)
454
- $stderr.puts "A server is already running (pid: #{pid}, file: #{options[:pid]})."
455
- exit(1)
456
- end
457
- end
458
-
459
- end