gitlab-grack 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ coverage/
2
+ pkg/
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "tests/example"]
2
+ path = tests/example
3
+ url = git://github.com/schacon/simplegit.git
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ Grack - Ruby/Rack Git Smart-HTTP Server Handler
2
+ ===============================================
3
+
4
+ This project aims to replace the builtin git-http-backend CGI handler
5
+ distributed with C Git with a Rack application. This reason for doing this
6
+ is to allow far more webservers to be able to handle Git smart http requests.
7
+
8
+ The default git-http-backend only runs as a CGI script, and specifically is
9
+ only targeted for Apache 2.x usage (it requires PATH_INFO to be set and
10
+ specifically formatted). So, instead of trying to get it to work with
11
+ other CGI capable webservers (Lighttpd, etc), we can get it running on nearly
12
+ every major and minor webserver out there by making it Rack capable. Rack
13
+ applications can run with the following handlers:
14
+
15
+ * CGI
16
+ * FCGI
17
+ * Mongrel (and EventedMongrel and SwiftipliedMongrel)
18
+ * WEBrick
19
+ * SCGI
20
+ * LiteSpeed
21
+ * Thin
22
+
23
+ These web servers include Rack handlers in their distributions:
24
+
25
+ * Ebb
26
+ * Fuzed
27
+ * Phusion Passenger (which is mod_rack for Apache and for nginx)
28
+ * Unicorn
29
+
30
+ With [Warbler](http://caldersphere.rubyforge.org/warbler/classes/Warbler.html),
31
+ and JRuby, we can also generate a WAR file that can be deployed in any Java
32
+ web application server (Tomcat, Glassfish, Websphere, JBoss, etc).
33
+
34
+ Since the git-http-backend is really just a simple wrapper for the upload-pack
35
+ and receive-pack processes with the '--stateless-rpc' option, it does not
36
+ actually re-implement very much.
37
+
38
+ Dependencies
39
+ ========================
40
+ * Ruby - http://www.ruby-lang.org
41
+ * Rack - http://rack.rubyforge.org
42
+ * A Rack-compatible web server
43
+ * Git >= 1.7 (currently the 'pu' branch)
44
+ * Mocha (only for running the tests)
45
+
46
+ Quick Start
47
+ ========================
48
+ $ gem install rack
49
+ $ (edit config.ru to set git project path)
50
+ $ rackup --host 127.0.0.1 -p 8080 config.ru
51
+ $ git clone http://127.0.0.1:8080/schacon/grit.git
52
+
53
+ Contributing
54
+ ========================
55
+ If you would like to contribute to the Grack project, I prefer to get
56
+ pull-requests via GitHub. You should include tests for whatever functionality
57
+ you add. Just fork this project, push your changes to your fork and click
58
+ the 'pull request' button. To run the tests, you first need to install the
59
+ 'mocha' mocking library and initialize the submodule.
60
+
61
+ $ sudo gem install mocha
62
+ $ git submodule init
63
+ $ git submodule update
64
+
65
+ Then you should be able to run the tests with a 'rake' command. You can also
66
+ run coverage tests with 'rake rcov' if you have rcov installed.
67
+
68
+ License
69
+ ========================
70
+ (The MIT License)
71
+
72
+ Copyright (c) 2009 Scott Chacon <schacon@gmail.com>
73
+
74
+ Permission is hereby granted, free of charge, to any person obtaining
75
+ a copy of this software and associated documentation files (the
76
+ 'Software'), to deal in the Software without restriction, including
77
+ without limitation the rights to use, copy, modify, merge, publish,
78
+ distribute, sublicense, and/or sell copies of the Software, and to
79
+ permit persons to whom the Software is furnished to do so, subject to
80
+ the following conditions:
81
+
82
+ The above copyright notice and this permission notice shall be
83
+ included in all copies or substantial portions of the Software.
84
+
85
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
88
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
89
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
90
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
91
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ task :default => :test
5
+
6
+ desc "Run the tests."
7
+ task :test do
8
+ Dir.glob("tests/*_test.rb").each do |f|
9
+ system "ruby #{f}"
10
+ end
11
+ end
12
+
13
+ desc "Run test coverage."
14
+ task :rcov do
15
+ system "rcov tests/*_test.rb -i lib/git_http.rb -x rack -x Library -x tests"
16
+ system "open coverage/index.html"
17
+ end
18
+
19
+ namespace :grack do
20
+ desc "Start Grack"
21
+ task :start do
22
+ system "rackup config.ru -p 8080"
23
+ end
24
+ end
25
+
26
+ desc "Start everything."
27
+ multitask :start => [ 'grack:start' ]
@@ -0,0 +1,9 @@
1
+ #! /usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/lib')
3
+ require 'lib/git_http'
4
+ config = {
5
+ :project_root => "/opt",
6
+ :upload_pack => true,
7
+ :receive_pack => false,
8
+ }
9
+ Rack::Handler::FastCGI.run(GitHttp::App.new(config))
data/grack.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/grack/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Scott Chacon"]
6
+ gem.email = ["schacon@gmail.com"]
7
+ gem.description = %q{Ruby/Rack Git Smart-HTTP Server Handler}
8
+ gem.summary = %q{Ruby/Rack Git Smart-HTTP Server Handler}
9
+ gem.homepage = "https://github.com/schacon/grack"
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- tests/*`.split("\n")
14
+ gem.name = "gitlab-grack"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Grack::VERSION
17
+
18
+ gem.add_dependency("rack", "~> 1.4.1")
19
+ gem.add_development_dependency("mocha", "~> 0.11")
20
+ end
data/install.txt ADDED
@@ -0,0 +1,60 @@
1
+ Installation
2
+ ========================
3
+
4
+ ** This documentation is not finished yet. I haven't tested all of
5
+ these and it's obviously incomplete - these are currently just notes.
6
+
7
+ FastCGI
8
+ ---------------------------------------
9
+ Here is an example config from lighttpd server:
10
+ ----
11
+ # main fastcgi entry
12
+ $HTTP["url"] =~ "^/myapp/.+$" {
13
+ fastcgi.server = ( "/myapp" =>
14
+ ( "localhost" =>
15
+ ( "bin-path" => "/var/www/localhost/cgi-bin/dispatch.fcgi",
16
+ "docroot" => "/var/www/localhost/htdocs/myapp",
17
+ "host" => "127.0.0.1",
18
+ "port" => 1026,
19
+ "check-local" => "disable"
20
+ )
21
+ )
22
+ )
23
+ } # HTTP[url]
24
+ ----
25
+ You can use the examples/dispatch.fcgi file as your dispatcher.
26
+
27
+ (Example Apache setup?)
28
+
29
+ Installing in a Java application server
30
+ ---------------------------------------
31
+ # install Warbler
32
+ $ sudo gem install warbler
33
+ $ cd gitsmart
34
+ $ (edit config.ru)
35
+ $ warble
36
+ $ cp gitsmart.war /path/to/java/autodeploy/dir
37
+
38
+ Unicorn
39
+ ---------------------------------------
40
+ With Unicorn (http://unicorn.bogomips.org/) you can just run 'unicorn'
41
+ in the directory with the config.ru file.
42
+
43
+ Thin
44
+ ---------------------------------------
45
+ thin.yml
46
+ ---
47
+ pid: /home/deploy/myapp/server/thin.pid
48
+ log: /home/deploy/myapp/logs/thin.log
49
+ timeout: 30
50
+ port: 7654
51
+ max_conns: 1024
52
+ chdir: /home/deploy/myapp/site_files
53
+ rackup: /home/deploy/myapp/server/config.ru
54
+ max_persistent_conns: 512
55
+ environment: production
56
+ address: 127.0.0.1
57
+ servers: 1
58
+ daemonize: true
59
+
60
+
data/lib/grack.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "grack/bundle"
2
+
3
+ module Grack
4
+
5
+ end
data/lib/grack/auth.rb ADDED
@@ -0,0 +1,37 @@
1
+ require 'rack/auth/basic'
2
+ require 'rack/auth/abstract/handler'
3
+ require 'rack/auth/abstract/request'
4
+
5
+ module Grack
6
+ class Auth < Rack::Auth::Basic
7
+ def call(env)
8
+ @env = env
9
+ @request = Rack::Request.new(env)
10
+ @auth = Request.new(env)
11
+
12
+ if not @auth.provided?
13
+ unauthorized
14
+ elsif not @auth.basic?
15
+ bad_request
16
+ else
17
+ result = if (access = valid? and access == true)
18
+ @env['REMOTE_USER'] = @auth.username
19
+ @app.call(env)
20
+ else
21
+ if access == '404'
22
+ render_not_found
23
+ elsif access == '403'
24
+ render_no_access
25
+ else
26
+ unauthorized
27
+ end
28
+ end
29
+ result
30
+ end
31
+ end# method call
32
+
33
+ def valid?
34
+ false
35
+ end
36
+ end# class Auth
37
+ end# module Grack
@@ -0,0 +1,20 @@
1
+ require 'rack/builder'
2
+ require 'grack/auth'
3
+ require 'grack/server'
4
+
5
+ module Grack
6
+ module Bundle
7
+ extend self
8
+
9
+ def new(config)
10
+ Rack::Builder.new do
11
+ use Grack::Auth do |username, password|
12
+ false
13
+ end
14
+
15
+ run Grack::Server.new(config)
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,304 @@
1
+ require 'zlib'
2
+ require 'rack/request'
3
+ require 'rack/response'
4
+ require 'rack/utils'
5
+ require 'time'
6
+
7
+ module Grack
8
+ class Server
9
+
10
+ SERVICES = [
11
+ ["POST", 'service_rpc', "(.*?)/git-upload-pack$", 'upload-pack'],
12
+ ["POST", 'service_rpc', "(.*?)/git-receive-pack$", 'receive-pack'],
13
+
14
+ ["GET", 'get_info_refs', "(.*?)/info/refs$"],
15
+ ["GET", 'get_text_file', "(.*?)/HEAD$"],
16
+ ["GET", 'get_text_file', "(.*?)/objects/info/alternates$"],
17
+ ["GET", 'get_text_file', "(.*?)/objects/info/http-alternates$"],
18
+ ["GET", 'get_info_packs', "(.*?)/objects/info/packs$"],
19
+ ["GET", 'get_text_file', "(.*?)/objects/info/[^/]*$"],
20
+ ["GET", 'get_loose_object', "(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$"],
21
+ ["GET", 'get_pack_file', "(.*?)/objects/pack/pack-[0-9a-f]{40}\\.pack$"],
22
+ ["GET", 'get_idx_file', "(.*?)/objects/pack/pack-[0-9a-f]{40}\\.idx$"],
23
+ ]
24
+
25
+ def initialize(config = false)
26
+ set_config(config)
27
+ end
28
+
29
+ def set_config(config)
30
+ @config = config || {}
31
+ end
32
+
33
+ def set_config_setting(key, value)
34
+ @config[key] = value
35
+ end
36
+
37
+ def call(env)
38
+ @env = env
39
+ @req = Rack::Request.new(env)
40
+
41
+ cmd, path, @reqfile, @rpc = match_routing
42
+
43
+ return render_method_not_allowed if cmd == 'not_allowed'
44
+ return render_not_found if !cmd
45
+
46
+ @dir = get_git_dir(path)
47
+ return render_not_found if !@dir
48
+
49
+ Dir.chdir(@dir) do
50
+ self.method(cmd).call()
51
+ end
52
+ end
53
+
54
+ # ---------------------------------
55
+ # actual command handling functions
56
+ # ---------------------------------
57
+
58
+ def service_rpc
59
+ return render_no_access if !has_access(@rpc, true)
60
+ input = read_body
61
+
62
+ @res = Rack::Response.new
63
+ @res.status = 200
64
+ @res["Content-Type"] = "application/x-git-%s-result" % @rpc
65
+ @res.finish do
66
+ command = git_command("#{@rpc} --stateless-rpc #{@dir}")
67
+ IO.popen(command, File::RDWR) do |pipe|
68
+ pipe.write(input)
69
+ while !pipe.eof?
70
+ block = pipe.read(8192) # 8M at a time
71
+ @res.write block # steam it to the client
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ def get_info_refs
78
+ service_name = get_service_type
79
+
80
+ if has_access(service_name)
81
+ cmd = git_command("#{service_name} --stateless-rpc --advertise-refs .")
82
+ refs = `#{cmd}`
83
+
84
+ @res = Rack::Response.new
85
+ @res.status = 200
86
+ @res["Content-Type"] = "application/x-git-%s-advertisement" % service_name
87
+ hdr_nocache
88
+ @res.write(pkt_write("# service=git-#{service_name}\n"))
89
+ @res.write(pkt_flush)
90
+ @res.write(refs)
91
+ @res.finish
92
+ else
93
+ dumb_info_refs
94
+ end
95
+ end
96
+
97
+ def dumb_info_refs
98
+ update_server_info
99
+ send_file(@reqfile, "text/plain; charset=utf-8") do
100
+ hdr_nocache
101
+ end
102
+ end
103
+
104
+ def get_info_packs
105
+ # objects/info/packs
106
+ send_file(@reqfile, "text/plain; charset=utf-8") do
107
+ hdr_nocache
108
+ end
109
+ end
110
+
111
+ def get_loose_object
112
+ send_file(@reqfile, "application/x-git-loose-object") do
113
+ hdr_cache_forever
114
+ end
115
+ end
116
+
117
+ def get_pack_file
118
+ send_file(@reqfile, "application/x-git-packed-objects") do
119
+ hdr_cache_forever
120
+ end
121
+ end
122
+
123
+ def get_idx_file
124
+ send_file(@reqfile, "application/x-git-packed-objects-toc") do
125
+ hdr_cache_forever
126
+ end
127
+ end
128
+
129
+ def get_text_file
130
+ send_file(@reqfile, "text/plain") do
131
+ hdr_nocache
132
+ end
133
+ end
134
+
135
+ # ------------------------
136
+ # logic helping functions
137
+ # ------------------------
138
+
139
+ F = ::File
140
+
141
+ # some of this borrowed from the Rack::File implementation
142
+ def send_file(reqfile, content_type)
143
+ reqfile = File.join(@dir, reqfile)
144
+ return render_not_found if !F.exists?(reqfile)
145
+
146
+ @res = Rack::Response.new
147
+ @res.status = 200
148
+ @res["Content-Type"] = content_type
149
+ @res["Last-Modified"] = F.mtime(reqfile).httpdate
150
+
151
+ yield
152
+
153
+ if size = F.size?(reqfile)
154
+ @res["Content-Length"] = size.to_s
155
+ @res.finish do
156
+ F.open(reqfile, "rb") do |file|
157
+ while part = file.read(8192)
158
+ @res.write part
159
+ end
160
+ end
161
+ end
162
+ else
163
+ body = [F.read(reqfile)]
164
+ size = Rack::Utils.bytesize(body.first)
165
+ @res["Content-Length"] = size
166
+ @res.write body
167
+ @res.finish
168
+ end
169
+ end
170
+
171
+ def get_git_dir(path)
172
+ root = @config[:project_root] || `pwd`
173
+ path = File.join(root, path)
174
+ if File.exists?(path) # TODO: check is a valid git directory
175
+ return path
176
+ end
177
+ false
178
+ end
179
+
180
+ def get_service_type
181
+ service_type = @req.params['service']
182
+ return false if !service_type
183
+ return false if service_type[0, 4] != 'git-'
184
+ service_type.gsub('git-', '')
185
+ end
186
+
187
+ def match_routing
188
+ cmd = nil
189
+ path = nil
190
+ SERVICES.each do |method, handler, match, rpc|
191
+ if m = Regexp.new(match).match(@req.path_info)
192
+ return ['not_allowed'] if method != @req.request_method
193
+ cmd = handler
194
+ path = m[1]
195
+ file = @req.path_info.sub(path + '/', '')
196
+ return [cmd, path, file, rpc]
197
+ end
198
+ end
199
+ return nil
200
+ end
201
+
202
+ def has_access(rpc, check_content_type = false)
203
+ if check_content_type
204
+ return false if @req.content_type != "application/x-git-%s-request" % rpc
205
+ end
206
+ return false if !['upload-pack', 'receive-pack'].include? rpc
207
+ if rpc == 'receive-pack'
208
+ return @config[:receive_pack] if @config.include? :receive_pack
209
+ end
210
+ if rpc == 'upload-pack'
211
+ return @config[:upload_pack] if @config.include? :upload_pack
212
+ end
213
+ return get_config_setting(rpc)
214
+ end
215
+
216
+ def get_config_setting(service_name)
217
+ service_name = service_name.gsub('-', '')
218
+ setting = get_git_config("http.#{service_name}")
219
+ if service_name == 'uploadpack'
220
+ return setting != 'false'
221
+ else
222
+ return setting == 'true'
223
+ end
224
+ end
225
+
226
+ def get_git_config(config_name)
227
+ cmd = git_command("config #{config_name}")
228
+ `#{cmd}`.chomp
229
+ end
230
+
231
+ def read_body
232
+ if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/
233
+ input = Zlib::GzipReader.new(@req.body).read
234
+ else
235
+ input = @req.body.read
236
+ end
237
+ end
238
+
239
+ def update_server_info
240
+ cmd = git_command("update-server-info")
241
+ `#{cmd}`
242
+ end
243
+
244
+ def git_command(command)
245
+ git_bin = @config[:git_path] || 'git'
246
+ command = "#{git_bin} #{command}"
247
+ command
248
+ end
249
+
250
+ # --------------------------------------
251
+ # HTTP error response handling functions
252
+ # --------------------------------------
253
+
254
+ PLAIN_TYPE = {"Content-Type" => "text/plain"}
255
+
256
+ def render_method_not_allowed
257
+ if @env['SERVER_PROTOCOL'] == "HTTP/1.1"
258
+ [405, PLAIN_TYPE, ["Method Not Allowed"]]
259
+ else
260
+ [400, PLAIN_TYPE, ["Bad Request"]]
261
+ end
262
+ end
263
+
264
+ def render_not_found
265
+ [404, PLAIN_TYPE, ["Not Found"]]
266
+ end
267
+
268
+ def render_no_access
269
+ [403, PLAIN_TYPE, ["Forbidden"]]
270
+ end
271
+
272
+
273
+ # ------------------------------
274
+ # packet-line handling functions
275
+ # ------------------------------
276
+
277
+ def pkt_flush
278
+ '0000'
279
+ end
280
+
281
+ def pkt_write(str)
282
+ (str.size + 4).to_s(base=16).rjust(4, '0') + str
283
+ end
284
+
285
+
286
+ # ------------------------
287
+ # header writing functions
288
+ # ------------------------
289
+
290
+ def hdr_nocache
291
+ @res["Expires"] = "Fri, 01 Jan 1980 00:00:00 GMT"
292
+ @res["Pragma"] = "no-cache"
293
+ @res["Cache-Control"] = "no-cache, max-age=0, must-revalidate"
294
+ end
295
+
296
+ def hdr_cache_forever
297
+ now = Time.now().to_i
298
+ @res["Date"] = now.to_s
299
+ @res["Expires"] = (now + 31536000).to_s;
300
+ @res["Cache-Control"] = "public, max-age=31536000";
301
+ end
302
+
303
+ end
304
+ end
@@ -0,0 +1,3 @@
1
+ module Grack
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,237 @@
1
+ require 'rack'
2
+ require 'rack/test'
3
+ require 'test/unit'
4
+ require 'mocha'
5
+ require 'digest/sha1'
6
+
7
+ require_relative '../lib/grack/server.rb'
8
+ require 'pp'
9
+
10
+ class GitHttpTest < Test::Unit::TestCase
11
+ include Rack::Test::Methods
12
+
13
+ def example
14
+ File.expand_path(File.dirname(__FILE__))
15
+ end
16
+
17
+ def app
18
+ config = {
19
+ :project_root => example,
20
+ :upload_pack => true,
21
+ :receive_pack => true,
22
+ }
23
+ Grack::Server.new(config)
24
+ end
25
+
26
+ def test_upload_pack_advertisement
27
+ get "/example/info/refs?service=git-upload-pack"
28
+ assert_equal 200, r.status
29
+ assert_equal "application/x-git-upload-pack-advertisement", r.headers["Content-Type"]
30
+ assert_equal "001e# service=git-upload-pack", r.body.split("\n").first
31
+ assert_match 'multi_ack_detailed', r.body
32
+ end
33
+
34
+ def test_no_access_wrong_content_type_up
35
+ post "/example/git-upload-pack"
36
+ assert_equal 403, r.status
37
+ end
38
+
39
+ def test_no_access_wrong_content_type_rp
40
+ post "/example/git-receive-pack"
41
+ assert_equal 403, r.status
42
+ end
43
+
44
+ def test_no_access_wrong_method_rcp
45
+ get "/example/git-upload-pack"
46
+ assert_equal 400, r.status
47
+ end
48
+
49
+ def test_no_access_wrong_command_rcp
50
+ post "/example/git-upload-packfile"
51
+ assert_equal 404, r.status
52
+ end
53
+
54
+ def test_no_access_wrong_path_rcp
55
+ post "/example-wrong/git-upload-pack"
56
+ assert_equal 404, r.status
57
+ end
58
+
59
+ def test_upload_pack_rpc
60
+ IO.stubs(:popen).returns(MockProcess.new)
61
+ post "/example/git-upload-pack", {}, {"CONTENT_TYPE" => "application/x-git-upload-pack-request"}
62
+ assert_equal 200, r.status
63
+ assert_equal "application/x-git-upload-pack-result", r.headers["Content-Type"]
64
+ end
65
+
66
+ def test_receive_pack_advertisement
67
+ get "/example/info/refs?service=git-receive-pack"
68
+ assert_equal 200, r.status
69
+ assert_equal "application/x-git-receive-pack-advertisement", r.headers["Content-Type"]
70
+ assert_equal "001f# service=git-receive-pack", r.body.split("\n").first
71
+ assert_match 'report-status', r.body
72
+ assert_match 'delete-refs', r.body
73
+ assert_match 'ofs-delta', r.body
74
+ end
75
+
76
+ def test_recieve_pack_rpc
77
+ IO.stubs(:popen).yields(MockProcess.new)
78
+ post "/example/git-receive-pack", {}, {"CONTENT_TYPE" => "application/x-git-receive-pack-request"}
79
+ assert_equal 200, r.status
80
+ assert_equal "application/x-git-receive-pack-result", r.headers["Content-Type"]
81
+ end
82
+
83
+ def test_info_refs_dumb
84
+ get "/example/.git/info/refs"
85
+ assert_equal 200, r.status
86
+ end
87
+
88
+ def test_info_packs
89
+ get "/example/.git/objects/info/packs"
90
+ assert_equal 200, r.status
91
+ assert_match /P pack-(.*?).pack/, r.body
92
+ end
93
+
94
+ def test_loose_objects
95
+ path, content = write_test_objects
96
+ get "/example/.git/objects/#{path}"
97
+ assert_equal 200, r.status
98
+ assert_equal content, r.body
99
+ remove_test_objects
100
+ end
101
+
102
+ def test_pack_file
103
+ path, content = write_test_objects
104
+ get "/example/.git/objects/pack/pack-#{content}.pack"
105
+ assert_equal 200, r.status
106
+ assert_equal content, r.body
107
+ remove_test_objects
108
+ end
109
+
110
+ def test_index_file
111
+ path, content = write_test_objects
112
+ get "/example/.git/objects/pack/pack-#{content}.idx"
113
+ assert_equal 200, r.status
114
+ assert_equal content, r.body
115
+ remove_test_objects
116
+ end
117
+
118
+ def test_text_file
119
+ get "/example/.git/HEAD"
120
+ assert_equal 200, r.status
121
+ assert_equal 41, r.body.size # submodules have detached head
122
+ end
123
+
124
+ def test_no_size_avail
125
+ File.stubs('size?').returns(false)
126
+ get "/example/.git/HEAD"
127
+ assert_equal 200, r.status
128
+ assert_equal 46, r.body.size # submodules have detached head
129
+ end
130
+
131
+ def test_config_upload_pack_off
132
+ a1 = app
133
+ a1.set_config_setting(:upload_pack, false)
134
+ session = Rack::Test::Session.new(a1)
135
+ session.get "/example/info/refs?service=git-upload-pack"
136
+ assert_equal 404, session.last_response.status
137
+ end
138
+
139
+ def test_config_receive_pack_off
140
+ a1 = app
141
+ a1.set_config_setting(:receive_pack, false)
142
+ session = Rack::Test::Session.new(a1)
143
+ session.get "/example/info/refs?service=git-receive-pack"
144
+ assert_equal 404, session.last_response.status
145
+ end
146
+
147
+ def test_config_bad_service
148
+ get "/example/info/refs?service=git-receive-packfile"
149
+ assert_equal 404, r.status
150
+ end
151
+
152
+ def test_git_config_receive_pack
153
+ app1 = Grack::Server.new({:project_root => example})
154
+ session = Rack::Test::Session.new(app1)
155
+
156
+ app1.stubs(:get_git_config).with('http.receivepack').returns('')
157
+ session.get "/example/info/refs?service=git-receive-pack"
158
+ assert_equal 404, session.last_response.status
159
+
160
+ app1.stubs(:get_git_config).with('http.receivepack').returns('true')
161
+ session.get "/example/info/refs?service=git-receive-pack"
162
+ assert_equal 200, session.last_response.status
163
+
164
+ app1.stubs(:get_git_config).with('http.receivepack').returns('false')
165
+ session.get "/example/info/refs?service=git-receive-pack"
166
+ assert_equal 404, session.last_response.status
167
+ end
168
+
169
+ def test_git_config_upload_pack
170
+ app1 = Grack::Server.new({:project_root => example})
171
+ session = Rack::Test::Session.new(app1)
172
+
173
+ app1.stubs(:get_git_config).with('http.uploadpack').returns('')
174
+ session.get "/example/info/refs?service=git-upload-pack"
175
+ assert_equal 200, session.last_response.status
176
+
177
+ app1.stubs(:get_git_config).with('http.uploadpack').returns('true')
178
+ session.get "/example/info/refs?service=git-upload-pack"
179
+ assert_equal 200, session.last_response.status
180
+
181
+ app1.stubs(:get_git_config).with('http.uploadpack').returns('false')
182
+ session.get "/example/info/refs?service=git-upload-pack"
183
+ assert_equal 404, session.last_response.status
184
+ end
185
+
186
+ private
187
+
188
+ def r
189
+ last_response
190
+ end
191
+
192
+ def write_test_objects
193
+ content = Digest::SHA1.hexdigest('gitrocks')
194
+ base = File.join(File.expand_path(File.dirname(__FILE__)), 'example', '.git', 'objects')
195
+ obj = File.join(base, '20')
196
+ Dir.mkdir(obj) rescue nil
197
+ file = File.join(obj, content[0, 38])
198
+ File.open(file, 'w') { |f| f.write(content) }
199
+ pack = File.join(base, 'pack', "pack-#{content}.pack")
200
+ File.open(pack, 'w') { |f| f.write(content) }
201
+ idx = File.join(base, 'pack', "pack-#{content}.idx")
202
+ File.open(idx, 'w') { |f| f.write(content) }
203
+ ["20/#{content[0,38]}", content]
204
+ end
205
+
206
+ def remove_test_objects
207
+ content = Digest::SHA1.hexdigest('gitrocks')
208
+ base = File.join(File.expand_path(File.dirname(__FILE__)), 'example', '.git', 'objects')
209
+ obj = File.join(base, '20')
210
+ file = File.join(obj, content[0, 38])
211
+ pack = File.join(base, 'pack', "pack-#{content}.pack")
212
+ idx = File.join(base, 'pack', "pack-#{content}.idx")
213
+ File.unlink(file)
214
+ File.unlink(pack)
215
+ File.unlink(idx)
216
+ end
217
+
218
+ end
219
+
220
+ class MockProcess
221
+
222
+ def initialize
223
+ @counter = 0
224
+ end
225
+
226
+ def write(data)
227
+ end
228
+
229
+ def read(data)
230
+ end
231
+
232
+ def eof?
233
+ @counter += 1
234
+ @counter > 1 ? true : false
235
+ end
236
+
237
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gitlab-grack
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Scott Chacon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.4.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.1
30
+ - !ruby/object:Gem::Dependency
31
+ name: mocha
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '0.11'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '0.11'
46
+ description: Ruby/Rack Git Smart-HTTP Server Handler
47
+ email:
48
+ - schacon@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - .gitmodules
55
+ - README.md
56
+ - Rakefile
57
+ - examples/dispatch.fcgi
58
+ - grack.gemspec
59
+ - install.txt
60
+ - lib/grack.rb
61
+ - lib/grack/auth.rb
62
+ - lib/grack/bundle.rb
63
+ - lib/grack/server.rb
64
+ - lib/grack/version.rb
65
+ - tests/main_test.rb
66
+ homepage: https://github.com/schacon/grack
67
+ licenses: []
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 1.8.24
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: Ruby/Rack Git Smart-HTTP Server Handler
90
+ test_files:
91
+ - tests/main_test.rb