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.
Files changed (93) hide show
  1. data/README.md +19 -0
  2. data/lib/egalite/version.rb +1 -1
  3. data/lib/egalite.rb +11 -2
  4. data/test/test_auth.rb +1 -2
  5. data/test/test_blank.rb +2 -3
  6. data/test/test_errorconsole.rb +5 -5
  7. data/test/test_keitai.rb +2 -2
  8. data/test/test_m17n.rb +1 -3
  9. data/test/test_template.rb +11 -0
  10. metadata +4 -87
  11. data/auth/basic.rb +0 -32
  12. data/blank.rb +0 -53
  13. data/egalite.rb +0 -742
  14. data/errorconsole.rb +0 -77
  15. data/helper.rb +0 -251
  16. data/keitai/keitai.rb +0 -107
  17. data/keitai/ketai.rb +0 -11
  18. data/keitai/rack/ketai/carrier/abstract.rb +0 -131
  19. data/keitai/rack/ketai/carrier/au.rb +0 -78
  20. data/keitai/rack/ketai/carrier/docomo.rb +0 -80
  21. data/keitai/rack/ketai/carrier/emoji/ausjisstrtoemojiid.rb +0 -1391
  22. data/keitai/rack/ketai/carrier/emoji/docomosjisstrtoemojiid.rb +0 -759
  23. data/keitai/rack/ketai/carrier/emoji/emojidata.rb +0 -836
  24. data/keitai/rack/ketai/carrier/emoji/softbankutf8strtoemojiid.rb +0 -1119
  25. data/keitai/rack/ketai/carrier/emoji/softbankwebcodetoutf8str.rb +0 -499
  26. data/keitai/rack/ketai/carrier/iphone.rb +0 -8
  27. data/keitai/rack/ketai/carrier/softbank.rb +0 -82
  28. data/keitai/rack/ketai/carrier.rb +0 -17
  29. data/keitai/rack/ketai/middleware.rb +0 -24
  30. data/m17n.rb +0 -193
  31. data/rack/auth/abstract/handler.rb +0 -37
  32. data/rack/auth/abstract/request.rb +0 -37
  33. data/rack/auth/basic.rb +0 -58
  34. data/rack/auth/digest/md5.rb +0 -124
  35. data/rack/auth/digest/nonce.rb +0 -51
  36. data/rack/auth/digest/params.rb +0 -55
  37. data/rack/auth/digest/request.rb +0 -40
  38. data/rack/builder.rb +0 -80
  39. data/rack/cascade.rb +0 -41
  40. data/rack/chunked.rb +0 -49
  41. data/rack/commonlogger.rb +0 -49
  42. data/rack/conditionalget.rb +0 -47
  43. data/rack/config.rb +0 -15
  44. data/rack/content_length.rb +0 -29
  45. data/rack/content_type.rb +0 -23
  46. data/rack/deflater.rb +0 -96
  47. data/rack/directory.rb +0 -157
  48. data/rack/etag.rb +0 -32
  49. data/rack/file.rb +0 -92
  50. data/rack/handler/cgi.rb +0 -62
  51. data/rack/handler/evented_mongrel.rb +0 -8
  52. data/rack/handler/fastcgi.rb +0 -89
  53. data/rack/handler/lsws.rb +0 -63
  54. data/rack/handler/mongrel.rb +0 -90
  55. data/rack/handler/scgi.rb +0 -59
  56. data/rack/handler/swiftiplied_mongrel.rb +0 -8
  57. data/rack/handler/thin.rb +0 -18
  58. data/rack/handler/webrick.rb +0 -73
  59. data/rack/handler.rb +0 -88
  60. data/rack/head.rb +0 -19
  61. data/rack/lint.rb +0 -567
  62. data/rack/lobster.rb +0 -65
  63. data/rack/lock.rb +0 -16
  64. data/rack/logger.rb +0 -20
  65. data/rack/methodoverride.rb +0 -27
  66. data/rack/mime.rb +0 -208
  67. data/rack/mock.rb +0 -190
  68. data/rack/nulllogger.rb +0 -18
  69. data/rack/recursive.rb +0 -61
  70. data/rack/reloader.rb +0 -109
  71. data/rack/request.rb +0 -273
  72. data/rack/response.rb +0 -150
  73. data/rack/rewindable_input.rb +0 -103
  74. data/rack/runtime.rb +0 -27
  75. data/rack/sendfile.rb +0 -144
  76. data/rack/server.rb +0 -271
  77. data/rack/session/abstract/id.rb +0 -140
  78. data/rack/session/cookie.rb +0 -90
  79. data/rack/session/memcache.rb +0 -119
  80. data/rack/session/pool.rb +0 -100
  81. data/rack/showexceptions.rb +0 -349
  82. data/rack/showstatus.rb +0 -106
  83. data/rack/static.rb +0 -38
  84. data/rack/urlmap.rb +0 -55
  85. data/rack/utils.rb +0 -662
  86. data/rack.rb +0 -81
  87. data/route.rb +0 -231
  88. data/sendmail.rb +0 -222
  89. data/sequel_helper.rb +0 -20
  90. data/session.rb +0 -132
  91. data/stringify_hash.rb +0 -63
  92. data/support.rb +0 -35
  93. 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
@@ -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