lib/git/webby/http_backend.rb
module Git::Webby
module HttpBackendHelpers #:nodoc:
include GitHelpers
def service_request?
not params[:service].nil?
end
# select_service feature
def service
@service = params[:service]
return false if @service.nil?
return false if @service[0, 4] != "git-"
@service = @service.gsub("git-", "")
end
# pkt_write feature
def packet_write(line)
(line.size + 4).to_s(16).rjust(4, "0") + line
end
# pkt_flush feature
def packet_flush
"0000"
end
# hdr_nocache feature
def header_nocache
headers "Expires" => "Fri, 01 Jan 1980 00:00:00 GMT",
"Pragma" => "no-cache",
"Cache-Control" => "no-cache, max-age=0, must-revalidate"
end
# hdr_cache_forever feature
def header_cache_forever
now = Time.now
headers "Date" => now.to_s,
"Expires" => (now + 31536000).to_s,
"Cache-Control" => "public, max-age=31536000"
end
# select_getanyfile feature
def read_any_file
unless settings.get_any_file
halt 403, "Unsupported service: getanyfile"
end
end
# get_text_file feature
def read_text_file(*file)
read_any_file
header_nocache
content_type "text/plain"
repository.read_file(*file)
end
# get_loose_object feature
def send_loose_object(prefix, suffix)
read_any_file
header_cache_forever
content_type_for_git :loose, :object
send_file(repository.loose_object_path(prefix, suffix))
end
# get_pack_file and get_idx_file
def send_pack_idx_file(pack, idx = false)
read_any_file
header_cache_forever
content_type_for_git :packed, :objects, (idx ? :toc : nil)
send_file(repository.pack_idx_path(pack))
end
def send_info_packs
read_any_file
header_nocache
content_type "text/plain; charset=utf-8"
send_file(repository.info_packs_path)
end
# run_service feature
def run_advertisement(service)
header_nocache
content_type_for_git service, :advertisement
response.body.clear
response.body << packet_write("# service=git-#{service}\n")
response.body << packet_flush
response.body << repository.run(service, "--stateless-rpc --advertise-refs .")
response.finish
end
def run_process(service)
content_type_for_git service, :result
input = request.body.read
command = repository.cli(service, "--stateless-rpc #{git.repository}")
# This source has extracted from Grack written by Scott Chacon.
IO.popen(command, File::RDWR) do |pipe|
pipe.write(input)
while !pipe.eof?
block = pipe.read(8192) # 8M at a time
response.write block # steam it to the client
end
end # IO
response.finish
end
end # HttpBackendHelpers
# The Smart HTTP handler server. This is the main Web application which respond to following requests:
#
# <repo.git>/HEAD :: HEAD contents
# <repo.git>/info/refs :: Text file that contains references.
# <repo.git>/objects/info/* :: Text file that contains all list of packets, alternates or http-alternates.
# <repo.git>/objects/*/* :: Git objects, packets or indexes.
# <repo.git>/upload-pack :: Post an upload packets.
# <repo.git>/receive-pack :: Post a receive packets.
#
# See ::configure for more details.
class HttpBackend < Application
set :authenticate, true
set :get_any_file, true
set :upload_pack, true
set :receive_pack, false
helpers HttpBackendHelpers
before do
authenticate! if settings.authenticate
end
# implements the get_text_file function
get "/:repository/HEAD" do
read_text_file("HEAD")
end
# implements the get_info_refs function
get "/:repository/info/refs" do
if service_request? # by URL query parameters
run_advertisement service
else
read_text_file(:info, :refs)
end
end
# implements the get_text_file and get_info_packs functions
get %r{/(.*?)/objects/info/(packs|alternates|http-alternates)$} do |repository, file|
if file == "packs"
send_info_packs
else
read_text_file(:objects, :info, file)
end
end
# implements the get_loose_object function
get %r{/(.*?)/objects/([0-9a-f]{2})/([0-9a-f]{38})$} do |repository, prefix, suffix|
send_loose_object(prefix, suffix)
end
# implements the get_pack_file and get_idx_file functions
get %r{/(.*?)/objects/pack/(pack-[0-9a-f]{40}.(pack|idx))$} do |repository, pack, ext|
send_pack_idx_file(pack, ext == "idx")
end
# implements the service_rpc function
post "/:repository/:service" do
run_process service
end
private
helpers AuthenticationHelpers
end # HttpBackendServer
end # Git::Webby