blob: 9ec85cd869fcd8f9f5b522573b3c6679a903e8f7 [file] [log] [blame]
# respond_to (The MIT License)
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software
# and associated documentation files (the 'Software'), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
module Rack
module RespondTo
# This method is triggered after this helper is registred
# within Sinatra.
# We need to overide the default render method to supply correct path to the
# template, since Sinatra is by default looking in the current __FILE__ path
def self.registered(app)
app.use Rack::Accept
app.use Rack::MediaType
app.helpers Rack::RespondTo::Helpers
app.class_eval do
alias :render_without_format :render
def render(*args, &block)
begin
assumed_layout = args[1] == :layout
args[1] = "#{args[1]}.#{@media_type}".to_sym if args[1].is_a?(::Symbol)
render_without_format(*args, &block)
rescue Errno::ENOENT => e
raise "ERROR: Missing template: #{args[1]}.#{args[0]}" unless assumed_layout
raise e
end
end
private :render
end
end
module Helpers
# This code was inherited from respond_to plugin
# http://github.com/cehoffman/sinatra-respond_to
#
# This method is used to overide the default content_type returned from
# rack-accept middleware.
def self.included(klass)
klass.class_eval do
alias_method :original_content_type, :content_type
def content_type(*args)
original_content_type(*args)
request.env['rack-accept.formats'] = { args.first.to_sym => 1 }
response['Content-Type']
end
end
end
def accepting_formats
request.env['rack-accept.formats']
end
def static_file?(path)
public_dir = File.expand_path(settings.public)
path = File.expand_path(File.join(public_dir, unescape(path)))
path[0, public_dir.length] == public_dir && File.file?(path)
end
def respond_to(&block)
wants = {}
def wants.method_missing(type, *args, &handler)
self[type] = handler
end
yield wants
if request.env["SCRIPT_NAME"].include?("cimi") || Deltacloud.default_frontend.name == :cimi
#when cimi and neither json or xml defined... default to _something_ - json?
if ([:json, :xml] & accepting_formats.keys).empty?
request.env['rack-accept.formats'] = {:json=>0}
end
@media_type = (accepting_formats.has_key?(:xml) ? [:xml, accepting_formats[:xml]] : nil)
end if Deltacloud.respond_to? :default_frontend
@media_type ||= accepting_formats.to_a.sort { |a,b| a[1]<=>b[1] }.reverse.select do |format, priority|
wants.keys.include?(format) == true
end.first
if @media_type and @media_type.kind_of? Symbol
@media_type = [ @media_type ]
end
if @media_type and @media_type[0]
@media_type = @media_type[0]
if Rack::MediaType::ACCEPTED_MEDIA_TYPES[@media_type]
headers 'Content-Type' => Rack::MediaType::ACCEPTED_MEDIA_TYPES[@media_type][:return]
else
headers 'Content-Type' => 'application/xml'
end
wants[@media_type.to_sym].call if wants[@media_type.to_sym]
else
headers 'Content-Type' => nil
status 406
end
end
end
end
class MediaType < Sinatra::Base
include Rack::RespondTo::Helpers
# Define supported media types here
# The :return key stands for content-type which will be returned
# The :match key stands for the matching Accept header
ACCEPTED_MEDIA_TYPES = {
:xml => { :return => 'application/xml', :match => ['application/xml', 'text/xml'] },
:json => { :return => 'application/json', :match => ['application/json'] },
:html => { :return => 'text/html', :match => ['application/xhtml+xml', 'text/html', '*/*'] },
:png => { :return => 'image/png', :match => ['image/png'] },
:gv => { :return => 'application/ghostscript', :match => ['application/ghostscript'] }
} unless defined?(ACCEPTED_MEDIA_TYPES)
def call(env)
accept, index = env['rack-accept.request'], {}
# Skip everything when 'format' parameter is set in URL
if env['rack.request.query_hash'] and env['rack.request.query_hash']["format"]
media_type = case env['rack.request.query_hash']["format"]
when 'html' then :html
when 'xml' then :xml
when 'json' then :json
when 'gv' then :gv
when 'png' then :png
end
index[media_type] = 1 if media_type
else
# Sort all requested media types in Accept using their 'q' values
sorted_media_types = accept.media_type.qvalues.to_a.sort{ |a,b| a[1]<=>b[1] }.collect { |t| t.first }
# If Accept header is missing or is empty, fallback to XML format
sorted_media_types << 'application/xml' if sorted_media_types.empty?
# Choose the right format with the media type according to the priority
ACCEPTED_MEDIA_TYPES.each do |format, definition|
definition[:match].each do |mt|
break if index[format] = sorted_media_types.index(mt)
end
end
# Reject formats with no/nil priority
index.reject! { |format, priority| not priority }
end
#puts sorted_media_types.inspect
#puts index.inspect
# If after all we don't have any matching format assume that client has
# requested unknown/wrong media type and throw an 406 error with no body
if index.keys.empty?
status, headers, response = 406, {}, ""
else
env['rack-accept.formats'] = index
status, headers, response = @app.call(env)
end
[status, headers, response]
end
end
end