ramaze 2010.06.18 → 2011.01
Sign up to get free protection for your applications and to get access to all the features.
- 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
|