module Sinatra::Helpers

def attachment(filename=nil)

instructing the user agents to prompt to save.
Set the Content-Disposition to "attachment" with the specified filename,
def attachment(filename=nil)
  response['Content-Disposition'] = 'attachment'
  if filename
    params = '; filename="%s"' % File.basename(filename)
    response['Content-Disposition'] << params
  end
end

def body(value=nil, &block)

evaluation is deferred until the body is read with #each.
Set or retrieve the response body. When a block is given,
def body(value=nil, &block)
  if block_given?
    def block.each ; yield call ; end
    response.body = block
  else
    response.body = value
  end
end

def content_type(type, params={})

extension.
Set the Content-Type of the response body given a media type or file
def content_type(type, params={})
  media_type = self.media_type(type)
  fail "Unknown media type: %p" % type if media_type.nil?
  if params.any?
    params = params.collect { |kv| "%s=%s" % kv }.join(', ')
    response['Content-Type'] = [media_type, params].join(";")
  else
    response['Content-Type'] = media_type
  end
end

def error(code, body=nil)

Halt processing and return the error status provided.
def error(code, body=nil)
  code, body = 500, code.to_str if code.respond_to? :to_str
  response.body = body unless body.nil?
  halt code
end

def etag(value, kind=:strong)

GET or HEAD, a '304 Not Modified' response is sent.
matching etag, execution is immediately halted. If the request method is
When the current request includes an 'If-None-Match' header with a

cache validator.
indicates whether the etag should be used as a :strong (default) or :weak
identifies the current version of the resource. The +strength+ argument
GET matches. The +value+ argument is an identifier that uniquely
Set the response entity tag (HTTP 'ETag' header) and halt if conditional
def etag(value, kind=:strong)
  raise TypeError, ":strong or :weak expected" if ![:strong,:weak].include?(kind)
  value = '"%s"' % value
  value = 'W/' + value if kind == :weak
  response['ETag'] = value
  # Conditional GET check
  if etags = env['HTTP_IF_NONE_MATCH']
    etags = etags.split(/\s*,\s*/)
    halt 304 if etags.include?(value) || etags.include?('*')
  end
end

def last_modified(time)

'304 Not Modified' response.
matches the time specified, execution is immediately halted with a
When the current request includes an 'If-Modified-Since' header that

DateTime, or other object that responds to +to_time+.
and halt if conditional GET matches. The +time+ argument is a Time,
Set the last modified time of the resource (HTTP 'Last-Modified' header)
def last_modified(time)
  time = time.to_time if time.respond_to?(:to_time)
  time = time.httpdate if time.respond_to?(:httpdate)
  response['Last-Modified'] = time
  halt 304 if time == request.env['HTTP_IF_MODIFIED_SINCE']
  time
end

def media_type(type)

Look up a media type by file extension in Rack's mime registry.
def media_type(type)
  Base.media_type(type)
end

def not_found(body=nil)

Halt processing and return a 404 Not Found.
def not_found(body=nil)
  error 404, body
end

def redirect(uri, *args)

Halt processing and redirect to the URI provided.
def redirect(uri, *args)
  status 302
  response['Location'] = uri
  halt(*args)
end

def send_file(path, opts={})

Use the contents of the file as the response body and attempt to
def send_file(path, opts={})
  stat = File.stat(path)
  last_modified stat.mtime
  content_type media_type(opts[:type]) ||
    media_type(File.extname(path)) ||
    response['Content-Type'] ||
    'application/octet-stream'
  response['Content-Length'] ||= (opts[:length] || stat.size).to_s
  halt StaticFile.open(path, 'rb')
rescue Errno::ENOENT
  not_found
end

def session

Access the underlying Rack session.
def session
  env['rack.session'] ||= {}
end

def status(value=nil)

Set or retrieve the response status code.
def status(value=nil)
  response.status = value if value
  response.status
end