Commit 6ba53d9d authored by Jacob Vosmaer's avatar Jacob Vosmaer

Buffer request in tempfile, not memory

parent ba4d77e5
...@@ -6,15 +6,13 @@ import ( ...@@ -6,15 +6,13 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/api" "gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper" "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
) )
func handleUploadPack(w *GitHttpResponseWriter, r *http.Request, a *api.Response) (writtenIn int64, err error) { func handleUploadPack(w *GitHttpResponseWriter, r *http.Request, a *api.Response) (writtenIn int64, err error) {
var isShallowClone bool
var body io.Reader
buffer := &bytes.Buffer{} buffer := &bytes.Buffer{}
// Only sniff on the first 4096 bytes: we assume that if we find no // 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 // 'deepen' message in the first 4096 bytes there won't be one later
...@@ -24,19 +22,18 @@ func handleUploadPack(w *GitHttpResponseWriter, r *http.Request, a *api.Response ...@@ -24,19 +22,18 @@ func handleUploadPack(w *GitHttpResponseWriter, r *http.Request, a *api.Response
fail500(w) fail500(w)
return writtenIn, &copyError{fmt.Errorf("buffer git-upload-pack body: %v", err)} return writtenIn, &copyError{fmt.Errorf("buffer git-upload-pack body: %v", err)}
} }
isShallowClone := scanDeepen(bytes.NewReader(buffer.Bytes()))
isShallowClone = scanDeepen(bytes.NewReader(buffer.Bytes())) // We must drain the request body before writing the response, to avoid
body = io.MultiReader(buffer, r.Body) // upsetting NGINX.
remainder, err := bufferInTempfile(r.Body)
// Read out the full HTTP request body so that we can reply
buf, err := ioutil.ReadAll(body)
if err != nil { if err != nil {
fail500(w) fail500(w)
return writtenIn, &copyError{fmt.Errorf("full buffer git-upload-pack body: %v", err)} return writtenIn, fmt.Errorf("bufferInTempfile: %v", err)
} }
defer remainder.Close()
body = ioutil.NopCloser(bytes.NewBuffer(buf)) body := ioutil.NopCloser(io.MultiReader(buffer, remainder))
r.Body.Close() r.Body.Close()
action := getService(r) action := getService(r)
...@@ -52,11 +49,10 @@ func handleUploadPack(w *GitHttpResponseWriter, r *http.Request, a *api.Response ...@@ -52,11 +49,10 @@ func handleUploadPack(w *GitHttpResponseWriter, r *http.Request, a *api.Response
defer helper.CleanUpProcessGroup(cmd) // Ensure brute force subprocess clean-up defer helper.CleanUpProcessGroup(cmd) // Ensure brute force subprocess clean-up
stdoutError := make(chan error, 1) stdoutError := make(chan error, 1)
// Start writing the response
writePostRPCHeader(w, action)
go func() { go func() {
writePostRPCHeader(w, action)
// Start reading from stdout already to avoid blocking while writing to
// stdin below.
_, err := io.Copy(w, stdout) _, err := io.Copy(w, stdout)
// This error may be lost if some other error prevents us from <-ing on this channel. // This error may be lost if some other error prevents us from <-ing on this channel.
stdoutError <- err stdoutError <- err
...@@ -87,3 +83,24 @@ func handleUploadPack(w *GitHttpResponseWriter, r *http.Request, a *api.Response ...@@ -87,3 +83,24 @@ func handleUploadPack(w *GitHttpResponseWriter, r *http.Request, a *api.Response
func fail500(w http.ResponseWriter) { func fail500(w http.ResponseWriter) {
helper.Fail500(w, nil, nil) helper.Fail500(w, nil, nil)
} }
func bufferInTempfile(r io.Reader) (io.ReadCloser, error) {
buffer, err := ioutil.TempFile("", "gitlab-workhorse-git-request-body")
if err != nil {
return nil, err
}
if err := os.Remove(buffer.Name()); err != nil {
return nil, err
}
if _, err := io.Copy(buffer, r); err != nil {
return nil, err
}
if _, err := buffer.Seek(0, 0); err != nil {
return nil, err
}
return buffer, nil
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment