Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
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-ce
Commits
59c95c75
Commit
59c95c75
authored
Jan 15, 2017
by
Jacob Vosmaer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Put Git actions in separate files
parent
1bdde7a0
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
239 additions
and
208 deletions
+239
-208
internal/git/git-http.go
internal/git/git-http.go
+0
-208
internal/git/info-refs.go
internal/git/info-refs.go
+85
-0
internal/git/receive-pack.go
internal/git/receive-pack.go
+59
-0
internal/git/upload-pack.go
internal/git/upload-pack.go
+95
-0
No files found.
internal/git/git-http.go
View file @
59c95c75
...
@@ -5,10 +5,8 @@ In this file we handle the Git 'smart HTTP' protocol
...
@@ -5,10 +5,8 @@ In this file we handle the Git 'smart HTTP' protocol
package
git
package
git
import
(
import
(
"bytes"
"fmt"
"fmt"
"io"
"io"
"io/ioutil"
"log"
"log"
"net/http"
"net/http"
"os"
"os"
...
@@ -16,24 +14,11 @@ import (
...
@@ -16,24 +14,11 @@ import (
"path"
"path"
"path/filepath"
"path/filepath"
"strings"
"strings"
"sync"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/config"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/gitaly"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
)
func
GetInfoRefsHandler
(
a
*
api
.
API
,
cfg
*
config
.
Config
)
http
.
Handler
{
return
repoPreAuthorizeHandler
(
a
,
func
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
,
apiResponse
*
api
.
Response
)
{
if
apiResponse
.
GitalySocketPath
==
""
{
handleGetInfoRefs
(
rw
,
r
,
apiResponse
)
}
else
{
handleGetInfoRefsWithGitaly
(
rw
,
r
,
apiResponse
,
gitaly
.
NewClient
(
apiResponse
.
GitalySocketPath
,
cfg
))
}
})
}
func
PostRPC
(
a
*
api
.
API
)
http
.
Handler
{
func
PostRPC
(
a
*
api
.
API
)
http
.
Handler
{
return
repoPreAuthorizeHandler
(
a
,
handlePostRPC
)
return
repoPreAuthorizeHandler
(
a
,
handlePostRPC
)
}
}
...
@@ -64,68 +49,6 @@ func repoPreAuthorizeHandler(myAPI *api.API, handleFunc api.HandleFunc) http.Han
...
@@ -64,68 +49,6 @@ func repoPreAuthorizeHandler(myAPI *api.API, handleFunc api.HandleFunc) http.Han
},
""
)
},
""
)
}
}
func
handleGetInfoRefsWithGitaly
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
,
gitalyClient
*
gitaly
.
Client
)
{
req
:=
*
r
// Make a copy of r
req
.
Header
=
helper
.
HeaderClone
(
r
.
Header
)
req
.
Header
.
Add
(
"Gitaly-Repo-Path"
,
a
.
RepoPath
)
req
.
Header
.
Add
(
"Gitaly-GL-Id"
,
a
.
GL_ID
)
req
.
URL
.
Path
=
path
.
Join
(
a
.
GitalyResourcePath
,
subCommand
(
getService
(
r
)))
req
.
URL
.
RawQuery
=
""
gitalyClient
.
Proxy
.
ServeHTTP
(
rw
,
&
req
)
}
func
handleGetInfoRefs
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
)
{
w
:=
NewGitHttpResponseWriter
(
rw
)
// Log 0 bytes in because we ignore the request body (and there usually is none anyway).
defer
w
.
Log
(
r
,
0
)
rpc
:=
getService
(
r
)
if
!
(
rpc
==
"git-upload-pack"
||
rpc
==
"git-receive-pack"
)
{
// The 'dumb' Git HTTP protocol is not supported
http
.
Error
(
w
,
"Not Found"
,
404
)
return
}
// Prepare our Git subprocess
cmd
:=
gitCommand
(
a
.
GL_ID
,
"git"
,
subCommand
(
rpc
),
"--stateless-rpc"
,
"--advertise-refs"
,
a
.
RepoPath
)
stdout
,
err
:=
cmd
.
StdoutPipe
()
if
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
fmt
.
Errorf
(
"handleGetInfoRefs: stdout: %v"
,
err
))
return
}
defer
stdout
.
Close
()
if
err
:=
cmd
.
Start
();
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
fmt
.
Errorf
(
"handleGetInfoRefs: start %v: %v"
,
cmd
.
Args
,
err
))
return
}
defer
helper
.
CleanUpProcessGroup
(
cmd
)
// Ensure brute force subprocess clean-up
// Start writing the response
w
.
Header
()
.
Set
(
"Content-Type"
,
fmt
.
Sprintf
(
"application/x-%s-advertisement"
,
rpc
))
w
.
Header
()
.
Set
(
"Cache-Control"
,
"no-cache"
)
w
.
WriteHeader
(
200
)
// Don't bother with HTTP 500 from this point on, just return
if
err
:=
pktLine
(
w
,
fmt
.
Sprintf
(
"# service=%s
\n
"
,
rpc
));
err
!=
nil
{
helper
.
LogError
(
r
,
fmt
.
Errorf
(
"handleGetInfoRefs: pktLine: %v"
,
err
))
return
}
if
err
:=
pktFlush
(
w
);
err
!=
nil
{
helper
.
LogError
(
r
,
fmt
.
Errorf
(
"handleGetInfoRefs: pktFlush: %v"
,
err
))
return
}
if
_
,
err
:=
io
.
Copy
(
w
,
stdout
);
err
!=
nil
{
helper
.
LogError
(
r
,
&
copyError
{
fmt
.
Errorf
(
"handleGetInfoRefs: copy output of %v: %v"
,
cmd
.
Args
,
err
)},
)
return
}
if
err
:=
cmd
.
Wait
();
err
!=
nil
{
helper
.
LogError
(
r
,
fmt
.
Errorf
(
"handleGetInfoRefs: wait for %v: %v"
,
cmd
.
Args
,
err
))
return
}
}
func
handlePostRPC
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
)
{
func
handlePostRPC
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
)
{
var
writtenIn
int64
var
writtenIn
int64
...
@@ -148,137 +71,6 @@ func handlePostRPC(rw http.ResponseWriter, r *http.Request, a *api.Response) {
...
@@ -148,137 +71,6 @@ func handlePostRPC(rw http.ResponseWriter, r *http.Request, a *api.Response) {
}
}
}
}
func
handleReceivePack
(
action
string
,
w
*
GitHttpResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
)
(
writtenIn
int64
,
err
error
)
{
body
:=
r
.
Body
cmd
,
stdin
,
stdout
,
err
:=
setupGitCommand
(
action
,
a
,
w
,
r
)
if
err
!=
nil
{
return
}
defer
stdout
.
Close
()
defer
stdin
.
Close
()
defer
helper
.
CleanUpProcessGroup
(
cmd
)
// Ensure brute force subprocess clean-up
// Write the client request body to Git's standard input
writtenIn
,
err
=
io
.
Copy
(
stdin
,
body
)
if
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
fmt
.
Errorf
(
"handleReceivePack: write to %v: %v"
,
cmd
.
Args
,
err
))
return
}
// Signal to the Git subprocess that no more data is coming
stdin
.
Close
()
// It may take a while before we return and the deferred closes happen
// so let's free up some resources already.
r
.
Body
.
Close
()
writePostRPCHeader
(
w
,
action
)
// This io.Copy may take a long time, both for Git push and pull.
_
,
err
=
io
.
Copy
(
w
,
stdout
)
if
err
!=
nil
{
helper
.
LogError
(
r
,
&
copyError
{
fmt
.
Errorf
(
"handleReceivePack: copy output of %v: %v"
,
cmd
.
Args
,
err
)},
)
return
}
err
=
cmd
.
Wait
()
if
err
!=
nil
{
helper
.
LogError
(
r
,
fmt
.
Errorf
(
"handleReceivePack: wait for %v: %v"
,
cmd
.
Args
,
err
))
return
}
return
writtenIn
,
nil
}
func
handleUploadPack
(
action
string
,
w
*
GitHttpResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
)
(
writtenIn
int64
,
err
error
)
{
var
isShallowClone
bool
var
body
io
.
Reader
buffer
:=
&
bytes
.
Buffer
{}
// Only sniff on the first 4096 bytes: we assume that if we find no
// 'deepen' message in the first 4096 bytes there won't be one later
// either.
_
,
err
=
io
.
Copy
(
buffer
,
io
.
LimitReader
(
r
.
Body
,
4096
))
if
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
&
copyError
{
fmt
.
Errorf
(
"handleUploadPack: buffer git-upload-pack body: %v"
,
err
)})
return
}
isShallowClone
=
scanDeepen
(
bytes
.
NewReader
(
buffer
.
Bytes
()))
body
=
io
.
MultiReader
(
buffer
,
r
.
Body
)
// Read out the full HTTP request body so that we can reply
buf
,
err
:=
ioutil
.
ReadAll
(
body
)
if
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
&
copyError
{
fmt
.
Errorf
(
"handleUploadPack: full buffer git-upload-pack body: %v"
,
err
)})
return
}
body
=
ioutil
.
NopCloser
(
bytes
.
NewBuffer
(
buf
))
r
.
Body
.
Close
()
cmd
,
stdin
,
stdout
,
err
:=
setupGitCommand
(
action
,
a
,
w
,
r
)
if
err
!=
nil
{
return
}
defer
stdout
.
Close
()
defer
stdin
.
Close
()
defer
helper
.
CleanUpProcessGroup
(
cmd
)
// Ensure brute force subprocess clean-up
stdoutError
:=
make
(
chan
error
,
1
)
var
wg
sync
.
WaitGroup
wg
.
Add
(
1
)
// Start writing the response
writePostRPCHeader
(
w
,
action
)
go
func
()
{
defer
wg
.
Done
()
if
_
,
err
:=
io
.
Copy
(
w
,
stdout
);
err
!=
nil
{
helper
.
LogError
(
r
,
&
copyError
{
fmt
.
Errorf
(
"handleUploadPack: copy output of %v: %v"
,
cmd
.
Args
,
err
)},
)
stdoutError
<-
err
return
}
}()
// Write the client request body to Git's standard input
if
writtenIn
,
err
=
io
.
Copy
(
stdin
,
body
);
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
fmt
.
Errorf
(
"handleUploadPack: write to %v: %v"
,
cmd
.
Args
,
err
))
return
}
// Signal to the Git subprocess that no more data is coming
stdin
.
Close
()
wg
.
Wait
()
if
len
(
stdoutError
)
>
0
{
return
}
err
=
cmd
.
Wait
()
if
err
!=
nil
&&
!
(
isExitError
(
err
)
&&
isShallowClone
)
{
helper
.
LogError
(
r
,
fmt
.
Errorf
(
"handleUploadPack: wait for %v: %v"
,
cmd
.
Args
,
err
))
return
}
return
writtenIn
,
nil
}
func
setupGitCommand
(
action
string
,
a
*
api
.
Response
,
w
*
GitHttpResponseWriter
,
r
*
http
.
Request
)
(
cmd
*
exec
.
Cmd
,
stdin
io
.
WriteCloser
,
stdout
io
.
ReadCloser
,
err
error
)
{
func
setupGitCommand
(
action
string
,
a
*
api
.
Response
,
w
*
GitHttpResponseWriter
,
r
*
http
.
Request
)
(
cmd
*
exec
.
Cmd
,
stdin
io
.
WriteCloser
,
stdout
io
.
ReadCloser
,
err
error
)
{
// Prepare our Git subprocess
// Prepare our Git subprocess
cmd
=
gitCommand
(
a
.
GL_ID
,
"git"
,
subCommand
(
action
),
"--stateless-rpc"
,
a
.
RepoPath
)
cmd
=
gitCommand
(
a
.
GL_ID
,
"git"
,
subCommand
(
action
),
"--stateless-rpc"
,
a
.
RepoPath
)
...
...
internal/git/info-refs.go
0 → 100644
View file @
59c95c75
package
git
import
(
"fmt"
"io"
"net/http"
"path"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/config"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/gitaly"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
func
GetInfoRefsHandler
(
a
*
api
.
API
,
cfg
*
config
.
Config
)
http
.
Handler
{
return
repoPreAuthorizeHandler
(
a
,
func
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
,
apiResponse
*
api
.
Response
)
{
if
apiResponse
.
GitalySocketPath
==
""
{
handleGetInfoRefs
(
rw
,
r
,
apiResponse
)
}
else
{
handleGetInfoRefsWithGitaly
(
rw
,
r
,
apiResponse
,
gitaly
.
NewClient
(
apiResponse
.
GitalySocketPath
,
cfg
))
}
})
}
func
handleGetInfoRefsWithGitaly
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
,
gitalyClient
*
gitaly
.
Client
)
{
req
:=
*
r
// Make a copy of r
req
.
Header
=
helper
.
HeaderClone
(
r
.
Header
)
req
.
Header
.
Add
(
"Gitaly-Repo-Path"
,
a
.
RepoPath
)
req
.
Header
.
Add
(
"Gitaly-GL-Id"
,
a
.
GL_ID
)
req
.
URL
.
Path
=
path
.
Join
(
a
.
GitalyResourcePath
,
subCommand
(
getService
(
r
)))
req
.
URL
.
RawQuery
=
""
gitalyClient
.
Proxy
.
ServeHTTP
(
rw
,
&
req
)
}
func
handleGetInfoRefs
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
)
{
w
:=
NewGitHttpResponseWriter
(
rw
)
// Log 0 bytes in because we ignore the request body (and there usually is none anyway).
defer
w
.
Log
(
r
,
0
)
rpc
:=
getService
(
r
)
if
!
(
rpc
==
"git-upload-pack"
||
rpc
==
"git-receive-pack"
)
{
// The 'dumb' Git HTTP protocol is not supported
http
.
Error
(
w
,
"Not Found"
,
404
)
return
}
// Prepare our Git subprocess
cmd
:=
gitCommand
(
a
.
GL_ID
,
"git"
,
subCommand
(
rpc
),
"--stateless-rpc"
,
"--advertise-refs"
,
a
.
RepoPath
)
stdout
,
err
:=
cmd
.
StdoutPipe
()
if
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
fmt
.
Errorf
(
"handleGetInfoRefs: stdout: %v"
,
err
))
return
}
defer
stdout
.
Close
()
if
err
:=
cmd
.
Start
();
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
fmt
.
Errorf
(
"handleGetInfoRefs: start %v: %v"
,
cmd
.
Args
,
err
))
return
}
defer
helper
.
CleanUpProcessGroup
(
cmd
)
// Ensure brute force subprocess clean-up
// Start writing the response
w
.
Header
()
.
Set
(
"Content-Type"
,
fmt
.
Sprintf
(
"application/x-%s-advertisement"
,
rpc
))
w
.
Header
()
.
Set
(
"Cache-Control"
,
"no-cache"
)
w
.
WriteHeader
(
200
)
// Don't bother with HTTP 500 from this point on, just return
if
err
:=
pktLine
(
w
,
fmt
.
Sprintf
(
"# service=%s
\n
"
,
rpc
));
err
!=
nil
{
helper
.
LogError
(
r
,
fmt
.
Errorf
(
"handleGetInfoRefs: pktLine: %v"
,
err
))
return
}
if
err
:=
pktFlush
(
w
);
err
!=
nil
{
helper
.
LogError
(
r
,
fmt
.
Errorf
(
"handleGetInfoRefs: pktFlush: %v"
,
err
))
return
}
if
_
,
err
:=
io
.
Copy
(
w
,
stdout
);
err
!=
nil
{
helper
.
LogError
(
r
,
&
copyError
{
fmt
.
Errorf
(
"handleGetInfoRefs: copy output of %v: %v"
,
cmd
.
Args
,
err
)},
)
return
}
if
err
:=
cmd
.
Wait
();
err
!=
nil
{
helper
.
LogError
(
r
,
fmt
.
Errorf
(
"handleGetInfoRefs: wait for %v: %v"
,
cmd
.
Args
,
err
))
return
}
}
internal/git/receive-pack.go
0 → 100644
View file @
59c95c75
package
git
import
(
"fmt"
"io"
"net/http"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
func
handleReceivePack
(
action
string
,
w
*
GitHttpResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
)
(
writtenIn
int64
,
err
error
)
{
body
:=
r
.
Body
cmd
,
stdin
,
stdout
,
err
:=
setupGitCommand
(
action
,
a
,
w
,
r
)
if
err
!=
nil
{
return
}
defer
stdout
.
Close
()
defer
stdin
.
Close
()
defer
helper
.
CleanUpProcessGroup
(
cmd
)
// Ensure brute force subprocess clean-up
// Write the client request body to Git's standard input
writtenIn
,
err
=
io
.
Copy
(
stdin
,
body
)
if
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
fmt
.
Errorf
(
"handleReceivePack: write to %v: %v"
,
cmd
.
Args
,
err
))
return
}
// Signal to the Git subprocess that no more data is coming
stdin
.
Close
()
// It may take a while before we return and the deferred closes happen
// so let's free up some resources already.
r
.
Body
.
Close
()
writePostRPCHeader
(
w
,
action
)
// This io.Copy may take a long time, both for Git push and pull.
_
,
err
=
io
.
Copy
(
w
,
stdout
)
if
err
!=
nil
{
helper
.
LogError
(
r
,
&
copyError
{
fmt
.
Errorf
(
"handleReceivePack: copy output of %v: %v"
,
cmd
.
Args
,
err
)},
)
return
}
err
=
cmd
.
Wait
()
if
err
!=
nil
{
helper
.
LogError
(
r
,
fmt
.
Errorf
(
"handleReceivePack: wait for %v: %v"
,
cmd
.
Args
,
err
))
return
}
return
writtenIn
,
nil
}
internal/git/upload-pack.go
0 → 100644
View file @
59c95c75
package
git
import
(
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"sync"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
func
handleUploadPack
(
action
string
,
w
*
GitHttpResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
)
(
writtenIn
int64
,
err
error
)
{
var
isShallowClone
bool
var
body
io
.
Reader
buffer
:=
&
bytes
.
Buffer
{}
// Only sniff on the first 4096 bytes: we assume that if we find no
// 'deepen' message in the first 4096 bytes there won't be one later
// either.
_
,
err
=
io
.
Copy
(
buffer
,
io
.
LimitReader
(
r
.
Body
,
4096
))
if
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
&
copyError
{
fmt
.
Errorf
(
"handleUploadPack: buffer git-upload-pack body: %v"
,
err
)})
return
}
isShallowClone
=
scanDeepen
(
bytes
.
NewReader
(
buffer
.
Bytes
()))
body
=
io
.
MultiReader
(
buffer
,
r
.
Body
)
// Read out the full HTTP request body so that we can reply
buf
,
err
:=
ioutil
.
ReadAll
(
body
)
if
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
&
copyError
{
fmt
.
Errorf
(
"handleUploadPack: full buffer git-upload-pack body: %v"
,
err
)})
return
}
body
=
ioutil
.
NopCloser
(
bytes
.
NewBuffer
(
buf
))
r
.
Body
.
Close
()
cmd
,
stdin
,
stdout
,
err
:=
setupGitCommand
(
action
,
a
,
w
,
r
)
if
err
!=
nil
{
return
}
defer
stdout
.
Close
()
defer
stdin
.
Close
()
defer
helper
.
CleanUpProcessGroup
(
cmd
)
// Ensure brute force subprocess clean-up
stdoutError
:=
make
(
chan
error
,
1
)
var
wg
sync
.
WaitGroup
wg
.
Add
(
1
)
// Start writing the response
writePostRPCHeader
(
w
,
action
)
go
func
()
{
defer
wg
.
Done
()
if
_
,
err
:=
io
.
Copy
(
w
,
stdout
);
err
!=
nil
{
helper
.
LogError
(
r
,
&
copyError
{
fmt
.
Errorf
(
"handleUploadPack: copy output of %v: %v"
,
cmd
.
Args
,
err
)},
)
stdoutError
<-
err
return
}
}()
// Write the client request body to Git's standard input
if
writtenIn
,
err
=
io
.
Copy
(
stdin
,
body
);
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
fmt
.
Errorf
(
"handleUploadPack: write to %v: %v"
,
cmd
.
Args
,
err
))
return
}
// Signal to the Git subprocess that no more data is coming
stdin
.
Close
()
wg
.
Wait
()
if
len
(
stdoutError
)
>
0
{
return
}
err
=
cmd
.
Wait
()
if
err
!=
nil
&&
!
(
isExitError
(
err
)
&&
isShallowClone
)
{
helper
.
LogError
(
r
,
fmt
.
Errorf
(
"handleUploadPack: wait for %v: %v"
,
cmd
.
Args
,
err
))
return
}
return
writtenIn
,
nil
}
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