rack 1.4.7 → 2.1.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

Files changed (183) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +77 -0
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +122 -456
  5. data/Rakefile +32 -31
  6. data/SPEC +119 -29
  7. data/bin/rackup +1 -0
  8. data/contrib/rack_logo.svg +164 -111
  9. data/example/lobster.ru +2 -0
  10. data/example/protectedlobster.rb +4 -2
  11. data/example/protectedlobster.ru +3 -1
  12. data/lib/rack/auth/abstract/handler.rb +7 -5
  13. data/lib/rack/auth/abstract/request.rb +8 -6
  14. data/lib/rack/auth/basic.rb +5 -2
  15. data/lib/rack/auth/digest/md5.rb +10 -8
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +5 -4
  18. data/lib/rack/auth/digest/request.rb +4 -2
  19. data/lib/rack/body_proxy.rb +11 -9
  20. data/lib/rack/builder.rb +63 -20
  21. data/lib/rack/cascade.rb +10 -9
  22. data/lib/rack/chunked.rb +45 -11
  23. data/lib/rack/{commonlogger.rb → common_logger.rb} +24 -15
  24. data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -6
  25. data/lib/rack/config.rb +7 -0
  26. data/lib/rack/content_length.rb +12 -6
  27. data/lib/rack/content_type.rb +4 -2
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +73 -42
  30. data/lib/rack/directory.rb +77 -56
  31. data/lib/rack/etag.rb +25 -13
  32. data/lib/rack/events.rb +156 -0
  33. data/lib/rack/file.rb +4 -143
  34. data/lib/rack/files.rb +178 -0
  35. data/lib/rack/handler/cgi.rb +18 -17
  36. data/lib/rack/handler/fastcgi.rb +21 -17
  37. data/lib/rack/handler/lsws.rb +14 -12
  38. data/lib/rack/handler/scgi.rb +27 -21
  39. data/lib/rack/handler/thin.rb +19 -5
  40. data/lib/rack/handler/webrick.rb +66 -24
  41. data/lib/rack/handler.rb +29 -19
  42. data/lib/rack/head.rb +21 -14
  43. data/lib/rack/lint.rb +259 -65
  44. data/lib/rack/lobster.rb +17 -10
  45. data/lib/rack/lock.rb +19 -10
  46. data/lib/rack/logger.rb +4 -2
  47. data/lib/rack/media_type.rb +43 -0
  48. data/lib/rack/method_override.rb +52 -0
  49. data/lib/rack/mime.rb +43 -6
  50. data/lib/rack/mock.rb +109 -44
  51. data/lib/rack/multipart/generator.rb +11 -12
  52. data/lib/rack/multipart/parser.rb +302 -115
  53. data/lib/rack/multipart/uploaded_file.rb +4 -3
  54. data/lib/rack/multipart.rb +40 -9
  55. data/lib/rack/null_logger.rb +39 -0
  56. data/lib/rack/query_parser.rb +218 -0
  57. data/lib/rack/recursive.rb +14 -11
  58. data/lib/rack/reloader.rb +12 -5
  59. data/lib/rack/request.rb +484 -270
  60. data/lib/rack/response.rb +196 -77
  61. data/lib/rack/rewindable_input.rb +5 -14
  62. data/lib/rack/runtime.rb +13 -6
  63. data/lib/rack/sendfile.rb +44 -20
  64. data/lib/rack/server.rb +175 -61
  65. data/lib/rack/session/abstract/id.rb +276 -133
  66. data/lib/rack/session/cookie.rb +75 -40
  67. data/lib/rack/session/memcache.rb +4 -87
  68. data/lib/rack/session/pool.rb +24 -18
  69. data/lib/rack/show_exceptions.rb +392 -0
  70. data/lib/rack/{showstatus.rb → show_status.rb} +11 -9
  71. data/lib/rack/static.rb +65 -38
  72. data/lib/rack/tempfile_reaper.rb +24 -0
  73. data/lib/rack/urlmap.rb +40 -15
  74. data/lib/rack/utils.rb +316 -285
  75. data/lib/rack.rb +78 -23
  76. data/rack.gemspec +26 -19
  77. metadata +44 -209
  78. data/KNOWN-ISSUES +0 -30
  79. data/lib/rack/backports/uri/common_18.rb +0 -56
  80. data/lib/rack/backports/uri/common_192.rb +0 -52
  81. data/lib/rack/backports/uri/common_193.rb +0 -29
  82. data/lib/rack/handler/evented_mongrel.rb +0 -8
  83. data/lib/rack/handler/mongrel.rb +0 -100
  84. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  85. data/lib/rack/methodoverride.rb +0 -33
  86. data/lib/rack/nulllogger.rb +0 -18
  87. data/lib/rack/showexceptions.rb +0 -378
  88. data/test/builder/anything.rb +0 -5
  89. data/test/builder/comment.ru +0 -4
  90. data/test/builder/end.ru +0 -5
  91. data/test/builder/line.ru +0 -1
  92. data/test/builder/options.ru +0 -2
  93. data/test/cgi/assets/folder/test.js +0 -1
  94. data/test/cgi/assets/fonts/font.eot +0 -1
  95. data/test/cgi/assets/images/image.png +0 -1
  96. data/test/cgi/assets/index.html +0 -1
  97. data/test/cgi/assets/javascripts/app.js +0 -1
  98. data/test/cgi/assets/stylesheets/app.css +0 -1
  99. data/test/cgi/lighttpd.conf +0 -26
  100. data/test/cgi/lighttpd.errors +0 -1
  101. data/test/cgi/rackup_stub.rb +0 -6
  102. data/test/cgi/sample_rackup.ru +0 -5
  103. data/test/cgi/test +0 -9
  104. data/test/cgi/test+directory/test+file +0 -1
  105. data/test/cgi/test.fcgi +0 -8
  106. data/test/cgi/test.ru +0 -5
  107. data/test/gemloader.rb +0 -10
  108. data/test/multipart/bad_robots +0 -259
  109. data/test/multipart/binary +0 -0
  110. data/test/multipart/content_type_and_no_filename +0 -6
  111. data/test/multipart/empty +0 -10
  112. data/test/multipart/fail_16384_nofile +0 -814
  113. data/test/multipart/file1.txt +0 -1
  114. data/test/multipart/filename_and_modification_param +0 -7
  115. data/test/multipart/filename_with_escaped_quotes +0 -6
  116. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  117. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  118. data/test/multipart/filename_with_unescaped_percentages +0 -6
  119. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  120. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  121. data/test/multipart/filename_with_unescaped_quotes +0 -6
  122. data/test/multipart/ie +0 -6
  123. data/test/multipart/mixed_files +0 -21
  124. data/test/multipart/nested +0 -10
  125. data/test/multipart/none +0 -9
  126. data/test/multipart/semicolon +0 -6
  127. data/test/multipart/text +0 -15
  128. data/test/multipart/three_files_three_fields +0 -31
  129. data/test/multipart/webkit +0 -32
  130. data/test/rackup/config.ru +0 -31
  131. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  132. data/test/spec_auth.rb +0 -57
  133. data/test/spec_auth_basic.rb +0 -81
  134. data/test/spec_auth_digest.rb +0 -259
  135. data/test/spec_body_proxy.rb +0 -69
  136. data/test/spec_builder.rb +0 -207
  137. data/test/spec_cascade.rb +0 -61
  138. data/test/spec_cgi.rb +0 -102
  139. data/test/spec_chunked.rb +0 -87
  140. data/test/spec_commonlogger.rb +0 -57
  141. data/test/spec_conditionalget.rb +0 -102
  142. data/test/spec_config.rb +0 -22
  143. data/test/spec_content_length.rb +0 -86
  144. data/test/spec_content_type.rb +0 -45
  145. data/test/spec_deflater.rb +0 -187
  146. data/test/spec_directory.rb +0 -88
  147. data/test/spec_etag.rb +0 -98
  148. data/test/spec_fastcgi.rb +0 -107
  149. data/test/spec_file.rb +0 -200
  150. data/test/spec_handler.rb +0 -59
  151. data/test/spec_head.rb +0 -48
  152. data/test/spec_lint.rb +0 -515
  153. data/test/spec_lobster.rb +0 -58
  154. data/test/spec_lock.rb +0 -167
  155. data/test/spec_logger.rb +0 -23
  156. data/test/spec_methodoverride.rb +0 -72
  157. data/test/spec_mock.rb +0 -269
  158. data/test/spec_mongrel.rb +0 -182
  159. data/test/spec_multipart.rb +0 -479
  160. data/test/spec_nulllogger.rb +0 -23
  161. data/test/spec_recursive.rb +0 -72
  162. data/test/spec_request.rb +0 -955
  163. data/test/spec_response.rb +0 -313
  164. data/test/spec_rewindable_input.rb +0 -118
  165. data/test/spec_runtime.rb +0 -49
  166. data/test/spec_sendfile.rb +0 -90
  167. data/test/spec_server.rb +0 -121
  168. data/test/spec_session_abstract_id.rb +0 -43
  169. data/test/spec_session_cookie.rb +0 -361
  170. data/test/spec_session_memcache.rb +0 -321
  171. data/test/spec_session_pool.rb +0 -209
  172. data/test/spec_showexceptions.rb +0 -92
  173. data/test/spec_showstatus.rb +0 -84
  174. data/test/spec_static.rb +0 -145
  175. data/test/spec_thin.rb +0 -86
  176. data/test/spec_urlmap.rb +0 -213
  177. data/test/spec_utils.rb +0 -554
  178. data/test/spec_webrick.rb +0 -143
  179. data/test/static/another/index.html +0 -1
  180. data/test/static/index.html +0 -1
  181. data/test/testrequest.rb +0 -78
  182. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  183. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/lib/rack/file.rb CHANGED
@@ -1,146 +1,7 @@
1
- require 'time'
2
- require 'rack/utils'
3
- require 'rack/mime'
1
+ # frozen_string_literal: true
4
2
 
5
- module Rack
6
- # Rack::File serves files below the +root+ directory given, according to the
7
- # path info of the Rack request.
8
- # e.g. when Rack::File.new("/etc") is used, you can access 'passwd' file
9
- # as http://localhost:9292/passwd
10
- #
11
- # Handlers can detect if bodies are a Rack::File, and use mechanisms
12
- # like sendfile on the +path+.
13
-
14
- class File
15
- SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact)
16
- ALLOWED_VERBS = %w[GET HEAD]
17
-
18
- attr_accessor :root
19
- attr_accessor :path
20
- attr_accessor :cache_control
21
-
22
- alias :to_path :path
23
-
24
- def initialize(root, headers={})
25
- @root = root
26
- # Allow a cache_control string for backwards compatibility
27
- if headers.instance_of? String
28
- warn \
29
- "Rack::File headers parameter replaces cache_control after Rack 1.5."
30
- @headers = { 'Cache-Control' => headers }
31
- else
32
- @headers = headers
33
- end
34
- end
35
-
36
- def call(env)
37
- dup._call(env)
38
- end
39
-
40
- F = ::File
41
-
42
- def _call(env)
43
- unless ALLOWED_VERBS.include? env["REQUEST_METHOD"]
44
- return fail(405, "Method Not Allowed")
45
- end
46
-
47
- @path_info = Utils.unescape(env["PATH_INFO"])
48
- parts = @path_info.split SEPS
49
-
50
- clean = []
51
-
52
- parts.each do |part|
53
- next if part.empty? || part == '.'
54
- part == '..' ? clean.pop : clean << part
55
- end
56
-
57
- @path = F.join(@root, *clean)
3
+ require 'rack/files'
58
4
 
59
- available = begin
60
- F.file?(@path) && F.readable?(@path)
61
- rescue SystemCallError
62
- false
63
- end
64
-
65
- if available
66
- serving(env)
67
- else
68
- fail(404, "File not found: #{@path_info}")
69
- end
70
- end
71
-
72
- def serving(env)
73
- last_modified = F.mtime(@path).httpdate
74
- return [304, {}, []] if env['HTTP_IF_MODIFIED_SINCE'] == last_modified
75
- response = [
76
- 200,
77
- {
78
- "Last-Modified" => last_modified,
79
- "Content-Type" => Mime.mime_type(F.extname(@path), 'text/plain')
80
- },
81
- env["REQUEST_METHOD"] == "HEAD" ? [] : self
82
- ]
83
-
84
- # Set custom headers
85
- @headers.each { |field, content| response[1][field] = content } if @headers
86
-
87
- # NOTE:
88
- # We check via File::size? whether this file provides size info
89
- # via stat (e.g. /proc files often don't), otherwise we have to
90
- # figure it out by reading the whole file into memory.
91
- size = F.size?(@path) || Utils.bytesize(F.read(@path))
92
-
93
- ranges = Rack::Utils.byte_ranges(env, size)
94
- if ranges.nil? || ranges.length > 1
95
- # No ranges, or multiple ranges (which we don't support):
96
- # TODO: Support multiple byte-ranges
97
- response[0] = 200
98
- @range = 0..size-1
99
- elsif ranges.empty?
100
- # Unsatisfiable. Return error, and file size:
101
- response = fail(416, "Byte range unsatisfiable")
102
- response[1]["Content-Range"] = "bytes */#{size}"
103
- return response
104
- else
105
- # Partial content:
106
- @range = ranges[0]
107
- response[0] = 206
108
- response[1]["Content-Range"] = "bytes #{@range.begin}-#{@range.end}/#{size}"
109
- size = @range.end - @range.begin + 1
110
- end
111
-
112
- response[1]["Content-Length"] = size.to_s
113
- response
114
- end
115
-
116
- def each
117
- F.open(@path, "rb") do |file|
118
- file.seek(@range.begin)
119
- remaining_len = @range.end-@range.begin+1
120
- while remaining_len > 0
121
- part = file.read([8192, remaining_len].min)
122
- break unless part
123
- remaining_len -= part.length
124
-
125
- yield part
126
- end
127
- end
128
- end
129
-
130
- private
131
-
132
- def fail(status, body)
133
- body += "\n"
134
- [
135
- status,
136
- {
137
- "Content-Type" => "text/plain",
138
- "Content-Length" => body.size.to_s,
139
- "X-Cascade" => "pass"
140
- },
141
- [body]
142
- ]
143
- end
144
-
145
- end
5
+ module Rack
6
+ File = Files
146
7
  end
data/lib/rack/files.rb ADDED
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+ require 'rack/utils'
5
+ require 'rack/mime'
6
+ require 'rack/request'
7
+ require 'rack/head'
8
+
9
+ module Rack
10
+ # Rack::Files serves files below the +root+ directory given, according to the
11
+ # path info of the Rack request.
12
+ # e.g. when Rack::Files.new("/etc") is used, you can access 'passwd' file
13
+ # as http://localhost:9292/passwd
14
+ #
15
+ # Handlers can detect if bodies are a Rack::Files, and use mechanisms
16
+ # like sendfile on the +path+.
17
+
18
+ class Files
19
+ ALLOWED_VERBS = %w[GET HEAD OPTIONS]
20
+ ALLOW_HEADER = ALLOWED_VERBS.join(', ')
21
+
22
+ attr_reader :root
23
+
24
+ def initialize(root, headers = {}, default_mime = 'text/plain')
25
+ @root = (::File.expand_path(root) if root)
26
+ @headers = headers
27
+ @default_mime = default_mime
28
+ @head = Rack::Head.new(lambda { |env| get env })
29
+ end
30
+
31
+ def call(env)
32
+ # HEAD requests drop the response body, including 4xx error messages.
33
+ @head.call env
34
+ end
35
+
36
+ def get(env)
37
+ request = Rack::Request.new env
38
+ unless ALLOWED_VERBS.include? request.request_method
39
+ return fail(405, "Method Not Allowed", { 'Allow' => ALLOW_HEADER })
40
+ end
41
+
42
+ path_info = Utils.unescape_path request.path_info
43
+ return fail(400, "Bad Request") unless Utils.valid_path?(path_info)
44
+
45
+ clean_path_info = Utils.clean_path_info(path_info)
46
+ path = ::File.join(@root, clean_path_info)
47
+
48
+ available = begin
49
+ ::File.file?(path) && ::File.readable?(path)
50
+ rescue SystemCallError
51
+ false
52
+ end
53
+
54
+ if available
55
+ serving(request, path)
56
+ else
57
+ fail(404, "File not found: #{path_info}")
58
+ end
59
+ end
60
+
61
+ def serving(request, path)
62
+ if request.options?
63
+ return [200, { 'Allow' => ALLOW_HEADER, CONTENT_LENGTH => '0' }, []]
64
+ end
65
+ last_modified = ::File.mtime(path).httpdate
66
+ return [304, {}, []] if request.get_header('HTTP_IF_MODIFIED_SINCE') == last_modified
67
+
68
+ headers = { "Last-Modified" => last_modified }
69
+ mime_type = mime_type path, @default_mime
70
+ headers[CONTENT_TYPE] = mime_type if mime_type
71
+
72
+ # Set custom headers
73
+ @headers.each { |field, content| headers[field] = content } if @headers
74
+
75
+ response = [ 200, headers ]
76
+
77
+ size = filesize path
78
+
79
+ range = nil
80
+ ranges = Rack::Utils.get_byte_ranges(request.get_header('HTTP_RANGE'), size)
81
+ if ranges.nil? || ranges.length > 1
82
+ # No ranges, or multiple ranges (which we don't support):
83
+ # TODO: Support multiple byte-ranges
84
+ response[0] = 200
85
+ range = 0..size - 1
86
+ elsif ranges.empty?
87
+ # Unsatisfiable. Return error, and file size:
88
+ response = fail(416, "Byte range unsatisfiable")
89
+ response[1]["Content-Range"] = "bytes */#{size}"
90
+ return response
91
+ else
92
+ # Partial content:
93
+ range = ranges[0]
94
+ response[0] = 206
95
+ response[1]["Content-Range"] = "bytes #{range.begin}-#{range.end}/#{size}"
96
+ size = range.end - range.begin + 1
97
+ end
98
+
99
+ response[2] = [response_body] unless response_body.nil?
100
+
101
+ response[1][CONTENT_LENGTH] = size.to_s
102
+ response[2] = make_body request, path, range
103
+ response
104
+ end
105
+
106
+ class Iterator
107
+ attr_reader :path, :range
108
+ alias :to_path :path
109
+
110
+ def initialize path, range
111
+ @path = path
112
+ @range = range
113
+ end
114
+
115
+ def each
116
+ ::File.open(path, "rb") do |file|
117
+ file.seek(range.begin)
118
+ remaining_len = range.end - range.begin + 1
119
+ while remaining_len > 0
120
+ part = file.read([8192, remaining_len].min)
121
+ break unless part
122
+ remaining_len -= part.length
123
+
124
+ yield part
125
+ end
126
+ end
127
+ end
128
+
129
+ def close; end
130
+ end
131
+
132
+ private
133
+
134
+ def make_body request, path, range
135
+ if request.head?
136
+ []
137
+ else
138
+ Iterator.new path, range
139
+ end
140
+ end
141
+
142
+ def fail(status, body, headers = {})
143
+ body += "\n"
144
+
145
+ [
146
+ status,
147
+ {
148
+ CONTENT_TYPE => "text/plain",
149
+ CONTENT_LENGTH => body.size.to_s,
150
+ "X-Cascade" => "pass"
151
+ }.merge!(headers),
152
+ [body]
153
+ ]
154
+ end
155
+
156
+ # The MIME type for the contents of the file located at @path
157
+ def mime_type path, default_mime
158
+ Mime.mime_type(::File.extname(path), default_mime)
159
+ end
160
+
161
+ def filesize path
162
+ # If response_body is present, use its size.
163
+ return response_body.bytesize if response_body
164
+
165
+ # We check via File::size? whether this file provides size info
166
+ # via stat (e.g. /proc files often don't), otherwise we have to
167
+ # figure it out by reading the whole file into memory.
168
+ ::File.size?(path) || ::File.read(path).bytesize
169
+ end
170
+
171
+ # By default, the response body for file requests is nil.
172
+ # In this case, the response body will be generated later
173
+ # from the file at @path
174
+ def response_body
175
+ nil
176
+ end
177
+ end
178
+ end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack/content_length'
2
4
  require 'rack/rewindable_input'
3
5
 
4
6
  module Rack
5
7
  module Handler
6
8
  class CGI
7
- def self.run(app, options=nil)
9
+ def self.run(app, options = nil)
8
10
  $stdin.binmode
9
11
  serve app
10
12
  end
@@ -13,22 +15,21 @@ module Rack
13
15
  env = ENV.to_hash
14
16
  env.delete "HTTP_CONTENT_LENGTH"
15
17
 
16
- env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
17
-
18
- env.update({"rack.version" => Rack::VERSION,
19
- "rack.input" => Rack::RewindableInput.new($stdin),
20
- "rack.errors" => $stderr,
21
-
22
- "rack.multithread" => false,
23
- "rack.multiprocess" => true,
24
- "rack.run_once" => true,
25
-
26
- "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http"
27
- })
28
-
29
- env["QUERY_STRING"] ||= ""
30
- env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
31
- env["REQUEST_PATH"] ||= "/"
18
+ env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/"
19
+
20
+ env.update(
21
+ RACK_VERSION => Rack::VERSION,
22
+ RACK_INPUT => Rack::RewindableInput.new($stdin),
23
+ RACK_ERRORS => $stderr,
24
+ RACK_MULTITHREAD => false,
25
+ RACK_MULTIPROCESS => true,
26
+ RACK_RUNONCE => true,
27
+ RACK_URL_SCHEME => ["yes", "on", "1"].include?(ENV[HTTPS]) ? "https" : "http"
28
+ )
29
+
30
+ env[QUERY_STRING] ||= ""
31
+ env[HTTP_VERSION] ||= env[SERVER_PROTOCOL]
32
+ env[REQUEST_PATH] ||= "/"
32
33
 
33
34
  status, headers, body = app.call(env)
34
35
  begin
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fcgi'
2
4
  require 'socket'
3
5
  require 'rack/content_length'
@@ -7,7 +9,7 @@ if defined? FCGI::Stream
7
9
  class FCGI::Stream
8
10
  alias _rack_read_without_buffer read
9
11
 
10
- def read(n, buffer=nil)
12
+ def read(n, buffer = nil)
11
13
  buf = _rack_read_without_buffer n
12
14
  buffer.replace(buf.to_s) if buffer
13
15
  buf
@@ -18,7 +20,7 @@ end
18
20
  module Rack
19
21
  module Handler
20
22
  class FastCGI
21
- def self.run(app, options={})
23
+ def self.run(app, options = {})
22
24
  if options[:File]
23
25
  STDIN.reopen(UNIXServer.new(options[:File]))
24
26
  elsif options[:Port]
@@ -30,8 +32,11 @@ module Rack
30
32
  end
31
33
 
32
34
  def self.valid_options
35
+ environment = ENV['RACK_ENV'] || 'development'
36
+ default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
37
+
33
38
  {
34
- "Host=HOST" => "Hostname to listen on (default: localhost)",
39
+ "Host=HOST" => "Hostname to listen on (default: #{default_host})",
35
40
  "Port=PORT" => "Port to listen on (default: 8080)",
36
41
  "File=PATH" => "Creates a Domain socket at PATH instead of a TCP socket. Ignores Host and Port if set.",
37
42
  }
@@ -41,24 +46,23 @@ module Rack
41
46
  env = request.env
42
47
  env.delete "HTTP_CONTENT_LENGTH"
43
48
 
44
- env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
49
+ env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/"
45
50
 
46
51
  rack_input = RewindableInput.new(request.in)
47
52
 
48
- env.update({"rack.version" => Rack::VERSION,
49
- "rack.input" => rack_input,
50
- "rack.errors" => request.err,
51
-
52
- "rack.multithread" => false,
53
- "rack.multiprocess" => true,
54
- "rack.run_once" => false,
55
-
56
- "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http"
57
- })
53
+ env.update(
54
+ RACK_VERSION => Rack::VERSION,
55
+ RACK_INPUT => rack_input,
56
+ RACK_ERRORS => request.err,
57
+ RACK_MULTITHREAD => false,
58
+ RACK_MULTIPROCESS => true,
59
+ RACK_RUNONCE => false,
60
+ RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http"
61
+ )
58
62
 
59
- env["QUERY_STRING"] ||= ""
60
- env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
61
- env["REQUEST_PATH"] ||= "/"
63
+ env[QUERY_STRING] ||= ""
64
+ env[HTTP_VERSION] ||= env[SERVER_PROTOCOL]
65
+ env[REQUEST_PATH] ||= "/"
62
66
  env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == ""
63
67
  env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == ""
64
68
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'lsapi'
2
4
  require 'rack/content_length'
3
5
  require 'rack/rewindable_input'
@@ -5,7 +7,7 @@ require 'rack/rewindable_input'
5
7
  module Rack
6
8
  module Handler
7
9
  class LSWS
8
- def self.run(app, options=nil)
10
+ def self.run(app, options = nil)
9
11
  while LSAPI.accept != nil
10
12
  serve app
11
13
  end
@@ -13,23 +15,23 @@ module Rack
13
15
  def self.serve(app)
14
16
  env = ENV.to_hash
15
17
  env.delete "HTTP_CONTENT_LENGTH"
16
- env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
18
+ env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/"
17
19
 
18
20
  rack_input = RewindableInput.new($stdin.read.to_s)
19
21
 
20
22
  env.update(
21
- "rack.version" => Rack::VERSION,
22
- "rack.input" => rack_input,
23
- "rack.errors" => $stderr,
24
- "rack.multithread" => false,
25
- "rack.multiprocess" => true,
26
- "rack.run_once" => false,
27
- "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http"
23
+ RACK_VERSION => Rack::VERSION,
24
+ RACK_INPUT => rack_input,
25
+ RACK_ERRORS => $stderr,
26
+ RACK_MULTITHREAD => false,
27
+ RACK_MULTIPROCESS => true,
28
+ RACK_RUNONCE => false,
29
+ RACK_URL_SCHEME => ["yes", "on", "1"].include?(ENV[HTTPS]) ? "https" : "http"
28
30
  )
29
31
 
30
- env["QUERY_STRING"] ||= ""
31
- env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
32
- env["REQUEST_PATH"] ||= "/"
32
+ env[QUERY_STRING] ||= ""
33
+ env[HTTP_VERSION] ||= env[SERVER_PROTOCOL]
34
+ env[REQUEST_PATH] ||= "/"
33
35
  status, headers, body = app.call(env)
34
36
  begin
35
37
  send_headers status, headers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'scgi'
2
4
  require 'stringio'
3
5
  require 'rack/content_length'
@@ -8,17 +10,20 @@ module Rack
8
10
  class SCGI < ::SCGI::Processor
9
11
  attr_accessor :app
10
12
 
11
- def self.run(app, options=nil)
13
+ def self.run(app, options = nil)
12
14
  options[:Socket] = UNIXServer.new(options[:File]) if options[:File]
13
- new(options.merge(:app=>app,
14
- :host=>options[:Host],
15
- :port=>options[:Port],
16
- :socket=>options[:Socket])).listen
15
+ new(options.merge(app: app,
16
+ host: options[:Host],
17
+ port: options[:Port],
18
+ socket: options[:Socket])).listen
17
19
  end
18
20
 
19
21
  def self.valid_options
22
+ environment = ENV['RACK_ENV'] || 'development'
23
+ default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
24
+
20
25
  {
21
- "Host=HOST" => "Hostname to listen on (default: localhost)",
26
+ "Host=HOST" => "Hostname to listen on (default: #{default_host})",
22
27
  "Port=PORT" => "Port to listen on (default: 8080)",
23
28
  }
24
29
  end
@@ -29,27 +34,28 @@ module Rack
29
34
  end
30
35
 
31
36
  def process_request(request, input_body, socket)
32
- env = {}.replace(request)
37
+ env = Hash[request]
33
38
  env.delete "HTTP_CONTENT_TYPE"
34
39
  env.delete "HTTP_CONTENT_LENGTH"
35
- env["REQUEST_PATH"], env["QUERY_STRING"] = env["REQUEST_URI"].split('?', 2)
36
- env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
37
- env["PATH_INFO"] = env["REQUEST_PATH"]
38
- env["QUERY_STRING"] ||= ""
39
- env["SCRIPT_NAME"] = ""
40
+ env[REQUEST_PATH], env[QUERY_STRING] = env["REQUEST_URI"].split('?', 2)
41
+ env[HTTP_VERSION] ||= env[SERVER_PROTOCOL]
42
+ env[PATH_INFO] = env[REQUEST_PATH]
43
+ env[QUERY_STRING] ||= ""
44
+ env[SCRIPT_NAME] = ""
40
45
 
41
46
  rack_input = StringIO.new(input_body)
42
- rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
47
+ rack_input.set_encoding(Encoding::BINARY)
43
48
 
44
- env.update({"rack.version" => Rack::VERSION,
45
- "rack.input" => rack_input,
46
- "rack.errors" => $stderr,
47
- "rack.multithread" => true,
48
- "rack.multiprocess" => true,
49
- "rack.run_once" => false,
49
+ env.update(
50
+ RACK_VERSION => Rack::VERSION,
51
+ RACK_INPUT => rack_input,
52
+ RACK_ERRORS => $stderr,
53
+ RACK_MULTITHREAD => true,
54
+ RACK_MULTIPROCESS => true,
55
+ RACK_RUNONCE => false,
56
+ RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http"
57
+ )
50
58
 
51
- "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http"
52
- })
53
59
  status, headers, body = app.call(env)
54
60
  begin
55
61
  socket.write("Status: #{status}\r\n")
@@ -1,21 +1,35 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "thin"
4
+ require "thin/server"
5
+ require "thin/logging"
6
+ require "thin/backends/tcp_server"
2
7
  require "rack/content_length"
3
8
  require "rack/chunked"
4
9
 
5
10
  module Rack
6
11
  module Handler
7
12
  class Thin
8
- def self.run(app, options={})
9
- server = ::Thin::Server.new(options[:Host] || '0.0.0.0',
10
- options[:Port] || 8080,
11
- app)
13
+ def self.run(app, options = {})
14
+ environment = ENV['RACK_ENV'] || 'development'
15
+ default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
16
+
17
+ host = options.delete(:Host) || default_host
18
+ port = options.delete(:Port) || 8080
19
+ args = [host, port, app, options]
20
+ # Thin versions below 0.8.0 do not support additional options
21
+ args.pop if ::Thin::VERSION::MAJOR < 1 && ::Thin::VERSION::MINOR < 8
22
+ server = ::Thin::Server.new(*args)
12
23
  yield server if block_given?
13
24
  server.start
14
25
  end
15
26
 
16
27
  def self.valid_options
28
+ environment = ENV['RACK_ENV'] || 'development'
29
+ default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
30
+
17
31
  {
18
- "Host=HOST" => "Hostname to listen on (default: localhost)",
32
+ "Host=HOST" => "Hostname to listen on (default: #{default_host})",
19
33
  "Port=PORT" => "Port to listen on (default: 8080)",
20
34
  }
21
35
  end