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
23a16410
Commit
23a16410
authored
Sep 30, 2016
by
Jacob Vosmaer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Suppress upload-pack Wait() error on shallow clone
parent
c3d62d2b
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
150 additions
and
12 deletions
+150
-12
internal/git/git-http.go
internal/git/git-http.go
+30
-12
internal/git/pktline.go
internal/git/pktline.go
+70
-0
internal/git/pktline_test.go
internal/git/pktline_test.go
+50
-0
No files found.
internal/git/git-http.go
View file @
23a16410
...
...
@@ -5,11 +5,13 @@ In this file we handle the Git 'smart HTTP' protocol
package
git
import
(
"bytes"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
...
...
@@ -101,6 +103,8 @@ func handleGetInfoRefs(w http.ResponseWriter, r *http.Request, a *api.Response)
func
handlePostRPC
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
)
{
var
err
error
var
body
io
.
Reader
var
isShallowClone
bool
// Get Git action from URL
action
:=
filepath
.
Base
(
r
.
URL
.
Path
)
...
...
@@ -110,6 +114,25 @@ func handlePostRPC(w http.ResponseWriter, r *http.Request, a *api.Response) {
return
}
if
action
==
"git-upload-pack"
{
buffer
:=
&
bytes
.
Buffer
{}
if
_
,
err
:=
io
.
Copy
(
buffer
,
r
.
Body
);
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
&
copyError
{
fmt
.
Errorf
(
"handlePostRPC: buffer git-upload-pack body: %v"
)})
return
}
isShallowClone
,
err
=
scanDeepen
(
bytes
.
NewReader
(
buffer
.
Bytes
()))
body
=
buffer
if
err
!=
nil
{
// Do not pass on the error: our failure to parse the
// request body should not abort the request.
helper
.
LogError
(
r
,
fmt
.
Errorf
(
"parseBody: %v"
,
err
))
}
}
else
{
body
=
r
.
Body
}
// Prepare our Git subprocess
cmd
:=
gitCommand
(
a
.
GL_ID
,
"git"
,
subCommand
(
action
),
"--stateless-rpc"
,
a
.
RepoPath
)
stdout
,
err
:=
cmd
.
StdoutPipe
()
...
...
@@ -131,7 +154,7 @@ func handlePostRPC(w http.ResponseWriter, r *http.Request, a *api.Response) {
defer
helper
.
CleanUpProcessGroup
(
cmd
)
// Ensure brute force subprocess clean-up
// Write the client request body to Git's standard input
if
_
,
err
:=
io
.
Copy
(
stdin
,
r
.
B
ody
);
err
!=
nil
{
if
_
,
err
:=
io
.
Copy
(
stdin
,
b
ody
);
err
!=
nil
{
helper
.
Fail500
(
w
,
r
,
fmt
.
Errorf
(
"handlePostRPC: write to %v: %v"
,
cmd
.
Args
,
err
))
return
}
...
...
@@ -155,22 +178,17 @@ func handlePostRPC(w http.ResponseWriter, r *http.Request, a *api.Response) {
)
return
}
if
err
:=
cmd
.
Wait
();
err
!=
nil
{
if
err
:=
cmd
.
Wait
();
err
!=
nil
&&
!
(
isExitError
(
err
)
&&
isShallowClone
)
{
helper
.
LogError
(
r
,
fmt
.
Errorf
(
"handlePostRPC: wait for %v: %v"
,
cmd
.
Args
,
err
))
return
}
}
func
subCommand
(
rpc
string
)
string
{
return
strings
.
TrimPrefix
(
rpc
,
"git-"
)
func
isExitError
(
err
error
)
bool
{
_
,
ok
:=
err
.
(
*
exec
.
ExitError
)
return
ok
}
func
pktLine
(
w
io
.
Writer
,
s
string
)
error
{
_
,
err
:=
fmt
.
Fprintf
(
w
,
"%04x%s"
,
len
(
s
)
+
4
,
s
)
return
err
}
func
pktFlush
(
w
io
.
Writer
)
error
{
_
,
err
:=
fmt
.
Fprint
(
w
,
"0000"
)
return
err
func
subCommand
(
rpc
string
)
string
{
return
strings
.
TrimPrefix
(
rpc
,
"git-"
)
}
internal/git/pktline.go
0 → 100644
View file @
23a16410
package
git
import
(
"bufio"
"bytes"
"fmt"
"io"
"strconv"
)
func
pktLine
(
w
io
.
Writer
,
s
string
)
error
{
_
,
err
:=
fmt
.
Fprintf
(
w
,
"%04x%s"
,
len
(
s
)
+
4
,
s
)
return
err
}
func
pktFlush
(
w
io
.
Writer
)
error
{
_
,
err
:=
fmt
.
Fprint
(
w
,
"0000"
)
return
err
}
func
scanDeepen
(
body
io
.
Reader
)
(
bool
,
error
)
{
hasDeepen
:=
false
scanner
:=
bufio
.
NewScanner
(
body
)
scanner
.
Split
(
pktLineSplitter
)
for
scanner
.
Scan
()
{
if
bytes
.
HasPrefix
(
scanner
.
Bytes
(),
[]
byte
(
"deepen"
))
{
hasDeepen
=
true
break
}
}
return
hasDeepen
,
scanner
.
Err
()
}
func
pktLineSplitter
(
data
[]
byte
,
atEOF
bool
)
(
advance
int
,
token
[]
byte
,
err
error
)
{
if
len
(
data
)
<
4
{
if
atEOF
&&
len
(
data
)
>
0
{
return
0
,
nil
,
fmt
.
Errorf
(
"pktLineSplitter: incomplete length prefix on %q"
,
data
)
}
return
0
,
nil
,
nil
// want more data
}
if
bytes
.
HasPrefix
(
data
,
[]
byte
(
"0000"
))
{
// special case: "0000" terminator packet: return empty token
return
4
,
data
[
4
:
4
],
nil
}
// We have at least 4 bytes available so we can decode the 4-hex digit
// length prefix of the packet line.
pktLength64
,
err
:=
strconv
.
ParseInt
(
string
(
data
[
:
4
]),
16
,
0
)
if
err
!=
nil
{
return
0
,
nil
,
fmt
.
Errorf
(
"pktLineSplitter: decode length: %v"
,
err
)
}
pktLength
:=
int
(
pktLength64
)
if
pktLength
<
0
{
return
0
,
nil
,
fmt
.
Errorf
(
"pktLineSplitter: invalid length: %d"
,
pktLength
)
}
if
len
(
data
)
<
pktLength
{
if
atEOF
{
return
0
,
nil
,
fmt
.
Errorf
(
"pktLineSplitter: less than %d bytes in input %q"
,
pktLength
,
data
)
}
return
0
,
nil
,
nil
// want more data
}
return
pktLength
,
data
[
4
:
pktLength
],
nil
}
internal/git/pktline_test.go
0 → 100644
View file @
23a16410
package
git
import
(
"bytes"
"testing"
)
func
TestSuccessfulScanDeepen
(
t
*
testing
.
T
)
{
examples
:=
[]
struct
{
input
string
output
bool
}{
{
"000dsomething000cdeepen 10000"
,
true
},
{
"000dsomething0000000cdeepen 1"
,
true
},
{
"000dsomething0000"
,
false
},
}
for
_
,
example
:=
range
examples
{
ok
,
err
:=
scanDeepen
(
bytes
.
NewReader
([]
byte
(
example
.
input
)))
if
err
!=
nil
{
t
.
Fatalf
(
"error scanning %q: %v"
,
example
.
input
,
err
)
}
if
ok
!=
example
.
output
{
t
.
Fatalf
(
"scanDeepen %q: expected %v, got %v"
,
example
.
input
,
example
.
output
,
ok
)
}
}
}
func
TestFailedScanDeepen
(
t
*
testing
.
T
)
{
examples
:=
[]
string
{
"invalid data"
,
"deepen"
,
"000cdeepen"
,
}
for
_
,
example
:=
range
examples
{
ok
,
err
:=
scanDeepen
(
bytes
.
NewReader
([]
byte
(
example
)))
if
err
==
nil
{
t
.
Fatalf
(
"expected error scanning %q"
,
example
)
}
t
.
Log
(
err
)
if
ok
==
true
{
t
.
Fatalf
(
"scanDeepen %q: expected result to be false, got true"
,
example
)
}
}
}
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