Now, users can set content type explicitly for their files in a number of ways, or rely on automatic file-extension content types. Proxied files default to automatic file-extension content types, but then fall back to the content type of the resource they proxy to. There is also a bug fixed around correctly setting content type inside send_file. Fixes #821.
172 lines
4.9 KiB
Ruby
172 lines
4.9 KiB
Ruby
module Middleman
|
|
|
|
module Sitemap
|
|
|
|
module Extensions
|
|
|
|
module Proxies
|
|
|
|
# Setup extension
|
|
class << self
|
|
|
|
# Once registered
|
|
def registered(app)
|
|
::Middleman::Sitemap::Resource.send :include, ResourceInstanceMethods
|
|
|
|
# Include methods
|
|
app.send :include, InstanceMethods
|
|
end
|
|
|
|
alias :included :registered
|
|
end
|
|
|
|
module ResourceInstanceMethods
|
|
# Whether this page is a proxy
|
|
# @return [Boolean]
|
|
def proxy?
|
|
!!@proxied_to
|
|
end
|
|
|
|
# Set this page to proxy to a target path
|
|
# @param [String] target
|
|
# @return [void]
|
|
def proxy_to(target)
|
|
target = ::Middleman::Util.normalize_path(target)
|
|
raise "You can't proxy #{path} to itself!" if target == path
|
|
@proxied_to = target
|
|
end
|
|
|
|
# The path of the page this page is proxied to, or nil if it's not proxied.
|
|
# @return [String]
|
|
def proxied_to
|
|
@proxied_to
|
|
end
|
|
|
|
# The resource for the page this page is proxied to. Throws an exception
|
|
# if there is no resource.
|
|
# @return [Sitemap::Resource]
|
|
def proxied_to_resource
|
|
proxy_resource = store.find_resource_by_path(proxied_to)
|
|
|
|
unless proxy_resource
|
|
raise "Path #{path} proxies to unknown file #{proxied_to}:#{store.resources.map(&:path)}"
|
|
end
|
|
|
|
if proxy_resource.proxy?
|
|
raise "You can't proxy #{path} to #{proxied_to} which is itself a proxy."
|
|
end
|
|
|
|
proxy_resource
|
|
end
|
|
|
|
def get_source_file
|
|
if proxy?
|
|
proxied_to_resource.source_file
|
|
else
|
|
super
|
|
end
|
|
end
|
|
|
|
def content_type
|
|
mime_type = super
|
|
return mime_type if mime_type
|
|
|
|
if proxy?
|
|
proxied_to_resource.content_type
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
end
|
|
|
|
module InstanceMethods
|
|
def proxy_manager
|
|
@_proxy_manager ||= ProxyManager.new(self)
|
|
end
|
|
|
|
def proxy(*args, &block)
|
|
proxy_manager.proxy(*args, &block)
|
|
end
|
|
end
|
|
|
|
# Manages the list of proxy configurations and manipulates the sitemap
|
|
# to include new resources based on those configurations
|
|
class ProxyManager
|
|
def initialize(app)
|
|
@app = app
|
|
@proxy_configs = Set.new
|
|
end
|
|
|
|
# Setup a proxy from a path to a target
|
|
# @param [String] path
|
|
# @param [String] target
|
|
# @param [Hash] opts options to apply to the proxy, including things like
|
|
# :locals, :ignore to hide the proxy target, :layout, and :directory_indexes.
|
|
# @return [void]
|
|
def proxy(path, target, opts={}, &block)
|
|
metadata = { :options => {}, :locals => {}, :blocks => [] }
|
|
metadata[:blocks] << block if block_given?
|
|
metadata[:locals] = opts.delete(:locals) || {}
|
|
|
|
@app.ignore(target) if opts.delete(:ignore)
|
|
metadata[:options] = opts
|
|
|
|
@proxy_configs << ProxyConfiguration.new(:path => path, :target => target, :metadata => metadata)
|
|
|
|
@app.sitemap.rebuild_resource_list!(:added_proxy)
|
|
end
|
|
|
|
# Update the main sitemap resource list
|
|
# @return [void]
|
|
def manipulate_resource_list(resources)
|
|
resources + @proxy_configs.map do |config|
|
|
p = ::Middleman::Sitemap::Resource.new(
|
|
@app.sitemap,
|
|
config.path
|
|
)
|
|
p.proxy_to(config.target)
|
|
p.add_metadata(config.metadata)
|
|
p
|
|
end
|
|
end
|
|
end
|
|
|
|
# Configuration for a proxy instance
|
|
class ProxyConfiguration
|
|
# The path that this proxy will appear at in the sitemap
|
|
attr_reader :path
|
|
def path=(p)
|
|
@path = ::Middleman::Util.normalize_path(p)
|
|
end
|
|
|
|
# The existing sitemap path that this will proxy to
|
|
attr_reader :target
|
|
def target=(t)
|
|
@target = ::Middleman::Util.normalize_path(t)
|
|
end
|
|
|
|
# Additional metadata like blocks and locals to apply to the proxy
|
|
attr_accessor :metadata
|
|
|
|
# Create a new proxy configuration from hash options
|
|
def initialize(options={})
|
|
options.each do |key, value|
|
|
send "#{key}=", value
|
|
end
|
|
end
|
|
|
|
# Two configurations are equal if they reference the same path
|
|
def eql?(other)
|
|
other.path == path
|
|
end
|
|
|
|
# Two configurations are equal if they reference the same path
|
|
def hash
|
|
path.hash
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|