Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-workhorse
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-workhorse
Commits
956288f7
Commit
956288f7
authored
Nov 04, 2015
by
Jacob Vosmaer
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
https://gitlab.com/gitlab-org/gitlab-workhorse
into serve-uploads
parents
86971fa6
c2697091
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
63 additions
and
49 deletions
+63
-49
Makefile
Makefile
+1
-1
main.go
main.go
+2
-2
main_test.go
main_test.go
+1
-1
upstream.go
upstream.go
+59
-45
No files found.
Makefile
View file @
956288f7
PREFIX
=
/usr/local
VERSION
=
$(
shell
git describe
)
-
$(
shell
date
-u
+%Y%m%d.%H%M%S
)
gitlab-workhorse
:
main.go
githandler
.go archive.go git-http.go helpers.go upload.go
gitlab-workhorse
:
main.go
upstream
.go archive.go git-http.go helpers.go upload.go
go build
-ldflags
"-X main.Version
${VERSION}
"
-o
gitlab-workhorse
install
:
gitlab-workhorse
...
...
main.go
View file @
956288f7
...
...
@@ -9,7 +9,7 @@ backend (for authentication and authorization) and local disk access
to Git repositories managed by GitLab. In GitLab, this role was previously
performed by gitlab-grack.
In this file we start the web server and hand off to the
gitHandler
type.
In this file we start the web server and hand off to the
upstream
type.
*/
package
main
...
...
@@ -92,6 +92,6 @@ func main() {
// Because net/http/pprof installs itself in the DefaultServeMux
// we create a fresh one for the Git server.
serveMux
:=
http
.
NewServeMux
()
serveMux
.
Handle
(
"/"
,
new
GitHandler
(
*
authBackend
,
authTransport
))
serveMux
.
Handle
(
"/"
,
new
Upstream
(
*
authBackend
,
authTransport
))
log
.
Fatal
(
http
.
Serve
(
listener
,
serveMux
))
}
main_test.go
View file @
956288f7
...
...
@@ -269,7 +269,7 @@ func testAuthServer(code int, body string) *httptest.Server {
}
func
startServerOrFail
(
t
*
testing
.
T
,
ts
*
httptest
.
Server
)
*
exec
.
Cmd
{
cmd
:=
exec
.
Command
(
"go"
,
"run"
,
"main.go"
,
"
githandler
.go"
,
"archive.go"
,
"git-http.go"
,
"helpers.go"
,
fmt
.
Sprintf
(
"-authBackend=%s"
,
ts
.
URL
),
fmt
.
Sprintf
(
"-listenAddr=%s"
,
servAddr
))
cmd
:=
exec
.
Command
(
"go"
,
"run"
,
"main.go"
,
"
upstream
.go"
,
"archive.go"
,
"git-http.go"
,
"helpers.go"
,
fmt
.
Sprintf
(
"-authBackend=%s"
,
ts
.
URL
),
fmt
.
Sprintf
(
"-listenAddr=%s"
,
servAddr
))
cmd
.
SysProcAttr
=
&
syscall
.
SysProcAttr
{
Setpgid
:
true
}
cmd
.
Stdout
=
os
.
Stdout
cmd
.
Stderr
=
os
.
Stderr
...
...
githandler
.go
→
upstream
.go
View file @
956288f7
/*
The
gitHandler
type implements http.Handler.
The
upstream
type implements http.Handler.
In this file we handle request routing and interaction with the authBackend.
*/
...
...
@@ -11,20 +11,23 @@ import (
"io"
"log"
"net/http"
"os"
"path"
"regexp"
"strings"
)
type
gitHandler
struct
{
type
upstream
struct
{
httpClient
*
http
.
Client
authBackend
string
}
type
gitService
struct
{
method
string
regex
*
regexp
.
Regexp
handleFunc
func
(
w
http
.
ResponseWriter
,
r
*
gitRequest
,
rpc
string
)
rpc
string
method
string
regex
*
regexp
.
Regexp
middlewareFunc
func
(
u
*
upstream
,
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
handleFunc
func
(
w
http
.
ResponseWriter
,
r
*
gitRequest
,
rpc
string
),
rpc
string
)
handleFunc
func
(
w
http
.
ResponseWriter
,
r
*
gitRequest
,
rpc
string
)
rpc
string
}
// A gitReqest is an *http.Request decorated with attributes returned by the
...
...
@@ -46,30 +49,25 @@ type gitRequest struct {
// CommitId is used do prevent race conditions between the 'time of check'
// in the GitLab Rails app and the 'time of use' in gitlab-workhorse.
CommitId
string
// ContentPath is a file on disk we can serve to the client
ContentPath
string
// ContentDisposition is used to set the Content-Disposition header
ContentDisposition
string
}
// Routing table
var
gitServices
=
[
...
]
gitService
{
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/info/refs\z`
),
handleGetInfoRefs
,
""
},
gitService
{
"POST"
,
regexp
.
MustCompile
(
`/git-upload-pack\z`
),
handlePostRPC
,
"git-upload-pack"
},
gitService
{
"POST"
,
regexp
.
MustCompile
(
`/git-receive-pack\z`
),
handlePostRPC
,
"git-receive-pack"
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/repository/archive\z`
),
handleGetArchive
,
"tar.gz"
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/repository/archive.zip\z`
),
handleGetArchive
,
"zip"
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/repository/archive.tar\z`
),
handleGetArchive
,
"tar"
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/repository/archive.tar.gz\z`
),
handleGetArchive
,
"tar.gz"
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/repository/archive.tar.bz2\z`
),
handleGetArchive
,
"tar.bz2"
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/uploads/`
),
handleGetUpload
,
""
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/info/refs\z`
),
repoPreAuth
,
handleGetInfoRefs
,
""
},
gitService
{
"POST"
,
regexp
.
MustCompile
(
`/git-upload-pack\z`
),
repoPreAuth
,
handlePostRPC
,
"git-upload-pack"
},
gitService
{
"POST"
,
regexp
.
MustCompile
(
`/git-receive-pack\z`
),
repoPreAuth
,
handlePostRPC
,
"git-receive-pack"
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/repository/archive\z`
),
repoPreAuth
,
handleGetArchive
,
"tar.gz"
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/repository/archive.zip\z`
),
repoPreAuth
,
handleGetArchive
,
"zip"
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/repository/archive.tar\z`
),
repoPreAuth
,
handleGetArchive
,
"tar"
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/repository/archive.tar.gz\z`
),
repoPreAuth
,
handleGetArchive
,
"tar.gz"
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`/repository/archive.tar.bz2\z`
),
repoPreAuth
,
handleGetArchive
,
"tar.bz2"
},
}
func
new
GitHandler
(
authBackend
string
,
authTransport
http
.
RoundTripper
)
*
gitHandler
{
return
&
gitHandler
{
&
http
.
Client
{
Transport
:
authTransport
},
authBackend
}
func
new
Upstream
(
authBackend
string
,
authTransport
http
.
RoundTripper
)
*
upstream
{
return
&
upstream
{
&
http
.
Client
{
Transport
:
authTransport
},
authBackend
}
}
func
(
h
*
gitHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
(
u
*
upstream
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
var
g
gitService
log
.
Printf
(
"%s %q"
,
r
.
Method
,
r
.
URL
)
...
...
@@ -89,16 +87,38 @@ func (h *gitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
// Ask the auth backend if the request is allowed, and what the
// user ID (GL_ID) is.
authResponse
,
err
:=
h
.
doAuthRequest
(
r
)
g
.
middlewareFunc
(
u
,
w
,
r
,
g
.
handleFunc
,
g
.
rpc
)
}
func
repoPreAuth
(
u
*
upstream
,
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
handleFunc
func
(
w
http
.
ResponseWriter
,
r
*
gitRequest
,
rpc
string
),
rpc
string
)
{
url
:=
u
.
authBackend
+
r
.
URL
.
RequestURI
()
authReq
,
err
:=
http
.
NewRequest
(
r
.
Method
,
url
,
nil
)
if
err
!=
nil
{
fail500
(
w
,
"doAuthRequest"
,
err
)
return
}
// Forward all headers from our client to the auth backend. This includes
// HTTP Basic authentication credentials (the 'Authorization' header).
for
k
,
v
:=
range
r
.
Header
{
authReq
.
Header
[
k
]
=
v
}
// Also forward the Host header, which is excluded from the Header map by the http libary.
// This allows the Host header received by the backend to be consistent with other
// requests not going through gitlab-workhorse.
authReq
.
Host
=
r
.
Host
// Set a custom header for the request. This can be used in some
// configurations (Passenger) to solve auth request routing problems.
authReq
.
Header
.
Set
(
"GitLab-Git-HTTP-Server"
,
Version
)
authResponse
,
err
:=
u
.
httpClient
.
Do
(
authReq
)
if
err
!=
nil
{
fail500
(
w
,
"doAuthRequest"
,
err
)
return
}
defer
authResponse
.
Body
.
Close
()
if
authResponse
.
StatusCode
!=
200
||
authResponse
.
Header
.
Get
(
"GitLab-Workhorse"
)
==
"reject"
{
if
authResponse
.
StatusCode
!=
200
{
// The Git request is not allowed by the backend. Maybe the
// client needs to send HTTP Basic credentials. Forward the
// response from the auth backend to our client. This includes
...
...
@@ -137,26 +157,20 @@ func (h *gitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
g
.
handleFunc
(
w
,
gitReq
,
g
.
rpc
)
if
!
looksLikeRepo
(
gitReq
.
RepoPath
)
{
http
.
Error
(
w
,
"Not Found"
,
404
)
return
}
handleFunc
(
w
,
gitReq
,
rpc
)
}
func
(
h
*
gitHandler
)
doAuthRequest
(
r
*
http
.
Request
)
(
result
*
http
.
Response
,
err
error
)
{
url
:=
h
.
authBackend
+
r
.
URL
.
RequestURI
()
authReq
,
err
:=
http
.
NewRequest
(
r
.
Method
,
url
,
nil
)
if
err
!=
nil
{
return
nil
,
err
func
looksLikeRepo
(
p
string
)
bool
{
// If /path/to/foo.git/objects exists then let's assume it is a valid Git
// repository.
if
_
,
err
:=
os
.
Stat
(
path
.
Join
(
p
,
"objects"
));
err
!=
nil
{
log
.
Print
(
err
)
return
false
}
// Forward all headers from our client to the auth backend. This includes
// HTTP Basic authentication credentials (the 'Authorization' header).
for
k
,
v
:=
range
r
.
Header
{
authReq
.
Header
[
k
]
=
v
}
// Also forward the Host header, which is excluded from the Header map by the http libary.
// This allows the Host header received by the backend to be consistent with other
// requests not going through gitlab-workhorse.
authReq
.
Host
=
r
.
Host
// Set a custom header for the request. This can be used in some
// configurations (Passenger) to solve auth request routing problems.
authReq
.
Header
.
Set
(
"GitLab-Git-HTTP-Server"
,
Version
)
return
h
.
httpClient
.
Do
(
authReq
)
return
true
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment