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
0
Merge Requests
0
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
iv
gitlab-workhorse
Commits
241facbb
Commit
241facbb
authored
Jul 28, 2015
by
Jacob Vosmaer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Get rid of underscores
Supposedly they are not idiomatic!
parent
23ff988f
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
69 additions
and
69 deletions
+69
-69
main.go
main.go
+69
-69
No files found.
main.go
View file @
241facbb
...
@@ -27,24 +27,24 @@ import (
...
@@ -27,24 +27,24 @@ import (
)
)
type
gitService
struct
{
type
gitService
struct
{
method
string
method
string
regexp
*
regexp
.
Regexp
regexp
*
regexp
.
Regexp
handle
_f
unc
func
(
string
,
string
,
string
,
http
.
ResponseWriter
,
*
http
.
Request
)
handle
F
unc
func
(
string
,
string
,
string
,
http
.
ResponseWriter
,
*
http
.
Request
)
rpc
string
rpc
string
}
}
var
http
_c
lient
=
&
http
.
Client
{}
var
http
C
lient
=
&
http
.
Client
{}
var
path
_t
raversal
=
regexp
.
MustCompile
(
`/../`
)
var
path
T
raversal
=
regexp
.
MustCompile
(
`/../`
)
// Command-line options
// Command-line options
var
repo
_r
oot
string
var
repo
R
oot
string
var
listen
_addr
=
flag
.
String
(
"listen_a
ddr"
,
"localhost:8181"
,
"Listen address for HTTP server"
)
var
listen
Addr
=
flag
.
String
(
"listenA
ddr"
,
"localhost:8181"
,
"Listen address for HTTP server"
)
var
auth
_backend
=
flag
.
String
(
"auth_b
ackend"
,
"http://localhost:8080"
,
"Authentication/authorization backend"
)
var
auth
Backend
=
flag
.
String
(
"authB
ackend"
,
"http://localhost:8080"
,
"Authentication/authorization backend"
)
var
git
_s
ervices
=
[
...
]
gitService
{
var
git
S
ervices
=
[
...
]
gitService
{
gitService
{
"GET"
,
regexp
.
MustCompile
(
`\A(/..*)/info/refs\z`
),
handle
_get_info_r
efs
,
""
},
gitService
{
"GET"
,
regexp
.
MustCompile
(
`\A(/..*)/info/refs\z`
),
handle
GetInfoR
efs
,
""
},
gitService
{
"POST"
,
regexp
.
MustCompile
(
`\A(/..*)/git-upload-pack\z`
),
handle
_post_rpc
,
"git-upload-pack"
},
gitService
{
"POST"
,
regexp
.
MustCompile
(
`\A(/..*)/git-upload-pack\z`
),
handle
PostRPC
,
"git-upload-pack"
},
gitService
{
"POST"
,
regexp
.
MustCompile
(
`\A(/..*)/git-receive-pack\z`
),
handle
_post_rpc
,
"git-receive-pack"
},
gitService
{
"POST"
,
regexp
.
MustCompile
(
`\A(/..*)/git-receive-pack\z`
),
handle
PostRPC
,
"git-receive-pack"
},
}
}
func
main
()
{
func
main
()
{
...
@@ -55,107 +55,107 @@ func main() {
...
@@ -55,107 +55,107 @@ func main() {
flag
.
PrintDefaults
()
flag
.
PrintDefaults
()
}
}
flag
.
Parse
()
flag
.
Parse
()
repo
_r
oot
=
flag
.
Arg
(
0
)
repo
R
oot
=
flag
.
Arg
(
0
)
if
repo
_r
oot
==
""
{
if
repo
R
oot
==
""
{
flag
.
Usage
()
flag
.
Usage
()
os
.
Exit
(
1
)
os
.
Exit
(
1
)
}
}
log
.
Printf
(
"repo
_root: %s"
,
repo_r
oot
)
log
.
Printf
(
"repo
Root: %s"
,
repoR
oot
)
http
.
HandleFunc
(
"/"
,
git
_h
andler
)
http
.
HandleFunc
(
"/"
,
git
H
andler
)
log
.
Fatal
(
http
.
ListenAndServe
(
*
listen
_a
ddr
,
nil
))
log
.
Fatal
(
http
.
ListenAndServe
(
*
listen
A
ddr
,
nil
))
}
}
func
git
_h
andler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
git
H
andler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
var
gl_id
string
var
gl_id
string
var
path
_m
atch
[]
string
var
path
M
atch
[]
string
var
g
gitService
var
g
gitService
var
found
_s
ervice
bool
var
found
S
ervice
bool
log
.
Print
(
r
.
Method
,
" "
,
r
.
URL
)
log
.
Print
(
r
.
Method
,
" "
,
r
.
URL
)
// Look for a matching Git service
// Look for a matching Git service
for
_
,
g
=
range
git
_s
ervices
{
for
_
,
g
=
range
git
S
ervices
{
path
_m
atch
=
g
.
regexp
.
FindStringSubmatch
(
r
.
URL
.
Path
)
path
M
atch
=
g
.
regexp
.
FindStringSubmatch
(
r
.
URL
.
Path
)
if
r
.
Method
==
g
.
method
&&
path
_m
atch
!=
nil
{
if
r
.
Method
==
g
.
method
&&
path
M
atch
!=
nil
{
found
_s
ervice
=
true
found
S
ervice
=
true
break
break
}
}
}
}
if
!
found
_s
ervice
{
if
!
found
S
ervice
{
http
.
Error
(
w
,
"Not Found"
,
404
)
http
.
Error
(
w
,
"Not Found"
,
404
)
return
return
}
}
// Ask the auth backend if the request is allowed, and what the
// Ask the auth backend if the request is allowed, and what the
// user ID (GL_ID) is.
// user ID (GL_ID) is.
auth
_response
,
err
:=
do_auth_r
equest
(
r
)
auth
Response
,
err
:=
doAuthR
equest
(
r
)
if
err
!=
nil
{
if
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
return
}
}
if
auth
_r
esponse
.
StatusCode
!=
200
{
if
auth
R
esponse
.
StatusCode
!=
200
{
// The Git request is not allowed by the backend. Maybe the
// The Git request is not allowed by the backend. Maybe the
// client needs to send HTTP Basic credentials. Forward the
// client needs to send HTTP Basic credentials. Forward the
// response from the auth backend to our client. This includes
// response from the auth backend to our client. This includes
// the 'WWW-Authentication' header that acts as a hint that
// the 'WWW-Authentication' header that acts as a hint that
// Basic auth credentials are needed.
// Basic auth credentials are needed.
for
k
,
v
:=
range
auth
_r
esponse
.
Header
{
for
k
,
v
:=
range
auth
R
esponse
.
Header
{
w
.
Header
()[
k
]
=
v
w
.
Header
()[
k
]
=
v
}
}
w
.
WriteHeader
(
auth
_r
esponse
.
StatusCode
)
w
.
WriteHeader
(
auth
R
esponse
.
StatusCode
)
io
.
Copy
(
w
,
auth
_r
esponse
.
Body
)
io
.
Copy
(
w
,
auth
R
esponse
.
Body
)
return
return
}
}
// The auth backend validated the client request and told us who
// The auth backend validated the client request and told us who
// the user is according to them (GL_ID). We must extract this
// the user is according to them (GL_ID). We must extract this
// information from the auth response body.
// information from the auth response body.
if
_
,
err
:=
fmt
.
Fscan
(
auth
_r
esponse
.
Body
,
&
gl_id
);
err
!=
nil
{
if
_
,
err
:=
fmt
.
Fscan
(
auth
R
esponse
.
Body
,
&
gl_id
);
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
return
}
}
// Validate the path to the Git repository
// Validate the path to the Git repository
found
_path
:=
path_m
atch
[
1
]
found
Path
:=
pathM
atch
[
1
]
if
!
valid
_path
(
found_p
ath
)
{
if
!
valid
Path
(
foundP
ath
)
{
http
.
Error
(
w
,
"Not Found"
,
404
)
http
.
Error
(
w
,
"Not Found"
,
404
)
return
return
}
}
g
.
handle
_func
(
gl_id
,
g
.
rpc
,
path
.
Join
(
repo_root
,
found_p
ath
),
w
,
r
)
g
.
handle
Func
(
gl_id
,
g
.
rpc
,
path
.
Join
(
repoRoot
,
foundP
ath
),
w
,
r
)
}
}
func
valid
_p
ath
(
p
string
)
bool
{
func
valid
P
ath
(
p
string
)
bool
{
if
path
_t
raversal
.
MatchString
(
p
)
{
if
path
T
raversal
.
MatchString
(
p
)
{
log
.
Printf
(
"path traversal detected in %s"
,
p
)
log
.
Printf
(
"path traversal detected in %s"
,
p
)
return
false
return
false
}
}
// If /path/to/foo.git/objects exists then let's assume it is a valid Git
// If /path/to/foo.git/objects exists then let's assume it is a valid Git
// repository.
// repository.
if
_
,
err
:=
os
.
Stat
(
path
.
Join
(
repo
_r
oot
,
p
,
"objects"
));
err
!=
nil
{
if
_
,
err
:=
os
.
Stat
(
path
.
Join
(
repo
R
oot
,
p
,
"objects"
));
err
!=
nil
{
log
.
Print
(
err
)
log
.
Print
(
err
)
return
false
return
false
}
}
return
true
return
true
}
}
func
do
_auth_r
equest
(
r
*
http
.
Request
)
(
result
*
http
.
Response
,
err
error
)
{
func
do
AuthR
equest
(
r
*
http
.
Request
)
(
result
*
http
.
Response
,
err
error
)
{
url
:=
fmt
.
Sprintf
(
"%s%s"
,
*
auth
_b
ackend
,
r
.
URL
.
RequestURI
())
url
:=
fmt
.
Sprintf
(
"%s%s"
,
*
auth
B
ackend
,
r
.
URL
.
RequestURI
())
auth
_r
eq
,
err
:=
http
.
NewRequest
(
r
.
Method
,
url
,
nil
)
auth
R
eq
,
err
:=
http
.
NewRequest
(
r
.
Method
,
url
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
// Forward all headers from our client to the auth backend. This includes
// Forward all headers from our client to the auth backend. This includes
// HTTP Basic authentication credentials (the 'Authorization' header).
// HTTP Basic authentication credentials (the 'Authorization' header).
for
k
,
v
:=
range
r
.
Header
{
for
k
,
v
:=
range
r
.
Header
{
auth
_r
eq
.
Header
[
k
]
=
v
auth
R
eq
.
Header
[
k
]
=
v
}
}
return
http
_client
.
Do
(
auth_r
eq
)
return
http
Client
.
Do
(
authR
eq
)
}
}
func
handle
_get_info_r
efs
(
gl_id
string
,
_
string
,
path
string
,
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
handle
GetInfoR
efs
(
gl_id
string
,
_
string
,
path
string
,
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
rpc
:=
r
.
URL
.
Query
()
.
Get
(
"service"
)
rpc
:=
r
.
URL
.
Query
()
.
Get
(
"service"
)
if
!
(
rpc
==
"git-upload-pack"
||
rpc
==
"git-receive-pack"
)
{
if
!
(
rpc
==
"git-upload-pack"
||
rpc
==
"git-receive-pack"
)
{
// The 'dumb' Git HTTP protocol is not supported
// The 'dumb' Git HTTP protocol is not supported
...
@@ -164,28 +164,28 @@ func handle_get_info_refs(gl_id string, _ string, path string, w http.ResponseWr
...
@@ -164,28 +164,28 @@ func handle_get_info_refs(gl_id string, _ string, path string, w http.ResponseWr
}
}
// Prepare our Git subprocess
// Prepare our Git subprocess
cmd
:=
exec
.
Command
(
"git"
,
sub
_c
ommand
(
rpc
),
"--stateless-rpc"
,
"--advertise-refs"
,
path
)
cmd
:=
exec
.
Command
(
"git"
,
sub
C
ommand
(
rpc
),
"--stateless-rpc"
,
"--advertise-refs"
,
path
)
set
_cmd_e
nv
(
cmd
,
gl_id
)
set
CmdE
nv
(
cmd
,
gl_id
)
stdout
,
err
:=
cmd
.
StdoutPipe
()
stdout
,
err
:=
cmd
.
StdoutPipe
()
if
err
!=
nil
{
if
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
return
}
}
defer
stdout
.
Close
()
defer
stdout
.
Close
()
if
err
:=
cmd
.
Start
();
err
!=
nil
{
if
err
:=
cmd
.
Start
();
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
return
}
}
defer
cmd
.
Wait
()
defer
cmd
.
Wait
()
// Start writing the response
// Start writing the response
w
.
Header
()
.
Add
(
"Content-Type"
,
fmt
.
Sprintf
(
"application/x-%s-advertisement"
,
rpc
))
w
.
Header
()
.
Add
(
"Content-Type"
,
fmt
.
Sprintf
(
"application/x-%s-advertisement"
,
rpc
))
header_no_c
ache
(
w
)
setHeaderNoC
ache
(
w
)
w
.
WriteHeader
(
200
)
// Don't bother with HTTP 500 from this point on, just panic
w
.
WriteHeader
(
200
)
// Don't bother with HTTP 500 from this point on, just panic
if
err
:=
pkt
_l
ine
(
w
,
fmt
.
Sprintf
(
"# service=%s
\n
"
,
rpc
));
err
!=
nil
{
if
err
:=
pkt
L
ine
(
w
,
fmt
.
Sprintf
(
"# service=%s
\n
"
,
rpc
));
err
!=
nil
{
panic
(
err
)
panic
(
err
)
}
}
if
err
:=
pkt
_f
lush
(
w
);
err
!=
nil
{
if
err
:=
pkt
F
lush
(
w
);
err
!=
nil
{
panic
(
err
)
panic
(
err
)
}
}
if
_
,
err
:=
io
.
Copy
(
w
,
stdout
);
err
!=
nil
{
if
_
,
err
:=
io
.
Copy
(
w
,
stdout
);
err
!=
nil
{
...
@@ -196,18 +196,18 @@ func handle_get_info_refs(gl_id string, _ string, path string, w http.ResponseWr
...
@@ -196,18 +196,18 @@ func handle_get_info_refs(gl_id string, _ string, path string, w http.ResponseWr
}
}
}
}
func
sub
_c
ommand
(
rpc
string
)
string
{
func
sub
C
ommand
(
rpc
string
)
string
{
return
strings
.
TrimPrefix
(
rpc
,
"git-"
)
return
strings
.
TrimPrefix
(
rpc
,
"git-"
)
}
}
func
set
_cmd_e
nv
(
cmd
*
exec
.
Cmd
,
gl_id
string
)
{
func
set
CmdE
nv
(
cmd
*
exec
.
Cmd
,
gl_id
string
)
{
cmd
.
Env
=
[]
string
{
cmd
.
Env
=
[]
string
{
fmt
.
Sprintf
(
"PATH=%s"
,
os
.
Getenv
(
"PATH"
)),
fmt
.
Sprintf
(
"PATH=%s"
,
os
.
Getenv
(
"PATH"
)),
fmt
.
Sprintf
(
"GL_ID=%s"
,
gl_id
),
fmt
.
Sprintf
(
"GL_ID=%s"
,
gl_id
),
}
}
}
}
func
handle
_post_rpc
(
gl_id
string
,
rpc
string
,
path
string
,
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
handle
PostRPC
(
gl_id
string
,
rpc
string
,
path
string
,
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
var
body
io
.
Reader
var
body
io
.
Reader
var
err
error
var
err
error
...
@@ -215,7 +215,7 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite
...
@@ -215,7 +215,7 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite
if
r
.
Header
.
Get
(
"Content-Encoding"
)
==
"gzip"
{
if
r
.
Header
.
Get
(
"Content-Encoding"
)
==
"gzip"
{
body
,
err
=
gzip
.
NewReader
(
r
.
Body
)
body
,
err
=
gzip
.
NewReader
(
r
.
Body
)
if
err
!=
nil
{
if
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
return
}
}
}
else
{
}
else
{
...
@@ -223,36 +223,36 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite
...
@@ -223,36 +223,36 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite
}
}
// Prepare our Git subprocess
// Prepare our Git subprocess
cmd
:=
exec
.
Command
(
"git"
,
sub
_c
ommand
(
rpc
),
"--stateless-rpc"
,
path
)
cmd
:=
exec
.
Command
(
"git"
,
sub
C
ommand
(
rpc
),
"--stateless-rpc"
,
path
)
set
_cmd_e
nv
(
cmd
,
gl_id
)
set
CmdE
nv
(
cmd
,
gl_id
)
stdout
,
err
:=
cmd
.
StdoutPipe
()
stdout
,
err
:=
cmd
.
StdoutPipe
()
if
err
!=
nil
{
if
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
return
}
}
defer
stdout
.
Close
()
defer
stdout
.
Close
()
stdin
,
err
:=
cmd
.
StdinPipe
()
stdin
,
err
:=
cmd
.
StdinPipe
()
if
err
!=
nil
{
if
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
return
}
}
defer
stdin
.
Close
()
defer
stdin
.
Close
()
if
err
:=
cmd
.
Start
();
err
!=
nil
{
if
err
:=
cmd
.
Start
();
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
return
}
}
defer
cmd
.
Wait
()
defer
cmd
.
Wait
()
// Write the client request body to Git's standard input
// Write the client request body to Git's standard input
if
_
,
err
:=
io
.
Copy
(
stdin
,
body
);
err
!=
nil
{
if
_
,
err
:=
io
.
Copy
(
stdin
,
body
);
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
return
}
}
stdin
.
Close
()
stdin
.
Close
()
// Start writing the response
// Start writing the response
w
.
Header
()
.
Add
(
"Content-Type"
,
fmt
.
Sprintf
(
"application/x-%s-result"
,
rpc
))
w
.
Header
()
.
Add
(
"Content-Type"
,
fmt
.
Sprintf
(
"application/x-%s-result"
,
rpc
))
header_no_c
ache
(
w
)
setHeaderNoC
ache
(
w
)
w
.
WriteHeader
(
200
)
// Don't bother with HTTP 500 from this point on, just panic
w
.
WriteHeader
(
200
)
// Don't bother with HTTP 500 from this point on, just panic
if
_
,
err
:=
io
.
Copy
(
w
,
stdout
);
err
!=
nil
{
if
_
,
err
:=
io
.
Copy
(
w
,
stdout
);
err
!=
nil
{
panic
(
err
)
panic
(
err
)
...
@@ -262,21 +262,21 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite
...
@@ -262,21 +262,21 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite
}
}
}
}
func
pkt
_l
ine
(
w
io
.
Writer
,
s
string
)
error
{
func
pkt
L
ine
(
w
io
.
Writer
,
s
string
)
error
{
_
,
err
:=
fmt
.
Fprintf
(
w
,
"%04x%s"
,
len
(
s
)
+
4
,
s
)
_
,
err
:=
fmt
.
Fprintf
(
w
,
"%04x%s"
,
len
(
s
)
+
4
,
s
)
return
err
return
err
}
}
func
pkt
_f
lush
(
w
io
.
Writer
)
error
{
func
pkt
F
lush
(
w
io
.
Writer
)
error
{
_
,
err
:=
fmt
.
Fprint
(
w
,
"0000"
)
_
,
err
:=
fmt
.
Fprint
(
w
,
"0000"
)
return
err
return
err
}
}
func
fail
_
500
(
w
http
.
ResponseWriter
,
err
error
)
{
func
fail500
(
w
http
.
ResponseWriter
,
err
error
)
{
http
.
Error
(
w
,
"Internal server error"
,
500
)
http
.
Error
(
w
,
"Internal server error"
,
500
)
log
.
Print
(
err
)
log
.
Print
(
err
)
}
}
func
header_no_c
ache
(
w
http
.
ResponseWriter
)
{
func
setHeaderNoC
ache
(
w
http
.
ResponseWriter
)
{
w
.
Header
()
.
Add
(
"Cache-Control"
,
"no-cache"
)
w
.
Header
()
.
Add
(
"Cache-Control"
,
"no-cache"
)
}
}
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