module GitObjectBrowser module Server class GitServlet < WEBrick::HTTPServlet::AbstractServlet def initialize(server, target) @target = File.expand_path(target) end def do_GET(request, response) # status, content_type, body = do_stuff_with request path = request.path unless path =~ %r{/.git(?:/(.*))?} not_found(response) return end @relpath = $1.to_s path = File.join(@target, @relpath) unless File.exist?(path) not_found(response) unless redirect_to_packed_object(response) return end if path =~ /\.\./ not_found(response) return end return if response_directory(response) return if response_index(response) return if response_object(response) return if response_ref(response) return if response_packed_object(response, request.query["offset"]) return if response_pack_file(response) return if response_pack_index(response) return if response_info_refs(response) return if response_packed_refs(response) response_file(response) end def redirect_to_packed_object(response) return false unless GitObjectBrowser::Models::GitObject.path?(@relpath) sha1 = @relpath.gsub(%r{\A.*/([0-9a-f]{2})/([0-9a-f]{38})\z}, '\1\2') Dir.chdir(@target) do Dir.glob('objects/pack/*.idx') do |path| File.open(path) do |input| index = GitObjectBrowser::Models::PackIndex.new(input) result = index.find(sha1) unless result.nil? packfile = path.sub(/\.idx\z/, '.pack') response.status = 302 response["Location"] = "/.git/#{ packfile }?offset=#{ result[:offset] }" return true end end end end false end def response_wrapped_object(response, type, obj) ok(response) hash = {} hash[:type] = type hash[:object] = obj.to_hash hash[:root] = @target hash[:path] = @relpath hash[:wroking_dir] = File.basename(File.dirname(@target)) if type == 'packed_object' sha1 = hash[:object][:object][:sha1] hash[:unpacked] = File.exist?(File.join(@target, 'objects', sha1[0..1], sha1[2..-1]).to_s) end response.body = ::JSON.generate(hash) end def response_directory(response) return false unless File.directory?(File.join(@target, @relpath)) obj = GitObjectBrowser::Models::Directory.new(@target, @relpath) response_wrapped_object(response, "directory", obj) return true end def response_index(response) return false unless @relpath == "index" obj = {} File.open(File.join(@target, @relpath)) do |input| obj = GitObjectBrowser::Models::Index.new(input).parse end response_wrapped_object(response, "index", obj) return true end def response_object(response) return false unless GitObjectBrowser::Models::GitObject.path?(@relpath) obj = {} File.open(File.join(@target, @relpath)) do |input| obj = GitObjectBrowser::Models::GitObject.new(input).parse end response_wrapped_object(response, "object", obj) return true end def response_ref(response) return false unless GitObjectBrowser::Models::Ref.path?(@relpath) obj = {} File.open(File.join(@target, @relpath)) do |input| obj = GitObjectBrowser::Models::Ref.new(input) end response_wrapped_object(response, "ref", obj) return true end def response_pack_index(response) return false unless GitObjectBrowser::Models::PackIndex.path?(@relpath) obj = {} File.open(File.join(@target, @relpath)) do |input| obj = GitObjectBrowser::Models::PackIndex.new(input).parse end File.open(index_to_pack_path) do |input| obj.load_object_types(input) end response_wrapped_object(response, "pack_index", obj) return true end def response_pack_file(response) return false unless GitObjectBrowser::Models::PackFile.path?(@relpath) obj = {} File.open(File.join(@target, @relpath)) do |input| obj = GitObjectBrowser::Models::PackFile.new(input).parse end response_wrapped_object(response, 'pack_file', obj) return true end def index_to_pack_path File.join(@target, @relpath.sub(/\.idx\z/, '.pack')) end def pack_to_index_path File.join(@target, @relpath.sub(/\.pack\z/, '.idx')) end def response_packed_object(response, offset) return false if offset.nil? return false unless GitObjectBrowser::Models::PackedObject.path?(@relpath) obj = {} File.open(pack_to_index_path) do |index_input| index = GitObjectBrowser::Models::PackIndex.new(index_input) File.open(File.join(@target, @relpath)) do |input| obj = GitObjectBrowser::Models::PackedObject.new(index, input).parse(offset.to_i) end end response_wrapped_object(response, "packed_object", obj) return true end def response_info_refs(response) return false unless GitObjectBrowser::Models::InfoRefs.path?(@relpath) obj = {} File.open(File.join(@target, @relpath)) do |input| obj = GitObjectBrowser::Models::InfoRefs.new(input) end response_wrapped_object(response, "info_refs", obj) return true end def response_packed_refs(response) return false unless GitObjectBrowser::Models::PackedRefs.path?(@relpath) obj = {} File.open(File.join(@target, @relpath)) do |input| obj = GitObjectBrowser::Models::PackedRefs.new(input) end response_wrapped_object(response, "packed_refs", obj) return true end def response_file(response) path = File.join(@target, @relpath) obj = {} File.open(path) do |input| obj = GitObjectBrowser::Models::PlainFile.new(input).parse end response_wrapped_object(response, "file", obj) return true end def ok(response) response.status = 200 response['Content-Type'] = 'application/json' end def not_found(response) response.status = 404 response['Content-Type'] = 'application/json' response.body = '{}' end end end end