rack-contrib 1.8.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rack-contrib might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +11 -0
- data/lib/rack/contrib.rb +0 -2
- data/lib/rack/contrib/jsonp.rb +1 -1
- data/lib/rack/contrib/nested_params.rb +3 -120
- metadata +23 -25
- data/lib/rack/contrib/accept_format.rb +0 -66
- data/lib/rack/contrib/sendfile.rb +0 -138
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b545ac91ebc6596e463da4596aa475e98f170759
|
4
|
+
data.tar.gz: 7185814a488ba9dfc59071569d9ae7175e2f5eb3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b8b85e0c0d7541825991235ec8b20057d9d8965d031540f056741fb99b9bd6ac524096988066ba717221ec6f6f134db76f9bf5f6325794f28d6a8f2b8831a0f
|
7
|
+
data.tar.gz: 3413f89de71509f68b16b21d4e40dc0eb7fbd98c5210a5fa9e0512521f630f044a75933ce05eca29f19536f052184722c79ca37ba443d49f8161a3702054ac40
|
data/README.md
CHANGED
@@ -61,6 +61,17 @@ use Rack::MailExceptions
|
|
61
61
|
run theapp
|
62
62
|
```
|
63
63
|
|
64
|
+
#### Versioning
|
65
|
+
|
66
|
+
This package is [semver compliant](https://semver.org); you should use a
|
67
|
+
pessimistic version constraint (`~>`) against the relevant `2.x` version of
|
68
|
+
this gem.
|
69
|
+
|
70
|
+
This version of `rack-contrib` is only compatible with `rack` 2.x. If you
|
71
|
+
are using `rack` 1.x, you will need to use `rack-contrib` 1.x. A suitable
|
72
|
+
pessimistic version constraint (`~>`) is recommended.
|
73
|
+
|
74
|
+
|
64
75
|
### Testing
|
65
76
|
|
66
77
|
To contribute to the project, begin by cloning the repo and installing the necessary gems:
|
data/lib/rack/contrib.rb
CHANGED
@@ -14,7 +14,6 @@ module Rack
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
autoload :AcceptFormat, "rack/contrib/accept_format"
|
18
17
|
autoload :Access, "rack/contrib/access"
|
19
18
|
autoload :BounceFavicon, "rack/contrib/bounce_favicon"
|
20
19
|
autoload :Cookies, "rack/contrib/cookies"
|
@@ -34,7 +33,6 @@ module Rack
|
|
34
33
|
autoload :Profiler, "rack/contrib/profiler"
|
35
34
|
autoload :ResponseHeaders, "rack/contrib/response_headers"
|
36
35
|
autoload :Runtime, "rack/contrib/runtime"
|
37
|
-
autoload :Sendfile, "rack/contrib/sendfile"
|
38
36
|
autoload :Signals, "rack/contrib/signals"
|
39
37
|
autoload :SimpleEndpoint, "rack/contrib/simple_endpoint"
|
40
38
|
autoload :TimeZone, "rack/contrib/time_zone"
|
data/lib/rack/contrib/jsonp.rb
CHANGED
@@ -53,7 +53,7 @@ module Rack
|
|
53
53
|
|
54
54
|
# Set new Content-Length, if it was set before we mutated the response body
|
55
55
|
if headers['Content-Length']
|
56
|
-
length = response.to_ary.inject(0) { |len, part| len + bytesize
|
56
|
+
length = response.to_ary.inject(0) { |len, part| len + part.bytesize }
|
57
57
|
headers['Content-Length'] = length.to_s
|
58
58
|
end
|
59
59
|
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'strscan'
|
1
|
+
require 'rack/utils'
|
3
2
|
|
4
3
|
module Rack
|
5
4
|
# Rack middleware for parsing POST/PUT body data into nested parameters
|
@@ -20,130 +19,14 @@ module Rack
|
|
20
19
|
|
21
20
|
def call(env)
|
22
21
|
if form_vars = env[FORM_VARS]
|
23
|
-
|
22
|
+
Rack::Utils.parse_nested_query(form_vars)
|
24
23
|
elsif env[CONTENT_TYPE] == URL_ENCODED
|
25
24
|
post_body = env[POST_BODY]
|
26
25
|
env[FORM_INPUT] = post_body
|
27
|
-
env[FORM_HASH] =
|
26
|
+
env[FORM_HASH] = Rack::Utils.parse_nested_query(post_body.read)
|
28
27
|
post_body.rewind if post_body.respond_to?(:rewind)
|
29
28
|
end
|
30
29
|
@app.call(env)
|
31
30
|
end
|
32
|
-
|
33
|
-
## the rest is nabbed from Rails ##
|
34
|
-
|
35
|
-
def parse_query_parameters(query_string)
|
36
|
-
return {} if query_string.nil? or query_string.empty?
|
37
|
-
|
38
|
-
pairs = query_string.split('&').collect do |chunk|
|
39
|
-
next if chunk.empty?
|
40
|
-
key, value = chunk.split('=', 2)
|
41
|
-
next if key.empty?
|
42
|
-
value = value.nil? ? nil : CGI.unescape(value)
|
43
|
-
[ CGI.unescape(key), value ]
|
44
|
-
end.compact
|
45
|
-
|
46
|
-
UrlEncodedPairParser.new(pairs).result
|
47
|
-
end
|
48
|
-
|
49
|
-
class UrlEncodedPairParser < StringScanner
|
50
|
-
attr_reader :top, :parent, :result
|
51
|
-
|
52
|
-
def initialize(pairs = [])
|
53
|
-
super('')
|
54
|
-
@result = {}
|
55
|
-
pairs.each { |key, value| parse(key, value) }
|
56
|
-
end
|
57
|
-
|
58
|
-
KEY_REGEXP = %r{([^\[\]=&]+)}
|
59
|
-
BRACKETED_KEY_REGEXP = %r{\[([^\[\]=&]+)\]}
|
60
|
-
|
61
|
-
# Parse the query string
|
62
|
-
def parse(key, value)
|
63
|
-
self.string = key
|
64
|
-
@top, @parent = result, nil
|
65
|
-
|
66
|
-
# First scan the bare key
|
67
|
-
key = scan(KEY_REGEXP) or return
|
68
|
-
key = post_key_check(key)
|
69
|
-
|
70
|
-
# Then scan as many nestings as present
|
71
|
-
until eos?
|
72
|
-
r = scan(BRACKETED_KEY_REGEXP) or return
|
73
|
-
key = self[1]
|
74
|
-
key = post_key_check(key)
|
75
|
-
end
|
76
|
-
|
77
|
-
bind(key, value)
|
78
|
-
end
|
79
|
-
|
80
|
-
private
|
81
|
-
# After we see a key, we must look ahead to determine our next action. Cases:
|
82
|
-
#
|
83
|
-
# [] follows the key. Then the value must be an array.
|
84
|
-
# = follows the key. (A value comes next)
|
85
|
-
# & or the end of string follows the key. Then the key is a flag.
|
86
|
-
# otherwise, a hash follows the key.
|
87
|
-
def post_key_check(key)
|
88
|
-
if scan(/\[\]/) # a[b][] indicates that b is an array
|
89
|
-
container(key, Array)
|
90
|
-
nil
|
91
|
-
elsif check(/\[[^\]]/) # a[b] indicates that a is a hash
|
92
|
-
container(key, Hash)
|
93
|
-
nil
|
94
|
-
else # End of key? We do nothing.
|
95
|
-
key
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
# Add a container to the stack.
|
100
|
-
def container(key, klass)
|
101
|
-
type_conflict! klass, top[key] if top.is_a?(Hash) && top.key?(key) && ! top[key].is_a?(klass)
|
102
|
-
value = bind(key, klass.new)
|
103
|
-
type_conflict! klass, value unless value.is_a?(klass)
|
104
|
-
push(value)
|
105
|
-
end
|
106
|
-
|
107
|
-
# Push a value onto the 'stack', which is actually only the top 2 items.
|
108
|
-
def push(value)
|
109
|
-
@parent, @top = @top, value
|
110
|
-
end
|
111
|
-
|
112
|
-
# Bind a key (which may be nil for items in an array) to the provided value.
|
113
|
-
def bind(key, value)
|
114
|
-
if top.is_a? Array
|
115
|
-
if key
|
116
|
-
if top[-1].is_a?(Hash) && ! top[-1].key?(key)
|
117
|
-
top[-1][key] = value
|
118
|
-
else
|
119
|
-
top << {key => value}
|
120
|
-
end
|
121
|
-
push top.last
|
122
|
-
return top[key]
|
123
|
-
else
|
124
|
-
top << value
|
125
|
-
return value
|
126
|
-
end
|
127
|
-
elsif top.is_a? Hash
|
128
|
-
key = CGI.unescape(key)
|
129
|
-
parent << (@top = {}) if top.key?(key) && parent.is_a?(Array)
|
130
|
-
|
131
|
-
if top.include?(key) && value.is_a?(String)
|
132
|
-
warn "Rack::NestedParams' parsing behavior will change in rack-contrib 2.0"
|
133
|
-
warn "Currently 'foo=1&foo=2' is parsed to {'foo' => '1'}, in 2.0 it will be parsed to {'foo' => '2'}"
|
134
|
-
end
|
135
|
-
|
136
|
-
top[key] ||= value
|
137
|
-
return top[key]
|
138
|
-
else
|
139
|
-
raise ArgumentError, "Don't know what to do: top is #{top.inspect}"
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def type_conflict!(klass, value)
|
144
|
-
raise TypeError, "Conflicting types for parameter containers. Expected an instance of #{klass} but found an instance of #{value.class}. This can be caused by colliding Array and Hash parameters like qs[]=value&qs[key]=value. (The parameters received were #{value.inspect}.)"
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
31
|
end
|
149
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-contrib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- rack-devel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-11-
|
11
|
+
date: 2017-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -72,54 +72,48 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0.
|
75
|
+
version: '0.6'
|
76
76
|
- - ">="
|
77
77
|
- !ruby/object:Gem::Version
|
78
|
-
version: 0.
|
78
|
+
version: 0.6.8
|
79
79
|
type: :development
|
80
80
|
prerelease: false
|
81
81
|
version_requirements: !ruby/object:Gem::Requirement
|
82
82
|
requirements:
|
83
83
|
- - "~>"
|
84
84
|
- !ruby/object:Gem::Version
|
85
|
-
version: '0.
|
85
|
+
version: '0.6'
|
86
86
|
- - ">="
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version: 0.
|
88
|
+
version: 0.6.8
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
90
|
name: json
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
92
92
|
requirements:
|
93
93
|
- - "~>"
|
94
94
|
- !ruby/object:Gem::Version
|
95
|
-
version: '
|
96
|
-
- - ">="
|
97
|
-
- !ruby/object:Gem::Version
|
98
|
-
version: 1.8.5
|
95
|
+
version: '2.0'
|
99
96
|
type: :development
|
100
97
|
prerelease: false
|
101
98
|
version_requirements: !ruby/object:Gem::Requirement
|
102
99
|
requirements:
|
103
100
|
- - "~>"
|
104
101
|
- !ruby/object:Gem::Version
|
105
|
-
version: '
|
106
|
-
- - ">="
|
107
|
-
- !ruby/object:Gem::Version
|
108
|
-
version: 1.8.5
|
102
|
+
version: '2.0'
|
109
103
|
- !ruby/object:Gem::Dependency
|
110
104
|
name: mime-types
|
111
105
|
requirement: !ruby/object:Gem::Requirement
|
112
106
|
requirements:
|
113
|
-
- - "
|
107
|
+
- - "~>"
|
114
108
|
- !ruby/object:Gem::Version
|
115
|
-
version: '3'
|
109
|
+
version: '3.0'
|
116
110
|
type: :development
|
117
111
|
prerelease: false
|
118
112
|
version_requirements: !ruby/object:Gem::Requirement
|
119
113
|
requirements:
|
120
|
-
- - "
|
114
|
+
- - "~>"
|
121
115
|
- !ruby/object:Gem::Version
|
122
|
-
version: '3'
|
116
|
+
version: '3.0'
|
123
117
|
- !ruby/object:Gem::Dependency
|
124
118
|
name: minitest
|
125
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -155,6 +149,9 @@ dependencies:
|
|
155
149
|
- - "~>"
|
156
150
|
- !ruby/object:Gem::Version
|
157
151
|
version: '2.3'
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: 2.6.4
|
158
155
|
type: :development
|
159
156
|
prerelease: false
|
160
157
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -162,6 +159,9 @@ dependencies:
|
|
162
159
|
- - "~>"
|
163
160
|
- !ruby/object:Gem::Version
|
164
161
|
version: '2.3'
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: 2.6.4
|
165
165
|
- !ruby/object:Gem::Dependency
|
166
166
|
name: nbio-csshttprequest
|
167
167
|
requirement: !ruby/object:Gem::Requirement
|
@@ -202,14 +202,14 @@ dependencies:
|
|
202
202
|
requirements:
|
203
203
|
- - "~>"
|
204
204
|
- !ruby/object:Gem::Version
|
205
|
-
version: '
|
205
|
+
version: '5.0'
|
206
206
|
type: :development
|
207
207
|
prerelease: false
|
208
208
|
version_requirements: !ruby/object:Gem::Requirement
|
209
209
|
requirements:
|
210
210
|
- - "~>"
|
211
211
|
- !ruby/object:Gem::Version
|
212
|
-
version: '
|
212
|
+
version: '5.0'
|
213
213
|
- !ruby/object:Gem::Dependency
|
214
214
|
name: ruby-prof
|
215
215
|
requirement: !ruby/object:Gem::Requirement
|
@@ -236,7 +236,6 @@ files:
|
|
236
236
|
- COPYING
|
237
237
|
- README.md
|
238
238
|
- lib/rack/contrib.rb
|
239
|
-
- lib/rack/contrib/accept_format.rb
|
240
239
|
- lib/rack/contrib/access.rb
|
241
240
|
- lib/rack/contrib/backstage.rb
|
242
241
|
- lib/rack/contrib/bounce_favicon.rb
|
@@ -267,7 +266,6 @@ files:
|
|
267
266
|
- lib/rack/contrib/response_headers.rb
|
268
267
|
- lib/rack/contrib/route_exceptions.rb
|
269
268
|
- lib/rack/contrib/runtime.rb
|
270
|
-
- lib/rack/contrib/sendfile.rb
|
271
269
|
- lib/rack/contrib/signals.rb
|
272
270
|
- lib/rack/contrib/simple_endpoint.rb
|
273
271
|
- lib/rack/contrib/static_cache.rb
|
@@ -291,7 +289,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
291
289
|
requirements:
|
292
290
|
- - ">="
|
293
291
|
- !ruby/object:Gem::Version
|
294
|
-
version:
|
292
|
+
version: 2.2.2
|
295
293
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
296
294
|
requirements:
|
297
295
|
- - ">="
|
@@ -1,66 +0,0 @@
|
|
1
|
-
module Rack
|
2
|
-
#
|
3
|
-
# CAUTION: THIS MIDDLEWARE IS DEPRECATED. DO NOT USE IT.
|
4
|
-
#
|
5
|
-
# This middleware is slated for removal as of rack-contrib 2.0.0, because
|
6
|
-
# it is terribad. Applications should *always* use the `Accept` header to
|
7
|
-
# detect response formats (when it is available), rather than ignoring
|
8
|
-
# that and instead examining the extension of the request. We recommend
|
9
|
-
# using the `rack-accept` gem for handling the `Accept` family of entity
|
10
|
-
# request headers.
|
11
|
-
#
|
12
|
-
# A Rack middleware for automatically adding a <tt>format</tt> token at the end of the request path
|
13
|
-
# when there is none. It can detect formats passed in the HTTP_ACCEPT header to populate this token.
|
14
|
-
#
|
15
|
-
# e.g.:
|
16
|
-
# GET /some/resource HTTP/1.1
|
17
|
-
# Accept: application/json
|
18
|
-
# ->
|
19
|
-
# GET /some/resource.json HTTP/1.1
|
20
|
-
# Accept: application/json
|
21
|
-
#
|
22
|
-
# You can add custom types with this kind of function (taken from sinatra):
|
23
|
-
# def mime(ext, type)
|
24
|
-
# ext = ".#{ext}" unless ext.to_s[0] == ?.
|
25
|
-
# Rack::Mime::MIME_TYPES[ext.to_s] = type
|
26
|
-
# end
|
27
|
-
# and then:
|
28
|
-
# mime :json, 'application/json'
|
29
|
-
#
|
30
|
-
# Note: it does not take into account multiple media types in the Accept header.
|
31
|
-
# The first media type takes precedence over all the others.
|
32
|
-
#
|
33
|
-
# MIT-License - Cyril Rohr
|
34
|
-
#
|
35
|
-
class AcceptFormat
|
36
|
-
def self.deprecation_acknowledged
|
37
|
-
@deprecation_acknowledged
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.acknowledge_deprecation
|
41
|
-
@deprecation_acknowledged = true
|
42
|
-
end
|
43
|
-
|
44
|
-
def initialize(app, default_extention = '.html')
|
45
|
-
unless self.class.deprecation_acknowledged
|
46
|
-
warn "Rack::AcceptFormat is DEPRECATED and will be removed in rack-contrib 2.0.0"
|
47
|
-
warn "Please see this middleware's documentation for more info."
|
48
|
-
end
|
49
|
-
@ext = default_extention.to_s.strip
|
50
|
-
@ext = ".#{@ext}" unless @ext[0] == ?.
|
51
|
-
@app = app
|
52
|
-
end
|
53
|
-
|
54
|
-
def call(env)
|
55
|
-
req = Rack::Request.new(env)
|
56
|
-
|
57
|
-
if ::File.extname(req.path_info).empty?
|
58
|
-
accept = env['HTTP_ACCEPT'].to_s.scan(/[^;,\s]*\/[^;,\s]*/)[0].to_s
|
59
|
-
extension = Rack::Mime::MIME_TYPES.invert[accept] || @ext
|
60
|
-
req.path_info = req.path_info.chomp('/') << "#{extension}"
|
61
|
-
end
|
62
|
-
|
63
|
-
@app.call(env)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,138 +0,0 @@
|
|
1
|
-
require 'rack/file'
|
2
|
-
|
3
|
-
warn "rack-contrib deprecation warning: the rack-contrib version of Rack::Sendfile is deprecated and will be removed in rack-contrib 2.0. Please use the Rack::Sendfile from Rack 2.x instead."
|
4
|
-
|
5
|
-
module Rack
|
6
|
-
|
7
|
-
#
|
8
|
-
# The Sendfile middleware intercepts responses whose body is being
|
9
|
-
# served from a file and replaces it with a server specific X-Sendfile
|
10
|
-
# header. The web server is then responsible for writing the file contents
|
11
|
-
# to the client. This can dramatically reduce the amount of work required
|
12
|
-
# by the Ruby backend and takes advantage of the web servers optimized file
|
13
|
-
# delivery code.
|
14
|
-
#
|
15
|
-
# In order to take advantage of this middleware, the response body must
|
16
|
-
# respond to +to_path+ and the request must include an X-Sendfile-Type
|
17
|
-
# header. Rack::File and other components implement +to_path+ so there's
|
18
|
-
# rarely anything you need to do in your application. The X-Sendfile-Type
|
19
|
-
# header is typically set in your web servers configuration. The following
|
20
|
-
# sections attempt to document
|
21
|
-
#
|
22
|
-
# === Nginx
|
23
|
-
#
|
24
|
-
# Nginx supports the X-Accel-Redirect header. This is similar to X-Sendfile
|
25
|
-
# but requires parts of the filesystem to be mapped into a private URL
|
26
|
-
# hierarachy.
|
27
|
-
#
|
28
|
-
# The following example shows the Nginx configuration required to create
|
29
|
-
# a private "/files/" area, enable X-Accel-Redirect, and pass the special
|
30
|
-
# X-Sendfile-Type and X-Accel-Mapping headers to the backend:
|
31
|
-
#
|
32
|
-
# location /files/ {
|
33
|
-
# internal;
|
34
|
-
# alias /var/www/;
|
35
|
-
# }
|
36
|
-
#
|
37
|
-
# location / {
|
38
|
-
# proxy_redirect false;
|
39
|
-
#
|
40
|
-
# proxy_set_header Host $host;
|
41
|
-
# proxy_set_header X-Real-IP $remote_addr;
|
42
|
-
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
43
|
-
#
|
44
|
-
# proxy_set_header X-Sendfile-Type X-Accel-Redirect
|
45
|
-
# proxy_set_header X-Accel-Mapping /files/=/var/www/;
|
46
|
-
#
|
47
|
-
# proxy_pass http://127.0.0.1:8080/;
|
48
|
-
# }
|
49
|
-
#
|
50
|
-
# Note that the X-Sendfile-Type header must be set exactly as shown above. The
|
51
|
-
# X-Accel-Mapping header should specify the name of the private URL pattern,
|
52
|
-
# followed by an equals sign (=), followed by the location on the file system
|
53
|
-
# that it maps to. The middleware performs a simple substitution on the
|
54
|
-
# resulting path.
|
55
|
-
#
|
56
|
-
# See Also: http://wiki.codemongers.com/NginxXSendfile
|
57
|
-
#
|
58
|
-
# === lighttpd
|
59
|
-
#
|
60
|
-
# Lighttpd has supported some variation of the X-Sendfile header for some
|
61
|
-
# time, although only recent version support X-Sendfile in a reverse proxy
|
62
|
-
# configuration.
|
63
|
-
#
|
64
|
-
# $HTTP["host"] == "example.com" {
|
65
|
-
# proxy-core.protocol = "http"
|
66
|
-
# proxy-core.balancer = "round-robin"
|
67
|
-
# proxy-core.backends = (
|
68
|
-
# "127.0.0.1:8000",
|
69
|
-
# "127.0.0.1:8001",
|
70
|
-
# ...
|
71
|
-
# )
|
72
|
-
#
|
73
|
-
# proxy-core.allow-x-sendfile = "enable"
|
74
|
-
# proxy-core.rewrite-request = (
|
75
|
-
# "X-Sendfile-Type" => (".*" => "X-Sendfile")
|
76
|
-
# )
|
77
|
-
# }
|
78
|
-
#
|
79
|
-
# See Also: http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModProxyCore
|
80
|
-
#
|
81
|
-
# === Apache
|
82
|
-
#
|
83
|
-
# X-Sendfile is supported under Apache 2.x using a separate module:
|
84
|
-
#
|
85
|
-
# http://tn123.ath.cx/mod_xsendfile/
|
86
|
-
#
|
87
|
-
# Once the module is compiled and installed, you can enable it using
|
88
|
-
# XSendFile config directive:
|
89
|
-
#
|
90
|
-
# RequestHeader Set X-Sendfile-Type X-Sendfile
|
91
|
-
# ProxyPassReverse / http://localhost:8001/
|
92
|
-
# XSendFile on
|
93
|
-
|
94
|
-
class Sendfile
|
95
|
-
def initialize(app, variation=nil)
|
96
|
-
@app = app
|
97
|
-
@variation = variation
|
98
|
-
end
|
99
|
-
|
100
|
-
def call(env)
|
101
|
-
status, headers, body = @app.call(env)
|
102
|
-
if body.respond_to?(:to_path)
|
103
|
-
case type = variation(env)
|
104
|
-
when 'X-Accel-Redirect'
|
105
|
-
path = ::File.expand_path(body.to_path)
|
106
|
-
if url = map_accel_path(env, path)
|
107
|
-
headers[type] = url
|
108
|
-
body = []
|
109
|
-
else
|
110
|
-
env['rack.errors'] << "X-Accel-Mapping header missing"
|
111
|
-
end
|
112
|
-
when 'X-Sendfile', 'X-Lighttpd-Send-File'
|
113
|
-
path = ::File.expand_path(body.to_path)
|
114
|
-
headers[type] = path
|
115
|
-
body = []
|
116
|
-
when '', nil
|
117
|
-
else
|
118
|
-
env['rack.errors'] << "Unknown x-sendfile variation: '#{variation}'.\n"
|
119
|
-
end
|
120
|
-
end
|
121
|
-
[status, headers, body]
|
122
|
-
end
|
123
|
-
|
124
|
-
private
|
125
|
-
def variation(env)
|
126
|
-
@variation ||
|
127
|
-
env['sendfile.type'] ||
|
128
|
-
env['HTTP_X_SENDFILE_TYPE']
|
129
|
-
end
|
130
|
-
|
131
|
-
def map_accel_path(env, file)
|
132
|
-
if mapping = env['HTTP_X_ACCEL_MAPPING']
|
133
|
-
internal, external = mapping.split('=', 2).map{ |p| p.strip }
|
134
|
-
file.sub(/^#{internal}/i, external)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|