egalite 0.0.7 → 1.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.
- data/README.md +19 -0
- data/lib/egalite/version.rb +1 -1
- data/lib/egalite.rb +11 -2
- data/test/test_auth.rb +1 -2
- data/test/test_blank.rb +2 -3
- data/test/test_errorconsole.rb +5 -5
- data/test/test_keitai.rb +2 -2
- data/test/test_m17n.rb +1 -3
- data/test/test_template.rb +11 -0
- metadata +4 -87
- data/auth/basic.rb +0 -32
- data/blank.rb +0 -53
- data/egalite.rb +0 -742
- data/errorconsole.rb +0 -77
- data/helper.rb +0 -251
- data/keitai/keitai.rb +0 -107
- data/keitai/ketai.rb +0 -11
- data/keitai/rack/ketai/carrier/abstract.rb +0 -131
- data/keitai/rack/ketai/carrier/au.rb +0 -78
- data/keitai/rack/ketai/carrier/docomo.rb +0 -80
- data/keitai/rack/ketai/carrier/emoji/ausjisstrtoemojiid.rb +0 -1391
- data/keitai/rack/ketai/carrier/emoji/docomosjisstrtoemojiid.rb +0 -759
- data/keitai/rack/ketai/carrier/emoji/emojidata.rb +0 -836
- data/keitai/rack/ketai/carrier/emoji/softbankutf8strtoemojiid.rb +0 -1119
- data/keitai/rack/ketai/carrier/emoji/softbankwebcodetoutf8str.rb +0 -499
- data/keitai/rack/ketai/carrier/iphone.rb +0 -8
- data/keitai/rack/ketai/carrier/softbank.rb +0 -82
- data/keitai/rack/ketai/carrier.rb +0 -17
- data/keitai/rack/ketai/middleware.rb +0 -24
- data/m17n.rb +0 -193
- data/rack/auth/abstract/handler.rb +0 -37
- data/rack/auth/abstract/request.rb +0 -37
- data/rack/auth/basic.rb +0 -58
- data/rack/auth/digest/md5.rb +0 -124
- data/rack/auth/digest/nonce.rb +0 -51
- data/rack/auth/digest/params.rb +0 -55
- data/rack/auth/digest/request.rb +0 -40
- data/rack/builder.rb +0 -80
- data/rack/cascade.rb +0 -41
- data/rack/chunked.rb +0 -49
- data/rack/commonlogger.rb +0 -49
- data/rack/conditionalget.rb +0 -47
- data/rack/config.rb +0 -15
- data/rack/content_length.rb +0 -29
- data/rack/content_type.rb +0 -23
- data/rack/deflater.rb +0 -96
- data/rack/directory.rb +0 -157
- data/rack/etag.rb +0 -32
- data/rack/file.rb +0 -92
- data/rack/handler/cgi.rb +0 -62
- data/rack/handler/evented_mongrel.rb +0 -8
- data/rack/handler/fastcgi.rb +0 -89
- data/rack/handler/lsws.rb +0 -63
- data/rack/handler/mongrel.rb +0 -90
- data/rack/handler/scgi.rb +0 -59
- data/rack/handler/swiftiplied_mongrel.rb +0 -8
- data/rack/handler/thin.rb +0 -18
- data/rack/handler/webrick.rb +0 -73
- data/rack/handler.rb +0 -88
- data/rack/head.rb +0 -19
- data/rack/lint.rb +0 -567
- data/rack/lobster.rb +0 -65
- data/rack/lock.rb +0 -16
- data/rack/logger.rb +0 -20
- data/rack/methodoverride.rb +0 -27
- data/rack/mime.rb +0 -208
- data/rack/mock.rb +0 -190
- data/rack/nulllogger.rb +0 -18
- data/rack/recursive.rb +0 -61
- data/rack/reloader.rb +0 -109
- data/rack/request.rb +0 -273
- data/rack/response.rb +0 -150
- data/rack/rewindable_input.rb +0 -103
- data/rack/runtime.rb +0 -27
- data/rack/sendfile.rb +0 -144
- data/rack/server.rb +0 -271
- data/rack/session/abstract/id.rb +0 -140
- data/rack/session/cookie.rb +0 -90
- data/rack/session/memcache.rb +0 -119
- data/rack/session/pool.rb +0 -100
- data/rack/showexceptions.rb +0 -349
- data/rack/showstatus.rb +0 -106
- data/rack/static.rb +0 -38
- data/rack/urlmap.rb +0 -55
- data/rack/utils.rb +0 -662
- data/rack.rb +0 -81
- data/route.rb +0 -231
- data/sendmail.rb +0 -222
- data/sequel_helper.rb +0 -20
- data/session.rb +0 -132
- data/stringify_hash.rb +0 -63
- data/support.rb +0 -35
- data/template.rb +0 -287
data/rack/request.rb
DELETED
@@ -1,273 +0,0 @@
|
|
1
|
-
require 'rack/utils'
|
2
|
-
|
3
|
-
module Rack
|
4
|
-
# Rack::Request provides a convenient interface to a Rack
|
5
|
-
# environment. It is stateless, the environment +env+ passed to the
|
6
|
-
# constructor will be directly modified.
|
7
|
-
#
|
8
|
-
# req = Rack::Request.new(env)
|
9
|
-
# req.post?
|
10
|
-
# req.params["data"]
|
11
|
-
#
|
12
|
-
# The environment hash passed will store a reference to the Request object
|
13
|
-
# instantiated so that it will only instantiate if an instance of the Request
|
14
|
-
# object doesn't already exist.
|
15
|
-
|
16
|
-
class Request
|
17
|
-
# The environment of the request.
|
18
|
-
attr_reader :env
|
19
|
-
|
20
|
-
def initialize(env)
|
21
|
-
@env = env
|
22
|
-
end
|
23
|
-
|
24
|
-
def body; @env["rack.input"] end
|
25
|
-
def scheme; @env["rack.url_scheme"] end
|
26
|
-
def script_name; @env["SCRIPT_NAME"].to_s end
|
27
|
-
def path_info; @env["PATH_INFO"].to_s end
|
28
|
-
def port; @env["SERVER_PORT"].to_i end
|
29
|
-
def request_method; @env["REQUEST_METHOD"] end
|
30
|
-
def query_string; @env["QUERY_STRING"].to_s end
|
31
|
-
def content_length; @env['CONTENT_LENGTH'] end
|
32
|
-
def content_type; @env['CONTENT_TYPE'] end
|
33
|
-
def session; @env['rack.session'] ||= {} end
|
34
|
-
def session_options; @env['rack.session.options'] ||= {} end
|
35
|
-
def logger; @env['rack.logger'] end
|
36
|
-
|
37
|
-
# The media type (type/subtype) portion of the CONTENT_TYPE header
|
38
|
-
# without any media type parameters. e.g., when CONTENT_TYPE is
|
39
|
-
# "text/plain;charset=utf-8", the media-type is "text/plain".
|
40
|
-
#
|
41
|
-
# For more information on the use of media types in HTTP, see:
|
42
|
-
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
|
43
|
-
def media_type
|
44
|
-
content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase
|
45
|
-
end
|
46
|
-
|
47
|
-
# The media type parameters provided in CONTENT_TYPE as a Hash, or
|
48
|
-
# an empty Hash if no CONTENT_TYPE or media-type parameters were
|
49
|
-
# provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8",
|
50
|
-
# this method responds with the following Hash:
|
51
|
-
# { 'charset' => 'utf-8' }
|
52
|
-
def media_type_params
|
53
|
-
return {} if content_type.nil?
|
54
|
-
content_type.split(/\s*[;,]\s*/)[1..-1].
|
55
|
-
collect { |s| s.split('=', 2) }.
|
56
|
-
inject({}) { |hash,(k,v)| hash[k.downcase] = v ; hash }
|
57
|
-
end
|
58
|
-
|
59
|
-
# The character set of the request body if a "charset" media type
|
60
|
-
# parameter was given, or nil if no "charset" was specified. Note
|
61
|
-
# that, per RFC2616, text/* media types that specify no explicit
|
62
|
-
# charset are to be considered ISO-8859-1.
|
63
|
-
def content_charset
|
64
|
-
media_type_params['charset']
|
65
|
-
end
|
66
|
-
|
67
|
-
def host_with_port
|
68
|
-
if forwarded = @env["HTTP_X_FORWARDED_HOST"]
|
69
|
-
forwarded.split(/,\s?/).last
|
70
|
-
else
|
71
|
-
@env['HTTP_HOST'] || "#{@env['SERVER_NAME'] || @env['SERVER_ADDR']}:#{@env['SERVER_PORT']}"
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def host
|
76
|
-
# Remove port number.
|
77
|
-
host_with_port.to_s.gsub(/:\d+\z/, '')
|
78
|
-
end
|
79
|
-
|
80
|
-
def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end
|
81
|
-
def path_info=(s); @env["PATH_INFO"] = s.to_s end
|
82
|
-
|
83
|
-
def delete?; request_method == "DELETE" end
|
84
|
-
def get?; request_method == "GET" end
|
85
|
-
def head?; request_method == "HEAD" end
|
86
|
-
def options?; request_method == "OPTIONS" end
|
87
|
-
def post?; request_method == "POST" end
|
88
|
-
def put?; request_method == "PUT" end
|
89
|
-
def trace?; request_method == "TRACE" end
|
90
|
-
|
91
|
-
# The set of form-data media-types. Requests that do not indicate
|
92
|
-
# one of the media types presents in this list will not be eligible
|
93
|
-
# for form-data / param parsing.
|
94
|
-
FORM_DATA_MEDIA_TYPES = [
|
95
|
-
'application/x-www-form-urlencoded',
|
96
|
-
'multipart/form-data'
|
97
|
-
]
|
98
|
-
|
99
|
-
# The set of media-types. Requests that do not indicate
|
100
|
-
# one of the media types presents in this list will not be eligible
|
101
|
-
# for param parsing like soap attachments or generic multiparts
|
102
|
-
PARSEABLE_DATA_MEDIA_TYPES = [
|
103
|
-
'multipart/related',
|
104
|
-
'multipart/mixed'
|
105
|
-
]
|
106
|
-
|
107
|
-
# Determine whether the request body contains form-data by checking
|
108
|
-
# the request Content-Type for one of the media-types:
|
109
|
-
# "application/x-www-form-urlencoded" or "multipart/form-data". The
|
110
|
-
# list of form-data media types can be modified through the
|
111
|
-
# +FORM_DATA_MEDIA_TYPES+ array.
|
112
|
-
#
|
113
|
-
# A request body is also assumed to contain form-data when no
|
114
|
-
# Content-Type header is provided and the request_method is POST.
|
115
|
-
def form_data?
|
116
|
-
type = media_type
|
117
|
-
meth = env["rack.methodoverride.original_method"] || env['REQUEST_METHOD']
|
118
|
-
(meth == 'POST' && type.nil?) || FORM_DATA_MEDIA_TYPES.include?(type)
|
119
|
-
end
|
120
|
-
|
121
|
-
# Determine whether the request body contains data by checking
|
122
|
-
# the request media_type against registered parse-data media-types
|
123
|
-
def parseable_data?
|
124
|
-
PARSEABLE_DATA_MEDIA_TYPES.include?(media_type)
|
125
|
-
end
|
126
|
-
|
127
|
-
# Returns the data recieved in the query string.
|
128
|
-
def GET
|
129
|
-
if @env["rack.request.query_string"] == query_string
|
130
|
-
@env["rack.request.query_hash"]
|
131
|
-
else
|
132
|
-
@env["rack.request.query_string"] = query_string
|
133
|
-
@env["rack.request.query_hash"] = parse_query(query_string)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
# Returns the data recieved in the request body.
|
138
|
-
#
|
139
|
-
# This method support both application/x-www-form-urlencoded and
|
140
|
-
# multipart/form-data.
|
141
|
-
def POST
|
142
|
-
if @env["rack.input"].nil?
|
143
|
-
raise "Missing rack.input"
|
144
|
-
elsif @env["rack.request.form_input"].eql? @env["rack.input"]
|
145
|
-
@env["rack.request.form_hash"]
|
146
|
-
elsif form_data? || parseable_data?
|
147
|
-
@env["rack.request.form_input"] = @env["rack.input"]
|
148
|
-
unless @env["rack.request.form_hash"] = parse_multipart(env)
|
149
|
-
form_vars = @env["rack.input"].read
|
150
|
-
|
151
|
-
# Fix for Safari Ajax postings that always append \0
|
152
|
-
form_vars.sub!(/\0\z/, '')
|
153
|
-
|
154
|
-
@env["rack.request.form_vars"] = form_vars
|
155
|
-
@env["rack.request.form_hash"] = parse_query(form_vars)
|
156
|
-
|
157
|
-
@env["rack.input"].rewind
|
158
|
-
end
|
159
|
-
@env["rack.request.form_hash"]
|
160
|
-
else
|
161
|
-
{}
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
# The union of GET and POST data.
|
166
|
-
def params
|
167
|
-
self.GET.update(self.POST)
|
168
|
-
rescue EOFError => e
|
169
|
-
self.GET
|
170
|
-
end
|
171
|
-
|
172
|
-
# shortcut for request.params[key]
|
173
|
-
def [](key)
|
174
|
-
params[key.to_s]
|
175
|
-
end
|
176
|
-
|
177
|
-
# shortcut for request.params[key] = value
|
178
|
-
def []=(key, value)
|
179
|
-
params[key.to_s] = value
|
180
|
-
end
|
181
|
-
|
182
|
-
# like Hash#values_at
|
183
|
-
def values_at(*keys)
|
184
|
-
keys.map{|key| params[key] }
|
185
|
-
end
|
186
|
-
|
187
|
-
# the referer of the client or '/'
|
188
|
-
def referer
|
189
|
-
@env['HTTP_REFERER'] || '/'
|
190
|
-
end
|
191
|
-
alias referrer referer
|
192
|
-
|
193
|
-
def user_agent
|
194
|
-
@env['HTTP_USER_AGENT']
|
195
|
-
end
|
196
|
-
|
197
|
-
def cookies
|
198
|
-
return {} unless @env["HTTP_COOKIE"]
|
199
|
-
|
200
|
-
if @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"]
|
201
|
-
@env["rack.request.cookie_hash"]
|
202
|
-
else
|
203
|
-
@env["rack.request.cookie_string"] = @env["HTTP_COOKIE"]
|
204
|
-
# According to RFC 2109:
|
205
|
-
# If multiple cookies satisfy the criteria above, they are ordered in
|
206
|
-
# the Cookie header such that those with more specific Path attributes
|
207
|
-
# precede those with less specific. Ordering with respect to other
|
208
|
-
# attributes (e.g., Domain) is unspecified.
|
209
|
-
@env["rack.request.cookie_hash"] =
|
210
|
-
Utils.parse_query(@env["rack.request.cookie_string"], ';,').inject({}) {|h,(k,v)|
|
211
|
-
h[k] = Array === v ? v.first : v
|
212
|
-
h
|
213
|
-
}
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
def xhr?
|
218
|
-
@env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest"
|
219
|
-
end
|
220
|
-
|
221
|
-
# Tries to return a remake of the original request URL as a string.
|
222
|
-
def url
|
223
|
-
url = scheme + "://"
|
224
|
-
url << host
|
225
|
-
|
226
|
-
if scheme == "https" && port != 443 ||
|
227
|
-
scheme == "http" && port != 80
|
228
|
-
url << ":#{port}"
|
229
|
-
end
|
230
|
-
|
231
|
-
url << fullpath
|
232
|
-
|
233
|
-
url
|
234
|
-
end
|
235
|
-
|
236
|
-
def path
|
237
|
-
script_name + path_info
|
238
|
-
end
|
239
|
-
|
240
|
-
def fullpath
|
241
|
-
query_string.empty? ? path : "#{path}?#{query_string}"
|
242
|
-
end
|
243
|
-
|
244
|
-
def accept_encoding
|
245
|
-
@env["HTTP_ACCEPT_ENCODING"].to_s.split(/,\s*/).map do |part|
|
246
|
-
m = /^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$/.match(part) # From WEBrick
|
247
|
-
|
248
|
-
if m
|
249
|
-
[m[1], (m[2] || 1.0).to_f]
|
250
|
-
else
|
251
|
-
raise "Invalid value for Accept-Encoding: #{part.inspect}"
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
def ip
|
257
|
-
if addr = @env['HTTP_X_FORWARDED_FOR']
|
258
|
-
(addr.split(',').grep(/\d\./).first || @env['REMOTE_ADDR']).to_s.strip
|
259
|
-
else
|
260
|
-
@env['REMOTE_ADDR']
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
protected
|
265
|
-
def parse_query(qs)
|
266
|
-
Utils.parse_nested_query(qs)
|
267
|
-
end
|
268
|
-
|
269
|
-
def parse_multipart(env)
|
270
|
-
Utils::Multipart.parse_multipart(env)
|
271
|
-
end
|
272
|
-
end
|
273
|
-
end
|
data/rack/response.rb
DELETED
@@ -1,150 +0,0 @@
|
|
1
|
-
require 'rack/request'
|
2
|
-
require 'rack/utils'
|
3
|
-
require 'time'
|
4
|
-
|
5
|
-
module Rack
|
6
|
-
# Rack::Response provides a convenient interface to create a Rack
|
7
|
-
# response.
|
8
|
-
#
|
9
|
-
# It allows setting of headers and cookies, and provides useful
|
10
|
-
# defaults (a OK response containing HTML).
|
11
|
-
#
|
12
|
-
# You can use Response#write to iteratively generate your response,
|
13
|
-
# but note that this is buffered by Rack::Response until you call
|
14
|
-
# +finish+. +finish+ however can take a block inside which calls to
|
15
|
-
# +write+ are syncronous with the Rack response.
|
16
|
-
#
|
17
|
-
# Your application's +call+ should end returning Response#finish.
|
18
|
-
|
19
|
-
class Response
|
20
|
-
attr_accessor :length
|
21
|
-
|
22
|
-
def initialize(body=[], status=200, header={}, &block)
|
23
|
-
@status = status.to_i
|
24
|
-
@header = Utils::HeaderHash.new({"Content-Type" => "text/html"}.
|
25
|
-
merge(header))
|
26
|
-
|
27
|
-
@writer = lambda { |x| @body << x }
|
28
|
-
@block = nil
|
29
|
-
@length = 0
|
30
|
-
|
31
|
-
@body = []
|
32
|
-
|
33
|
-
if body.respond_to? :to_str
|
34
|
-
write body.to_str
|
35
|
-
elsif body.respond_to?(:each)
|
36
|
-
body.each { |part|
|
37
|
-
write part.to_s
|
38
|
-
}
|
39
|
-
else
|
40
|
-
raise TypeError, "stringable or iterable required"
|
41
|
-
end
|
42
|
-
|
43
|
-
yield self if block_given?
|
44
|
-
end
|
45
|
-
|
46
|
-
attr_reader :header
|
47
|
-
attr_accessor :status, :body
|
48
|
-
|
49
|
-
def [](key)
|
50
|
-
header[key]
|
51
|
-
end
|
52
|
-
|
53
|
-
def []=(key, value)
|
54
|
-
header[key] = value
|
55
|
-
end
|
56
|
-
|
57
|
-
def set_cookie(key, value)
|
58
|
-
Utils.set_cookie_header!(header, key, value)
|
59
|
-
end
|
60
|
-
|
61
|
-
def delete_cookie(key, value={})
|
62
|
-
Utils.delete_cookie_header!(header, key, value)
|
63
|
-
end
|
64
|
-
|
65
|
-
def redirect(target, status=302)
|
66
|
-
self.status = status
|
67
|
-
self["Location"] = target
|
68
|
-
end
|
69
|
-
|
70
|
-
def finish(&block)
|
71
|
-
@block = block
|
72
|
-
|
73
|
-
if [204, 304].include?(status.to_i)
|
74
|
-
header.delete "Content-Type"
|
75
|
-
[status.to_i, header, []]
|
76
|
-
else
|
77
|
-
[status.to_i, header, self]
|
78
|
-
end
|
79
|
-
end
|
80
|
-
alias to_a finish # For *response
|
81
|
-
|
82
|
-
def each(&callback)
|
83
|
-
@body.each(&callback)
|
84
|
-
@writer = callback
|
85
|
-
@block.call(self) if @block
|
86
|
-
end
|
87
|
-
|
88
|
-
# Append to body and update Content-Length.
|
89
|
-
#
|
90
|
-
# NOTE: Do not mix #write and direct #body access!
|
91
|
-
#
|
92
|
-
def write(str)
|
93
|
-
s = str.to_s
|
94
|
-
@length += Rack::Utils.bytesize(s)
|
95
|
-
@writer.call s
|
96
|
-
|
97
|
-
header["Content-Length"] = @length.to_s
|
98
|
-
str
|
99
|
-
end
|
100
|
-
|
101
|
-
def close
|
102
|
-
body.close if body.respond_to?(:close)
|
103
|
-
end
|
104
|
-
|
105
|
-
def empty?
|
106
|
-
@block == nil && @body.empty?
|
107
|
-
end
|
108
|
-
|
109
|
-
alias headers header
|
110
|
-
|
111
|
-
module Helpers
|
112
|
-
def invalid?; @status < 100 || @status >= 600; end
|
113
|
-
|
114
|
-
def informational?; @status >= 100 && @status < 200; end
|
115
|
-
def successful?; @status >= 200 && @status < 300; end
|
116
|
-
def redirection?; @status >= 300 && @status < 400; end
|
117
|
-
def client_error?; @status >= 400 && @status < 500; end
|
118
|
-
def server_error?; @status >= 500 && @status < 600; end
|
119
|
-
|
120
|
-
def ok?; @status == 200; end
|
121
|
-
def forbidden?; @status == 403; end
|
122
|
-
def not_found?; @status == 404; end
|
123
|
-
|
124
|
-
def redirect?; [301, 302, 303, 307].include? @status; end
|
125
|
-
def empty?; [201, 204, 304].include? @status; end
|
126
|
-
|
127
|
-
# Headers
|
128
|
-
attr_reader :headers, :original_headers
|
129
|
-
|
130
|
-
def include?(header)
|
131
|
-
!!headers[header]
|
132
|
-
end
|
133
|
-
|
134
|
-
def content_type
|
135
|
-
headers["Content-Type"]
|
136
|
-
end
|
137
|
-
|
138
|
-
def content_length
|
139
|
-
cl = headers["Content-Length"]
|
140
|
-
cl ? cl.to_i : cl
|
141
|
-
end
|
142
|
-
|
143
|
-
def location
|
144
|
-
headers["Location"]
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
include Helpers
|
149
|
-
end
|
150
|
-
end
|
data/rack/rewindable_input.rb
DELETED
@@ -1,103 +0,0 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
|
-
require 'tempfile'
|
3
|
-
require 'rack/utils'
|
4
|
-
|
5
|
-
module Rack
|
6
|
-
# Class which can make any IO object rewindable, including non-rewindable ones. It does
|
7
|
-
# this by buffering the data into a tempfile, which is rewindable.
|
8
|
-
#
|
9
|
-
# rack.input is required to be rewindable, so if your input stream IO is non-rewindable
|
10
|
-
# by nature (e.g. a pipe or a socket) then you can wrap it in an object of this class
|
11
|
-
# to easily make it rewindable.
|
12
|
-
#
|
13
|
-
# Don't forget to call #close when you're done. This frees up temporary resources that
|
14
|
-
# RewindableInput uses, though it does *not* close the original IO object.
|
15
|
-
class RewindableInput
|
16
|
-
def initialize(io)
|
17
|
-
@io = io
|
18
|
-
@rewindable_io = nil
|
19
|
-
@unlinked = false
|
20
|
-
end
|
21
|
-
|
22
|
-
def gets
|
23
|
-
make_rewindable unless @rewindable_io
|
24
|
-
@rewindable_io.gets
|
25
|
-
end
|
26
|
-
|
27
|
-
def read(*args)
|
28
|
-
make_rewindable unless @rewindable_io
|
29
|
-
@rewindable_io.read(*args)
|
30
|
-
end
|
31
|
-
|
32
|
-
def each(&block)
|
33
|
-
make_rewindable unless @rewindable_io
|
34
|
-
@rewindable_io.each(&block)
|
35
|
-
end
|
36
|
-
|
37
|
-
def rewind
|
38
|
-
make_rewindable unless @rewindable_io
|
39
|
-
@rewindable_io.rewind
|
40
|
-
end
|
41
|
-
|
42
|
-
# Closes this RewindableInput object without closing the originally
|
43
|
-
# wrapped IO oject. Cleans up any temporary resources that this RewindableInput
|
44
|
-
# has created.
|
45
|
-
#
|
46
|
-
# This method may be called multiple times. It does nothing on subsequent calls.
|
47
|
-
def close
|
48
|
-
if @rewindable_io
|
49
|
-
if @unlinked
|
50
|
-
@rewindable_io.close
|
51
|
-
else
|
52
|
-
@rewindable_io.close!
|
53
|
-
end
|
54
|
-
@rewindable_io = nil
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
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
|
-
def make_rewindable
|
70
|
-
# Buffer all data into a tempfile. Since this tempfile is private to this
|
71
|
-
# RewindableInput object, we chmod it so that nobody else can read or write
|
72
|
-
# it. On POSIX filesystems we also unlink the file so that it doesn't
|
73
|
-
# even have a file entry on the filesystem anymore, though we can still
|
74
|
-
# access it because we have the file handle open.
|
75
|
-
@rewindable_io = Tempfile.new('RackRewindableInput')
|
76
|
-
@rewindable_io.chmod(0000)
|
77
|
-
@rewindable_io.set_encoding(Encoding::BINARY) if @rewindable_io.respond_to?(:set_encoding)
|
78
|
-
@rewindable_io.binmode
|
79
|
-
if filesystem_has_posix_semantics?
|
80
|
-
@rewindable_io.unlink
|
81
|
-
raise 'Unlink failed. IO closed.' if @rewindable_io.closed?
|
82
|
-
@unlinked = true
|
83
|
-
end
|
84
|
-
|
85
|
-
buffer = ""
|
86
|
-
while @io.read(1024 * 4, buffer)
|
87
|
-
entire_buffer_written_out = false
|
88
|
-
while !entire_buffer_written_out
|
89
|
-
written = @rewindable_io.write(buffer)
|
90
|
-
entire_buffer_written_out = written == Rack::Utils.bytesize(buffer)
|
91
|
-
if !entire_buffer_written_out
|
92
|
-
buffer.slice!(0 .. written - 1)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
@rewindable_io.rewind
|
97
|
-
end
|
98
|
-
|
99
|
-
def filesystem_has_posix_semantics?
|
100
|
-
RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
data/rack/runtime.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
module Rack
|
2
|
-
# Sets an "X-Runtime" response header, indicating the response
|
3
|
-
# time of the request, in seconds
|
4
|
-
#
|
5
|
-
# You can put it right before the application to see the processing
|
6
|
-
# time, or before all the other middlewares to include time for them,
|
7
|
-
# too.
|
8
|
-
class Runtime
|
9
|
-
def initialize(app, name = nil)
|
10
|
-
@app = app
|
11
|
-
@header_name = "X-Runtime"
|
12
|
-
@header_name << "-#{name}" if name
|
13
|
-
end
|
14
|
-
|
15
|
-
def call(env)
|
16
|
-
start_time = Time.now
|
17
|
-
status, headers, body = @app.call(env)
|
18
|
-
request_time = Time.now - start_time
|
19
|
-
|
20
|
-
if !headers.has_key?(@header_name)
|
21
|
-
headers[@header_name] = "%0.6f" % request_time
|
22
|
-
end
|
23
|
-
|
24
|
-
[status, headers, body]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/rack/sendfile.rb
DELETED
@@ -1,144 +0,0 @@
|
|
1
|
-
require 'rack/file'
|
2
|
-
|
3
|
-
module Rack
|
4
|
-
class File #:nodoc:
|
5
|
-
unless instance_methods(false).include?('to_path')
|
6
|
-
alias :to_path :path
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
# = Sendfile
|
11
|
-
#
|
12
|
-
# The Sendfile middleware intercepts responses whose body is being
|
13
|
-
# served from a file and replaces it with a server specific X-Sendfile
|
14
|
-
# header. The web server is then responsible for writing the file contents
|
15
|
-
# to the client. This can dramatically reduce the amount of work required
|
16
|
-
# by the Ruby backend and takes advantage of the web server's optimized file
|
17
|
-
# delivery code.
|
18
|
-
#
|
19
|
-
# In order to take advantage of this middleware, the response body must
|
20
|
-
# respond to +to_path+ and the request must include an X-Sendfile-Type
|
21
|
-
# header. Rack::File and other components implement +to_path+ so there's
|
22
|
-
# rarely anything you need to do in your application. The X-Sendfile-Type
|
23
|
-
# header is typically set in your web servers configuration. The following
|
24
|
-
# sections attempt to document
|
25
|
-
#
|
26
|
-
# === Nginx
|
27
|
-
#
|
28
|
-
# Nginx supports the X-Accel-Redirect header. This is similar to X-Sendfile
|
29
|
-
# but requires parts of the filesystem to be mapped into a private URL
|
30
|
-
# hierarachy.
|
31
|
-
#
|
32
|
-
# The following example shows the Nginx configuration required to create
|
33
|
-
# a private "/files/" area, enable X-Accel-Redirect, and pass the special
|
34
|
-
# X-Sendfile-Type and X-Accel-Mapping headers to the backend:
|
35
|
-
#
|
36
|
-
# location ~ /files/(.*) {
|
37
|
-
# internal;
|
38
|
-
# alias /var/www/$1;
|
39
|
-
# }
|
40
|
-
#
|
41
|
-
# location / {
|
42
|
-
# proxy_redirect off;
|
43
|
-
#
|
44
|
-
# proxy_set_header Host $host;
|
45
|
-
# proxy_set_header X-Real-IP $remote_addr;
|
46
|
-
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
47
|
-
#
|
48
|
-
# proxy_set_header X-Sendfile-Type X-Accel-Redirect;
|
49
|
-
# proxy_set_header X-Accel-Mapping /files/=/var/www/;
|
50
|
-
#
|
51
|
-
# proxy_pass http://127.0.0.1:8080/;
|
52
|
-
# }
|
53
|
-
#
|
54
|
-
# Note that the X-Sendfile-Type header must be set exactly as shown above. The
|
55
|
-
# X-Accel-Mapping header should specify the name of the private URL pattern,
|
56
|
-
# followed by an equals sign (=), followed by the location on the file system
|
57
|
-
# that it maps to. The middleware performs a simple substitution on the
|
58
|
-
# resulting path.
|
59
|
-
#
|
60
|
-
# See Also: http://wiki.codemongers.com/NginxXSendfile
|
61
|
-
#
|
62
|
-
# === lighttpd
|
63
|
-
#
|
64
|
-
# Lighttpd has supported some variation of the X-Sendfile header for some
|
65
|
-
# time, although only recent version support X-Sendfile in a reverse proxy
|
66
|
-
# configuration.
|
67
|
-
#
|
68
|
-
# $HTTP["host"] == "example.com" {
|
69
|
-
# proxy-core.protocol = "http"
|
70
|
-
# proxy-core.balancer = "round-robin"
|
71
|
-
# proxy-core.backends = (
|
72
|
-
# "127.0.0.1:8000",
|
73
|
-
# "127.0.0.1:8001",
|
74
|
-
# ...
|
75
|
-
# )
|
76
|
-
#
|
77
|
-
# proxy-core.allow-x-sendfile = "enable"
|
78
|
-
# proxy-core.rewrite-request = (
|
79
|
-
# "X-Sendfile-Type" => (".*" => "X-Sendfile")
|
80
|
-
# )
|
81
|
-
# }
|
82
|
-
#
|
83
|
-
# See Also: http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModProxyCore
|
84
|
-
#
|
85
|
-
# === Apache
|
86
|
-
#
|
87
|
-
# X-Sendfile is supported under Apache 2.x using a separate module:
|
88
|
-
#
|
89
|
-
# http://tn123.ath.cx/mod_xsendfile/
|
90
|
-
#
|
91
|
-
# Once the module is compiled and installed, you can enable it using
|
92
|
-
# XSendFile config directive:
|
93
|
-
#
|
94
|
-
# RequestHeader Set X-Sendfile-Type X-Sendfile
|
95
|
-
# ProxyPassReverse / http://localhost:8001/
|
96
|
-
# XSendFile on
|
97
|
-
|
98
|
-
class Sendfile
|
99
|
-
F = ::File
|
100
|
-
|
101
|
-
def initialize(app, variation=nil)
|
102
|
-
@app = app
|
103
|
-
@variation = variation
|
104
|
-
end
|
105
|
-
|
106
|
-
def call(env)
|
107
|
-
status, headers, body = @app.call(env)
|
108
|
-
if body.respond_to?(:to_path)
|
109
|
-
case type = variation(env)
|
110
|
-
when 'X-Accel-Redirect'
|
111
|
-
path = F.expand_path(body.to_path)
|
112
|
-
if url = map_accel_path(env, path)
|
113
|
-
headers[type] = url
|
114
|
-
body = []
|
115
|
-
else
|
116
|
-
env['rack.errors'] << "X-Accel-Mapping header missing"
|
117
|
-
end
|
118
|
-
when 'X-Sendfile', 'X-Lighttpd-Send-File'
|
119
|
-
path = F.expand_path(body.to_path)
|
120
|
-
headers[type] = path
|
121
|
-
body = []
|
122
|
-
when '', nil
|
123
|
-
else
|
124
|
-
env['rack.errors'] << "Unknown x-sendfile variation: '#{variation}'.\n"
|
125
|
-
end
|
126
|
-
end
|
127
|
-
[status, headers, body]
|
128
|
-
end
|
129
|
-
|
130
|
-
private
|
131
|
-
def variation(env)
|
132
|
-
@variation ||
|
133
|
-
env['sendfile.type'] ||
|
134
|
-
env['HTTP_X_SENDFILE_TYPE']
|
135
|
-
end
|
136
|
-
|
137
|
-
def map_accel_path(env, file)
|
138
|
-
if mapping = env['HTTP_X_ACCEL_MAPPING']
|
139
|
-
internal, external = mapping.split('=', 2).map{ |p| p.strip }
|
140
|
-
file.sub(/^#{internal}/i, external)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|