merb-core 0.9.8 → 0.9.9
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/CONTRIBUTORS +33 -0
- data/README +7 -3
- data/Rakefile +3 -3
- data/lib/merb-core.rb +165 -94
- data/lib/merb-core/bootloader.rb +469 -100
- data/lib/merb-core/config.rb +79 -3
- data/lib/merb-core/constants.rb +24 -2
- data/lib/merb-core/controller/abstract_controller.rb +172 -67
- data/lib/merb-core/controller/exceptions.rb +50 -6
- data/lib/merb-core/controller/merb_controller.rb +215 -108
- data/lib/merb-core/controller/mime.rb +36 -12
- data/lib/merb-core/controller/mixins/authentication.rb +52 -7
- data/lib/merb-core/controller/mixins/conditional_get.rb +14 -0
- data/lib/merb-core/controller/mixins/controller.rb +90 -58
- data/lib/merb-core/controller/mixins/render.rb +34 -10
- data/lib/merb-core/controller/mixins/responder.rb +40 -16
- data/lib/merb-core/controller/template.rb +37 -16
- data/lib/merb-core/core_ext/hash.rb +9 -0
- data/lib/merb-core/core_ext/kernel.rb +92 -41
- data/lib/merb-core/dispatch/dispatcher.rb +29 -45
- data/lib/merb-core/dispatch/request.rb +186 -82
- data/lib/merb-core/dispatch/router.rb +141 -53
- data/lib/merb-core/dispatch/router/behavior.rb +296 -139
- data/lib/merb-core/dispatch/router/resources.rb +51 -19
- data/lib/merb-core/dispatch/router/route.rb +76 -23
- data/lib/merb-core/dispatch/session.rb +80 -36
- data/lib/merb-core/dispatch/session/container.rb +31 -15
- data/lib/merb-core/dispatch/session/cookie.rb +51 -22
- data/lib/merb-core/dispatch/session/memcached.rb +10 -6
- data/lib/merb-core/dispatch/session/memory.rb +17 -5
- data/lib/merb-core/dispatch/session/store_container.rb +21 -9
- data/lib/merb-core/dispatch/worker.rb +16 -2
- data/lib/merb-core/gem_ext/erubis.rb +4 -0
- data/lib/merb-core/plugins.rb +13 -0
- data/lib/merb-core/rack.rb +1 -0
- data/lib/merb-core/rack/adapter.rb +1 -0
- data/lib/merb-core/rack/adapter/abstract.rb +95 -17
- data/lib/merb-core/rack/adapter/irb.rb +50 -5
- data/lib/merb-core/rack/application.rb +27 -5
- data/lib/merb-core/rack/handler/mongrel.rb +6 -6
- data/lib/merb-core/rack/helpers.rb +33 -0
- data/lib/merb-core/rack/middleware/conditional_get.rb +1 -1
- data/lib/merb-core/rack/middleware/path_prefix.rb +3 -3
- data/lib/merb-core/rack/middleware/static.rb +11 -7
- data/lib/merb-core/server.rb +134 -69
- data/lib/merb-core/tasks/gem_management.rb +153 -80
- data/lib/merb-core/tasks/merb_rake_helper.rb +12 -4
- data/lib/merb-core/tasks/stats.rake +1 -1
- data/lib/merb-core/test/helpers/mock_request_helper.rb +29 -22
- data/lib/merb-core/test/helpers/request_helper.rb +1 -1
- data/lib/merb-core/test/helpers/route_helper.rb +50 -4
- data/lib/merb-core/test/matchers/request_matchers.rb +2 -36
- data/lib/merb-core/test/matchers/view_matchers.rb +32 -22
- data/lib/merb-core/test/run_specs.rb +6 -5
- data/lib/merb-core/test/test_ext/rspec.rb +6 -19
- data/lib/merb-core/version.rb +1 -1
- metadata +5 -4
@@ -1,12 +1,32 @@
|
|
1
1
|
module Merb
|
2
2
|
class << self
|
3
3
|
|
4
|
+
|
5
|
+
# Returns a hash of the available mime types.
|
6
|
+
#
|
4
7
|
# ==== Returns
|
5
|
-
# Hash:: The available mime types.
|
8
|
+
# Hash{Symbol => Hash{Symbol => Object}}:: The available mime types.
|
9
|
+
#
|
10
|
+
# ==== Notes
|
11
|
+
# Each entry corresponds to a call to add_mime_type, having the mime type key (:html, :xml, :json, etc.)
|
12
|
+
# as the key and a hash containing the following entries:
|
13
|
+
# :accepts # the mime types that will be recognized by this entry
|
14
|
+
# :transform_method # the method called on an object to convert it to content of this type (such as to_json)
|
15
|
+
# :content_type # the value set to the "Content-Type" HTTP header when this mime is sent in a response
|
16
|
+
# :response_headers # sent in a response using this content type
|
17
|
+
# :default_quality # the scale factor used in describing content type preference
|
18
|
+
# :response_block # the block to be called with the controller when a request responds to this mime type
|
19
|
+
#
|
20
|
+
# @api public
|
6
21
|
def available_mime_types
|
7
22
|
ResponderMixin::TYPES
|
8
23
|
end
|
9
24
|
|
25
|
+
# ==== Returns
|
26
|
+
# Hash{String => Symbol}::
|
27
|
+
# A hash mapping Content-Type values to the mime type key of the appropriate entry in #available_mime_types
|
28
|
+
#
|
29
|
+
# @api public
|
10
30
|
def available_accepts
|
11
31
|
ResponderMixin::MIMES
|
12
32
|
end
|
@@ -42,6 +62,11 @@ module Merb
|
|
42
62
|
# correctly appended to the mimetype itself.
|
43
63
|
# &block:: a block which recieves the current controller when the format
|
44
64
|
# is set (in the controller's #content_type method)
|
65
|
+
#
|
66
|
+
# ==== Returns
|
67
|
+
# nil
|
68
|
+
#
|
69
|
+
# @api public
|
45
70
|
def add_mime_type(key, transform_method, mimes, new_response_headers = {}, default_quality = 1, &block)
|
46
71
|
enforce!(key => Symbol, mimes => Array)
|
47
72
|
|
@@ -69,6 +94,8 @@ module Merb
|
|
69
94
|
render thing, opts
|
70
95
|
end
|
71
96
|
EOS
|
97
|
+
|
98
|
+
nil
|
72
99
|
end
|
73
100
|
|
74
101
|
# Removes a MIME-type from the mime-type list.
|
@@ -76,8 +103,14 @@ module Merb
|
|
76
103
|
# ==== Parameters
|
77
104
|
# key<Symbol>:: The key that represents the mime-type to remove.
|
78
105
|
#
|
106
|
+
# ==== Returns
|
107
|
+
# (Boolean, Hash{Symbol => Object}):: If it was present, the old specification of the MIME-type. Same structure
|
108
|
+
# as a value in Merb.available_mime_types. False if the key was not present.
|
109
|
+
#
|
79
110
|
# ==== Notes
|
80
111
|
# :all is the key for */*; It can't be removed.
|
112
|
+
#
|
113
|
+
# @api public
|
81
114
|
def remove_mime_type(key)
|
82
115
|
return false if key == :all
|
83
116
|
ResponderMixin::TYPES.delete(key)
|
@@ -91,21 +124,12 @@ module Merb
|
|
91
124
|
#
|
92
125
|
# ==== Raises
|
93
126
|
# ArgumentError:: The requested mime type is not valid.
|
127
|
+
#
|
128
|
+
# @api private
|
94
129
|
def mime_transform_method(key)
|
95
130
|
raise ArgumentError, ":#{key} is not a valid MIME-type" unless ResponderMixin::TYPES.key?(key)
|
96
131
|
ResponderMixin::TYPES[key][:transform_method]
|
97
132
|
end
|
98
133
|
|
99
|
-
# The mime-type for a particular inbound Accepts header.
|
100
|
-
#
|
101
|
-
# ==== Parameters
|
102
|
-
# header<String>:: The name of the header to find the mime-type for.
|
103
|
-
#
|
104
|
-
# ==== Returns
|
105
|
-
# Hash:: The mime type information.
|
106
|
-
def mime_by_request_header(header)
|
107
|
-
available_mime_types.find {|key,info| info[:accepts].include?(header)}.first
|
108
|
-
end
|
109
|
-
|
110
134
|
end
|
111
135
|
end
|
@@ -12,6 +12,9 @@ module Merb::AuthenticationMixin
|
|
12
12
|
# realm<~to_s>:: The realm to authenticate against. Defaults to 'Application'.
|
13
13
|
# &authenticator:: A block to check if the authentication is valid.
|
14
14
|
#
|
15
|
+
# ==== Returns
|
16
|
+
# Merb::AuthenticationMixin::BasicAuthentication
|
17
|
+
#
|
15
18
|
# ==== Examples
|
16
19
|
# class Application < Merb::Controller
|
17
20
|
#
|
@@ -47,7 +50,7 @@ module Merb::AuthenticationMixin
|
|
47
50
|
#
|
48
51
|
# If you need to request basic authentication inside an action you need to use the request! method.
|
49
52
|
#
|
50
|
-
# ====Example
|
53
|
+
# ==== Example
|
51
54
|
#
|
52
55
|
# class Sessions < Application
|
53
56
|
#
|
@@ -55,15 +58,24 @@ module Merb::AuthenticationMixin
|
|
55
58
|
# case content_type
|
56
59
|
# when :html
|
57
60
|
# render
|
61
|
+
#
|
58
62
|
# else
|
59
|
-
#
|
63
|
+
# user = basic_authentication.authenticate do |username, password|
|
64
|
+
# User.authenticate(username, password)
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# if user
|
68
|
+
# display(user)
|
69
|
+
# else
|
70
|
+
# basic_authentication.request
|
71
|
+
# end
|
60
72
|
# end
|
61
73
|
# end
|
62
74
|
#
|
63
75
|
# end
|
64
76
|
#
|
65
|
-
|
66
|
-
# @public
|
77
|
+
#
|
78
|
+
# @api public
|
67
79
|
def basic_authentication(realm = "Application", &authenticator)
|
68
80
|
@_basic_authentication ||= BasicAuthentication.new(self, realm, &authenticator)
|
69
81
|
end
|
@@ -72,6 +84,7 @@ module Merb::AuthenticationMixin
|
|
72
84
|
# So we can have access to the status codes
|
73
85
|
include Merb::ControllerExceptions
|
74
86
|
|
87
|
+
# @api private
|
75
88
|
def initialize(controller, realm = "Application", &authenticator)
|
76
89
|
@controller = controller
|
77
90
|
@realm = realm
|
@@ -79,6 +92,15 @@ module Merb::AuthenticationMixin
|
|
79
92
|
authenticate_or_request(&authenticator) if authenticator
|
80
93
|
end
|
81
94
|
|
95
|
+
# Determines whether or not the user is authenticated using the criteria
|
96
|
+
# in the provided authenticator block.
|
97
|
+
#
|
98
|
+
# ==== Parameters
|
99
|
+
# &authenticator:: A block that decides whether the provided username and password
|
100
|
+
# are valid.
|
101
|
+
#
|
102
|
+
# ==== Returns
|
103
|
+
# Object:: False if basic auth is not provided, otherwise the return value of the authenticator block.
|
82
104
|
def authenticate(&authenticator)
|
83
105
|
if @auth.provided? and @auth.basic?
|
84
106
|
authenticator.call(*@auth.credentials)
|
@@ -87,33 +109,56 @@ module Merb::AuthenticationMixin
|
|
87
109
|
end
|
88
110
|
end
|
89
111
|
|
112
|
+
# Request basic authentication and halt the filter chain. This is for use in a before filter.
|
113
|
+
#
|
114
|
+
# ==== Throws
|
115
|
+
# :halt with an "HTTP Basic: Access denied." message with no layout, and sets the status to Unauthorized.
|
116
|
+
#
|
117
|
+
# @api public
|
90
118
|
def request
|
91
119
|
request!
|
92
120
|
throw :halt, @controller.render("HTTP Basic: Access denied.\n", :status => Unauthorized.status, :layout => false)
|
93
121
|
end
|
94
122
|
|
95
|
-
#
|
96
|
-
#
|
123
|
+
# Sets headers to request basic auth.
|
124
|
+
#
|
125
|
+
# ==== Returns
|
126
|
+
# String:: Returns the empty string to provide a response body.
|
127
|
+
#
|
128
|
+
# @api public
|
97
129
|
def request!
|
98
130
|
@controller.status = Unauthorized.status
|
99
131
|
@controller.headers['WWW-Authenticate'] = 'Basic realm="%s"' % @realm
|
132
|
+
""
|
100
133
|
end
|
101
134
|
|
102
|
-
#
|
135
|
+
# ==== Returns
|
136
|
+
# Boolean:: Whether there has been any basic authentication credentials provided
|
137
|
+
#
|
138
|
+
# @api public
|
103
139
|
def provided?
|
104
140
|
@auth.provided?
|
105
141
|
end
|
106
142
|
|
143
|
+
# ==== Returns
|
144
|
+
# String:: The username provided in the request.
|
145
|
+
#
|
146
|
+
# @api public
|
107
147
|
def username
|
108
148
|
provided? ? @auth.credentials.first : nil
|
109
149
|
end
|
110
150
|
|
151
|
+
# ==== Returns
|
152
|
+
# String:: The password provided in the request.
|
153
|
+
#
|
154
|
+
# @api public
|
111
155
|
def password
|
112
156
|
provided? ? @auth.credentials.last : nil
|
113
157
|
end
|
114
158
|
|
115
159
|
protected
|
116
160
|
|
161
|
+
# @api private
|
117
162
|
def authenticate_or_request(&authenticator)
|
118
163
|
authenticate(&authenticator) || request
|
119
164
|
end
|
@@ -29,6 +29,8 @@ module Merb::ConditionalGetMixin
|
|
29
29
|
# tag<~to_s>::
|
30
30
|
# value of ETag header enclosed in double quotes
|
31
31
|
# as required by the RFC
|
32
|
+
#
|
33
|
+
# @api public
|
32
34
|
def etag=(tag)
|
33
35
|
headers[Merb::Const::ETAG] = %("#{tag}")
|
34
36
|
end
|
@@ -36,6 +38,8 @@ module Merb::ConditionalGetMixin
|
|
36
38
|
# ==== Returns
|
37
39
|
# <String>::
|
38
40
|
# Value of ETag response header or nil if it's not set.
|
41
|
+
#
|
42
|
+
# @api public
|
39
43
|
def etag
|
40
44
|
headers[Merb::Const::ETAG]
|
41
45
|
end
|
@@ -44,6 +48,8 @@ module Merb::ConditionalGetMixin
|
|
44
48
|
# <Boolean>::
|
45
49
|
# true if ETag response header equals If-None-Match request header,
|
46
50
|
# false otherwise
|
51
|
+
#
|
52
|
+
# @api public
|
47
53
|
def etag_matches?(tag = self.etag)
|
48
54
|
tag == self.request.if_none_match
|
49
55
|
end
|
@@ -54,6 +60,8 @@ module Merb::ConditionalGetMixin
|
|
54
60
|
# tag<Time>::
|
55
61
|
# resource modification timestamp converted into format
|
56
62
|
# required by the RFC
|
63
|
+
#
|
64
|
+
# @api public
|
57
65
|
def last_modified=(time)
|
58
66
|
headers[Merb::Const::LAST_MODIFIED] = time.httpdate
|
59
67
|
end
|
@@ -61,6 +69,8 @@ module Merb::ConditionalGetMixin
|
|
61
69
|
# ==== Returns
|
62
70
|
# <String>::
|
63
71
|
# Value of Last-Modified response header or nil if it's not set.
|
72
|
+
#
|
73
|
+
# @api public
|
64
74
|
def last_modified
|
65
75
|
Time.rfc2822(headers[Merb::Const::LAST_MODIFIED])
|
66
76
|
end
|
@@ -69,6 +79,8 @@ module Merb::ConditionalGetMixin
|
|
69
79
|
# <Boolean>::
|
70
80
|
# true if Last-Modified response header is < than
|
71
81
|
# If-Modified-Since request header value, false otherwise.
|
82
|
+
#
|
83
|
+
# @api public
|
72
84
|
def not_modified?(time = self.last_modified)
|
73
85
|
request.if_modified_since && time && time <= request.if_modified_since
|
74
86
|
end
|
@@ -77,6 +89,8 @@ module Merb::ConditionalGetMixin
|
|
77
89
|
# <Boolean>::
|
78
90
|
# true if either ETag matches or entity is not modified,
|
79
91
|
# so request is fresh; false otherwise
|
92
|
+
#
|
93
|
+
# @api public
|
80
94
|
def request_fresh?
|
81
95
|
etag_matches?(self.etag) || not_modified?(self.last_modified)
|
82
96
|
end
|
@@ -4,26 +4,27 @@ module Merb
|
|
4
4
|
|
5
5
|
# Enqueu a block to run in a background thread outside of the request
|
6
6
|
# response dispatch
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# ==== Parameters
|
9
|
-
#
|
10
|
-
#
|
9
|
+
# &blk:: proc to run later
|
10
|
+
#
|
11
11
|
# ==== Example
|
12
12
|
# run_later do
|
13
13
|
# SomeBackgroundTask.run
|
14
14
|
# end
|
15
|
-
#
|
15
|
+
#
|
16
|
+
# @api public
|
16
17
|
def run_later(&blk)
|
17
18
|
Merb::Dispatcher.work_queue << blk
|
18
19
|
end
|
19
20
|
|
20
21
|
# Renders the block given as a parameter using chunked encoding.
|
21
|
-
#
|
22
|
+
#
|
22
23
|
# ==== Parameters
|
23
|
-
# &blk::
|
24
|
+
# &blk::
|
24
25
|
# A block that, when called, will use send_chunks to send chunks of data
|
25
26
|
# down to the server. The chunking will terminate once the block returns.
|
26
|
-
#
|
27
|
+
#
|
27
28
|
# ==== Examples
|
28
29
|
# def stream
|
29
30
|
# prefix = '<p>'
|
@@ -44,6 +45,8 @@ module Merb
|
|
44
45
|
# end
|
45
46
|
# end
|
46
47
|
# end
|
48
|
+
#
|
49
|
+
# @api public
|
47
50
|
def render_chunked(&blk)
|
48
51
|
must_support_streaming!
|
49
52
|
headers['Transfer-Encoding'] = 'chunked'
|
@@ -55,12 +58,14 @@ module Merb
|
|
55
58
|
response.write("0\r\n\r\n")
|
56
59
|
}
|
57
60
|
end
|
58
|
-
|
61
|
+
|
59
62
|
# Writes a chunk from +render_chunked+ to the response that is sent back to
|
60
63
|
# the client. This should only be called within a +render_chunked+ block.
|
61
64
|
#
|
62
65
|
# ==== Parameters
|
63
66
|
# data<String>:: a chunk of data to return.
|
67
|
+
#
|
68
|
+
# @api public
|
64
69
|
def send_chunk(data)
|
65
70
|
only_runs_on_mongrel!
|
66
71
|
@response.write('%x' % data.size + "\r\n")
|
@@ -71,53 +76,59 @@ module Merb
|
|
71
76
|
# &blk::
|
72
77
|
# A proc that should get called outside the mutex, and which will return
|
73
78
|
# the value to render.
|
74
|
-
#
|
79
|
+
#
|
75
80
|
# ==== Returns
|
76
81
|
# Proc::
|
77
|
-
# A block that
|
82
|
+
# A block that the server can call later, allowing Merb to release the
|
78
83
|
# thread lock and render another request.
|
84
|
+
#
|
85
|
+
# @api public
|
79
86
|
def render_deferred(&blk)
|
80
|
-
Proc.new
|
87
|
+
Proc.new do |response|
|
81
88
|
response.write(blk.call)
|
82
|
-
|
89
|
+
end
|
83
90
|
end
|
84
91
|
|
85
92
|
# Renders the passed in string, then calls the block outside the mutex and
|
86
93
|
# after the string has been returned to the client.
|
87
|
-
#
|
94
|
+
#
|
88
95
|
# ==== Parameters
|
89
96
|
# str<String>:: A +String+ to return to the client.
|
90
97
|
# &blk:: A block that should get called once the string has been returned.
|
91
|
-
#
|
98
|
+
#
|
92
99
|
# ==== Returns
|
93
100
|
# Proc::
|
94
101
|
# A block that Mongrel can call after returning the string to the user.
|
102
|
+
#
|
103
|
+
# @api public
|
95
104
|
def render_then_call(str, &blk)
|
96
|
-
Proc.new
|
105
|
+
Proc.new do |response|
|
97
106
|
response.write(str)
|
98
|
-
blk.call
|
99
|
-
|
107
|
+
blk.call
|
108
|
+
end
|
100
109
|
end
|
101
|
-
|
110
|
+
|
102
111
|
# ==== Parameters
|
103
112
|
# url<String>::
|
104
113
|
# URL to redirect to. It can be either a relative or fully-qualified URL.
|
105
114
|
# opts<Hash>:: An options hash (see below)
|
106
|
-
#
|
115
|
+
#
|
107
116
|
# ==== Options (opts)
|
108
117
|
# :message<Hash>::
|
109
118
|
# Messages to pass in url query string as value for "_message"
|
110
119
|
# :permanent<Boolean>::
|
111
120
|
# When true, return status 301 Moved Permanently
|
112
|
-
#
|
121
|
+
#
|
113
122
|
# ==== Returns
|
114
123
|
# String:: Explanation of redirect.
|
115
|
-
#
|
124
|
+
#
|
116
125
|
# ==== Examples
|
117
126
|
# redirect("/posts/34")
|
118
127
|
# redirect("/posts/34", :message => { :notice => 'Post updated successfully!' })
|
119
128
|
# redirect("http://www.merbivore.com/")
|
120
129
|
# redirect("http://www.merbivore.com/", :permanent => true)
|
130
|
+
#
|
131
|
+
# @api public
|
121
132
|
def redirect(url, opts = {})
|
122
133
|
default_redirect_options = { :message => nil, :permanent => false }
|
123
134
|
opts = default_redirect_options.merge(opts)
|
@@ -131,17 +142,20 @@ module Merb
|
|
131
142
|
"<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"
|
132
143
|
end
|
133
144
|
|
145
|
+
# Retreives the redirect message either locally or from the request.
|
146
|
+
#
|
147
|
+
# @api public
|
134
148
|
def message
|
135
149
|
@_message = defined?(@_message) ? @_message : request.message
|
136
150
|
end
|
137
151
|
|
138
152
|
# Sends a file over HTTP. When given a path to a file, it will set the
|
139
153
|
# right headers so that the static file is served directly.
|
140
|
-
#
|
154
|
+
#
|
141
155
|
# ==== Parameters
|
142
156
|
# file<String>:: Path to file to send to the client.
|
143
157
|
# opts<Hash>:: Options for sending the file (see below).
|
144
|
-
#
|
158
|
+
#
|
145
159
|
# ==== Options (opts)
|
146
160
|
# :disposition<String>::
|
147
161
|
# The disposition of the file send. Defaults to "attachment".
|
@@ -151,6 +165,8 @@ module Merb
|
|
151
165
|
#
|
152
166
|
# ==== Returns
|
153
167
|
# IO:: An I/O stream for the file.
|
168
|
+
#
|
169
|
+
# @api public
|
154
170
|
def send_file(file, opts={})
|
155
171
|
opts.update(Merb::Const::DEFAULT_SEND_FILE_OPTIONS.merge(opts))
|
156
172
|
disposition = opts[:disposition].dup || 'attachment'
|
@@ -160,28 +176,30 @@ module Merb
|
|
160
176
|
'Content-Disposition' => disposition,
|
161
177
|
'Content-Transfer-Encoding' => 'binary'
|
162
178
|
)
|
163
|
-
Proc.new
|
179
|
+
Proc.new do |response|
|
164
180
|
file = File.open(file, 'rb')
|
165
181
|
while chunk = file.read(16384)
|
166
182
|
response.write chunk
|
167
|
-
end
|
183
|
+
end
|
168
184
|
file.close
|
169
|
-
|
185
|
+
end
|
170
186
|
end
|
171
187
|
|
172
188
|
# Send binary data over HTTP to the user as a file download. May set content type,
|
173
189
|
# apparent file name, and specify whether to show data inline or download as an attachment.
|
174
|
-
#
|
190
|
+
#
|
175
191
|
# ==== Parameters
|
176
192
|
# data<String>:: Path to file to send to the client.
|
177
193
|
# opts<Hash>:: Options for sending the data (see below).
|
178
|
-
#
|
194
|
+
#
|
179
195
|
# ==== Options (opts)
|
180
196
|
# :disposition<String>::
|
181
197
|
# The disposition of the file send. Defaults to "attachment".
|
182
198
|
# :filename<String>::
|
183
199
|
# The name to use for the file. Defaults to the filename of file.
|
184
200
|
# :type<String>:: The content type.
|
201
|
+
#
|
202
|
+
# @api public
|
185
203
|
def send_data(data, opts={})
|
186
204
|
opts.update(Merb::Const::DEFAULT_SEND_FILE_OPTIONS.merge(opts))
|
187
205
|
disposition = opts[:disposition].dup || 'attachment'
|
@@ -195,13 +213,13 @@ module Merb
|
|
195
213
|
end
|
196
214
|
|
197
215
|
# Streams a file over HTTP.
|
198
|
-
#
|
216
|
+
#
|
199
217
|
# ==== Parameters
|
200
218
|
# opts<Hash>:: Options for the file streaming (see below).
|
201
219
|
# &stream::
|
202
220
|
# A block that, when called, will return an object that responds to
|
203
221
|
# +get_lines+ for streaming.
|
204
|
-
#
|
222
|
+
#
|
205
223
|
# ==== Options
|
206
224
|
# :disposition<String>::
|
207
225
|
# The disposition of the file send. Defaults to "attachment".
|
@@ -216,6 +234,8 @@ module Merb
|
|
216
234
|
# response.write chunk
|
217
235
|
# end
|
218
236
|
# end
|
237
|
+
#
|
238
|
+
# @api public
|
219
239
|
def stream_file(opts={}, &stream)
|
220
240
|
opts.update(Merb::Const::DEFAULT_SEND_FILE_OPTIONS.merge(opts))
|
221
241
|
disposition = opts[:disposition].dup || 'attachment'
|
@@ -227,32 +247,37 @@ module Merb
|
|
227
247
|
# Rack specification requires header values to respond to :each
|
228
248
|
'CONTENT-LENGTH' => opts[:content_length].to_s
|
229
249
|
)
|
230
|
-
Proc.new
|
250
|
+
Proc.new do |response|
|
231
251
|
stream.call(response)
|
232
|
-
|
252
|
+
end
|
233
253
|
end
|
234
|
-
|
254
|
+
|
235
255
|
# Uses the nginx specific +X-Accel-Redirect+ header to send a file directly
|
236
|
-
# from nginx.
|
256
|
+
# from nginx.
|
257
|
+
#
|
258
|
+
# ==== Notes
|
259
|
+
# Unless Content-Disposition is set before calling this method,
|
260
|
+
# it is set to attachment with streamed file name.
|
261
|
+
#
|
262
|
+
# For more information, see the nginx wiki:
|
237
263
|
# http://wiki.codemongers.com/NginxXSendfile
|
238
|
-
#
|
264
|
+
#
|
239
265
|
# and the following sample gist:
|
240
266
|
# http://gist.github.com/11225
|
241
|
-
#
|
267
|
+
#
|
242
268
|
# there's also example application up on GitHub:
|
243
|
-
#
|
269
|
+
#
|
244
270
|
# http://github.com/michaelklishin/nginx-x-accel-redirect-example-application/tree/master
|
245
|
-
#
|
246
|
-
# Unless Content-Disposition is set before calling this method,
|
247
|
-
# it is set to attachment with streamed file name.
|
248
|
-
#
|
271
|
+
#
|
249
272
|
# ==== Parameters
|
250
273
|
# path<String>:: Path to file to send to the client.
|
251
274
|
# content_type<String>:: content type header value. By default is set to empty string to let
|
252
275
|
# Nginx detect it.
|
253
|
-
#
|
276
|
+
#
|
254
277
|
# ==== Return
|
255
|
-
#
|
278
|
+
# String:: precisely a single space.
|
279
|
+
#
|
280
|
+
# @api public
|
256
281
|
def nginx_send_file(path, content_type = "")
|
257
282
|
# Let Nginx detect content type unless it is explicitly set
|
258
283
|
headers['Content-Type'] = content_type
|
@@ -262,17 +287,17 @@ module Merb
|
|
262
287
|
|
263
288
|
return ' '
|
264
289
|
end
|
265
|
-
|
290
|
+
|
266
291
|
# Sets a cookie to be included in the response.
|
267
|
-
#
|
292
|
+
#
|
268
293
|
# If you need to set a cookie, then use the +cookies+ hash.
|
269
|
-
#
|
294
|
+
#
|
270
295
|
# ==== Parameters
|
271
296
|
# name<~to_s>:: A name for the cookie.
|
272
297
|
# value<~to_s>:: A value for the cookie.
|
273
298
|
# expires<~gmtime:~strftime, Hash>:: An expiration time for the cookie, or a hash of cookie options.
|
274
|
-
#
|
275
|
-
# @public
|
299
|
+
#
|
300
|
+
# @api public
|
276
301
|
def set_cookie(name, value, expires)
|
277
302
|
options = expires.is_a?(Hash) ? expires : {:expires => expires}
|
278
303
|
cookies.set_cookie(name, value, options)
|
@@ -280,11 +305,13 @@ module Merb
|
|
280
305
|
|
281
306
|
# Marks a cookie as deleted and gives it an expires stamp in the past. This
|
282
307
|
# method is used primarily internally in Merb.
|
283
|
-
#
|
308
|
+
#
|
284
309
|
# Use the +cookies+ hash to manipulate cookies instead.
|
285
|
-
#
|
310
|
+
#
|
286
311
|
# ==== Parameters
|
287
312
|
# name<~to_s>:: A name for the cookie to delete.
|
313
|
+
#
|
314
|
+
# @api public
|
288
315
|
def delete_cookie(name)
|
289
316
|
set_cookie(name, nil, Merb::Const::COOKIE_EXPIRED_TIME)
|
290
317
|
end
|
@@ -296,6 +323,8 @@ module Merb
|
|
296
323
|
#
|
297
324
|
# ==== Returns
|
298
325
|
# String:: The escaped object.
|
326
|
+
#
|
327
|
+
# @api public
|
299
328
|
def escape_xml(obj)
|
300
329
|
Erubis::XmlHelper.escape_xml(obj.to_s)
|
301
330
|
end
|
@@ -303,14 +332,17 @@ module Merb
|
|
303
332
|
alias escape_html escape_xml
|
304
333
|
|
305
334
|
private
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
335
|
+
|
336
|
+
# Marks an output method that only runs on the Mongrel webserver.
|
337
|
+
#
|
338
|
+
# ==== Raises
|
339
|
+
# NotImplemented:: The Rack adapter is not mongrel.
|
340
|
+
#
|
341
|
+
# @api private
|
342
|
+
def only_runs_on_mongrel!
|
343
|
+
unless Merb::Config[:log_stream] == 'mongrel'
|
344
|
+
raise(Merb::ControllerExceptions::NotImplemented, "Current Rack adapter is not mongrel. cannot support this feature")
|
314
345
|
end
|
346
|
+
end
|
315
347
|
end
|
316
348
|
end
|