class Blaggard::Server

Constants

CRLF

Uses chunked (streaming) transfer, otherwise response blocks to calculate Content-Length header en.wikipedia.org/wiki/Chunked_transfer_encoding

PLAIN_TYPE

HTTP error response handling functions


SERVICES

Attributes

config[R]
git[R]

Public Class Methods

new(conf = false) click to toggle source
# File lib/blaggard/server.rb, line 19
def initialize(conf = false)
  if conf.instance_of? Hash
    @config = conf
  elsif (File.exist?(conf) rescue false)
    @config = YAML.load( File.read conf )
  else
    @config = {}
  end
end

Public Instance Methods

_call(env) click to toggle source
# File lib/blaggard/server.rb, line 37
def _call(env)
  @env = env
  # puts 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

  @git = get_git(path)
  return render_not_found unless git.valid_repo?


  identifier = env['REMOTE_USER']
  @groups = Blaggard::GroupFinder.new(@config).find(identifier) if @config[:use_acl]

  self.method(cmd).call()
end
call(env) click to toggle source
# File lib/blaggard/server.rb, line 33
def call(env)
  dup._call(env)
end
dumb_info_refs() click to toggle source
# File lib/blaggard/server.rb, line 123
def dumb_info_refs
  git.update_server_info
  send_file(@reqfile, "text/plain; charset=utf-8") do
    hdr_nocache
  end
end
encode_chunk(chunk) click to toggle source
# File lib/blaggard/server.rb, line 92
def encode_chunk(chunk)
  size_in_hex = chunk.size.to_s(16)
  [ size_in_hex, CRLF, chunk, CRLF ].join
end
get_git(path) click to toggle source
# File lib/blaggard/server.rb, line 199
def get_git(path)
  root = @config[:project_root] || Dir.pwd
  path = File.join(root, path)
  Blaggard::Git.new( path, @config[:git_path] )
end
get_idx_file() click to toggle source
# File lib/blaggard/server.rb, line 149
def get_idx_file
  send_file(@reqfile, "application/x-git-packed-objects-toc") do
    hdr_cache_forever
  end
end
get_info_packs() click to toggle source
# File lib/blaggard/server.rb, line 130
def get_info_packs
  # objects/info/packs
  send_file(@reqfile, "text/plain; charset=utf-8") do
    hdr_nocache
  end
end
get_info_refs() click to toggle source
# File lib/blaggard/server.rb, line 101
def get_info_refs
  service_name = get_service_type
  return render_no_access unless has_access?(service_name)

  refs = begin
    if @config[:use_acl]
      Blaggard::Advertisement.new(git.repo, @groups, service_name).advertise
    else
      git.execute(%W(#{service_name} --stateless-rpc --advertise-refs #{git.repo}))
    end
  end

  @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
end
get_loose_object() click to toggle source
# File lib/blaggard/server.rb, line 137
def get_loose_object
  send_file(@reqfile, "application/x-git-loose-object") do
    hdr_cache_forever
  end
end
get_pack_file() click to toggle source
# File lib/blaggard/server.rb, line 143
def get_pack_file
  send_file(@reqfile, "application/x-git-packed-objects") do
    hdr_cache_forever
  end
end
get_service_type() click to toggle source
# File lib/blaggard/server.rb, line 205
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() click to toggle source
# File lib/blaggard/server.rb, line 155
def get_text_file
  send_file(@reqfile, "text/plain") do
    hdr_nocache
  end
end
has_access?(rpc, check_content_type = false) click to toggle source
# File lib/blaggard/server.rb, line 229
def has_access?(rpc, check_content_type = false)
  if check_content_type
    return false unless smart_http?(rpc)
  end

  return false unless ['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

  git.config_setting(rpc)
end
hdr_cache_forever() click to toggle source
# File lib/blaggard/server.rb, line 303
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() click to toggle source

header writing functions


# File lib/blaggard/server.rb, line 297
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() click to toggle source
# File lib/blaggard/server.rb, line 212
def match_routing
  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() click to toggle source

packet-line handling functions


# File lib/blaggard/server.rb, line 284
def pkt_flush
  '0000'
end
pkt_write(str) click to toggle source
# File lib/blaggard/server.rb, line 288
def pkt_write(str)
  (str.size + 4).to_s(base=16).rjust(4, '0') + str
end
read_body() click to toggle source
# File lib/blaggard/server.rb, line 249
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() click to toggle source
# File lib/blaggard/server.rb, line 263
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() click to toggle source
# File lib/blaggard/server.rb, line 275
def render_no_access
  [403, PLAIN_TYPE, ["Forbidden"]]
end
render_not_found() click to toggle source
# File lib/blaggard/server.rb, line 271
def render_not_found
  [404, PLAIN_TYPE, ["Not Found"]]
end
send_file(reqfile, content_type) { || ... } click to toggle source

some of this borrowed from the Rack::File implementation

# File lib/blaggard/server.rb, line 166
 def send_file(reqfile, content_type)
  reqfile = File.join(git.repo, reqfile)
  return render_not_found unless File.exists?(reqfile)

  return render_not_found unless reqfile == File.realpath(reqfile)

  # reqfile looks legit: no path traversal, no leading '|'

  @res = Rack::Response.new
  @res.status = 200
  @res["Content-Type"]  = content_type
  @res["Last-Modified"] = File.mtime(reqfile).httpdate

  yield

  if size = File.size?(reqfile)
    @res["Content-Length"] = size.to_s
    @res.finish do
      File.open(reqfile, "rb") do |file|
        while part = file.read(8192)
          @res.write part
        end
      end
    end
  else
    body = [File.read(reqfile)]
    size = Rack::Utils.bytesize(body.first)
    @res["Content-Length"] = size
    @res.write body
    @res.finish
  end
end
service_rpc() click to toggle source
# File lib/blaggard/server.rb, line 66
def service_rpc
  return render_no_access unless has_access?(@rpc, true)

  input = read_body

  @res = Rack::Response.new
  @res.status = 200
  @res["Content-Type"] = "application/x-git-%s-result" % @rpc
  @res["Transfer-Encoding"] = "chunked"
  @res["Cache-Control"] = "no-cache"

  @res.finish do
    git.execute([@rpc, '--stateless-rpc', git.repo]) do |pipe|
      pipe.write(input)
      pipe.close_write

      while !pipe.eof?
        block = pipe.read(8192)     # 8KB at a time
        @res.write encode_chunk(block)  # stream it to the client
      end

      @res.write terminating_chunk
    end
  end
end
set_config_setting(key, value) click to toggle source
# File lib/blaggard/server.rb, line 29
def set_config_setting(key, value)
  @config[key] = value
end
smart_http?(rpc = @rpc) click to toggle source
# File lib/blaggard/server.rb, line 225
def smart_http?(rpc = @rpc)
  @req.content_type ==  "application/x-git-#{rpc}-request"
end
terminating_chunk() click to toggle source
# File lib/blaggard/server.rb, line 97
def terminating_chunk
  [ 0, CRLF, CRLF ].join
end