rack 1.6.12 → 2.0.3

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 (142) hide show
  1. checksums.yaml +5 -5
  2. data/COPYING +1 -1
  3. data/HISTORY.md +138 -8
  4. data/README.rdoc +17 -25
  5. data/Rakefile +6 -14
  6. data/SPEC +10 -11
  7. data/contrib/rack_logo.svg +164 -111
  8. data/example/protectedlobster.rb +1 -1
  9. data/example/protectedlobster.ru +1 -1
  10. data/lib/rack.rb +70 -21
  11. data/lib/rack/auth/abstract/request.rb +5 -1
  12. data/lib/rack/auth/digest/params.rb +2 -3
  13. data/lib/rack/auth/digest/request.rb +1 -1
  14. data/lib/rack/body_proxy.rb +14 -9
  15. data/lib/rack/builder.rb +3 -3
  16. data/lib/rack/chunked.rb +5 -5
  17. data/lib/rack/{commonlogger.rb → common_logger.rb} +3 -3
  18. data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
  19. data/lib/rack/content_length.rb +2 -2
  20. data/lib/rack/deflater.rb +4 -39
  21. data/lib/rack/directory.rb +66 -54
  22. data/lib/rack/etag.rb +4 -3
  23. data/lib/rack/events.rb +154 -0
  24. data/lib/rack/file.rb +64 -40
  25. data/lib/rack/handler.rb +3 -25
  26. data/lib/rack/handler/cgi.rb +15 -16
  27. data/lib/rack/handler/fastcgi.rb +13 -14
  28. data/lib/rack/handler/lsws.rb +11 -11
  29. data/lib/rack/handler/scgi.rb +15 -15
  30. data/lib/rack/handler/thin.rb +3 -0
  31. data/lib/rack/handler/webrick.rb +24 -26
  32. data/lib/rack/head.rb +15 -17
  33. data/lib/rack/lint.rb +40 -40
  34. data/lib/rack/lobster.rb +1 -1
  35. data/lib/rack/lock.rb +6 -10
  36. data/lib/rack/logger.rb +2 -2
  37. data/lib/rack/media_type.rb +38 -0
  38. data/lib/rack/{methodoverride.rb → method_override.rb} +6 -10
  39. data/lib/rack/mime.rb +18 -5
  40. data/lib/rack/mock.rb +36 -54
  41. data/lib/rack/multipart.rb +35 -6
  42. data/lib/rack/multipart/generator.rb +5 -5
  43. data/lib/rack/multipart/parser.rb +272 -158
  44. data/lib/rack/multipart/uploaded_file.rb +1 -2
  45. data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
  46. data/lib/rack/query_parser.rb +192 -0
  47. data/lib/rack/recursive.rb +8 -8
  48. data/lib/rack/request.rb +383 -307
  49. data/lib/rack/response.rb +130 -57
  50. data/lib/rack/rewindable_input.rb +1 -12
  51. data/lib/rack/runtime.rb +10 -18
  52. data/lib/rack/sendfile.rb +5 -7
  53. data/lib/rack/server.rb +30 -23
  54. data/lib/rack/session/abstract/id.rb +108 -138
  55. data/lib/rack/session/cookie.rb +26 -28
  56. data/lib/rack/session/memcache.rb +8 -14
  57. data/lib/rack/session/pool.rb +14 -21
  58. data/lib/rack/show_exceptions.rb +386 -0
  59. data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
  60. data/lib/rack/static.rb +30 -5
  61. data/lib/rack/tempfile_reaper.rb +2 -2
  62. data/lib/rack/urlmap.rb +15 -14
  63. data/lib/rack/utils.rb +136 -211
  64. data/rack.gemspec +7 -5
  65. data/test/builder/an_underscore_app.rb +5 -0
  66. data/test/builder/options.ru +1 -1
  67. data/test/cgi/test.fcgi +1 -0
  68. data/test/cgi/test.gz +0 -0
  69. data/test/helper.rb +34 -0
  70. data/test/multipart/filename_with_encoded_words +7 -0
  71. data/test/multipart/filename_with_single_quote +7 -0
  72. data/test/multipart/quoted +15 -0
  73. data/test/multipart/rack-logo.png +0 -0
  74. data/test/multipart/unity3d_wwwform +11 -0
  75. data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
  76. data/test/spec_auth_basic.rb +27 -19
  77. data/test/spec_auth_digest.rb +47 -46
  78. data/test/spec_body_proxy.rb +27 -27
  79. data/test/spec_builder.rb +51 -41
  80. data/test/spec_cascade.rb +24 -22
  81. data/test/spec_cgi.rb +49 -67
  82. data/test/spec_chunked.rb +37 -35
  83. data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
  84. data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
  85. data/test/spec_config.rb +3 -2
  86. data/test/spec_content_length.rb +18 -17
  87. data/test/spec_content_type.rb +13 -12
  88. data/test/spec_deflater.rb +85 -49
  89. data/test/spec_directory.rb +87 -27
  90. data/test/spec_etag.rb +32 -31
  91. data/test/spec_events.rb +133 -0
  92. data/test/spec_fastcgi.rb +50 -72
  93. data/test/spec_file.rb +120 -77
  94. data/test/spec_handler.rb +19 -34
  95. data/test/spec_head.rb +15 -14
  96. data/test/spec_lint.rb +164 -199
  97. data/test/spec_lobster.rb +24 -23
  98. data/test/spec_lock.rb +69 -39
  99. data/test/spec_logger.rb +4 -3
  100. data/test/spec_media_type.rb +42 -0
  101. data/test/{spec_methodoverride.rb → spec_method_override.rb} +22 -37
  102. data/test/spec_mime.rb +19 -19
  103. data/test/spec_mock.rb +206 -144
  104. data/test/spec_multipart.rb +322 -200
  105. data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
  106. data/test/spec_recursive.rb +17 -14
  107. data/test/spec_request.rb +768 -607
  108. data/test/spec_response.rb +215 -112
  109. data/test/spec_rewindable_input.rb +50 -40
  110. data/test/spec_runtime.rb +11 -10
  111. data/test/spec_sendfile.rb +30 -35
  112. data/test/spec_server.rb +78 -52
  113. data/test/spec_session_abstract_id.rb +11 -33
  114. data/test/spec_session_abstract_session_hash.rb +45 -0
  115. data/test/spec_session_cookie.rb +99 -67
  116. data/test/spec_session_memcache.rb +63 -101
  117. data/test/spec_session_pool.rb +48 -84
  118. data/test/spec_show_exceptions.rb +80 -0
  119. data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
  120. data/test/spec_static.rb +71 -32
  121. data/test/spec_tempfile_reaper.rb +11 -10
  122. data/test/spec_thin.rb +55 -50
  123. data/test/spec_urlmap.rb +79 -78
  124. data/test/spec_utils.rb +441 -346
  125. data/test/spec_version.rb +2 -8
  126. data/test/spec_webrick.rb +93 -68
  127. data/test/static/foo.html +1 -0
  128. data/test/testrequest.rb +1 -1
  129. data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
  130. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
  131. metadata +102 -66
  132. data/KNOWN-ISSUES +0 -44
  133. data/lib/rack/backports/uri/common_18.rb +0 -56
  134. data/lib/rack/backports/uri/common_192.rb +0 -52
  135. data/lib/rack/backports/uri/common_193.rb +0 -29
  136. data/lib/rack/handler/evented_mongrel.rb +0 -8
  137. data/lib/rack/handler/mongrel.rb +0 -106
  138. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  139. data/lib/rack/showexceptions.rb +0 -387
  140. data/lib/rack/utils/okjson.rb +0 -600
  141. data/test/spec_mongrel.rb +0 -182
  142. data/test/spec_showexceptions.rb +0 -98
@@ -1,6 +1,7 @@
1
1
  require 'rack/request'
2
2
  require 'rack/utils'
3
3
  require 'rack/body_proxy'
4
+ require 'rack/media_type'
4
5
  require 'time'
5
6
 
6
7
  module Rack
@@ -8,7 +9,7 @@ module Rack
8
9
  # response.
9
10
  #
10
11
  # It allows setting of headers and cookies, and provides useful
11
- # defaults (a OK response containing HTML).
12
+ # defaults (an OK response with empty headers and body).
12
13
  #
13
14
  # You can use Response#write to iteratively generate your response,
14
15
  # but note that this is buffered by Rack::Response until you call
@@ -18,15 +19,16 @@ module Rack
18
19
  # Your application's +call+ should end returning Response#finish.
19
20
 
20
21
  class Response
21
- attr_accessor :length
22
+ attr_accessor :length, :status, :body
23
+ attr_reader :header
24
+ alias headers header
22
25
 
23
26
  CHUNKED = 'chunked'.freeze
24
- TRANSFER_ENCODING = 'Transfer-Encoding'.freeze
27
+
25
28
  def initialize(body=[], status=200, header={})
26
29
  @status = status.to_i
27
30
  @header = Utils::HeaderHash.new.merge(header)
28
31
 
29
- @chunked = CHUNKED == @header[TRANSFER_ENCODING]
30
32
  @writer = lambda { |x| @body << x }
31
33
  @block = nil
32
34
  @length = 0
@@ -46,36 +48,21 @@ module Rack
46
48
  yield self if block_given?
47
49
  end
48
50
 
49
- attr_reader :header
50
- attr_accessor :status, :body
51
-
52
- def [](key)
53
- header[key]
54
- end
55
-
56
- def []=(key, value)
57
- header[key] = value
58
- end
59
-
60
- def set_cookie(key, value)
61
- Utils.set_cookie_header!(header, key, value)
62
- end
63
-
64
- def delete_cookie(key, value={})
65
- Utils.delete_cookie_header!(header, key, value)
66
- end
67
-
68
51
  def redirect(target, status=302)
69
52
  self.status = status
70
- self["Location"] = target
53
+ self.location = target
54
+ end
55
+
56
+ def chunked?
57
+ CHUNKED == get_header(TRANSFER_ENCODING)
71
58
  end
72
59
 
73
60
  def finish(&block)
74
61
  @block = block
75
62
 
76
- if [204, 205, 304].include?(status.to_i)
77
- header.delete CONTENT_TYPE
78
- header.delete CONTENT_LENGTH
63
+ if [204, 304].include?(status.to_i)
64
+ delete_header CONTENT_TYPE
65
+ delete_header CONTENT_LENGTH
79
66
  close
80
67
  [status.to_i, header, []]
81
68
  else
@@ -97,10 +84,10 @@ module Rack
97
84
  #
98
85
  def write(str)
99
86
  s = str.to_s
100
- @length += Rack::Utils.bytesize(s) unless @chunked
87
+ @length += s.bytesize unless chunked?
101
88
  @writer.call s
102
89
 
103
- header[CONTENT_LENGTH] = @length.to_s unless @chunked
90
+ set_header(CONTENT_LENGTH, @length.to_s) unless chunked?
104
91
  str
105
92
  end
106
93
 
@@ -112,51 +99,137 @@ module Rack
112
99
  @block == nil && @body.empty?
113
100
  end
114
101
 
115
- alias headers header
102
+ def has_header?(key); headers.key? key; end
103
+ def get_header(key); headers[key]; end
104
+ def set_header(key, v); headers[key] = v; end
105
+ def delete_header(key); headers.delete key; end
106
+
107
+ alias :[] :get_header
108
+ alias :[]= :set_header
116
109
 
117
110
  module Helpers
118
- def invalid?; status < 100 || status >= 600; end
119
-
120
- def informational?; status >= 100 && status < 200; end
121
- def successful?; status >= 200 && status < 300; end
122
- def redirection?; status >= 300 && status < 400; end
123
- def client_error?; status >= 400 && status < 500; end
124
- def server_error?; status >= 500 && status < 600; end
125
-
126
- def ok?; status == 200; end
127
- def created?; status == 201; end
128
- def accepted?; status == 202; end
129
- def bad_request?; status == 400; end
130
- def unauthorized?; status == 401; end
131
- def forbidden?; status == 403; end
132
- def not_found?; status == 404; end
133
- def method_not_allowed?; status == 405; end
134
- def i_m_a_teapot?; status == 418; end
135
- def unprocessable?; status == 422; end
136
-
137
- def redirect?; [301, 302, 303, 307].include? status; end
138
-
139
- # Headers
140
- attr_reader :headers, :original_headers
111
+ def invalid?; status < 100 || status >= 600; end
112
+
113
+ def informational?; status >= 100 && status < 200; end
114
+ def successful?; status >= 200 && status < 300; end
115
+ def redirection?; status >= 300 && status < 400; end
116
+ def client_error?; status >= 400 && status < 500; end
117
+ def server_error?; status >= 500 && status < 600; end
118
+
119
+ def ok?; status == 200; end
120
+ def created?; status == 201; end
121
+ def accepted?; status == 202; end
122
+ def no_content?; status == 204; end
123
+ def moved_permanently?; status == 301; end
124
+ def bad_request?; status == 400; end
125
+ def unauthorized?; status == 401; end
126
+ def forbidden?; status == 403; end
127
+ def not_found?; status == 404; end
128
+ def method_not_allowed?; status == 405; end
129
+ def precondition_failed?; status == 412; end
130
+ def unprocessable?; status == 422; end
131
+
132
+ def redirect?; [301, 302, 303, 307, 308].include? status; end
141
133
 
142
134
  def include?(header)
143
- !!headers[header]
135
+ has_header? header
136
+ end
137
+
138
+ # Add a header that may have multiple values.
139
+ #
140
+ # Example:
141
+ # response.add_header 'Vary', 'Accept-Encoding'
142
+ # response.add_header 'Vary', 'Cookie'
143
+ #
144
+ # assert_equal 'Accept-Encoding,Cookie', response.get_header('Vary')
145
+ #
146
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
147
+ def add_header key, v
148
+ if v.nil?
149
+ get_header key
150
+ elsif has_header? key
151
+ set_header key, "#{get_header key},#{v}"
152
+ else
153
+ set_header key, v
154
+ end
144
155
  end
145
156
 
146
157
  def content_type
147
- headers[CONTENT_TYPE]
158
+ get_header CONTENT_TYPE
159
+ end
160
+
161
+ def media_type
162
+ MediaType.type(content_type)
163
+ end
164
+
165
+ def media_type_params
166
+ MediaType.params(content_type)
148
167
  end
149
168
 
150
169
  def content_length
151
- cl = headers[CONTENT_LENGTH]
170
+ cl = get_header CONTENT_LENGTH
152
171
  cl ? cl.to_i : cl
153
172
  end
154
173
 
155
174
  def location
156
- headers["Location"]
175
+ get_header "Location"
176
+ end
177
+
178
+ def location=(location)
179
+ set_header "Location", location
180
+ end
181
+
182
+ def set_cookie(key, value)
183
+ cookie_header = get_header SET_COOKIE
184
+ set_header SET_COOKIE, ::Rack::Utils.add_cookie_to_header(cookie_header, key, value)
185
+ end
186
+
187
+ def delete_cookie(key, value={})
188
+ set_header SET_COOKIE, ::Rack::Utils.add_remove_cookie_to_header(get_header(SET_COOKIE), key, value)
189
+ end
190
+
191
+ def set_cookie_header
192
+ get_header SET_COOKIE
193
+ end
194
+
195
+ def set_cookie_header= v
196
+ set_header SET_COOKIE, v
197
+ end
198
+
199
+ def cache_control
200
+ get_header CACHE_CONTROL
201
+ end
202
+
203
+ def cache_control= v
204
+ set_header CACHE_CONTROL, v
205
+ end
206
+
207
+ def etag
208
+ get_header ETAG
209
+ end
210
+
211
+ def etag= v
212
+ set_header ETAG, v
157
213
  end
158
214
  end
159
215
 
160
216
  include Helpers
217
+
218
+ class Raw
219
+ include Helpers
220
+
221
+ attr_reader :headers
222
+ attr_accessor :status
223
+
224
+ def initialize status, headers
225
+ @status = status
226
+ @headers = headers
227
+ end
228
+
229
+ def has_header?(key); headers.key? key; end
230
+ def get_header(key); headers[key]; end
231
+ def set_header(key, v); headers[key] = v; end
232
+ def delete_header(key); headers.delete key; end
233
+ end
161
234
  end
162
235
  end
@@ -57,15 +57,6 @@ module Rack
57
57
 
58
58
  private
59
59
 
60
- # Ruby's Tempfile class has a bug. Subclass it and fix it.
61
- class Tempfile < ::Tempfile
62
- def _close
63
- @tmpfile.close if @tmpfile
64
- @data[1] = nil if @data
65
- @tmpfile = nil
66
- end
67
- end
68
-
69
60
  def make_rewindable
70
61
  # Buffer all data into a tempfile. Since this tempfile is private to this
71
62
  # RewindableInput object, we chmod it so that nobody else can read or write
@@ -77,8 +68,6 @@ module Rack
77
68
  @rewindable_io.set_encoding(Encoding::BINARY) if @rewindable_io.respond_to?(:set_encoding)
78
69
  @rewindable_io.binmode
79
70
  if filesystem_has_posix_semantics?
80
- # Use ::File.unlink as 1.9.1 Tempfile has a bug where unlink closes the file!
81
- ::File.unlink @rewindable_io.path
82
71
  raise 'Unlink failed. IO closed.' if @rewindable_io.closed?
83
72
  @unlinked = true
84
73
  end
@@ -88,7 +77,7 @@ module Rack
88
77
  entire_buffer_written_out = false
89
78
  while !entire_buffer_written_out
90
79
  written = @rewindable_io.write(buffer)
91
- entire_buffer_written_out = written == Rack::Utils.bytesize(buffer)
80
+ entire_buffer_written_out = written == buffer.bytesize
92
81
  if !entire_buffer_written_out
93
82
  buffer.slice!(0 .. written - 1)
94
83
  end
@@ -1,3 +1,5 @@
1
+ require 'rack/utils'
2
+
1
3
  module Rack
2
4
  # Sets an "X-Runtime" response header, indicating the response
3
5
  # time of the request, in seconds
@@ -6,35 +8,25 @@ module Rack
6
8
  # time, or before all the other middlewares to include time for them,
7
9
  # too.
8
10
  class Runtime
11
+ FORMAT_STRING = "%0.6f".freeze # :nodoc:
12
+ HEADER_NAME = "X-Runtime".freeze # :nodoc:
13
+
9
14
  def initialize(app, name = nil)
10
15
  @app = app
11
- @header_name = "X-Runtime"
12
- @header_name << "-#{name}" if name
16
+ @header_name = HEADER_NAME
17
+ @header_name += "-#{name}" if name
13
18
  end
14
19
 
15
- FORMAT_STRING = "%0.6f"
16
20
  def call(env)
17
- start_time = clock_time
21
+ start_time = Utils.clock_time
18
22
  status, headers, body = @app.call(env)
19
- request_time = clock_time - start_time
23
+ request_time = Utils.clock_time - start_time
20
24
 
21
- if !headers.has_key?(@header_name)
25
+ unless headers.has_key?(@header_name)
22
26
  headers[@header_name] = FORMAT_STRING % request_time
23
27
  end
24
28
 
25
29
  [status, headers, body]
26
30
  end
27
-
28
- private
29
-
30
- if defined?(Process::CLOCK_MONOTONIC)
31
- def clock_time
32
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
33
- end
34
- else
35
- def clock_time
36
- Time.now.to_f
37
- end
38
- end
39
31
  end
40
32
  end
@@ -99,8 +99,6 @@ module Rack
99
99
  # will be matched with case indifference.
100
100
 
101
101
  class Sendfile
102
- F = ::File
103
-
104
102
  def initialize(app, variation=nil, mappings=[])
105
103
  @app = app
106
104
  @variation = variation
@@ -114,7 +112,7 @@ module Rack
114
112
  if body.respond_to?(:to_path)
115
113
  case type = variation(env)
116
114
  when 'X-Accel-Redirect'
117
- path = F.expand_path(body.to_path)
115
+ path = ::File.expand_path(body.to_path)
118
116
  if url = map_accel_path(env, path)
119
117
  headers[CONTENT_LENGTH] = '0'
120
118
  headers[type] = url
@@ -123,10 +121,10 @@ module Rack
123
121
  obody.close if obody.respond_to?(:close)
124
122
  end
125
123
  else
126
- env['rack.errors'].puts "X-Accel-Mapping header missing"
124
+ env[RACK_ERRORS].puts "X-Accel-Mapping header missing"
127
125
  end
128
126
  when 'X-Sendfile', 'X-Lighttpd-Send-File'
129
- path = F.expand_path(body.to_path)
127
+ path = ::File.expand_path(body.to_path)
130
128
  headers[CONTENT_LENGTH] = '0'
131
129
  headers[type] = path
132
130
  obody = body
@@ -135,7 +133,7 @@ module Rack
135
133
  end
136
134
  when '', nil
137
135
  else
138
- env['rack.errors'].puts "Unknown x-sendfile variation: '#{type}'.\n"
136
+ env[RACK_ERRORS].puts "Unknown x-sendfile variation: '#{type}'.\n"
139
137
  end
140
138
  end
141
139
  [status, headers, body]
@@ -152,7 +150,7 @@ module Rack
152
150
  if mapping = @mappings.find { |internal,_| internal =~ path }
153
151
  path.sub(*mapping)
154
152
  elsif mapping = env['HTTP_X_ACCEL_MAPPING']
155
- internal, external = mapping.split('=', 2).map{ |p| p.strip }
153
+ internal, external = mapping.split('=', 2).map(&:strip)
156
154
  path.sub(/^#{internal}/i, external)
157
155
  end
158
156
  end
@@ -100,14 +100,14 @@ module Rack
100
100
  abort opt_parser.to_s
101
101
  end
102
102
 
103
- options[:config] = args.last if args.last
103
+ options[:config] = args.last if args.last && !args.last.empty?
104
104
  options
105
105
  end
106
106
 
107
107
  def handler_opts(options)
108
108
  begin
109
109
  info = []
110
- server = Rack::Handler.get(options[:server]) || Rack::Handler.default(options)
110
+ server = Rack::Handler.get(options[:server]) || Rack::Handler.default
111
111
  if server && server.respond_to?(:valid_options)
112
112
  info << ""
113
113
  info << "Server-specific options for #{server.name}:"
@@ -183,12 +183,22 @@ module Rack
183
183
  # * :require
184
184
  # require the given libraries
185
185
  def initialize(options = nil)
186
- @options = options
187
- @app = options[:app] if options && options[:app]
186
+ @ignore_options = []
187
+
188
+ if options
189
+ @use_default_options = false
190
+ @options = options
191
+ @app = options[:app] if options[:app]
192
+ else
193
+ argv = defined?(SPEC_ARGV) ? SPEC_ARGV : ARGV
194
+ @use_default_options = true
195
+ @options = parse_options(argv)
196
+ end
188
197
  end
189
198
 
190
199
  def options
191
- @options ||= parse_options(ARGV)
200
+ merged_options = @use_default_options ? default_options.merge(@options) : @options
201
+ merged_options.reject { |k, v| @ignore_options.include?(k) }
192
202
  end
193
203
 
194
204
  def default_options
@@ -288,7 +298,16 @@ module Rack
288
298
  end
289
299
 
290
300
  def server
291
- @_server ||= Rack::Handler.get(options[:server]) || Rack::Handler.default(options)
301
+ @_server ||= Rack::Handler.get(options[:server])
302
+
303
+ unless @_server
304
+ @_server = Rack::Handler.default
305
+
306
+ # We already speak FastCGI
307
+ @ignore_options = [:File, :Port] if @_server.to_s == 'Rack::Handler::FastCGI'
308
+ end
309
+
310
+ @_server
292
311
  end
293
312
 
294
313
  private
@@ -298,7 +317,7 @@ module Rack
298
317
  end
299
318
 
300
319
  app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
301
- self.options.merge! options
320
+ @options.merge!(options) { |key, old, new| old }
302
321
  app
303
322
  end
304
323
 
@@ -307,16 +326,14 @@ module Rack
307
326
  end
308
327
 
309
328
  def parse_options(args)
310
- options = default_options
311
-
312
329
  # Don't evaluate CGI ISINDEX parameters.
313
330
  # http://www.meb.uni-bonn.de/docs/cgi/cl.html
314
331
  args.clear if ENV.include?(REQUEST_METHOD)
315
332
 
316
- options.merge! opt_parser.parse!(args)
317
- options[:config] = ::File.expand_path(options[:config])
333
+ @options = opt_parser.parse!(args)
334
+ @options[:config] = ::File.expand_path(options[:config])
318
335
  ENV["RACK_ENV"] = options[:environment]
319
- options
336
+ @options
320
337
  end
321
338
 
322
339
  def opt_parser
@@ -338,17 +355,7 @@ module Rack
338
355
  end
339
356
 
340
357
  def daemonize_app
341
- if RUBY_VERSION < "1.9"
342
- exit if fork
343
- Process.setsid
344
- exit if fork
345
- Dir.chdir "/"
346
- STDIN.reopen "/dev/null"
347
- STDOUT.reopen "/dev/null", "a"
348
- STDERR.reopen "/dev/null", "a"
349
- else
350
- Process.daemon
351
- end
358
+ Process.daemon
352
359
  end
353
360
 
354
361
  def write_pid