| Module | Sinatra::Helpers |
| In: |
lib/sinatra/base.rb
|
Methods available to routes, before/after filters, and views.
Set the Content-Disposition to "attachment" with the specified filename, instructing the user agents to prompt to save.
# File lib/sinatra/base.rb, line 173
173: def attachment(filename=nil)
174: response['Content-Disposition'] = 'attachment'
175: if filename
176: params = '; filename="%s"' % File.basename(filename)
177: response['Content-Disposition'] << params
178: end
179: end
Set or retrieve the response body. When a block is given, evaluation is deferred until the body is read with each.
# File lib/sinatra/base.rb, line 85
85: def body(value=nil, &block)
86: if block_given?
87: def block.each; yield(call) end
88: response.body = block
89: elsif value
90: response.body = value
91: else
92: response.body
93: end
94: end
Specify response freshness policy for HTTP caches (Cache-Control header). Any number of non-value directives (:public, :private, :no_cache, :no_store, :must_revalidate, :proxy_revalidate) may be passed along with a Hash of value directives (:max_age, :min_stale, :s_max_age).
cache_control :public, :must_revalidate, :max_age => 60 => Cache-Control: public, must-revalidate, max-age=60
See RFC 2616 / 14.9 for more on standard cache control directives: tools.ietf.org/html/rfc2616#section-14.9.1
# File lib/sinatra/base.rb, line 290
290: def cache_control(*values)
291: if values.last.kind_of?(Hash)
292: hash = values.pop
293: hash.reject! { |k,v| v == false }
294: hash.reject! { |k,v| values << k if v == true }
295: else
296: hash = {}
297: end
298:
299: values = values.map { |value| value.to_s.tr('_','-') }
300: hash.each do |key, value|
301: key = key.to_s.tr('_', '-')
302: value = value.to_i if key == "max-age"
303: values << [key, value].join('=')
304: end
305:
306: response['Cache-Control'] = values.join(', ') if values.any?
307: end
Set the Content-Type of the response body given a media type or file extension.
# File lib/sinatra/base.rb, line 159
159: def content_type(type, params={})
160: default = params.delete :default
161: mime_type = mime_type(type) || default
162: fail "Unknown media type: %p" % type if mime_type.nil?
163: mime_type = mime_type.dup
164: unless params.include? :charset or settings.add_charset.all? { |p| not p === mime_type }
165: params[:charset] = params.delete('charset') || settings.default_encoding
166: end
167: mime_type << ";#{params.map { |kv| kv.join('=') }.join(', ')}" unless params.empty?
168: response['Content-Type'] = mime_type
169: end
Set the response entity tag (HTTP ‘ETag’ header) and halt if conditional GET matches. The value argument is an identifier that uniquely identifies the current version of the resource. The kind argument indicates whether the etag should be used as a :strong (default) or :weak cache validator.
When the current request includes an ‘If-None-Match’ header with a matching etag, execution is immediately halted. If the request method is GET or HEAD, a ‘304 Not Modified’ response is sent.
# File lib/sinatra/base.rb, line 360
360: def etag(value, kind=:strong)
361: raise TypeError, ":strong or :weak expected" if ![:strong,:weak].include?(kind)
362: value = '"%s"' % value
363: value = 'W/' + value if kind == :weak
364: response['ETag'] = value
365:
366: # Conditional GET check
367: if etags = env['HTTP_IF_NONE_MATCH']
368: etags = etags.split(/\s*,\s*/)
369: halt 304 if etags.include?(value) || etags.include?('*')
370: end
371: end
Set the Expires header and Cache-Control/max-age directive. Amount can be an integer number of seconds in the future or a Time object indicating when the response should be considered "stale". The remaining "values" arguments are passed to the cache_control helper:
expires 500, :public, :must_revalidate => Cache-Control: public, must-revalidate, max-age=60 => Expires: Mon, 08 Jun 2009 08:50:17 GMT
# File lib/sinatra/base.rb, line 318
318: def expires(amount, *values)
319: values << {} unless values.last.kind_of?(Hash)
320:
321: if Integer === amount
322: time = Time.now + amount
323: max_age = amount
324: else
325: time = time_for amount
326: max_age = time - Time.now
327: end
328:
329: values.last.merge!(:max_age => max_age)
330: cache_control(*values)
331:
332: response['Expires'] = time.httpdate
333: end
Set the last modified time of the resource (HTTP ‘Last-Modified’ header) and halt if conditional GET matches. The time argument is a Time, DateTime, or other object that responds to to_time.
When the current request includes an ‘If-Modified-Since’ header that is equal or later than the time specified, execution is immediately halted with a ‘304 Not Modified’ response.
# File lib/sinatra/base.rb, line 342
342: def last_modified(time)
343: return unless time
344: time = time_for time
345: response['Last-Modified'] = time.httpdate
346: # compare based on seconds since epoch
347: halt 304 if Time.httpdate(request.env['HTTP_IF_MODIFIED_SINCE']).to_i >= time.to_i
348: rescue ArgumentError
349: end
Look up a media type by file extension in Rack‘s mime registry.
# File lib/sinatra/base.rb, line 153
153: def mime_type(type)
154: Base.mime_type(type)
155: end
Halt processing and return a 404 Not Found.
# File lib/sinatra/base.rb, line 137
137: def not_found(body=nil)
138: error 404, body
139: end
Halt processing and redirect to the URI provided.
# File lib/sinatra/base.rb, line 97
97: def redirectredirect(uri, *args)
98: status 302
99:
100: # According to RFC 2616 section 14.30, "the field value consists of a
101: # single absolute URI"
102: response['Location'] = url(uri, settings.absolute_redirects?, settings.prefixed_redirects?)
103: halt(*args)
104: end
Use the contents of the file at path as the response body.
# File lib/sinatra/base.rb, line 182
182: def send_file(path, opts={})
183: stat = File.stat(path)
184: last_modified(opts[:last_modified] || stat.mtime)
185:
186: if opts[:type] or not response['Content-Type']
187: content_type opts[:type] || File.extname(path), :default => 'application/octet-stream'
188: end
189:
190: if opts[:disposition] == 'attachment' || opts[:filename]
191: attachment opts[:filename] || path
192: elsif opts[:disposition] == 'inline'
193: response['Content-Disposition'] = 'inline'
194: end
195:
196: file_length = opts[:length] || stat.size
197: sf = StaticFile.open(path, 'rb')
198: if ! sf.parse_ranges(env, file_length)
199: response['Content-Range'] = "bytes */#{file_length}"
200: halt 416
201: elsif r=sf.range
202: response['Content-Range'] = "bytes #{r.begin}-#{r.end}/#{file_length}"
203: response['Content-Length'] = (r.end - r.begin + 1).to_s
204: halt 206, sf
205: else
206: response['Content-Length'] ||= file_length.to_s
207: halt sf
208: end
209: rescue Errno::ENOENT
210: not_found
211: end
Generates the absolute URI for a given path in the app. Takes Rack routers and reverse proxies into account.
# File lib/sinatra/base.rb, line 108
108: def uri(addr = nil, absolute = true, add_script_name = true)
109: return addr if addr =~ /^https?:\/\//
110: uri = [host = ""]
111: if absolute
112: host << 'http'
113: host << 's' if request.secure?
114: host << "://"
115: if request.forwarded? or request.port != (request.secure? ? 443 : 80)
116: host << request.host_with_port
117: else
118: host << request.host
119: end
120: end
121: uri << request.script_name.to_s if add_script_name
122: uri << (addr ? addr : request.path_info).to_s
123: File.join uri
124: end