handler: Add callback to UnroutedHandler to remove restriction on upload URIs.
Fixes #340
This commit is contained in:
parent
b4db495cc6
commit
382abb9321
|
@ -9,6 +9,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
uri "net/url"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -112,12 +113,10 @@ func newHookEvent(info FileInfo, r *http.Request) HookEvent {
|
||||||
// such as PostFile, HeadFile, PatchFile and DelFile. In addition the GetFile method
|
// such as PostFile, HeadFile, PatchFile and DelFile. In addition the GetFile method
|
||||||
// is provided which is, however, not part of the specification.
|
// is provided which is, however, not part of the specification.
|
||||||
type UnroutedHandler struct {
|
type UnroutedHandler struct {
|
||||||
config Config
|
config Config
|
||||||
composer *StoreComposer
|
composer *StoreComposer
|
||||||
isBasePathAbs bool
|
logger *log.Logger
|
||||||
basePath string
|
extensions string
|
||||||
logger *log.Logger
|
|
||||||
extensions string
|
|
||||||
|
|
||||||
// CompleteUploads is used to send notifications whenever an upload is
|
// CompleteUploads is used to send notifications whenever an upload is
|
||||||
// completed by a user. The HookEvent will contain information about this
|
// completed by a user. The HookEvent will contain information about this
|
||||||
|
@ -149,6 +148,10 @@ type UnroutedHandler struct {
|
||||||
CreatedUploads chan HookEvent
|
CreatedUploads chan HookEvent
|
||||||
// Metrics provides numbers of the usage for this handler.
|
// Metrics provides numbers of the usage for this handler.
|
||||||
Metrics Metrics
|
Metrics Metrics
|
||||||
|
// GetID is a customisable callback used by the handler to determine the id of an upload in a request
|
||||||
|
GetID func(r *http.Request) (string, error)
|
||||||
|
// GetURL is a customisable callback used by the handler to determine the url that uniquely identifies the resource id
|
||||||
|
GetURL func(r *http.Request, id string) (*uri.URL, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUnroutedHandler creates a new handler without routing using the given
|
// NewUnroutedHandler creates a new handler without routing using the given
|
||||||
|
@ -175,8 +178,6 @@ func NewUnroutedHandler(config Config) (*UnroutedHandler, error) {
|
||||||
handler := &UnroutedHandler{
|
handler := &UnroutedHandler{
|
||||||
config: config,
|
config: config,
|
||||||
composer: config.StoreComposer,
|
composer: config.StoreComposer,
|
||||||
basePath: config.BasePath,
|
|
||||||
isBasePathAbs: config.isAbs,
|
|
||||||
CompleteUploads: make(chan HookEvent),
|
CompleteUploads: make(chan HookEvent),
|
||||||
TerminatedUploads: make(chan HookEvent),
|
TerminatedUploads: make(chan HookEvent),
|
||||||
UploadProgress: make(chan HookEvent),
|
UploadProgress: make(chan HookEvent),
|
||||||
|
@ -184,6 +185,21 @@ func NewUnroutedHandler(config Config) (*UnroutedHandler, error) {
|
||||||
logger: config.Logger,
|
logger: config.Logger,
|
||||||
extensions: extensions,
|
extensions: extensions,
|
||||||
Metrics: newMetrics(),
|
Metrics: newMetrics(),
|
||||||
|
GetID: func(r *http.Request) (string, error) {
|
||||||
|
return extractIDFromPath(r.URL.Path)
|
||||||
|
},
|
||||||
|
GetURL: func(r *http.Request, id string) (*uri.URL, error) {
|
||||||
|
if config.isAbs {
|
||||||
|
return uri.Parse(config.BasePath + id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read origin and protocol from request
|
||||||
|
host, proto := getHostAndProtocol(r, config.RespectForwardedHeaders)
|
||||||
|
|
||||||
|
url := proto + "://" + host + config.BasePath + id
|
||||||
|
|
||||||
|
return uri.Parse(url)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return handler, nil
|
return handler, nil
|
||||||
|
@ -289,12 +305,33 @@ func (handler *UnroutedHandler) PostFile(w http.ResponseWriter, r *http.Request)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse Upload-Concat header
|
// Parse Upload-Concat header
|
||||||
isPartial, isFinal, partialUploadIDs, err := parseConcat(concatHeader)
|
isPartial, isFinal, partialUploadPaths, err := parseConcat(concatHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handler.sendError(w, r, err)
|
handler.sendError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var partialUploadIDs []string
|
||||||
|
if len(partialUploadPaths) > 0 {
|
||||||
|
partialUploadIDs = make([]string, len(partialUploadPaths))
|
||||||
|
origURL := r.URL
|
||||||
|
for i, path := range partialUploadPaths {
|
||||||
|
// insert partialUpload URI and call GetID
|
||||||
|
r.URL, err = r.URL.Parse(path)
|
||||||
|
if err != nil {
|
||||||
|
handler.sendError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
partialUploadIDs[i], err = handler.GetID(r)
|
||||||
|
if err != nil {
|
||||||
|
handler.sendError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.URL = origURL
|
||||||
|
}
|
||||||
|
|
||||||
// If the upload is a final upload created by concatenation multiple partial
|
// If the upload is a final upload created by concatenation multiple partial
|
||||||
// uploads the size is sum of all sizes of these files (no need for
|
// uploads the size is sum of all sizes of these files (no need for
|
||||||
// Upload-Length header)
|
// Upload-Length header)
|
||||||
|
@ -364,11 +401,15 @@ func (handler *UnroutedHandler) PostFile(w http.ResponseWriter, r *http.Request)
|
||||||
|
|
||||||
// Add the Location header directly after creating the new resource to even
|
// Add the Location header directly after creating the new resource to even
|
||||||
// include it in cases of failure when an error is returned
|
// include it in cases of failure when an error is returned
|
||||||
url := handler.absFileURL(r, id)
|
url, err := handler.GetURL(r, id)
|
||||||
w.Header().Set("Location", url)
|
if err != nil {
|
||||||
|
handler.sendError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Location", url.String())
|
||||||
|
|
||||||
handler.Metrics.incUploadsCreated()
|
handler.Metrics.incUploadsCreated()
|
||||||
handler.log("UploadCreated", "id", id, "size", i64toa(size), "url", url)
|
handler.log("UploadCreated", "id", id, "size", i64toa(size), "url", url.String())
|
||||||
|
|
||||||
if handler.config.NotifyCreatedUploads {
|
if handler.config.NotifyCreatedUploads {
|
||||||
handler.CreatedUploads <- newHookEvent(info, r)
|
handler.CreatedUploads <- newHookEvent(info, r)
|
||||||
|
@ -416,7 +457,7 @@ func (handler *UnroutedHandler) PostFile(w http.ResponseWriter, r *http.Request)
|
||||||
func (handler *UnroutedHandler) HeadFile(w http.ResponseWriter, r *http.Request) {
|
func (handler *UnroutedHandler) HeadFile(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
id, err := extractIDFromPath(r.URL.Path)
|
id, err := handler.GetID(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handler.sendError(w, r, err)
|
handler.sendError(w, r, err)
|
||||||
return
|
return
|
||||||
|
@ -452,7 +493,12 @@ func (handler *UnroutedHandler) HeadFile(w http.ResponseWriter, r *http.Request)
|
||||||
if info.IsFinal {
|
if info.IsFinal {
|
||||||
v := "final;"
|
v := "final;"
|
||||||
for _, uploadID := range info.PartialUploads {
|
for _, uploadID := range info.PartialUploads {
|
||||||
v += handler.absFileURL(r, uploadID) + " "
|
url, err := handler.GetURL(r, uploadID)
|
||||||
|
if err != nil {
|
||||||
|
handler.sendError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v += url.String() + " "
|
||||||
}
|
}
|
||||||
// Remove trailing space
|
// Remove trailing space
|
||||||
v = v[:len(v)-1]
|
v = v[:len(v)-1]
|
||||||
|
@ -493,7 +539,7 @@ func (handler *UnroutedHandler) PatchFile(w http.ResponseWriter, r *http.Request
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := extractIDFromPath(r.URL.Path)
|
id, err := handler.GetID(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handler.sendError(w, r, err)
|
handler.sendError(w, r, err)
|
||||||
return
|
return
|
||||||
|
@ -695,7 +741,7 @@ func (handler *UnroutedHandler) finishUploadIfComplete(ctx context.Context, uplo
|
||||||
func (handler *UnroutedHandler) GetFile(w http.ResponseWriter, r *http.Request) {
|
func (handler *UnroutedHandler) GetFile(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
id, err := extractIDFromPath(r.URL.Path)
|
id, err := handler.GetID(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handler.sendError(w, r, err)
|
handler.sendError(w, r, err)
|
||||||
return
|
return
|
||||||
|
@ -822,7 +868,7 @@ func (handler *UnroutedHandler) DelFile(w http.ResponseWriter, r *http.Request)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := extractIDFromPath(r.URL.Path)
|
id, err := handler.GetID(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handler.sendError(w, r, err)
|
handler.sendError(w, r, err)
|
||||||
return
|
return
|
||||||
|
@ -934,21 +980,6 @@ func (handler *UnroutedHandler) sendResp(w http.ResponseWriter, r *http.Request,
|
||||||
handler.log("ResponseOutgoing", "status", strconv.Itoa(status), "method", r.Method, "path", r.URL.Path)
|
handler.log("ResponseOutgoing", "status", strconv.Itoa(status), "method", r.Method, "path", r.URL.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make an absolute URLs to the given upload id. If the base path is absolute
|
|
||||||
// it will be prepended else the host and protocol from the request is used.
|
|
||||||
func (handler *UnroutedHandler) absFileURL(r *http.Request, id string) string {
|
|
||||||
if handler.isBasePathAbs {
|
|
||||||
return handler.basePath + id
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read origin and protocol from request
|
|
||||||
host, proto := getHostAndProtocol(r, handler.config.RespectForwardedHeaders)
|
|
||||||
|
|
||||||
url := proto + "://" + host + handler.basePath + id
|
|
||||||
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
|
|
||||||
type progressWriter struct {
|
type progressWriter struct {
|
||||||
Offset int64
|
Offset int64
|
||||||
}
|
}
|
||||||
|
@ -1171,13 +1202,7 @@ func parseConcat(header string) (isPartial bool, isFinal bool, partialUploads []
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
id, extractErr := extractIDFromPath(value)
|
partialUploads = append(partialUploads, value)
|
||||||
if extractErr != nil {
|
|
||||||
err = extractErr
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
partialUploads = append(partialUploads, id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue