New upstream version 4.2.1+debian

parent 00354c81
......@@ -13,6 +13,10 @@ test using go 1.9:
image: golang:1.9
<<: *test_definition
test using go 1.10:
image: golang:1.10
<<: *test_definition
test:release:
only:
- tags
......
......@@ -2,6 +2,22 @@
Formerly known as 'gitlab-git-http-server'.
v 4.2.1
- Fix objectstore error shadowing !259
v 4.2.0
- Guess RemoteAddr from X-Forwarded-For !254
v 4.1.0
- Add websocket route for web terminal access to CI jobs !234
- Remove RepoPath check on Git HTTP !244
- Artifacts and Uploads must allow Objects Storage only requests !247
- Bridge between Gitaly and GitLab for a new repository snapshot endpoint !248
- Update gitaly proto !249
v 4.0.0
- Handle Object Store upload in upload.HandleFileUploads !238
......
......@@ -2,6 +2,7 @@ package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
......@@ -22,6 +23,8 @@ import (
pb "gitlab.com/gitlab-org/gitaly-proto/go"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
......@@ -579,6 +582,106 @@ func TestGetPatchProxiedToGitalyInterruptedStream(t *testing.T) {
}
}
func TestGetSnapshotProxiedToGitalySuccessfully(t *testing.T) {
gitalyServer, socketPath := startGitalyServer(t, codes.OK)
defer gitalyServer.Stop()
gitalyAddress := "unix://" + socketPath
expectedBody := testhelper.GitalyGetSnapshotResponseMock
archiveLength := len(expectedBody)
params := buildGetSnapshotParams(gitalyAddress, buildPbRepo("default", "foo/bar.git"))
resp, body, err := doSendDataRequest("/api/v4/projects/:id/snapshot", "git-snapshot", params)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode, "GET %q: status code", resp.Request.URL)
assert.Equal(t, expectedBody, string(body), "GET %q: body", resp.Request.URL)
assert.Equal(t, archiveLength, len(body), "GET %q: body size", resp.Request.URL)
testhelper.AssertResponseHeader(t, resp, "Content-Disposition", `attachment; filename="snapshot.tar"`)
testhelper.AssertResponseHeader(t, resp, "Content-Type", "application/x-tar")
testhelper.AssertResponseHeader(t, resp, "Content-Transfer-Encoding", "binary")
testhelper.AssertResponseHeader(t, resp, "Cache-Control", "private")
}
func TestGetSnapshotProxiedToGitalyInterruptedStream(t *testing.T) {
gitalyServer, socketPath := startGitalyServer(t, codes.OK)
defer gitalyServer.Stop()
gitalyAddress := "unix://" + socketPath
params := buildGetSnapshotParams(gitalyAddress, buildPbRepo("default", "foo/bar.git"))
resp, _, err := doSendDataRequest("/api/v4/projects/:id/snapshot", "git-snapshot", params)
require.NoError(t, err)
// This causes the server stream to be interrupted instead of consumed entirely.
resp.Body.Close()
done := make(chan struct{})
go func() {
gitalyServer.WaitGroup.Wait()
close(done)
}()
select {
case <-done:
return
case <-time.After(10 * time.Second):
t.Fatal("time out waiting for gitaly handler to return")
}
}
func buildGetSnapshotParams(gitalyAddress string, repo *pb.Repository) string {
msg := serializedMessage("GetSnapshotRequest", &pb.GetSnapshotRequest{Repository: repo})
return buildGitalyRPCParams(gitalyAddress, msg)
}
type rpcArg struct {
k string
v interface{}
}
// Gitlab asks workhorse to perform some long-running RPCs for it by sending
// the RPC arguments (which are protobuf messages) in HTTP response headers.
// The messages are encoded to JSON objects using pbjson, The strings are then
// re-encoded to JSON strings using json. We must replicate this behaviour here
func buildGitalyRPCParams(gitalyAddress string, rpcArgs ...rpcArg) string {
built := map[string]interface{}{
"GitalyServer": map[string]string{
"Address": gitalyAddress,
"Token": "",
},
}
for _, arg := range rpcArgs {
built[arg.k] = arg.v
}
b, err := json.Marshal(interface{}(built))
if err != nil {
panic(err)
}
return string(b)
}
func buildPbRepo(storageName, relativePath string) *pb.Repository {
return &pb.Repository{
StorageName: storageName,
RelativePath: relativePath,
}
}
func serializedMessage(name string, arg proto.Message) rpcArg {
m := &jsonpb.Marshaler{}
str, err := m.MarshalToString(arg)
if err != nil {
panic(err)
}
return rpcArg{name, str}
}
type combinedServer struct {
*grpc.Server
*testhelper.GitalyTestServer
......
......@@ -63,7 +63,12 @@ func TestUploadHandlerSendingToExternalStorage(t *testing.T) {
defer os.RemoveAll(tempPath)
archiveData, md5 := createTestZipArchive(t)
contentBuffer, contentType := createTestMultipartForm(t, archiveData)
archiveFile, err := ioutil.TempFile("", "artifact.zip")
require.NoError(t, err)
defer os.Remove(archiveFile.Name())
_, err = archiveFile.Write(archiveData)
require.NoError(t, err)
archiveFile.Close()
storeServerCalled := 0
storeServerMux := http.NewServeMux()
......@@ -78,6 +83,9 @@ func TestUploadHandlerSendingToExternalStorage(t *testing.T) {
w.Header().Set("ETag", md5)
w.WriteHeader(200)
})
storeServerMux.HandleFunc("/store-id", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, archiveFile.Name())
})
responseProcessorCalled := 0
responseProcessor := func(w http.ResponseWriter, r *http.Request) {
......@@ -90,22 +98,48 @@ func TestUploadHandlerSendingToExternalStorage(t *testing.T) {
storeServer := httptest.NewServer(storeServerMux)
defer storeServer.Close()
authResponse := api.Response{
TempPath: tempPath,
RemoteObject: api.RemoteObject{
StoreURL: storeServer.URL + "/url/put",
ID: "store-id",
GetURL: storeServer.URL + "/store-id",
tests := []struct {
name string
preauth api.Response
}{
{
name: "ObjectStore Upload",
preauth: api.Response{
RemoteObject: api.RemoteObject{
StoreURL: storeServer.URL + "/url/put",
ID: "store-id",
GetURL: storeServer.URL + "/store-id",
},
},
},
{
name: "ObjectStore and FileStore Upload",
preauth: api.Response{
TempPath: tempPath,
RemoteObject: api.RemoteObject{
StoreURL: storeServer.URL + "/url/put",
ID: "store-id",
GetURL: storeServer.URL + "/store-id",
},
},
},
}
ts := testArtifactsUploadServer(t, authResponse, responseProcessor)
defer ts.Close()
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
storeServerCalled = 0
responseProcessorCalled = 0
ts := testArtifactsUploadServer(t, test.preauth, responseProcessor)
defer ts.Close()
response := testUploadArtifacts(contentType, &contentBuffer, t, ts)
testhelper.AssertResponseCode(t, response, 200)
assert.Equal(t, 1, storeServerCalled, "store should be called only once")
assert.Equal(t, 1, responseProcessorCalled, "response processor should be called only once")
contentBuffer, contentType := createTestMultipartForm(t, archiveData)
response := testUploadArtifacts(contentType, &contentBuffer, t, ts)
testhelper.AssertResponseCode(t, response, 200)
assert.Equal(t, 1, storeServerCalled, "store should be called only once")
assert.Equal(t, 1, responseProcessorCalled, "response processor should be called only once")
})
}
}
func TestUploadHandlerSendingToExternalStorageAndStorageServerUnreachable(t *testing.T) {
......
......@@ -31,6 +31,9 @@ func (a *artifactsUploadProcessor) generateMetadataFromZip(ctx context.Context,
LocalTempPath: a.opts.LocalTempPath,
TempFilePrefix: "metadata.gz",
}
if metaOpts.LocalTempPath == "" {
metaOpts.LocalTempPath = os.TempDir()
}
fileName := file.LocalPath
if fileName == "" {
......@@ -115,11 +118,6 @@ func (a *artifactsUploadProcessor) Name() string {
func UploadArtifacts(myAPI *api.API, h http.Handler) http.Handler {
return myAPI.PreAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *api.Response) {
if a.TempPath == "" {
helper.Fail500(w, r, fmt.Errorf("UploadArtifacts: TempPath is empty"))
return
}
mg := &artifactsUploadProcessor{opts: filestore.GetOpts(a)}
upload.HandleFileUploads(w, r, h, a, mg)
......
......@@ -16,6 +16,7 @@ import (
"gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/badgateway"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/filestore"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/proxy"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
......@@ -38,24 +39,34 @@ func testArtifactsUploadServer(t *testing.T, authResponse api.Response, bodyProc
w.Write(data)
})
mux.HandleFunc("/url/path", func(w http.ResponseWriter, r *http.Request) {
opts := filestore.GetOpts(&authResponse)
if r.Method != "POST" {
t.Fatal("Expected POST request")
}
if r.FormValue("file.path") == "" {
if opts.IsLocal() {
if r.FormValue("file.path") == "" {
w.WriteHeader(501)
return
}
_, err := ioutil.ReadFile(r.FormValue("file.path"))
if err != nil {
w.WriteHeader(404)
return
}
}
if opts.IsRemote() && r.FormValue("file.remote_url") == "" {
w.WriteHeader(501)
return
}
if r.FormValue("metadata.path") == "" {
w.WriteHeader(502)
return
}
_, err := ioutil.ReadFile(r.FormValue("file.path"))
if err != nil {
w.WriteHeader(404)
return
}
metadata, err := ioutil.ReadFile(r.FormValue("metadata.path"))
if err != nil {
w.WriteHeader(404)
......
......@@ -63,11 +63,6 @@ func postRPCHandler(a *api.API, name string, handler func(*GitHttpResponseWriter
func repoPreAuthorizeHandler(myAPI *api.API, handleFunc api.HandleFunc) http.Handler {
return myAPI.PreAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *api.Response) {
if a.RepoPath == "" {
helper.Fail500(w, r, fmt.Errorf("repoPreAuthorizeHandler: RepoPath empty"))
return
}
handleFunc(w, r, a)
}, "")
}
......
package git
import (
"fmt"
"io"
"net/http"
"github.com/golang/protobuf/jsonpb"
pb "gitlab.com/gitlab-org/gitaly-proto/go"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/gitaly"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/senddata"
)
type snapshot struct {
senddata.Prefix
}
type snapshotParams struct {
GitalyServer gitaly.Server
GetSnapshotRequest string
}
var (
SendSnapshot = &snapshot{"git-snapshot:"}
)
func (s *snapshot) Inject(w http.ResponseWriter, r *http.Request, sendData string) {
var params snapshotParams
if err := s.Unpack(&params, sendData); err != nil {
helper.Fail500(w, r, fmt.Errorf("SendSnapshot: unpack sendData: %v", err))
return
}
request := &pb.GetSnapshotRequest{}
if err := jsonpb.UnmarshalString(params.GetSnapshotRequest, request); err != nil {
helper.Fail500(w, r, fmt.Errorf("SendSnapshot: unmarshal GetSnapshotRequest: %v", err))
return
}
c, err := gitaly.NewRepositoryClient(params.GitalyServer)
if err != nil {
helper.Fail500(w, r, fmt.Errorf("SendSnapshot: gitaly.NewRepositoryClient: %v", err))
return
}
reader, err := c.SnapshotReader(r.Context(), request)
if err != nil {
helper.Fail500(w, r, fmt.Errorf("SendSnapshot: client.SnapshotReader: %v", err))
return
}
w.Header().Del("Content-Length")
w.Header().Set("Content-Disposition", `attachment; filename="snapshot.tar"`)
w.Header().Set("Content-Type", "application/x-tar")
w.Header().Set("Content-Transfer-Encoding", "binary")
w.Header().Set("Cache-Control", "private")
w.WriteHeader(http.StatusOK) // Errors aren't detectable beyond this point
if _, err := io.Copy(w, reader); err != nil {
helper.LogError(r, fmt.Errorf("SendSnapshot: copy gitaly output: %v", err))
}
return
}
......@@ -28,3 +28,18 @@ func (client *RepositoryClient) ArchiveReader(ctx context.Context, request *pb.G
return resp.GetData(), err
}), nil
}
// SnapshotReader performs a GetSnapshot Gitaly request and returns an io.Reader
// for the response
func (client *RepositoryClient) SnapshotReader(ctx context.Context, request *pb.GetSnapshotRequest) (io.Reader, error) {
c, err := client.GetSnapshot(ctx, request)
if err != nil {
return nil, fmt.Errorf("RepositoryService::GetSnapshot: %v", err)
}
return streamio.NewReader(func() ([]byte, error) {
resp, err := c.Recv()
return resp.GetData(), err
}), nil
}
......@@ -43,7 +43,7 @@ func TestAccessLogFormatter_Format(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f := &accessLogFormatter{clock: &StubClock{time.Unix(1515283200, 0)}}
f := &accessLogFormatter{clock: &StubClock{time.Unix(1515283200, 0).UTC()}}
got, err := f.Format(tt.entry)
if err != nil {
......
......@@ -85,7 +85,7 @@ func TestComplainingWriterSanity(t *testing.T) {
w.CheerUp()
if _, err := io.Copy(w, testReader(testData)); err != nil {
t.Error("copy after CheerUp: %v", err)
t.Errorf("copy after CheerUp: %v", err)
}
if result := recorder.String(); result != testData {
......
......@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
......@@ -73,7 +74,8 @@ func NewObject(ctx context.Context, putURL, deleteURL string, timeout time.Durat
pr, pw := io.Pipe()
o.writeCloser = pw
req, err := http.NewRequest(http.MethodPut, o.PutURL, pr)
// we should prevent pr.Close() otherwise it may shadow error set with pr.CloseWithError(err)
req, err := http.NewRequest(http.MethodPut, o.PutURL, ioutil.NopCloser(pr))
if err != nil {
objectStorageUploadRequestsRequestFailed.Inc()
return nil, fmt.Errorf("PUT %q: %v", helper.ScrubURLParams(o.PutURL), err)
......@@ -103,7 +105,10 @@ func NewObject(ctx context.Context, putURL, deleteURL string, timeout time.Durat
go func() {
defer cancelFn()
defer objectStorageUploadsOpen.Dec()
defer pr.Close()
defer func() {
// This will be returned as error to the next write operation on the pipe
pr.CloseWithError(o.uploadError)
}()
req = req.WithContext(o.ctx)
......
......@@ -78,6 +78,7 @@ func TestObjectUpload(t *testing.T) {
func TestObjectUpload404(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
ts := httptest.NewServer(http.NotFoundHandler())
defer ts.Close()
......@@ -87,13 +88,56 @@ func TestObjectUpload404(t *testing.T) {
objectURL := ts.URL + test.ObjectPath
object, err := objectstore.NewObject(ctx, objectURL, "", testTimeout, test.ObjectSize)
require.NoError(t, err)
require.NoError(err)
_, err = io.Copy(object, strings.NewReader(test.ObjectContent))
assert.NoError(err)
err = object.Close()
assert.Error(err)
_, isStatusCodeError := err.(objectstore.StatusCodeError)
assert.True(isStatusCodeError, "Should fail with StatusCodeError")
assert.Contains(err.Error(), "404")
require.True(isStatusCodeError, "Should fail with StatusCodeError")
require.Contains(err.Error(), "404")
}
type endlessReader struct{}
func (e *endlessReader) Read(p []byte) (n int, err error) {
for i := 0; i < len(p); i++ {
p[i] = '*'
}
return len(p), nil
}
// TestObjectUploadBrokenConnection purpose is to ensure that errors caused by the upload destination get propagated back correctly.
// This is important for troubleshooting in production.
func TestObjectUploadBrokenConnection(t *testing.T) {
// This test server closes connection immediately
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
hj, ok := w.(http.Hijacker)
if !ok {
require.FailNow(t, "webserver doesn't support hijacking")
}
conn, _, err := hj.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
conn.Close()
}))
defer ts.Close()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
objectURL := ts.URL + test.ObjectPath
object, err := objectstore.NewObject(ctx, objectURL, "", testTimeout, -1)
require.NoError(t, err)
_, copyErr := io.Copy(object, &endlessReader{})
require.Error(t, copyErr)
require.NotEqual(t, io.ErrClosedPipe, copyErr, "We are shadowing the real error")
closeErr := object.Close()
require.Equal(t, copyErr, closeErr)
}
......@@ -23,11 +23,14 @@ type GitalyTestServer struct {
}
var (
GitalyInfoRefsResponseMock = strings.Repeat("Mock Gitaly InfoRefsResponse data", 100000)
GitalyGetBlobResponseMock = strings.Repeat("Mock Gitaly GetBlobResponse data", 100000)
GitalyGetArchiveResponseMock = strings.Repeat("Mock Gitaly GetArchiveResponse data", 100000)
GitalyGetDiffResponseMock = strings.Repeat("Mock Gitaly GetDiffResponse data", 100000)
GitalyGetPatchResponseMock = strings.Repeat("Mock Gitaly GetPatchResponse data", 100000)
GitalyInfoRefsResponseMock = strings.Repeat("Mock Gitaly InfoRefsResponse data", 100000)
GitalyGetBlobResponseMock = strings.Repeat("Mock Gitaly GetBlobResponse data", 100000)
GitalyGetArchiveResponseMock = strings.Repeat("Mock Gitaly GetArchiveResponse data", 100000)
GitalyGetDiffResponseMock = strings.Repeat("Mock Gitaly GetDiffResponse data", 100000)
GitalyGetPatchResponseMock = strings.Repeat("Mock Gitaly GetPatchResponse data", 100000)
GitalyGetSnapshotResponseMock = strings.Repeat("Mock Gitaly GetSnapshotResponse data", 100000)
GitalyReceivePackResponseMock []byte
GitalyUploadPackResponseMock []byte
)
......@@ -280,6 +283,27 @@ func (s *GitalyTestServer) RawPatch(in *pb.RawPatchRequest, stream pb.DiffServic
return s.finalError()
}
func (s *GitalyTestServer) GetSnapshot(in *pb.GetSnapshotRequest, stream pb.RepositoryService_GetSnapshotServer) error {
s.WaitGroup.Add(1)
defer s.WaitGroup.Done()
if err := validateRepository(in.GetRepository()); err != nil {
return err
}
nSends, err := sendBytes([]byte(GitalyGetSnapshotResponseMock), 100, func(p []byte) error {
return stream.Send(&pb.GetSnapshotResponse{Data: p})
})
if err != nil {
return err
}
if nSends <= 1 {
panic("should have sent more than one message")
}
return s.finalError()
}
func (s *GitalyTestServer) RepositoryExists(context.Context, *pb.RepositoryExistsRequest) (*pb.RepositoryExistsResponse, error) {
return nil, nil
}
......@@ -308,6 +332,10 @@ func (s *GitalyTestServer) FetchRemote(context.Context, *pb.FetchRemoteRequest)
return nil, nil
}
func (s *GitalyTestServer) FetchSourceBranch(context.Context, *pb.FetchSourceBranchRequest) (*pb.FetchSourceBranchResponse, error) {
return nil, nil
}
func (s *GitalyTestServer) CreateRepository(context.Context, *pb.CreateRepositoryRequest) (*pb.CreateRepositoryResponse, error) {
return nil, nil
}
......@@ -336,6 +364,78 @@ func (s *GitalyTestServer) GetBlobs(in *pb.GetBlobsRequest, stream pb.BlobServic
return nil
}
func (s *GitalyTestServer) GetAllLFSPointers(*pb.GetAllLFSPointersRequest, pb.BlobService_GetAllLFSPointersServer) error {
return nil
}
func (s *GitalyTestServer) GetLFSPointers(*pb.GetLFSPointersRequest, pb.BlobService_GetLFSPointersServer) error {
return nil
}
func (s *GitalyTestServer) GetNewLFSPointers(*pb.GetNewLFSPointersRequest, pb.BlobService_GetNewLFSPointersServer) error {
return nil
}
func (s *GitalyTestServer) CreateFork(context.Context, *pb.CreateForkRequest) (*pb.CreateForkResponse, error) {
return nil, nil
}
func (s *GitalyTestServer) CalculateChecksum(context.Context, *pb.CalculateChecksumRequest) (*pb.CalculateChecksumResponse, error) {
return nil, nil
}
func (s *GitalyTestServer) CreateBundle(*pb.CreateBundleRequest, pb.RepositoryService_CreateBundleServer) error {
return nil
}
func (s *GitalyTestServer) CreateRepositoryFromBundle(pb.RepositoryService_CreateRepositoryFromBundleServer) error {
return nil
}
func (s *GitalyTestServer) CreateRepositoryFromURL(context.Context, *pb.CreateRepositoryFromURLRequest) (*pb.CreateRepositoryFromURLResponse, error) {
return nil, nil
}
func (s *GitalyTestServer) FindLicense(context.Context, *pb.FindLicenseRequest) (*pb.FindLicenseResponse, error) {
return nil, nil
}
func (s *GitalyTestServer) FindMergeBase(context.Context, *pb.FindMergeBaseRequest) (*pb.FindMergeBaseResponse, error) {
return nil, nil
}
func (s *GitalyTestServer) Fsck(context.Context, *pb.FsckRequest) (*pb.FsckResponse, error) {
return nil, nil
}
func (s *GitalyTestServer) GetInfoAttributes(*pb.GetInfoAttributesRequest, pb.RepositoryService_GetInfoAttributesServer) error {
return nil
}
func (s *GitalyTestServer) IsRebaseInProgress(context.Context, *pb.IsRebaseInProgressRequest) (*pb.IsRebaseInProgressResponse, error) {
return nil, nil
}
func (s *GitalyTestServer) IsSquashInProgress(context.Context, *pb.IsSquashInProgressRequest) (*pb.IsSquashInProgressResponse, error) {
return nil, nil
}
func (s *GitalyTestServer) WriteConfig(context.Context, *pb.WriteConfigRequest) (*pb.WriteConfigResponse, error) {
return nil, nil
}
func (s *GitalyTestServer) WriteRef(context.Context, *pb.WriteRefRequest) (*pb.WriteRefResponse, error) {
return nil, nil
}
func (s *GitalyTestServer) Cleanup(context.Context, *pb.CleanupRequest) (*pb.CleanupResponse, error) {
return nil, nil
}
func (s *GitalyTestServer) CreateRepositoryFromSnapshot(context.Context, *pb.CreateRepositoryFromSnapshotRequest) (*pb.CreateRepositoryFromSnapshotResponse, error) {
return nil, nil
}
// sendBytes returns the number of times the 'sender' function was called and an error.
func sendBytes(data []byte, chunkSize int, sender func([]byte) error) (int, error) {
i := 0
......
......@@ -22,8 +22,9 @@ type MultipartFormProcessor interface {
}
func HandleFileUploads(w http.ResponseWriter, r *http.Request, h http.Handler, preauth *api.Response, filter MultipartFormProcessor) {
if preauth.TempPath == "" {
helper.Fail500(w, r, fmt.Errorf("handleFileUploads: tempPath empty"))
opts := filestore.GetOpts(preauth)
if !opts.IsLocal() && !opts.IsRemote() {
helper.Fail500(w, r, fmt.Errorf("handleFileUploads: missing destination storage"))
return
}
......
......@@ -20,6 +20,7 @@ import (
"gitlab.com/gitlab-org/gitlab-workhorse/internal/badgateway"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/filestore"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/objectstore/test"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/proxy"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
)
......@@ -29,9 +30,6 @@ var nilHandler = http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
type testFormProcessor struct{}
func (a *testFormProcessor) ProcessFile(ctx context.Context, formName string, file *filestore.FileHandler, writer *multipart.Writer) error {
if formName != "file" && file.LocalPath != "my.file" {
return errors.New("illegal file")
}
return nil
}