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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kirill Smelkov
gitlab-workhorse
Commits
0b34879b
Commit
0b34879b
authored
Oct 10, 2015
by
Jacob Vosmaer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Decorate http.Request with GitLab metadata
parent
a3f6c212
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
38 additions
and
26 deletions
+38
-26
githandler.go
githandler.go
+38
-26
No files found.
githandler.go
View file @
0b34879b
...
@@ -30,16 +30,29 @@ type gitHandler struct {
...
@@ -30,16 +30,29 @@ type gitHandler struct {
type
gitService
struct
{
type
gitService
struct
{
method
string
method
string
suffix
string
suffix
string
handleFunc
func
(
requestMetadata
,
string
,
http
.
ResponseWriter
,
*
http
.
Request
)
handleFunc
func
(
w
http
.
ResponseWriter
,
r
*
gitRequest
,
rpc
string
)
rpc
string
rpc
string
}
}
type
requestMetadata
struct
{
// A gitReqest is an *http.Request decorated with attributes returned by the
GL_ID
string
// GitLab Rails application.
RepoPath
string
type
gitRequest
struct
{
ArchivePath
string
*
http
.
Request
// GL_ID is an environment variable used by gitlab-shell hooks during 'git
// push' and 'git pull'
GL_ID
string
// RepoPath is the full path on disk to the Git repository the request is
// about
RepoPath
string
// ArchivePath is the full path where we should find/create a cached copy
// of a requested archive
ArchivePath
string
// ArchivePrefix is used to put extracted archive contents in a
// subdirectory
ArchivePrefix
string
ArchivePrefix
string
CommitId
string
// CommitId is used do prevent race conditions between the 'time of check'
// in the GitLab Rails app and the 'time of use' in gitlab-git-http-server.
CommitId
string
}
}
// Routing table
// Routing table
...
@@ -59,7 +72,6 @@ func newGitHandler(authBackend string) *gitHandler {
...
@@ -59,7 +72,6 @@ func newGitHandler(authBackend string) *gitHandler {
}
}
func
(
h
*
gitHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
(
h
*
gitHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
var
md
requestMetadata
var
g
gitService
var
g
gitService
log
.
Printf
(
"%s %q"
,
r
.
Method
,
r
.
URL
)
log
.
Printf
(
"%s %q"
,
r
.
Method
,
r
.
URL
)
...
@@ -102,11 +114,11 @@ func (h *gitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
...
@@ -102,11 +114,11 @@ func (h *gitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
return
}
}
// The auth backend validated the client request and told us
who
// The auth backend validated the client request and told us
additional
//
the user is according to them (GL_ID). We must extract this
//
request metadata. We must extract this information from the auth
//
information from the auth
response body.
// response body.
dec
:=
json
.
NewDecoder
(
authResponse
.
Body
)
gitReq
:=
&
gitRequest
{
Request
:
r
}
if
err
:=
dec
.
Decode
(
&
md
);
err
!=
nil
{
if
err
:=
json
.
NewDecoder
(
authResponse
.
Body
)
.
Decode
(
gitReq
);
err
!=
nil
{
fail500
(
w
,
"decode JSON GL_ID"
,
err
)
fail500
(
w
,
"decode JSON GL_ID"
,
err
)
return
return
}
}
...
@@ -122,12 +134,12 @@ func (h *gitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
...
@@ -122,12 +134,12 @@ func (h *gitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
}
}
if
!
looksLikeRepo
(
md
.
RepoPath
)
{
if
!
looksLikeRepo
(
gitReq
.
RepoPath
)
{
http
.
Error
(
w
,
"Not Found"
,
404
)
http
.
Error
(
w
,
"Not Found"
,
404
)
return
return
}
}
g
.
handleFunc
(
md
,
g
.
rpc
,
w
,
r
)
g
.
handleFunc
(
w
,
gitReq
,
g
.
rpc
)
}
}
func
looksLikeRepo
(
p
string
)
bool
{
func
looksLikeRepo
(
p
string
)
bool
{
...
@@ -161,7 +173,7 @@ func (h *gitHandler) doAuthRequest(r *http.Request) (result *http.Response, err
...
@@ -161,7 +173,7 @@ func (h *gitHandler) doAuthRequest(r *http.Request) (result *http.Response, err
return
h
.
httpClient
.
Do
(
authReq
)
return
h
.
httpClient
.
Do
(
authReq
)
}
}
func
handleGetInfoRefs
(
md
requestMetadata
,
_
string
,
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
handleGetInfoRefs
(
w
http
.
ResponseWriter
,
r
*
gitRequest
,
_
string
)
{
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
...
@@ -170,7 +182,7 @@ func handleGetInfoRefs(md requestMetadata, _ string, w http.ResponseWriter, r *h
...
@@ -170,7 +182,7 @@ func handleGetInfoRefs(md requestMetadata, _ string, w http.ResponseWriter, r *h
}
}
// Prepare our Git subprocess
// Prepare our Git subprocess
cmd
:=
gitCommand
(
md
.
GL_ID
,
"git"
,
subCommand
(
rpc
),
"--stateless-rpc"
,
"--advertise-refs"
,
md
.
RepoPath
)
cmd
:=
gitCommand
(
r
.
GL_ID
,
"git"
,
subCommand
(
rpc
),
"--stateless-rpc"
,
"--advertise-refs"
,
r
.
RepoPath
)
stdout
,
err
:=
cmd
.
StdoutPipe
()
stdout
,
err
:=
cmd
.
StdoutPipe
()
if
err
!=
nil
{
if
err
!=
nil
{
fail500
(
w
,
"handleGetInfoRefs"
,
err
)
fail500
(
w
,
"handleGetInfoRefs"
,
err
)
...
@@ -205,17 +217,17 @@ func handleGetInfoRefs(md requestMetadata, _ string, w http.ResponseWriter, r *h
...
@@ -205,17 +217,17 @@ func handleGetInfoRefs(md requestMetadata, _ string, w http.ResponseWriter, r *h
}
}
}
}
func
handleGetArchive
(
md
requestMetadata
,
format
string
,
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
handleGetArchive
(
w
http
.
ResponseWriter
,
r
*
gitRequest
,
format
string
)
{
archiveFilename
:=
path
.
Base
(
md
.
ArchivePath
)
archiveFilename
:=
path
.
Base
(
r
.
ArchivePath
)
if
cachedArchive
,
err
:=
os
.
Open
(
md
.
ArchivePath
);
err
==
nil
{
if
cachedArchive
,
err
:=
os
.
Open
(
r
.
ArchivePath
);
err
==
nil
{
defer
cachedArchive
.
Close
()
defer
cachedArchive
.
Close
()
log
.
Printf
(
"Serving cached file %q"
,
md
.
ArchivePath
)
log
.
Printf
(
"Serving cached file %q"
,
r
.
ArchivePath
)
setArchiveHeaders
(
w
,
format
,
archiveFilename
)
setArchiveHeaders
(
w
,
format
,
archiveFilename
)
// Even if somebody deleted the cachedArchive from disk since we opened
// Even if somebody deleted the cachedArchive from disk since we opened
// the file, Unix file semantics guarantee we can still read from the
// the file, Unix file semantics guarantee we can still read from the
// open file in this process.
// open file in this process.
http
.
ServeContent
(
w
,
r
,
""
,
time
.
Unix
(
0
,
0
),
cachedArchive
)
http
.
ServeContent
(
w
,
r
.
Request
,
""
,
time
.
Unix
(
0
,
0
),
cachedArchive
)
return
return
}
}
...
@@ -223,7 +235,7 @@ func handleGetArchive(md requestMetadata, format string, w http.ResponseWriter,
...
@@ -223,7 +235,7 @@ func handleGetArchive(md requestMetadata, format string, w http.ResponseWriter,
// safe. We create the tempfile in the same directory as the final cached
// safe. We create the tempfile in the same directory as the final cached
// archive we want to create so that we can use an atomic link(2) operation
// archive we want to create so that we can use an atomic link(2) operation
// to finalize the cached archive.
// to finalize the cached archive.
tempFile
,
err
:=
prepareArchiveTempfile
(
path
.
Dir
(
md
.
ArchivePath
),
tempFile
,
err
:=
prepareArchiveTempfile
(
path
.
Dir
(
r
.
ArchivePath
),
archiveFilename
)
archiveFilename
)
if
err
!=
nil
{
if
err
!=
nil
{
fail500
(
w
,
"handleGetArchive create tempfile for archive"
,
err
)
fail500
(
w
,
"handleGetArchive create tempfile for archive"
,
err
)
...
@@ -233,7 +245,7 @@ func handleGetArchive(md requestMetadata, format string, w http.ResponseWriter,
...
@@ -233,7 +245,7 @@ func handleGetArchive(md requestMetadata, format string, w http.ResponseWriter,
compressCmd
,
archiveFormat
:=
parseArchiveFormat
(
format
)
compressCmd
,
archiveFormat
:=
parseArchiveFormat
(
format
)
archiveCmd
:=
gitCommand
(
""
,
"git"
,
"--git-dir="
+
md
.
RepoPath
,
"archive"
,
"--format="
+
archiveFormat
,
"--prefix="
+
md
.
ArchivePrefix
+
"/"
,
md
.
CommitId
)
archiveCmd
:=
gitCommand
(
""
,
"git"
,
"--git-dir="
+
r
.
RepoPath
,
"archive"
,
"--format="
+
archiveFormat
,
"--prefix="
+
r
.
ArchivePrefix
+
"/"
,
r
.
CommitId
)
archiveStdout
,
err
:=
archiveCmd
.
StdoutPipe
()
archiveStdout
,
err
:=
archiveCmd
.
StdoutPipe
()
if
err
!=
nil
{
if
err
!=
nil
{
fail500
(
w
,
"handleGetArchive"
,
err
)
fail500
(
w
,
"handleGetArchive"
,
err
)
...
@@ -289,7 +301,7 @@ func handleGetArchive(md requestMetadata, format string, w http.ResponseWriter,
...
@@ -289,7 +301,7 @@ func handleGetArchive(md requestMetadata, format string, w http.ResponseWriter,
}
}
}
}
if
err
:=
finalizeCachedArchive
(
tempFile
,
md
.
ArchivePath
);
err
!=
nil
{
if
err
:=
finalizeCachedArchive
(
tempFile
,
r
.
ArchivePath
);
err
!=
nil
{
logContext
(
"handleGetArchive finalize cached archive"
,
err
)
logContext
(
"handleGetArchive finalize cached archive"
,
err
)
return
return
}
}
...
@@ -334,7 +346,7 @@ func finalizeCachedArchive(tempFile *os.File, archivePath string) error {
...
@@ -334,7 +346,7 @@ func finalizeCachedArchive(tempFile *os.File, archivePath string) error {
return
os
.
Link
(
tempFile
.
Name
(),
archivePath
)
return
os
.
Link
(
tempFile
.
Name
(),
archivePath
)
}
}
func
handlePostRPC
(
md
requestMetadata
,
rpc
string
,
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
handlePostRPC
(
w
http
.
ResponseWriter
,
r
*
gitRequest
,
rpc
string
)
{
var
body
io
.
ReadCloser
var
body
io
.
ReadCloser
var
err
error
var
err
error
...
@@ -351,7 +363,7 @@ func handlePostRPC(md requestMetadata, rpc string, w http.ResponseWriter, r *htt
...
@@ -351,7 +363,7 @@ func handlePostRPC(md requestMetadata, rpc string, w http.ResponseWriter, r *htt
defer
body
.
Close
()
defer
body
.
Close
()
// Prepare our Git subprocess
// Prepare our Git subprocess
cmd
:=
gitCommand
(
md
.
GL_ID
,
"git"
,
subCommand
(
rpc
),
"--stateless-rpc"
,
md
.
RepoPath
)
cmd
:=
gitCommand
(
r
.
GL_ID
,
"git"
,
subCommand
(
rpc
),
"--stateless-rpc"
,
r
.
RepoPath
)
stdout
,
err
:=
cmd
.
StdoutPipe
()
stdout
,
err
:=
cmd
.
StdoutPipe
()
if
err
!=
nil
{
if
err
!=
nil
{
fail500
(
w
,
"handlePostRPC"
,
err
)
fail500
(
w
,
"handlePostRPC"
,
err
)
...
...
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