ramaze 2010.06.18 → 2011.01
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/.gitignore +1 -0
- data/MANIFEST +9 -16
- data/README.md +37 -30
- data/Rakefile +5 -1
- data/TODO.md +19 -0
- data/doc/AUTHORS +5 -1
- data/doc/CHANGELOG +3553 -3272
- data/doc/tutorial/todolist.html +1512 -1512
- data/examples/app/blog/app.rb +2 -0
- data/examples/app/todolist/controller/init.rb +1 -2
- data/examples/app/wiktacular/mkd/main/2007-07-20_19-21-12.mkd +1 -1
- data/examples/app/wiktacular/mkd/main/2007-07-20_19-23-10.mkd +1 -1
- data/examples/app/wiktacular/mkd/main/2007-07-20_19-45-07.mkd +1 -1
- data/examples/app/wiktacular/mkd/main/current.mkd +1 -1
- data/examples/app/wiktacular/mkd/testing/2007-07-20_16-43-46.mkd +1 -1
- data/examples/app/wiktacular/mkd/testing/2007-07-20_19-43-50.mkd +2 -2
- data/examples/app/wiktacular/mkd/testing/2007-07-21_18-47-08.mkd +16 -16
- data/examples/app/wiktacular/mkd/testing/2007-07-21_18-47-54.mkd +16 -16
- data/examples/app/wiktacular/mkd/testing/current.mkd +16 -16
- data/lib/proto/model/init.rb +1 -1
- data/lib/proto/public/js/jquery.js +2034 -1095
- data/lib/proto/start.rb +2 -0
- data/lib/proto/view/index.xhtml +3 -3
- data/lib/ramaze.rb +1 -2
- data/lib/ramaze/cache.rb +1 -0
- data/lib/ramaze/cache/sequel.rb +131 -37
- data/lib/ramaze/controller.rb +1 -0
- data/lib/ramaze/gestalt.rb +75 -46
- data/lib/ramaze/helper.rb +1 -0
- data/lib/ramaze/helper/auth.rb +38 -4
- data/lib/ramaze/helper/blue_form.rb +498 -78
- data/lib/ramaze/helper/cache.rb +2 -2
- data/lib/ramaze/helper/csrf.rb +225 -0
- data/lib/ramaze/helper/erector.rb +67 -9
- data/lib/ramaze/helper/flash.rb +4 -2
- data/lib/ramaze/helper/gestalt.rb +2 -0
- data/lib/ramaze/helper/gravatar.rb +1 -1
- data/lib/ramaze/helper/localize.rb +4 -0
- data/lib/ramaze/helper/send_file.rb +30 -0
- data/lib/ramaze/helper/thread.rb +5 -0
- data/lib/ramaze/helper/user.rb +4 -3
- data/lib/ramaze/helper/xhtml.rb +87 -8
- data/lib/ramaze/log.rb +13 -0
- data/lib/ramaze/log/analogger.rb +15 -5
- data/lib/ramaze/log/growl.rb +28 -13
- data/lib/ramaze/log/hub.rb +12 -4
- data/lib/ramaze/log/informer.rb +28 -11
- data/lib/ramaze/log/knotify.rb +7 -2
- data/lib/ramaze/log/logger.rb +12 -4
- data/lib/ramaze/log/logging.rb +40 -14
- data/lib/ramaze/log/rotatinginformer.rb +47 -23
- data/lib/ramaze/log/syslog.rb +37 -31
- data/lib/ramaze/log/xosd.rb +7 -4
- data/lib/ramaze/middleware_compiler.rb +2 -2
- data/lib/ramaze/snippets/fiber.rb +63 -63
- data/lib/ramaze/snippets/ramaze/lru_hash.rb +1 -1
- data/lib/ramaze/tool/bin.rb +1 -1
- data/lib/ramaze/version.rb +1 -1
- data/lib/ramaze/view.rb +4 -4
- data/lib/ramaze/view/erector.rb +88 -13
- data/ramaze.gemspec +65 -65
- data/spec/ramaze/bin/ramaze.rb +1 -1
- data/spec/ramaze/cache/localmemcache.rb +20 -12
- data/spec/ramaze/cache/sequel.rb +19 -19
- data/spec/ramaze/helper/blue_form.rb +549 -257
- data/spec/ramaze/helper/csrf.rb +109 -0
- data/spec/ramaze/helper/httpdigest.rb +31 -29
- data/spec/ramaze/helper/user.rb +1 -1
- data/spec/ramaze/helper/xhtml.rb +17 -0
- data/spec/ramaze/log/growl.rb +34 -0
- data/spec/ramaze/log/informer.rb +1 -0
- data/spec/ramaze/view/erector.rb +49 -71
- data/spec/ramaze/view/erector/external_view.erector +5 -0
- data/spec/ramaze/view/erector/index.erector +5 -0
- data/spec/ramaze/view/erector/layout.erector +13 -3
- data/spec/ramaze/view/erector/tables.erector +23 -0
- data/spec/ramaze/view/erector/view.erector +6 -0
- data/tasks/git.rake +2 -2
- metadata +133 -176
- data/examples/helpers/form_with_sequel.rb +0 -24
- data/examples/helpers/nitro_form.rb +0 -23
- data/lib/ramaze/helper/form.rb +0 -133
- data/lib/ramaze/helper/nitroform.rb +0 -14
- data/lib/ramaze/helper/pager.rb +0 -367
- data/lib/ramaze/helper/partial.rb +0 -100
- data/lib/ramaze/helper/sequel.rb +0 -55
- data/lib/ramaze/helper/sequel_form.rb +0 -284
- data/lib/vendor/etag.rb +0 -22
- data/spec/ramaze/helper/form.rb +0 -360
- data/spec/ramaze/helper/pager.rb +0 -96
- data/spec/ramaze/helper/sequel_form.rb +0 -94
- data/spec/ramaze/view/erector/external.erector +0 -1
- data/spec/ramaze/view/erector/invoke_helper_method.erector +0 -1
- data/spec/ramaze/view/erector/strict_xhtml.erector +0 -3
- data/spec/ramaze/view/erector/sum.erector +0 -1
data/lib/ramaze/helper/cache.rb
CHANGED
@@ -66,11 +66,11 @@ module Ramaze
|
|
66
66
|
# to do lazy computation of the cached value conveniently when using a
|
67
67
|
# custom TTL or longer expressions that don't fit on one line with ||=.
|
68
68
|
#
|
69
|
-
# @
|
69
|
+
# @example to get the cache object directly
|
70
70
|
#
|
71
71
|
# count = cache_value[:count] ||= Article.count
|
72
72
|
#
|
73
|
-
# @
|
73
|
+
# @example with block
|
74
74
|
#
|
75
75
|
# count = cache_value(:count){ Article.count }
|
76
76
|
# count = cache_value(:count, :ttl => 60){ Article.count }
|
@@ -0,0 +1,225 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'digest'
|
3
|
+
|
4
|
+
module Ramaze
|
5
|
+
module Helper
|
6
|
+
##
|
7
|
+
# A relatively basic yet useful helper that can be used to protect your application
|
8
|
+
# from CSRF attacks/exploits. Note that this helper merely generates the required data,
|
9
|
+
# and provides several methods. You still need to manually add the token to each form.
|
10
|
+
#
|
11
|
+
# The reason for this is because this is quite simple. Ramaze is meant as a framework that
|
12
|
+
# works with any given helper, ORM, template engine and so on. If we were to automatically
|
13
|
+
# load this helper and include (a perhaps more advanced) CSRF system that would mean that
|
14
|
+
# every form helper, official or third-party, would have to support that specific system.
|
15
|
+
# However, there's no need to panic as it's very easy to setup a basic anti CSRF system.
|
16
|
+
#
|
17
|
+
# == Usage
|
18
|
+
#
|
19
|
+
# In order to enable CSRF protection we need to do two things. Load the helper and create
|
20
|
+
# a before_all block in a controller. Take a look at the following code:
|
21
|
+
#
|
22
|
+
# class BaseController < Ramaze::Controller
|
23
|
+
# before_all do
|
24
|
+
# puts "Hello, before_all!"
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# This would output "Hello, before_all!" to the console upon each request. Not very useful
|
29
|
+
# but it does show what the before_all block can do. On to actual CSRF related code!
|
30
|
+
#
|
31
|
+
# class BaseController < Ramaze::Controller
|
32
|
+
# before_all do
|
33
|
+
# csrf_protection :save do
|
34
|
+
# # ....
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# This example introduces an extra block that validates the current request.
|
40
|
+
# Whenever a user requests a controller that either extends BaseController or has it's own
|
41
|
+
# before_all block Ramaze will check if the current request data contains a CSRF token.
|
42
|
+
# Of course an if/end isn't very useful if it doesn't do anything, let's add some code.
|
43
|
+
#
|
44
|
+
# class BaseController < Ramaze::Controller
|
45
|
+
# before_all do
|
46
|
+
# csrf_protection :save do
|
47
|
+
# puts "Hello, unsafe data!"
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# The code above checks if the current method is "save" (or any other of the provided methods)
|
53
|
+
# and checks if an CSRF token is supplied if the method matches. Protected methods require
|
54
|
+
# a token in ALL HTTP requests (GET, POST, etc). While this may seem weird since GET is generally
|
55
|
+
# used for safe actions it actually makes sence. Ramaze stores both the POST and GET parameters in
|
56
|
+
# the request.params hash. While this makes it easy to work with POST/GET data this also makes it
|
57
|
+
# easier to spoof POST requests using a GET request, thus this helper protects ALL request methods.
|
58
|
+
#
|
59
|
+
# If you're a lazy person you can copy-paste the example below and adapt it to your needs.
|
60
|
+
#
|
61
|
+
# class BaseController < Ramaze::Controller
|
62
|
+
# before_all do
|
63
|
+
# csrf_protection :save do
|
64
|
+
# respond("The supplied CSRF token is invalid.", 401)
|
65
|
+
# end
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# @author Yorick Peterse
|
70
|
+
#
|
71
|
+
module CSRF
|
72
|
+
|
73
|
+
##
|
74
|
+
# Method that can be used to protect the specified methods against CSRF exploits.
|
75
|
+
# Each protected method will require the token to be stored in a field called "csrf_token".
|
76
|
+
# This method will then validate that token against the current token in the session.
|
77
|
+
#
|
78
|
+
# @author Yorick Peterse
|
79
|
+
# @param [Strings/Symbol] *methods Methods that will be protected/unprotected.
|
80
|
+
# @param [Block] Block that will be executed if the token is invalid.
|
81
|
+
# @example
|
82
|
+
#
|
83
|
+
# # Protect "create" and "save" against CSRF exploits
|
84
|
+
# before_all do
|
85
|
+
# csrf_protection :create, :save do
|
86
|
+
# respond("GET TO DA CHOPPA!", 401)
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
def csrf_protection *methods, &block
|
91
|
+
# Only protect the specified methods
|
92
|
+
if methods.include?(action.name) or methods.include?(action.name.to_sym)
|
93
|
+
# THINK: For now the field name is hard-coded to "csrf_token". While
|
94
|
+
# this is perfectly fine in most cases it might be a good idea
|
95
|
+
# to allow developers to change the name of this field (for whatever the reason).
|
96
|
+
if validate_csrf_token(request.params['csrf_token']) != true
|
97
|
+
yield
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# Generate a new token and create the session array that will be used to validate the client.
|
104
|
+
# The following items are stored in the session:
|
105
|
+
#
|
106
|
+
# * token: An unique hash that will be stored in each form
|
107
|
+
# * agent: The visitor's user agent
|
108
|
+
# * ip: The IP address of the visitor
|
109
|
+
# * time: Timestamp that indicates at what time the data was generated.
|
110
|
+
#
|
111
|
+
# Note that this method will be automatically called if no CSRF token exists.
|
112
|
+
#
|
113
|
+
# @author Yorick Peterse
|
114
|
+
# @param [Hash] Additional arguments that can be set such as the TTL.
|
115
|
+
# @return [Void]
|
116
|
+
#
|
117
|
+
def generate_csrf_token args = {}
|
118
|
+
# Default TTL is 15 minutes
|
119
|
+
if args[:ttl]
|
120
|
+
ttl = args[:ttl]
|
121
|
+
else
|
122
|
+
ttl = 900
|
123
|
+
end
|
124
|
+
|
125
|
+
# Generate all the required data
|
126
|
+
time = Time.new.to_i.to_s
|
127
|
+
number = SecureRandom.random_number(10000).to_s
|
128
|
+
base64 = SecureRandom.base64.to_s
|
129
|
+
token = Digest::SHA2.new(512).hexdigest(srand.to_s + rand.to_s + time + number + base64).to_s
|
130
|
+
|
131
|
+
# Get several details from the client such as the user agent, IP, etc
|
132
|
+
ip = request.env['REMOTE_ADDR']
|
133
|
+
agent = request.env['HTTP_USER_AGENT']
|
134
|
+
host = request.env['REMOTE_HOST']
|
135
|
+
|
136
|
+
# Time to store all the data
|
137
|
+
session[:_csrf] = {
|
138
|
+
:time => time.to_i,
|
139
|
+
:token => token,
|
140
|
+
:ip => ip,
|
141
|
+
:agent => agent,
|
142
|
+
:host => host,
|
143
|
+
:ttl => ttl
|
144
|
+
}
|
145
|
+
|
146
|
+
# Prevent this method from returning any value (it isn't needed anyway)
|
147
|
+
return
|
148
|
+
end
|
149
|
+
|
150
|
+
##
|
151
|
+
# Retrieves the current value of the CSRF token.
|
152
|
+
#
|
153
|
+
# @author Yorick Peterse
|
154
|
+
# @return [String] The current CSRF token.
|
155
|
+
# @example
|
156
|
+
#
|
157
|
+
# form(@data, :method => :post) do |f|
|
158
|
+
# f.input_hidden :csrf_token, get_csrf_token()
|
159
|
+
# end
|
160
|
+
#
|
161
|
+
def get_csrf_token
|
162
|
+
if !session[:_csrf] or !self.validate_csrf_token(session[:_csrf][:token])
|
163
|
+
self.generate_csrf_token
|
164
|
+
end
|
165
|
+
|
166
|
+
# Land ho!
|
167
|
+
return session[:_csrf][:token]
|
168
|
+
end
|
169
|
+
|
170
|
+
##
|
171
|
+
# Validates the request based on the current session date stored in _csrf.
|
172
|
+
# The following items are verified:
|
173
|
+
#
|
174
|
+
# * Do the user agent, ip and token match those supplied by the visitor?
|
175
|
+
# * Has the token been expired? (after 15 minutes).
|
176
|
+
#
|
177
|
+
# If any of these checks fail this method will return FALSE. It's your job to
|
178
|
+
# take action based on the results of this method.
|
179
|
+
#
|
180
|
+
# @author Yorick Peterse
|
181
|
+
# @param [String] input_token The CSRF token to validate.
|
182
|
+
# @return [Bool]
|
183
|
+
# @example
|
184
|
+
#
|
185
|
+
# before_all do
|
186
|
+
# if validate_csrf_token(request.params['csrf_token']) != true
|
187
|
+
# respond("Invalid CSRF token", 401)
|
188
|
+
# end
|
189
|
+
# end
|
190
|
+
#
|
191
|
+
def validate_csrf_token input_token
|
192
|
+
# Check if the CSRF data has been generated and generate it if this
|
193
|
+
# hasn't been done already (usually on the first request).
|
194
|
+
if !session[:_csrf] or session[:_csrf].empty?
|
195
|
+
self.generate_csrf_token
|
196
|
+
end
|
197
|
+
|
198
|
+
# Get several details from the client such as the user agent, IP, etc
|
199
|
+
ip = session[:_csrf][:ip]
|
200
|
+
agent = session[:_csrf][:agent]
|
201
|
+
host = session[:_csrf][:host]
|
202
|
+
|
203
|
+
# Get the current time and the time when the token was created
|
204
|
+
now = Time.new.to_i
|
205
|
+
token_time = session[:_csrf][:time]
|
206
|
+
|
207
|
+
# Mirror mirror on the wall, who's the most secure of them all?
|
208
|
+
results = Array.new
|
209
|
+
results.push( session[:_csrf][:token] == input_token )
|
210
|
+
results.push( (now - token_time) <= session[:_csrf][:ttl] )
|
211
|
+
results.push( host == request.env['REMOTE_HOST'] )
|
212
|
+
results.push( ip == request.env['REMOTE_ADDR'] )
|
213
|
+
results.push( agent == request.env['HTTP_USER_AGENT'] )
|
214
|
+
|
215
|
+
# Verify the results
|
216
|
+
if results.include?(false)
|
217
|
+
return false
|
218
|
+
else
|
219
|
+
return true
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end # <-- End of CSRF module
|
224
|
+
end
|
225
|
+
end
|
@@ -5,15 +5,19 @@ require 'erector'
|
|
5
5
|
|
6
6
|
module Ramaze
|
7
7
|
|
8
|
-
# Allows you to use some shortcuts for Erector in your Controller.
|
9
|
-
|
10
|
-
# use this inside your controller to directly build Erector
|
11
|
-
# Refer to the Erector-documentation and testsuite for more examples.
|
12
|
-
# Usage:
|
13
|
-
# erector { h1 "Apples & Oranges" } #=> "<h1>Apples & Oranges</h1>"
|
14
|
-
# erector { h1(:class => 'fruits&floots'){ text 'Apples' } } #=> "<h1 class=\"fruits&floots\">Apples</h1>"
|
15
|
-
|
16
8
|
module Helper
|
9
|
+
|
10
|
+
##
|
11
|
+
# Allows you to use some shortcuts for Erector in your Controller.
|
12
|
+
#
|
13
|
+
# use this inside your controller to directly build Erector
|
14
|
+
# Refer to the Erector-documentation and testsuite for more examples.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
#
|
18
|
+
# erector { h1 "Apples & Oranges" } #=> "<h1>Apples & Oranges</h1>"
|
19
|
+
# erector { h1(:class => 'fruits&floots'){ text 'Apples' } } #=> "<h1 class=\"fruits&floots\">Apples</h1>"
|
20
|
+
#
|
17
21
|
module Erector
|
18
22
|
include ::Erector::Mixin
|
19
23
|
|
@@ -21,27 +25,81 @@ module Ramaze
|
|
21
25
|
alias :raw! :rawtext
|
22
26
|
alias :old_css :css
|
23
27
|
|
28
|
+
##
|
29
|
+
# Method that generates a XHTML 1.0 Strict doctype.
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
#
|
33
|
+
# strict_html do
|
34
|
+
# head do
|
35
|
+
# title "Ramaze Rocks!"
|
36
|
+
# end
|
37
|
+
# body
|
38
|
+
# div do
|
39
|
+
#
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# @param [Hash] args Hash containing extra options such as the xml:lang and xmlns attribute.
|
45
|
+
# @param [Block] block Block that contains the inner data of the <html> element.
|
46
|
+
#
|
24
47
|
def strict_xhtml(*args, &block)
|
25
48
|
raw! '<?xml version="1.0" encoding="UTF-8"?>'
|
26
49
|
raw! '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">'
|
27
50
|
html(:xmlns => "http://www.w3.org/1999/xhtml", :"xml:lang" => "en", :lang => "en", &block)
|
28
51
|
end
|
29
52
|
|
53
|
+
##
|
54
|
+
# Generate a Javascript tag.
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
#
|
58
|
+
# js 'javascript/jquery.js'
|
59
|
+
#
|
60
|
+
# @param [String] src The full or relative path to the Javascript file.
|
61
|
+
#
|
30
62
|
def js(src)
|
31
63
|
script :src => src
|
32
64
|
end
|
33
65
|
|
66
|
+
##
|
67
|
+
# Generate a pair of conditional tags for a specific browser.
|
68
|
+
#
|
69
|
+
# @example
|
70
|
+
#
|
71
|
+
# ie_if 'IE' do
|
72
|
+
# ......
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# @param [String] expr The if expression, such as 'IE' or 'lte IE7'.
|
76
|
+
# @param [block] block Block that contains the data that needs to be loaded for the specified browser.
|
77
|
+
#
|
34
78
|
def ie_if(expr, &block)
|
35
79
|
raw! "<!--[if #{expr}]>"
|
36
80
|
yield
|
37
81
|
raw! "<![endif]-->"
|
38
82
|
end
|
39
83
|
|
40
|
-
|
84
|
+
##
|
85
|
+
# Inspect the specified element.
|
86
|
+
#
|
87
|
+
# @param [String] elem The element to inspect.
|
88
|
+
#
|
41
89
|
def inspect(elem)
|
42
90
|
text elem.inspect
|
43
91
|
end
|
44
92
|
|
93
|
+
##
|
94
|
+
# Generate a stylesheet tag.
|
95
|
+
#
|
96
|
+
# @example
|
97
|
+
#
|
98
|
+
# css 'css/reset.css', :media => 'print'
|
99
|
+
#
|
100
|
+
# @param [String] href The path (either absolute or relative) to the CSS file.
|
101
|
+
# @param [Hash] args A hash containing additional arguments to add to the CSS tag.
|
102
|
+
#
|
45
103
|
def css(href, args = {})
|
46
104
|
attrs = {
|
47
105
|
:rel => "stylesheet",
|
data/lib/ramaze/helper/flash.rb
CHANGED
@@ -14,7 +14,7 @@ module Ramaze
|
|
14
14
|
# On the first request, for example on registering:
|
15
15
|
#
|
16
16
|
# flash[:error] = "You should reconsider your username, it's taken already"
|
17
|
-
# redirect
|
17
|
+
# redirect r(:register)
|
18
18
|
#
|
19
19
|
# This is the request from the redirect:
|
20
20
|
#
|
@@ -28,7 +28,9 @@ module Ramaze
|
|
28
28
|
|
29
29
|
trait :flashbox => "<div class='flash' id='flash_%key'>%value</div>"
|
30
30
|
|
31
|
-
|
31
|
+
##
|
32
|
+
# Return the current value of Current.session.flash
|
33
|
+
#
|
32
34
|
def flash
|
33
35
|
Current.session.flash
|
34
36
|
end
|
@@ -50,7 +50,7 @@ module Ramaze
|
|
50
50
|
# Fall back to default if the given +email+ doesn't have an gravatar;
|
51
51
|
# may be an absolute url, 'identicon', 'monsterid', or 'wavatar'
|
52
52
|
#
|
53
|
-
# @
|
53
|
+
# @option opts [true, false] :force (false)
|
54
54
|
# Force use of the default avatar, useful if you want to use only
|
55
55
|
# identicons or the like
|
56
56
|
#
|
@@ -3,6 +3,10 @@ require 'locale'
|
|
3
3
|
|
4
4
|
module Ramaze
|
5
5
|
module Helper
|
6
|
+
##
|
7
|
+
# The localization helper can be used to output translated strings.
|
8
|
+
# This enables your application to use multiple language files for English, Dutch and so on.
|
9
|
+
#
|
6
10
|
module Localize
|
7
11
|
include Traited
|
8
12
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Ramaze
|
2
|
+
module Helper
|
3
|
+
##
|
4
|
+
# The SendFile module can be used to stream a file to the user's computer.
|
5
|
+
# While the performance of the module isn't optimal it's convenient and relatively easy to use.
|
6
|
+
#
|
7
|
+
module SendFile
|
8
|
+
##
|
9
|
+
# The send_file method streams the specified file to the user's browser.
|
10
|
+
#
|
11
|
+
# @param [String] filename The name or path to the file which will be streamed to the user.
|
12
|
+
# @param [String] content_type The type of file we're dealing with. For example, if we want to stream
|
13
|
+
# a JPG image we'd set this variable to 'image/jpg'.
|
14
|
+
# @param [String] content_disposition Value for the Content-Disposition header.
|
15
|
+
#
|
16
|
+
def send_file(filename, content_type = nil, content_disposition = nil)
|
17
|
+
content_type ||= Rack::Mime.mime_type(::File.extname(filename))
|
18
|
+
content_disposition ||= File.basename(filename)
|
19
|
+
|
20
|
+
response.body = ::File.open(filename, 'rb')
|
21
|
+
response['Content-Length'] = ::File.size(filename).to_s
|
22
|
+
response['Content-Type'] = content_type
|
23
|
+
response['Content-Disposition'] = content_disposition
|
24
|
+
response.status = 200
|
25
|
+
|
26
|
+
throw(:respond, response)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/ramaze/helper/thread.rb
CHANGED
@@ -3,6 +3,11 @@
|
|
3
3
|
|
4
4
|
module Ramaze
|
5
5
|
module Helper::Thread
|
6
|
+
##
|
7
|
+
# The thread method executes the specified block in a new thread.
|
8
|
+
#
|
9
|
+
# @param [Block] block The block that contains the code that will be executed in the new thread.
|
10
|
+
#
|
6
11
|
def thread &block
|
7
12
|
parent_thread = Thread.current
|
8
13
|
Thread.new do
|