83 lines
1.6 KiB
Ruby
83 lines
1.6 KiB
Ruby
require 'time'
|
|
require 'rack/utils'
|
|
require 'rack/mime'
|
|
|
|
module HostMeta
|
|
|
|
#
|
|
# Serve just a 'host-meta' request from a static file.
|
|
#
|
|
class File
|
|
attr_accessor :root
|
|
attr_accessor :path
|
|
|
|
alias :to_path :path
|
|
|
|
def initialize(root)
|
|
@root = root
|
|
end
|
|
|
|
def call(env)
|
|
dup._call(env)
|
|
end
|
|
|
|
F = ::File
|
|
|
|
def _call(env)
|
|
@path_info = Rack::Utils.unescape(env["PATH_INFO"])
|
|
@path = F.join(@root, @path_info)
|
|
|
|
available = begin
|
|
@path_info == "/host-meta" && F.file?(@path) && F.readable?(@path)
|
|
rescue SystemCallError
|
|
false
|
|
end
|
|
|
|
if available
|
|
serving(env)
|
|
else
|
|
fail(404, "File not found: #{@path_info}")
|
|
end
|
|
end
|
|
|
|
def serving(env)
|
|
# NOTE:
|
|
# We check via File::size? whether this file provides size info
|
|
# via stat (e.g. /proc files often don't), otherwise we have to
|
|
# figure it out by reading the whole file into memory.
|
|
@size = F.size?(@path) || Rack::Utils.bytesize(F.read(@path))
|
|
response = [
|
|
200,
|
|
{
|
|
"Last-Modified" => F.mtime(@path).httpdate,
|
|
"Content-Type" => 'application/xml+xrd; charset=utf-8'
|
|
},
|
|
self
|
|
]
|
|
response[1]["Content-Length"] = @size.to_s
|
|
response
|
|
end
|
|
|
|
def each
|
|
F.open(@path) do |file|
|
|
yield file.read( @size)
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def fail(status, body)
|
|
body += "\n"
|
|
[
|
|
status,
|
|
{
|
|
"Content-Type" => "text/plain",
|
|
"Content-Length" => body.size.to_s,
|
|
"X-Cascade" => "pass"
|
|
},
|
|
[body]
|
|
]
|
|
end
|
|
|
|
end
|
|
end
|