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
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 (
)
type
gitService
struct
{
method
string
regexp
*
regexp
.
Regexp
handle
_f
unc
func
(
string
,
string
,
string
,
http
.
ResponseWriter
,
*
http
.
Request
)
rpc
string
method
string
regexp
*
regexp
.
Regexp
handle
F
unc
func
(
string
,
string
,
string
,
http
.
ResponseWriter
,
*
http
.
Request
)
rpc
string
}
var
http
_c
lient
=
&
http
.
Client
{}
var
path
_t
raversal
=
regexp
.
MustCompile
(
`/../`
)
var
http
C
lient
=
&
http
.
Client
{}
var
path
T
raversal
=
regexp
.
MustCompile
(
`/../`
)
// Command-line options
var
repo
_r
oot
string
var
listen
_addr
=
flag
.
String
(
"listen_a
ddr"
,
"localhost:8181"
,
"Listen address for HTTP server"
)
var
auth
_backend
=
flag
.
String
(
"auth_b
ackend"
,
"http://localhost:8080"
,
"Authentication/authorization backend"
)
var
git
_s
ervices
=
[
...
]
gitService
{
gitService
{
"GET"
,
regexp
.
MustCompile
(
`\A(/..*)/info/refs\z`
),
handle
_get_info_r
efs
,
""
},
gitService
{
"POST"
,
regexp
.
MustCompile
(
`\A(/..*)/git-upload-pack\z`
),
handle
_post_rpc
,
"git-upload-pack"
},
gitService
{
"POST"
,
regexp
.
MustCompile
(
`\A(/..*)/git-receive-pack\z`
),
handle
_post_rpc
,
"git-receive-pack"
},
var
repo
R
oot
string
var
listen
Addr
=
flag
.
String
(
"listenA
ddr"
,
"localhost:8181"
,
"Listen address for HTTP server"
)
var
auth
Backend
=
flag
.
String
(
"authB
ackend"
,
"http://localhost:8080"
,
"Authentication/authorization backend"
)
var
git
S
ervices
=
[
...
]
gitService
{
gitService
{
"GET"
,
regexp
.
MustCompile
(
`\A(/..*)/info/refs\z`
),
handle
GetInfoR
efs
,
""
},
gitService
{
"POST"
,
regexp
.
MustCompile
(
`\A(/..*)/git-upload-pack\z`
),
handle
PostRPC
,
"git-upload-pack"
},
gitService
{
"POST"
,
regexp
.
MustCompile
(
`\A(/..*)/git-receive-pack\z`
),
handle
PostRPC
,
"git-receive-pack"
},
}
func
main
()
{
...
...
@@ -55,107 +55,107 @@ func main() {
flag
.
PrintDefaults
()
}
flag
.
Parse
()
repo
_r
oot
=
flag
.
Arg
(
0
)
if
repo
_r
oot
==
""
{
repo
R
oot
=
flag
.
Arg
(
0
)
if
repo
R
oot
==
""
{
flag
.
Usage
()
os
.
Exit
(
1
)
}
log
.
Printf
(
"repo
_root: %s"
,
repo_r
oot
)
log
.
Printf
(
"repo
Root: %s"
,
repoR
oot
)
http
.
HandleFunc
(
"/"
,
git
_h
andler
)
log
.
Fatal
(
http
.
ListenAndServe
(
*
listen
_a
ddr
,
nil
))
http
.
HandleFunc
(
"/"
,
git
H
andler
)
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
path
_m
atch
[]
string
var
path
M
atch
[]
string
var
g
gitService
var
found
_s
ervice
bool
var
found
S
ervice
bool
log
.
Print
(
r
.
Method
,
" "
,
r
.
URL
)
// Look for a matching Git service
for
_
,
g
=
range
git
_s
ervices
{
path
_m
atch
=
g
.
regexp
.
FindStringSubmatch
(
r
.
URL
.
Path
)
if
r
.
Method
==
g
.
method
&&
path
_m
atch
!=
nil
{
found
_s
ervice
=
true
for
_
,
g
=
range
git
S
ervices
{
path
M
atch
=
g
.
regexp
.
FindStringSubmatch
(
r
.
URL
.
Path
)
if
r
.
Method
==
g
.
method
&&
path
M
atch
!=
nil
{
found
S
ervice
=
true
break
}
}
if
!
found
_s
ervice
{
if
!
found
S
ervice
{
http
.
Error
(
w
,
"Not Found"
,
404
)
return
}
// Ask the auth backend if the request is allowed, and what the
// user ID (GL_ID) is.
auth
_response
,
err
:=
do_auth_r
equest
(
r
)
auth
Response
,
err
:=
doAuthR
equest
(
r
)
if
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
}
if
auth
_r
esponse
.
StatusCode
!=
200
{
if
auth
R
esponse
.
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
// the 'WWW-Authentication' header that acts as a hint that
// 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
.
WriteHeader
(
auth
_r
esponse
.
StatusCode
)
io
.
Copy
(
w
,
auth
_r
esponse
.
Body
)
w
.
WriteHeader
(
auth
R
esponse
.
StatusCode
)
io
.
Copy
(
w
,
auth
R
esponse
.
Body
)
return
}
// The auth backend validated the client request and told us who
// the user is according to them (GL_ID). We must extract this
// information from the auth response body.
if
_
,
err
:=
fmt
.
Fscan
(
auth
_r
esponse
.
Body
,
&
gl_id
);
err
!=
nil
{
fail
_
500
(
w
,
err
)
if
_
,
err
:=
fmt
.
Fscan
(
auth
R
esponse
.
Body
,
&
gl_id
);
err
!=
nil
{
fail500
(
w
,
err
)
return
}
// Validate the path to the Git repository
found
_path
:=
path_m
atch
[
1
]
if
!
valid
_path
(
found_p
ath
)
{
found
Path
:=
pathM
atch
[
1
]
if
!
valid
Path
(
foundP
ath
)
{
http
.
Error
(
w
,
"Not Found"
,
404
)
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
{
if
path
_t
raversal
.
MatchString
(
p
)
{
func
valid
P
ath
(
p
string
)
bool
{
if
path
T
raversal
.
MatchString
(
p
)
{
log
.
Printf
(
"path traversal detected in %s"
,
p
)
return
false
}
// If /path/to/foo.git/objects exists then let's assume it is a valid Git
// 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
)
return
false
}
return
true
}
func
do
_auth_r
equest
(
r
*
http
.
Request
)
(
result
*
http
.
Response
,
err
error
)
{
url
:=
fmt
.
Sprintf
(
"%s%s"
,
*
auth
_b
ackend
,
r
.
URL
.
RequestURI
())
auth
_r
eq
,
err
:=
http
.
NewRequest
(
r
.
Method
,
url
,
nil
)
func
do
AuthR
equest
(
r
*
http
.
Request
)
(
result
*
http
.
Response
,
err
error
)
{
url
:=
fmt
.
Sprintf
(
"%s%s"
,
*
auth
B
ackend
,
r
.
URL
.
RequestURI
())
auth
R
eq
,
err
:=
http
.
NewRequest
(
r
.
Method
,
url
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
// 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
{
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"
)
if
!
(
rpc
==
"git-upload-pack"
||
rpc
==
"git-receive-pack"
)
{
// 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
}
// Prepare our Git subprocess
cmd
:=
exec
.
Command
(
"git"
,
sub
_c
ommand
(
rpc
),
"--stateless-rpc"
,
"--advertise-refs"
,
path
)
set
_cmd_e
nv
(
cmd
,
gl_id
)
cmd
:=
exec
.
Command
(
"git"
,
sub
C
ommand
(
rpc
),
"--stateless-rpc"
,
"--advertise-refs"
,
path
)
set
CmdE
nv
(
cmd
,
gl_id
)
stdout
,
err
:=
cmd
.
StdoutPipe
()
if
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
}
defer
stdout
.
Close
()
if
err
:=
cmd
.
Start
();
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
}
defer
cmd
.
Wait
()
// Start writing the response
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
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
)
}
if
err
:=
pkt
_f
lush
(
w
);
err
!=
nil
{
if
err
:=
pkt
F
lush
(
w
);
err
!=
nil
{
panic
(
err
)
}
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
}
}
func
sub
_c
ommand
(
rpc
string
)
string
{
func
sub
C
ommand
(
rpc
string
)
string
{
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
{
fmt
.
Sprintf
(
"PATH=%s"
,
os
.
Getenv
(
"PATH"
)),
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
err
error
...
...
@@ -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"
{
body
,
err
=
gzip
.
NewReader
(
r
.
Body
)
if
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
}
}
else
{
...
...
@@ -223,36 +223,36 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite
}
// Prepare our Git subprocess
cmd
:=
exec
.
Command
(
"git"
,
sub
_c
ommand
(
rpc
),
"--stateless-rpc"
,
path
)
set
_cmd_e
nv
(
cmd
,
gl_id
)
cmd
:=
exec
.
Command
(
"git"
,
sub
C
ommand
(
rpc
),
"--stateless-rpc"
,
path
)
set
CmdE
nv
(
cmd
,
gl_id
)
stdout
,
err
:=
cmd
.
StdoutPipe
()
if
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
}
defer
stdout
.
Close
()
stdin
,
err
:=
cmd
.
StdinPipe
()
if
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
}
defer
stdin
.
Close
()
if
err
:=
cmd
.
Start
();
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
}
defer
cmd
.
Wait
()
// Write the client request body to Git's standard input
if
_
,
err
:=
io
.
Copy
(
stdin
,
body
);
err
!=
nil
{
fail
_
500
(
w
,
err
)
fail500
(
w
,
err
)
return
}
stdin
.
Close
()
// Start writing the response
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
if
_
,
err
:=
io
.
Copy
(
w
,
stdout
);
err
!=
nil
{
panic
(
err
)
...
...
@@ -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
)
return
err
}
func
pkt
_f
lush
(
w
io
.
Writer
)
error
{
func
pkt
F
lush
(
w
io
.
Writer
)
error
{
_
,
err
:=
fmt
.
Fprint
(
w
,
"0000"
)
return
err
}
func
fail
_
500
(
w
http
.
ResponseWriter
,
err
error
)
{
func
fail500
(
w
http
.
ResponseWriter
,
err
error
)
{
http
.
Error
(
w
,
"Internal server error"
,
500
)
log
.
Print
(
err
)
}
func
header_no_c
ache
(
w
http
.
ResponseWriter
)
{
func
setHeaderNoC
ache
(
w
http
.
ResponseWriter
)
{
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