summaryrefslogtreecommitdiffstats
path: root/script/git-daemon
blob: f5d91c2644590bc35c4e3bb685a6a462b771ec6d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/usr/bin/env ruby

require 'rubygems'
require 'daemons'
require 'geoip'
require 'socket'

ENV["RAILS_ENV"] ||= "production"
require File.dirname(__FILE__)+'/../config/environment'

Rails.configuration.log_level = :info # Disable debug

BASE_PATH = File.expand_path(GitoriousConfig['repository_base_path'])

module Git

class Daemon
  include Daemonize
  
  def self.start
    new
  end
  
  def initialize
    daemonize(File.join(RAILS_ROOT, "log", "git-daemon.log"))
    
    @geoip = GeoIP.new(File.join(RAILS_ROOT, "data", "GeoIP.dat"))
    trap "CLD" do
      pid = Process.wait
      log(pid, "Disconnected. (status=#{$?.exitstatus})")
    end
    
    port = 9418
    server = TCPServer.new('localhost', port)
    service_regexp = /(\w{4})(git-[\w-]+)\s(.+)\x0host=([\w\.\-]+)/.freeze
    while session = server.accept
      line = session.recv(1000)
      timeout = 30
      if line =~ service_regexp
        code = $1
        service = $2
        path = $3
        host = $4
        
        path = "#{BASE_PATH}/#{path}"
        if !File.directory?(path)
          log(Process.pid, "Invalid path: #{path}")
          session.close
          next
        end
        
        if !File.exist?(File.join(path, "git-daemon-export-ok"))
          session.close
          next
        end
        
        Dir.chdir(path) do
          cmd = "git-upload-pack --strict --timeout=#{timeout} ."
          
          fork do
            repository = nil
            begin
              ActiveRecord::Base.allow_concurrency = true
              repository = ::Repository.find_by_path(path)
            rescue Exception
            end
            pid = Process.pid
            domain, port, name, ip = session.addr
            log(pid, "Connection from #{ip}")
            
            $stdout.reopen(session)
            $stdin.reopen(session)
            session.close
            
            if repository
              localization = @geoip.country(ip)
              repository.cloned_from(ip, localization[3], localization[5])
            else
              log(pid, "Cannot find repository: #{path}")
            end
            
            exec(cmd)
            
            exit!
          end
        end
      else
        $stderr.puts "Invalid request: #{line}"
        session.close
      end
    end
  end
  
  def log(pid, msg)
    $stderr.puts "[#{pid}] #{msg}"
  end
end

end

trap "SIGINT" do
  $stderr.puts "Exiting..."
  exit 0
end

Git::Daemon.start