rack 1.6.13 → 2.1.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +92 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +105 -141
- data/Rakefile +27 -28
- data/SPEC +6 -7
- data/bin/rackup +1 -0
- data/contrib/rack_logo.svg +164 -111
- data/example/lobster.ru +2 -0
- data/example/protectedlobster.rb +4 -2
- data/example/protectedlobster.ru +3 -1
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +7 -1
- data/lib/rack/auth/basic.rb +4 -1
- data/lib/rack/auth/digest/md5.rb +9 -7
- data/lib/rack/auth/digest/nonce.rb +6 -3
- data/lib/rack/auth/digest/params.rb +5 -4
- data/lib/rack/auth/digest/request.rb +3 -1
- data/lib/rack/body_proxy.rb +11 -9
- data/lib/rack/builder.rb +42 -18
- data/lib/rack/cascade.rb +6 -5
- data/lib/rack/chunked.rb +33 -10
- data/lib/rack/{commonlogger.rb → common_logger.rb} +14 -10
- data/lib/rack/{conditionalget.rb → conditional_get.rb} +3 -1
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +5 -3
- data/lib/rack/content_type.rb +3 -1
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +33 -53
- data/lib/rack/directory.rb +75 -60
- data/lib/rack/etag.rb +8 -5
- data/lib/rack/events.rb +156 -0
- data/lib/rack/file.rb +4 -149
- data/lib/rack/files.rb +178 -0
- data/lib/rack/handler/cgi.rb +18 -17
- data/lib/rack/handler/fastcgi.rb +17 -16
- data/lib/rack/handler/lsws.rb +14 -12
- data/lib/rack/handler/scgi.rb +22 -19
- data/lib/rack/handler/thin.rb +6 -1
- data/lib/rack/handler/webrick.rb +28 -28
- data/lib/rack/handler.rb +9 -26
- data/lib/rack/head.rb +17 -17
- data/lib/rack/lint.rb +55 -52
- data/lib/rack/lobster.rb +8 -6
- data/lib/rack/lock.rb +17 -10
- data/lib/rack/logger.rb +4 -2
- data/lib/rack/media_type.rb +43 -0
- data/lib/rack/{methodoverride.rb → method_override.rb} +10 -8
- data/lib/rack/mime.rb +27 -6
- data/lib/rack/mock.rb +101 -60
- data/lib/rack/multipart/generator.rb +11 -12
- data/lib/rack/multipart/parser.rb +292 -161
- data/lib/rack/multipart/uploaded_file.rb +3 -2
- data/lib/rack/multipart.rb +38 -8
- data/lib/rack/{nulllogger.rb → null_logger.rb} +3 -1
- data/lib/rack/query_parser.rb +218 -0
- data/lib/rack/recursive.rb +11 -9
- data/lib/rack/reloader.rb +10 -4
- data/lib/rack/request.rb +447 -305
- data/lib/rack/response.rb +196 -83
- data/lib/rack/rewindable_input.rb +5 -14
- data/lib/rack/runtime.rb +12 -18
- data/lib/rack/sendfile.rb +19 -14
- data/lib/rack/server.rb +118 -41
- data/lib/rack/session/abstract/id.rb +139 -94
- data/lib/rack/session/cookie.rb +34 -26
- data/lib/rack/session/memcache.rb +4 -93
- data/lib/rack/session/pool.rb +12 -10
- data/lib/rack/show_exceptions.rb +392 -0
- data/lib/rack/{showstatus.rb → show_status.rb} +7 -5
- data/lib/rack/static.rb +41 -11
- data/lib/rack/tempfile_reaper.rb +4 -2
- data/lib/rack/urlmap.rb +25 -15
- data/lib/rack/utils.rb +203 -277
- data/lib/rack.rb +76 -24
- data/rack.gemspec +25 -14
- metadata +62 -183
- data/HISTORY.md +0 -375
- data/KNOWN-ISSUES +0 -44
- data/lib/rack/backports/uri/common_18.rb +0 -56
- data/lib/rack/backports/uri/common_192.rb +0 -52
- data/lib/rack/backports/uri/common_193.rb +0 -29
- data/lib/rack/handler/evented_mongrel.rb +0 -8
- data/lib/rack/handler/mongrel.rb +0 -106
- data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
- data/lib/rack/showexceptions.rb +0 -387
- data/lib/rack/utils/okjson.rb +0 -600
- data/test/builder/anything.rb +0 -5
- data/test/builder/comment.ru +0 -4
- data/test/builder/end.ru +0 -5
- data/test/builder/line.ru +0 -1
- data/test/builder/options.ru +0 -2
- data/test/cgi/assets/folder/test.js +0 -1
- data/test/cgi/assets/fonts/font.eot +0 -1
- data/test/cgi/assets/images/image.png +0 -1
- data/test/cgi/assets/index.html +0 -1
- data/test/cgi/assets/javascripts/app.js +0 -1
- data/test/cgi/assets/stylesheets/app.css +0 -1
- data/test/cgi/lighttpd.conf +0 -26
- data/test/cgi/rackup_stub.rb +0 -6
- data/test/cgi/sample_rackup.ru +0 -5
- data/test/cgi/test +0 -9
- data/test/cgi/test+directory/test+file +0 -1
- data/test/cgi/test.fcgi +0 -8
- data/test/cgi/test.ru +0 -5
- data/test/gemloader.rb +0 -10
- data/test/multipart/bad_robots +0 -259
- data/test/multipart/binary +0 -0
- data/test/multipart/content_type_and_no_filename +0 -6
- data/test/multipart/empty +0 -10
- data/test/multipart/fail_16384_nofile +0 -814
- data/test/multipart/file1.txt +0 -1
- data/test/multipart/filename_and_modification_param +0 -7
- data/test/multipart/filename_and_no_name +0 -6
- data/test/multipart/filename_with_escaped_quotes +0 -6
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
- data/test/multipart/filename_with_null_byte +0 -7
- data/test/multipart/filename_with_percent_escaped_quotes +0 -6
- data/test/multipart/filename_with_unescaped_percentages +0 -6
- data/test/multipart/filename_with_unescaped_percentages2 +0 -6
- data/test/multipart/filename_with_unescaped_percentages3 +0 -6
- data/test/multipart/filename_with_unescaped_quotes +0 -6
- data/test/multipart/ie +0 -6
- data/test/multipart/invalid_character +0 -6
- data/test/multipart/mixed_files +0 -21
- data/test/multipart/nested +0 -10
- data/test/multipart/none +0 -9
- data/test/multipart/semicolon +0 -6
- data/test/multipart/text +0 -15
- data/test/multipart/three_files_three_fields +0 -31
- data/test/multipart/webkit +0 -32
- data/test/rackup/config.ru +0 -31
- data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
- data/test/spec_auth_basic.rb +0 -81
- data/test/spec_auth_digest.rb +0 -259
- data/test/spec_body_proxy.rb +0 -85
- data/test/spec_builder.rb +0 -223
- data/test/spec_cascade.rb +0 -61
- data/test/spec_cgi.rb +0 -102
- data/test/spec_chunked.rb +0 -101
- data/test/spec_commonlogger.rb +0 -93
- data/test/spec_conditionalget.rb +0 -102
- data/test/spec_config.rb +0 -22
- data/test/spec_content_length.rb +0 -85
- data/test/spec_content_type.rb +0 -45
- data/test/spec_deflater.rb +0 -339
- data/test/spec_directory.rb +0 -88
- data/test/spec_etag.rb +0 -107
- data/test/spec_fastcgi.rb +0 -107
- data/test/spec_file.rb +0 -221
- data/test/spec_handler.rb +0 -72
- data/test/spec_head.rb +0 -45
- data/test/spec_lint.rb +0 -550
- data/test/spec_lobster.rb +0 -58
- data/test/spec_lock.rb +0 -164
- data/test/spec_logger.rb +0 -23
- data/test/spec_methodoverride.rb +0 -111
- data/test/spec_mime.rb +0 -51
- data/test/spec_mock.rb +0 -297
- data/test/spec_mongrel.rb +0 -182
- data/test/spec_multipart.rb +0 -600
- data/test/spec_nulllogger.rb +0 -20
- data/test/spec_recursive.rb +0 -72
- data/test/spec_request.rb +0 -1232
- data/test/spec_response.rb +0 -407
- data/test/spec_rewindable_input.rb +0 -118
- data/test/spec_runtime.rb +0 -49
- data/test/spec_sendfile.rb +0 -130
- data/test/spec_server.rb +0 -167
- data/test/spec_session_abstract_id.rb +0 -53
- data/test/spec_session_cookie.rb +0 -410
- data/test/spec_session_memcache.rb +0 -358
- data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
- data/test/spec_session_pool.rb +0 -246
- data/test/spec_showexceptions.rb +0 -98
- data/test/spec_showstatus.rb +0 -103
- data/test/spec_static.rb +0 -145
- data/test/spec_tempfile_reaper.rb +0 -63
- data/test/spec_thin.rb +0 -91
- data/test/spec_urlmap.rb +0 -236
- data/test/spec_utils.rb +0 -647
- data/test/spec_version.rb +0 -17
- data/test/spec_webrick.rb +0 -184
- data/test/static/another/index.html +0 -1
- data/test/static/index.html +0 -1
- data/test/testrequest.rb +0 -78
- data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/lib/rack/response.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack/request'
|
2
4
|
require 'rack/utils'
|
3
5
|
require 'rack/body_proxy'
|
6
|
+
require 'rack/media_type'
|
4
7
|
require 'time'
|
5
8
|
|
6
9
|
module Rack
|
@@ -8,7 +11,7 @@ module Rack
|
|
8
11
|
# response.
|
9
12
|
#
|
10
13
|
# It allows setting of headers and cookies, and provides useful
|
11
|
-
# defaults (
|
14
|
+
# defaults (an OK response with empty headers and body).
|
12
15
|
#
|
13
16
|
# You can use Response#write to iteratively generate your response,
|
14
17
|
# but note that this is buffered by Rack::Response until you call
|
@@ -18,145 +21,255 @@ module Rack
|
|
18
21
|
# Your application's +call+ should end returning Response#finish.
|
19
22
|
|
20
23
|
class Response
|
21
|
-
attr_accessor :length
|
24
|
+
attr_accessor :length, :status, :body
|
25
|
+
attr_reader :header
|
26
|
+
alias headers header
|
27
|
+
|
28
|
+
CHUNKED = 'chunked'
|
29
|
+
STATUS_WITH_NO_ENTITY_BODY = Utils::STATUS_WITH_NO_ENTITY_BODY
|
22
30
|
|
23
|
-
|
24
|
-
TRANSFER_ENCODING = 'Transfer-Encoding'.freeze
|
25
|
-
def initialize(body=[], status=200, header={})
|
31
|
+
def initialize(body = nil, status = 200, header = {})
|
26
32
|
@status = status.to_i
|
27
|
-
@header = Utils::HeaderHash.new
|
33
|
+
@header = Utils::HeaderHash.new(header)
|
28
34
|
|
29
|
-
@
|
30
|
-
@writer = lambda { |x| @body << x }
|
31
|
-
@block = nil
|
32
|
-
@length = 0
|
35
|
+
@writer = self.method(:append)
|
33
36
|
|
34
|
-
@
|
37
|
+
@block = nil
|
38
|
+
@length = 0
|
35
39
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
# Keep track of whether we have expanded the user supplied body.
|
41
|
+
if body.nil?
|
42
|
+
@body = []
|
43
|
+
@buffered = true
|
44
|
+
elsif body.respond_to?(:to_str)
|
45
|
+
@body = [body]
|
46
|
+
@buffered = true
|
42
47
|
else
|
43
|
-
|
48
|
+
@body = body
|
49
|
+
@buffered = false
|
44
50
|
end
|
45
51
|
|
46
|
-
yield self
|
47
|
-
end
|
48
|
-
|
49
|
-
attr_reader :header
|
50
|
-
attr_accessor :status, :body
|
51
|
-
|
52
|
-
def [](key)
|
53
|
-
header[key]
|
52
|
+
yield self if block_given?
|
54
53
|
end
|
55
54
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
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)
|
55
|
+
def redirect(target, status = 302)
|
56
|
+
self.status = status
|
57
|
+
self.location = target
|
66
58
|
end
|
67
59
|
|
68
|
-
def
|
69
|
-
|
70
|
-
self["Location"] = target
|
60
|
+
def chunked?
|
61
|
+
CHUNKED == get_header(TRANSFER_ENCODING)
|
71
62
|
end
|
72
63
|
|
73
64
|
def finish(&block)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
header.delete CONTENT_TYPE
|
78
|
-
header.delete CONTENT_LENGTH
|
65
|
+
if STATUS_WITH_NO_ENTITY_BODY[status.to_i]
|
66
|
+
delete_header CONTENT_TYPE
|
67
|
+
delete_header CONTENT_LENGTH
|
79
68
|
close
|
80
69
|
[status.to_i, header, []]
|
81
70
|
else
|
82
|
-
|
71
|
+
if block_given?
|
72
|
+
@block = block
|
73
|
+
[status.to_i, header, self]
|
74
|
+
else
|
75
|
+
[status.to_i, header, @body]
|
76
|
+
end
|
83
77
|
end
|
84
78
|
end
|
79
|
+
|
85
80
|
alias to_a finish # For *response
|
86
|
-
alias to_ary finish # For implicit-splat on Ruby 1.9.2
|
87
81
|
|
88
82
|
def each(&callback)
|
89
83
|
@body.each(&callback)
|
90
|
-
@
|
91
|
-
|
84
|
+
@buffered = true
|
85
|
+
|
86
|
+
if @block
|
87
|
+
@writer = callback
|
88
|
+
@block.call(self)
|
89
|
+
end
|
92
90
|
end
|
93
91
|
|
94
92
|
# Append to body and update Content-Length.
|
95
93
|
#
|
96
94
|
# NOTE: Do not mix #write and direct #body access!
|
97
95
|
#
|
98
|
-
def write(
|
99
|
-
|
100
|
-
@length += Rack::Utils.bytesize(s) unless @chunked
|
101
|
-
@writer.call s
|
96
|
+
def write(chunk)
|
97
|
+
buffered_body!
|
102
98
|
|
103
|
-
|
104
|
-
str
|
99
|
+
@writer.call(chunk.to_s)
|
105
100
|
end
|
106
101
|
|
107
102
|
def close
|
108
|
-
body.close if body.respond_to?(:close)
|
103
|
+
@body.close if @body.respond_to?(:close)
|
109
104
|
end
|
110
105
|
|
111
106
|
def empty?
|
112
107
|
@block == nil && @body.empty?
|
113
108
|
end
|
114
109
|
|
115
|
-
|
110
|
+
def has_header?(key); headers.key? key; end
|
111
|
+
def get_header(key); headers[key]; end
|
112
|
+
def set_header(key, v); headers[key] = v; end
|
113
|
+
def delete_header(key); headers.delete key; end
|
114
|
+
|
115
|
+
alias :[] :get_header
|
116
|
+
alias :[]= :set_header
|
116
117
|
|
117
118
|
module Helpers
|
118
|
-
def invalid?;
|
119
|
-
|
120
|
-
def informational?;
|
121
|
-
def successful?;
|
122
|
-
def redirection?;
|
123
|
-
def client_error?;
|
124
|
-
def server_error?;
|
125
|
-
|
126
|
-
def ok?;
|
127
|
-
def created?;
|
128
|
-
def accepted?;
|
129
|
-
def
|
130
|
-
def
|
131
|
-
def
|
132
|
-
def
|
133
|
-
def
|
134
|
-
def
|
135
|
-
def
|
136
|
-
|
137
|
-
def
|
138
|
-
|
139
|
-
|
140
|
-
attr_reader :headers, :original_headers
|
119
|
+
def invalid?; status < 100 || status >= 600; end
|
120
|
+
|
121
|
+
def informational?; status >= 100 && status < 200; end
|
122
|
+
def successful?; status >= 200 && status < 300; end
|
123
|
+
def redirection?; status >= 300 && status < 400; end
|
124
|
+
def client_error?; status >= 400 && status < 500; end
|
125
|
+
def server_error?; status >= 500 && status < 600; end
|
126
|
+
|
127
|
+
def ok?; status == 200; end
|
128
|
+
def created?; status == 201; end
|
129
|
+
def accepted?; status == 202; end
|
130
|
+
def no_content?; status == 204; end
|
131
|
+
def moved_permanently?; status == 301; end
|
132
|
+
def bad_request?; status == 400; end
|
133
|
+
def unauthorized?; status == 401; end
|
134
|
+
def forbidden?; status == 403; end
|
135
|
+
def not_found?; status == 404; end
|
136
|
+
def method_not_allowed?; status == 405; end
|
137
|
+
def precondition_failed?; status == 412; end
|
138
|
+
def unprocessable?; status == 422; end
|
139
|
+
|
140
|
+
def redirect?; [301, 302, 303, 307, 308].include? status; end
|
141
141
|
|
142
142
|
def include?(header)
|
143
|
-
|
143
|
+
has_header? header
|
144
|
+
end
|
145
|
+
|
146
|
+
# Add a header that may have multiple values.
|
147
|
+
#
|
148
|
+
# Example:
|
149
|
+
# response.add_header 'Vary', 'Accept-Encoding'
|
150
|
+
# response.add_header 'Vary', 'Cookie'
|
151
|
+
#
|
152
|
+
# assert_equal 'Accept-Encoding,Cookie', response.get_header('Vary')
|
153
|
+
#
|
154
|
+
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
|
155
|
+
def add_header key, v
|
156
|
+
if v.nil?
|
157
|
+
get_header key
|
158
|
+
elsif has_header? key
|
159
|
+
set_header key, "#{get_header key},#{v}"
|
160
|
+
else
|
161
|
+
set_header key, v
|
162
|
+
end
|
144
163
|
end
|
145
164
|
|
146
165
|
def content_type
|
147
|
-
|
166
|
+
get_header CONTENT_TYPE
|
167
|
+
end
|
168
|
+
|
169
|
+
def media_type
|
170
|
+
MediaType.type(content_type)
|
171
|
+
end
|
172
|
+
|
173
|
+
def media_type_params
|
174
|
+
MediaType.params(content_type)
|
148
175
|
end
|
149
176
|
|
150
177
|
def content_length
|
151
|
-
cl =
|
178
|
+
cl = get_header CONTENT_LENGTH
|
152
179
|
cl ? cl.to_i : cl
|
153
180
|
end
|
154
181
|
|
155
182
|
def location
|
156
|
-
|
183
|
+
get_header "Location"
|
184
|
+
end
|
185
|
+
|
186
|
+
def location=(location)
|
187
|
+
set_header "Location", location
|
188
|
+
end
|
189
|
+
|
190
|
+
def set_cookie(key, value)
|
191
|
+
cookie_header = get_header SET_COOKIE
|
192
|
+
set_header SET_COOKIE, ::Rack::Utils.add_cookie_to_header(cookie_header, key, value)
|
193
|
+
end
|
194
|
+
|
195
|
+
def delete_cookie(key, value = {})
|
196
|
+
set_header SET_COOKIE, ::Rack::Utils.add_remove_cookie_to_header(get_header(SET_COOKIE), key, value)
|
197
|
+
end
|
198
|
+
|
199
|
+
def set_cookie_header
|
200
|
+
get_header SET_COOKIE
|
201
|
+
end
|
202
|
+
|
203
|
+
def set_cookie_header= v
|
204
|
+
set_header SET_COOKIE, v
|
205
|
+
end
|
206
|
+
|
207
|
+
def cache_control
|
208
|
+
get_header CACHE_CONTROL
|
209
|
+
end
|
210
|
+
|
211
|
+
def cache_control= v
|
212
|
+
set_header CACHE_CONTROL, v
|
213
|
+
end
|
214
|
+
|
215
|
+
def etag
|
216
|
+
get_header ETAG
|
217
|
+
end
|
218
|
+
|
219
|
+
def etag= v
|
220
|
+
set_header ETAG, v
|
221
|
+
end
|
222
|
+
|
223
|
+
protected
|
224
|
+
|
225
|
+
def buffered_body!
|
226
|
+
return if @buffered
|
227
|
+
|
228
|
+
if @body.is_a?(Array)
|
229
|
+
# The user supplied body was an array:
|
230
|
+
@body = @body.compact
|
231
|
+
else
|
232
|
+
# Turn the user supplied body into a buffered array:
|
233
|
+
body = @body
|
234
|
+
@body = Array.new
|
235
|
+
|
236
|
+
body.each do |part|
|
237
|
+
@writer.call(part.to_s)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
@buffered = true
|
242
|
+
end
|
243
|
+
|
244
|
+
def append(chunk)
|
245
|
+
@body << chunk
|
246
|
+
|
247
|
+
unless chunked?
|
248
|
+
@length += chunk.bytesize
|
249
|
+
set_header(CONTENT_LENGTH, @length.to_s)
|
250
|
+
end
|
251
|
+
|
252
|
+
return chunk
|
157
253
|
end
|
158
254
|
end
|
159
255
|
|
160
256
|
include Helpers
|
257
|
+
|
258
|
+
class Raw
|
259
|
+
include Helpers
|
260
|
+
|
261
|
+
attr_reader :headers
|
262
|
+
attr_accessor :status
|
263
|
+
|
264
|
+
def initialize status, headers
|
265
|
+
@status = status
|
266
|
+
@headers = headers
|
267
|
+
end
|
268
|
+
|
269
|
+
def has_header?(key); headers.key? key; end
|
270
|
+
def get_header(key); headers[key]; end
|
271
|
+
def set_header(key, v); headers[key] = v; end
|
272
|
+
def delete_header(key); headers.delete key; end
|
273
|
+
end
|
161
274
|
end
|
162
275
|
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
require 'tempfile'
|
3
5
|
require 'rack/utils'
|
4
6
|
|
@@ -40,7 +42,7 @@ module Rack
|
|
40
42
|
end
|
41
43
|
|
42
44
|
# Closes this RewindableInput object without closing the originally
|
43
|
-
# wrapped IO
|
45
|
+
# wrapped IO object. Cleans up any temporary resources that this RewindableInput
|
44
46
|
# has created.
|
45
47
|
#
|
46
48
|
# This method may be called multiple times. It does nothing on subsequent calls.
|
@@ -57,15 +59,6 @@ module Rack
|
|
57
59
|
|
58
60
|
private
|
59
61
|
|
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
62
|
def make_rewindable
|
70
63
|
# Buffer all data into a tempfile. Since this tempfile is private to this
|
71
64
|
# RewindableInput object, we chmod it so that nobody else can read or write
|
@@ -77,18 +70,16 @@ module Rack
|
|
77
70
|
@rewindable_io.set_encoding(Encoding::BINARY) if @rewindable_io.respond_to?(:set_encoding)
|
78
71
|
@rewindable_io.binmode
|
79
72
|
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
73
|
raise 'Unlink failed. IO closed.' if @rewindable_io.closed?
|
83
74
|
@unlinked = true
|
84
75
|
end
|
85
76
|
|
86
|
-
buffer = ""
|
77
|
+
buffer = "".dup
|
87
78
|
while @io.read(1024 * 4, buffer)
|
88
79
|
entire_buffer_written_out = false
|
89
80
|
while !entire_buffer_written_out
|
90
81
|
written = @rewindable_io.write(buffer)
|
91
|
-
entire_buffer_written_out = written ==
|
82
|
+
entire_buffer_written_out = written == buffer.bytesize
|
92
83
|
if !entire_buffer_written_out
|
93
84
|
buffer.slice!(0 .. written - 1)
|
94
85
|
end
|
data/lib/rack/runtime.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rack/utils'
|
4
|
+
|
1
5
|
module Rack
|
2
6
|
# Sets an "X-Runtime" response header, indicating the response
|
3
7
|
# time of the request, in seconds
|
@@ -6,35 +10,25 @@ module Rack
|
|
6
10
|
# time, or before all the other middlewares to include time for them,
|
7
11
|
# too.
|
8
12
|
class Runtime
|
13
|
+
FORMAT_STRING = "%0.6f" # :nodoc:
|
14
|
+
HEADER_NAME = "X-Runtime" # :nodoc:
|
15
|
+
|
9
16
|
def initialize(app, name = nil)
|
10
17
|
@app = app
|
11
|
-
@header_name =
|
12
|
-
@header_name
|
18
|
+
@header_name = HEADER_NAME
|
19
|
+
@header_name += "-#{name}" if name
|
13
20
|
end
|
14
21
|
|
15
|
-
FORMAT_STRING = "%0.6f"
|
16
22
|
def call(env)
|
17
|
-
start_time = clock_time
|
23
|
+
start_time = Utils.clock_time
|
18
24
|
status, headers, body = @app.call(env)
|
19
|
-
request_time = clock_time - start_time
|
25
|
+
request_time = Utils.clock_time - start_time
|
20
26
|
|
21
|
-
|
27
|
+
unless headers.has_key?(@header_name)
|
22
28
|
headers[@header_name] = FORMAT_STRING % request_time
|
23
29
|
end
|
24
30
|
|
25
31
|
[status, headers, body]
|
26
32
|
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
33
|
end
|
40
34
|
end
|
data/lib/rack/sendfile.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rack/files'
|
2
4
|
require 'rack/body_proxy'
|
3
5
|
|
4
6
|
module Rack
|
@@ -14,7 +16,7 @@ module Rack
|
|
14
16
|
#
|
15
17
|
# In order to take advantage of this middleware, the response body must
|
16
18
|
# respond to +to_path+ and the request must include an X-Sendfile-Type
|
17
|
-
# header. Rack::
|
19
|
+
# header. Rack::Files and other components implement +to_path+ so there's
|
18
20
|
# rarely anything you need to do in your application. The X-Sendfile-Type
|
19
21
|
# header is typically set in your web servers configuration. The following
|
20
22
|
# sections attempt to document
|
@@ -53,7 +55,7 @@ module Rack
|
|
53
55
|
# that it maps to. The middleware performs a simple substitution on the
|
54
56
|
# resulting path.
|
55
57
|
#
|
56
|
-
# See Also:
|
58
|
+
# See Also: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile
|
57
59
|
#
|
58
60
|
# === lighttpd
|
59
61
|
#
|
@@ -99,9 +101,7 @@ module Rack
|
|
99
101
|
# will be matched with case indifference.
|
100
102
|
|
101
103
|
class Sendfile
|
102
|
-
|
103
|
-
|
104
|
-
def initialize(app, variation=nil, mappings=[])
|
104
|
+
def initialize(app, variation = nil, mappings = [])
|
105
105
|
@app = app
|
106
106
|
@variation = variation
|
107
107
|
@mappings = mappings.map do |internal, external|
|
@@ -114,19 +114,20 @@ module Rack
|
|
114
114
|
if body.respond_to?(:to_path)
|
115
115
|
case type = variation(env)
|
116
116
|
when 'X-Accel-Redirect'
|
117
|
-
path =
|
117
|
+
path = ::File.expand_path(body.to_path)
|
118
118
|
if url = map_accel_path(env, path)
|
119
119
|
headers[CONTENT_LENGTH] = '0'
|
120
|
-
|
120
|
+
# '?' must be percent-encoded because it is not query string but a part of path
|
121
|
+
headers[type] = ::Rack::Utils.escape_path(url).gsub('?', '%3F')
|
121
122
|
obody = body
|
122
123
|
body = Rack::BodyProxy.new([]) do
|
123
124
|
obody.close if obody.respond_to?(:close)
|
124
125
|
end
|
125
126
|
else
|
126
|
-
env[
|
127
|
+
env[RACK_ERRORS].puts "X-Accel-Mapping header missing"
|
127
128
|
end
|
128
129
|
when 'X-Sendfile', 'X-Lighttpd-Send-File'
|
129
|
-
path =
|
130
|
+
path = ::File.expand_path(body.to_path)
|
130
131
|
headers[CONTENT_LENGTH] = '0'
|
131
132
|
headers[type] = path
|
132
133
|
obody = body
|
@@ -135,7 +136,7 @@ module Rack
|
|
135
136
|
end
|
136
137
|
when '', nil
|
137
138
|
else
|
138
|
-
env[
|
139
|
+
env[RACK_ERRORS].puts "Unknown x-sendfile variation: '#{type}'.\n"
|
139
140
|
end
|
140
141
|
end
|
141
142
|
[status, headers, body]
|
@@ -149,11 +150,15 @@ module Rack
|
|
149
150
|
end
|
150
151
|
|
151
152
|
def map_accel_path(env, path)
|
152
|
-
if mapping = @mappings.find { |internal,_| internal =~ path }
|
153
|
+
if mapping = @mappings.find { |internal, _| internal =~ path }
|
153
154
|
path.sub(*mapping)
|
154
155
|
elsif mapping = env['HTTP_X_ACCEL_MAPPING']
|
155
|
-
|
156
|
-
|
156
|
+
mapping.split(',').map(&:strip).each do |m|
|
157
|
+
internal, external = m.split('=', 2).map(&:strip)
|
158
|
+
new_path = path.sub(/^#{internal}/i, external)
|
159
|
+
return new_path unless path == new_path
|
160
|
+
end
|
161
|
+
path
|
157
162
|
end
|
158
163
|
end
|
159
164
|
end
|