Class: GitHttp::App
- Inherits:
-
Object
- Object
- GitHttp::App
- Defined in:
- lib/models/git_http.rb
Constant Summary collapse
- SERVICES =
[ ["POST", 'service_rpc', "(.*?)/git-upload-pack$", 'upload-pack'], ["POST", 'service_rpc', "(.*?)/git-receive-pack$", 'receive-pack'], ["GET", 'get_info_refs', "(.*?)/info/refs$"], ["GET", 'get_text_file', "(.*?)/HEAD$"], ["GET", 'get_text_file', "(.*?)/objects/info/alternates$"], ["GET", 'get_text_file', "(.*?)/objects/info/http-alternates$"], ["GET", 'get_info_packs', "(.*?)/objects/info/packs$"], ["GET", 'get_text_file', "(.*?)/objects/info/[^/]*$"], ["GET", 'get_loose_object', "(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$"], ["GET", 'get_pack_file', "(.*?)/objects/pack/pack-[0-9a-f]{40}\\.pack$"], ["GET", 'get_idx_file', "(.*?)/objects/pack/pack-[0-9a-f]{40}\\.idx$"], ]
- F =
logic helping functions
::File
- PLAIN_TYPE =
HTTP error response handling functions
{"Content-Type" => "text/plain"}
Instance Method Summary collapse
- #call(env) ⇒ Object
- #dumb_info_refs ⇒ Object
- #get_config_setting(service_name) ⇒ Object
- #get_git_config(config_name) ⇒ Object
- #get_git_dir(path) ⇒ Object
- #get_idx_file ⇒ Object
- #get_info_packs ⇒ Object
- #get_info_refs ⇒ Object
- #get_loose_object ⇒ Object
- #get_pack_file ⇒ Object
- #get_service_type ⇒ Object
- #get_text_file ⇒ Object
- #git_command(command) ⇒ Object
- #has_access(rpc, check_content_type = false) ⇒ Object
- #hdr_cache_forever ⇒ Object
-
#hdr_nocache ⇒ Object
———————— header writing functions ————————.
-
#initialize(config = false) ⇒ App
constructor
A new instance of App.
- #match_routing ⇒ Object
-
#pkt_flush ⇒ Object
—————————— packet-line handling functions ——————————.
- #pkt_write(str) ⇒ Object
- #read_body ⇒ Object
- #render_method_not_allowed ⇒ Object
- #render_no_access ⇒ Object
- #render_not_found ⇒ Object
-
#send_file(reqfile, content_type) ⇒ Object
some of this borrowed from the Rack::File implementation.
-
#service_rpc ⇒ Object
——————————— actual command handling functions ———————————.
- #set_config(config) ⇒ Object
- #set_config_setting(key, value) ⇒ Object
- #update_server_info ⇒ Object
Constructor Details
#initialize(config = false) ⇒ App
Returns a new instance of App.
48 49 50 |
# File 'lib/models/git_http.rb', line 48 def initialize(config = false) set_config(config) end |
Instance Method Details
#call(env) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/models/git_http.rb', line 60 def call(env) @env = env @req = Rack::Request.new(env) cmd, path, @reqfile, @rpc = match_routing return render_method_not_allowed if cmd == 'not_allowed' return render_not_found if !cmd @dir = get_git_dir(path) return render_not_found if !@dir Dir.chdir(@dir) do self.method(cmd).call() end end |
#dumb_info_refs ⇒ Object
119 120 121 122 123 124 |
# File 'lib/models/git_http.rb', line 119 def dumb_info_refs update_server_info send_file(@reqfile, "text/plain; charset=utf-8") do hdr_nocache end end |
#get_config_setting(service_name) ⇒ Object
238 239 240 241 242 243 244 245 246 |
# File 'lib/models/git_http.rb', line 238 def get_config_setting(service_name) service_name = service_name.gsub('-', '') setting = get_git_config("http.#{service_name}") if service_name == 'uploadpack' return setting != 'false' else return setting == 'true' end end |
#get_git_config(config_name) ⇒ Object
248 249 250 251 |
# File 'lib/models/git_http.rb', line 248 def get_git_config(config_name) cmd = git_command("config #{config_name}") `#{cmd}`.chomp end |
#get_git_dir(path) ⇒ Object
193 194 195 196 197 198 199 200 |
# File 'lib/models/git_http.rb', line 193 def get_git_dir(path) root = @config[:project_root] || `pwd` path = File.join(root, path) if File.exists?(path) # TODO: check is a valid git directory return path end false end |
#get_idx_file ⇒ Object
145 146 147 148 149 |
# File 'lib/models/git_http.rb', line 145 def get_idx_file send_file(@reqfile, "application/x-git-packed-objects-toc") do hdr_cache_forever end end |
#get_info_packs ⇒ Object
126 127 128 129 130 131 |
# File 'lib/models/git_http.rb', line 126 def get_info_packs # objects/info/packs send_file(@reqfile, "text/plain; charset=utf-8") do hdr_nocache end end |
#get_info_refs ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/models/git_http.rb', line 99 def get_info_refs service_name = get_service_type if has_access(service_name) cmd = git_command("#{service_name} --stateless-rpc --advertise-refs .") refs = `#{cmd}` @res = Rack::Response.new @res.status = 200 @res["Content-Type"] = "application/x-git-%s-advertisement" % service_name hdr_nocache @res.write(pkt_write("# service=git-#{service_name}\n")) @res.write(pkt_flush) @res.write(refs) @res.finish else dumb_info_refs end end |
#get_loose_object ⇒ Object
133 134 135 136 137 |
# File 'lib/models/git_http.rb', line 133 def get_loose_object send_file(@reqfile, "application/x-git-loose-object") do hdr_cache_forever end end |
#get_pack_file ⇒ Object
139 140 141 142 143 |
# File 'lib/models/git_http.rb', line 139 def get_pack_file send_file(@reqfile, "application/x-git-packed-objects") do hdr_cache_forever end end |
#get_service_type ⇒ Object
202 203 204 205 206 207 |
# File 'lib/models/git_http.rb', line 202 def get_service_type service_type = @req.params['service'] return false if !service_type return false if service_type[0, 4] != 'git-' service_type.gsub('git-', '') end |
#get_text_file ⇒ Object
151 152 153 154 155 |
# File 'lib/models/git_http.rb', line 151 def get_text_file send_file(@reqfile, "text/plain") do hdr_nocache end end |
#git_command(command) ⇒ Object
266 267 268 269 270 |
# File 'lib/models/git_http.rb', line 266 def git_command(command) git_bin = @config[:git_path] || 'git' command = "#{git_bin} #{command}" command end |
#has_access(rpc, check_content_type = false) ⇒ Object
224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/models/git_http.rb', line 224 def has_access(rpc, check_content_type = false) if check_content_type return false if @req.content_type != "application/x-git-%s-request" % rpc end return false if !['upload-pack', 'receive-pack'].include? rpc if rpc == 'receive-pack' return @config[:receive_pack] if @config.include? :receive_pack end if rpc == 'upload-pack' return @config[:upload_pack] if @config.include? :upload_pack end return get_config_setting(rpc) end |
#hdr_cache_forever ⇒ Object
318 319 320 321 322 323 |
# File 'lib/models/git_http.rb', line 318 def hdr_cache_forever now = Time.now().to_i @res["Date"] = now.to_s @res["Expires"] = (now + 31536000).to_s; @res["Cache-Control"] = "public, max-age=31536000"; end |
#hdr_nocache ⇒ Object
header writing functions
312 313 314 315 316 |
# File 'lib/models/git_http.rb', line 312 def hdr_nocache @res["Expires"] = "Fri, 01 Jan 1980 00:00:00 GMT" @res["Pragma"] = "no-cache" @res["Cache-Control"] = "no-cache, max-age=0, must-revalidate" end |
#match_routing ⇒ Object
209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/models/git_http.rb', line 209 def match_routing cmd = nil path = nil SERVICES.each do |method, handler, match, rpc| if m = Regexp.new(match).match(@req.path_info) return ['not_allowed'] if method != @req.request_method cmd = handler path = m[1] file = @req.path_info.sub(path + '/', '') return [cmd, path, file, rpc] end end return nil end |
#pkt_flush ⇒ Object
packet-line handling functions
299 300 301 |
# File 'lib/models/git_http.rb', line 299 def pkt_flush '0000' end |
#pkt_write(str) ⇒ Object
303 304 305 |
# File 'lib/models/git_http.rb', line 303 def pkt_write(str) (str.size + 4).to_s(base=16).rjust(4, '0') + str end |
#read_body ⇒ Object
253 254 255 256 257 258 259 |
# File 'lib/models/git_http.rb', line 253 def read_body if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/ input = Zlib::GzipReader.new(@req.body).read else input = @req.body.read end end |
#render_method_not_allowed ⇒ Object
278 279 280 281 282 283 284 |
# File 'lib/models/git_http.rb', line 278 def render_method_not_allowed if @env['SERVER_PROTOCOL'] == "HTTP/1.1" [405, PLAIN_TYPE, ["Method Not Allowed"]] else [400, PLAIN_TYPE, ["Bad Request"]] end end |
#render_no_access ⇒ Object
290 291 292 |
# File 'lib/models/git_http.rb', line 290 def render_no_access [403, PLAIN_TYPE, ["Forbidden"]] end |
#render_not_found ⇒ Object
286 287 288 |
# File 'lib/models/git_http.rb', line 286 def render_not_found [404, PLAIN_TYPE, ["Not Found"]] end |
#send_file(reqfile, content_type) ⇒ Object
some of this borrowed from the Rack::File implementation
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/models/git_http.rb', line 164 def send_file(reqfile, content_type) reqfile = File.join(@dir, reqfile) return render_not_found if !F.exists?(reqfile) @res = Rack::Response.new @res.status = 200 @res["Content-Type"] = content_type @res["Last-Modified"] = F.mtime(reqfile).httpdate yield if size = F.size?(reqfile) @res["Content-Length"] = size.to_s @res.finish do F.open(reqfile, "rb") do |file| while part = file.read(8192) @res.write part end end end else body = [F.read(reqfile)] size = Rack::Utils.bytesize(body.first) @res["Content-Length"] = size @res.write body @res.finish end end |
#service_rpc ⇒ Object
actual command handling functions
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/models/git_http.rb', line 80 def service_rpc return render_no_access if !has_access(@rpc, true) input = read_body @res = Rack::Response.new @res.status = 200 @res["Content-Type"] = "application/x-git-%s-result" % @rpc @res.finish do command = git_command("#{@rpc} --stateless-rpc #{@dir}") IO.popen(command, File::RDWR) do |pipe| pipe.write(input) while !pipe.eof? block = pipe.read(8192) # 8M at a time @res.write block # steam it to the client end end end end |
#set_config(config) ⇒ Object
52 53 54 |
# File 'lib/models/git_http.rb', line 52 def set_config(config) @config = config || {} end |
#set_config_setting(key, value) ⇒ Object
56 57 58 |
# File 'lib/models/git_http.rb', line 56 def set_config_setting(key, value) @config[key] = value end |
#update_server_info ⇒ Object
261 262 263 264 |
# File 'lib/models/git_http.rb', line 261 def update_server_info cmd = git_command("update-server-info") `#{cmd}` end |