Commit d0bc5fbe authored by Jacob Vosmaer's avatar Jacob Vosmaer Committed by Patrick Bajao

Workhorse: improve doc comments in internal/upload

parent 82f91190
...@@ -17,6 +17,11 @@ type MultipartClaims struct { ...@@ -17,6 +17,11 @@ type MultipartClaims struct {
jwt.StandardClaims jwt.StandardClaims
} }
// Multipart is a request middleware. If the request has a MIME multipart
// request body, the middleware will iterate through the multipart parts.
// When it finds a file part (filename != ""), the middleware will save
// the file contents to a temporary location and replace the file part
// with a reference to the temporary location.
func Multipart(rails PreAuthorizer, h http.Handler, p Preparer) http.Handler { func Multipart(rails PreAuthorizer, h http.Handler, p Preparer) http.Handler {
return rails.PreAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *api.Response) { return rails.PreAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *api.Response) {
s := &SavedFileTracker{Request: r} s := &SavedFileTracker{Request: r}
......
...@@ -16,16 +16,23 @@ type PreAuthorizer interface { ...@@ -16,16 +16,23 @@ type PreAuthorizer interface {
PreAuthorizeHandler(next api.HandleFunc, suffix string) http.Handler PreAuthorizeHandler(next api.HandleFunc, suffix string) http.Handler
} }
// Verifier allows to check an upload before sending it to rails // Verifier is an optional pluggable behavior for upload paths. If
// Verify() returns an error, Workhorse will return an error response to
// the client instead of propagating the request to Rails. The motivating
// use case is Git LFS, where Workhorse checks the size and SHA256
// checksum of the uploaded file.
type Verifier interface { type Verifier interface {
// Verify can abort the upload returning an error // Verify can abort the upload by returning an error
Verify(handler *filestore.FileHandler) error Verify(handler *filestore.FileHandler) error
} }
// Preparer allows to customize RequestBody configuration // Preparer is a pluggable behavior that interprets a Rails API response
// and either tells Workhorse how to handle the upload, via the
// SaveFileOpts and Verifier, or it rejects the request by returning a
// non-nil error. Its intended use is to make sure the upload gets stored
// in the right location: either a local directory, or one of several
// supported object storage backends.
type Preparer interface { type Preparer interface {
// Prepare converts api.Response into a *SaveFileOpts, it can optionally return an Verifier that will be
// invoked after the real upload, before the finalization with rails
Prepare(a *api.Response) (*filestore.SaveFileOpts, Verifier, error) Prepare(a *api.Response) (*filestore.SaveFileOpts, Verifier, error)
} }
...@@ -36,9 +43,9 @@ func (s *DefaultPreparer) Prepare(a *api.Response) (*filestore.SaveFileOpts, Ver ...@@ -36,9 +43,9 @@ func (s *DefaultPreparer) Prepare(a *api.Response) (*filestore.SaveFileOpts, Ver
return opts, nil, err return opts, nil, err
} }
// RequestBody is an http.Handler that perform a pre authorization call to rails before hijacking the request body and // RequestBody is a request middleware. It will store the request body to
// uploading it. // a location by determined an api.Response value. It then forwards the
// Providing an Preparer allows to customize the upload process // request to gitlab-rails without the original request body.
func RequestBody(rails PreAuthorizer, h http.Handler, p Preparer) http.Handler { func RequestBody(rails PreAuthorizer, h http.Handler, p Preparer) http.Handler {
return rails.PreAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *api.Response) { return rails.PreAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *api.Response) {
opts, verifier, err := p.Prepare(a) opts, verifier, err := p.Prepare(a)
......
...@@ -6,15 +6,15 @@ import ( ...@@ -6,15 +6,15 @@ import (
"gitlab.com/gitlab-org/gitlab/workhorse/internal/api" "gitlab.com/gitlab-org/gitlab/workhorse/internal/api"
) )
// SkipRailsAuthorizer implements a fake PreAuthorizer that do not calls rails API and // SkipRailsAuthorizer implements a fake PreAuthorizer that does not call
// authorize each call as a local only upload to TempPath // the gitlab-rails API. It must be fast because it gets called on each
// request proxied to Rails.
type SkipRailsAuthorizer struct { type SkipRailsAuthorizer struct {
// TempPath is the temporary path for a local only upload // TempPath is a directory where workhorse can store files that can later
// be accessed by gitlab-rails.
TempPath string TempPath string
} }
// PreAuthorizeHandler implements PreAuthorizer. It always grant the upload.
// The fake API response contains only TempPath
func (l *SkipRailsAuthorizer) PreAuthorizeHandler(next api.HandleFunc, _ string) http.Handler { func (l *SkipRailsAuthorizer) PreAuthorizeHandler(next api.HandleFunc, _ string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
next(w, r, &api.Response{TempPath: l.TempPath}) next(w, r, &api.Response{TempPath: l.TempPath})
......
...@@ -15,7 +15,8 @@ import ( ...@@ -15,7 +15,8 @@ import (
"gitlab.com/gitlab-org/gitlab/workhorse/internal/zipartifacts" "gitlab.com/gitlab-org/gitlab/workhorse/internal/zipartifacts"
) )
// These methods are allowed to have thread-unsafe implementations. // MultipartFormProcessor abstracts away implementation differences
// between generic MIME multipart file uploads and CI artifact uploads.
type MultipartFormProcessor interface { type MultipartFormProcessor interface {
ProcessFile(ctx context.Context, formName string, file *filestore.FileHandler, writer *multipart.Writer) error ProcessFile(ctx context.Context, formName string, file *filestore.FileHandler, writer *multipart.Writer) error
ProcessField(ctx context.Context, formName string, writer *multipart.Writer) error ProcessField(ctx context.Context, formName string, writer *multipart.Writer) error
...@@ -24,6 +25,9 @@ type MultipartFormProcessor interface { ...@@ -24,6 +25,9 @@ type MultipartFormProcessor interface {
Count() int Count() int
} }
// InterceptMultipartFiles is the core of the implementation of
// Multipart. Because it is also used for CI artifact uploads it is a
// public function.
func InterceptMultipartFiles(w http.ResponseWriter, r *http.Request, h http.Handler, preauth *api.Response, filter MultipartFormProcessor, opts *filestore.SaveFileOpts) { func InterceptMultipartFiles(w http.ResponseWriter, r *http.Request, h http.Handler, preauth *api.Response, filter MultipartFormProcessor, opts *filestore.SaveFileOpts) {
var body bytes.Buffer var body bytes.Buffer
writer := multipart.NewWriter(&body) writer := multipart.NewWriter(&body)
......
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