diff --git a/cmd/tusd/cli/flags.go b/cmd/tusd/cli/flags.go index 0c4a896..b6d3e77 100644 --- a/cmd/tusd/cli/flags.go +++ b/cmd/tusd/cli/flags.go @@ -53,6 +53,7 @@ var Flags struct { ShowVersion bool ExposeMetrics bool MetricsPath string + CorsOrigin string BehindProxy bool VerboseOutput bool S3TransferAcceleration bool @@ -102,6 +103,7 @@ func ParseFlags() { flag.BoolVar(&Flags.ShowVersion, "version", false, "Print tusd version information") flag.BoolVar(&Flags.ExposeMetrics, "expose-metrics", true, "Expose metrics about tusd usage") flag.StringVar(&Flags.MetricsPath, "metrics-path", "/metrics", "Path under which the metrics endpoint will be accessible") + flag.StringVar(&Flags.CorsOrigin, "cors-origin", "", "Explicitly set Access-Control-Allow-Origin header") flag.BoolVar(&Flags.BehindProxy, "behind-proxy", false, "Respect X-Forwarded-* and similar headers which may be set by proxies") flag.BoolVar(&Flags.VerboseOutput, "verbose", true, "Enable verbose logging output") flag.BoolVar(&Flags.S3TransferAcceleration, "s3-transfer-acceleration", false, "Use AWS S3 transfer acceleration endpoint (requires -s3-bucket option and Transfer Acceleration property on S3 bucket to be set)") diff --git a/cmd/tusd/cli/serve.go b/cmd/tusd/cli/serve.go index 8449b6a..bb2f525 100644 --- a/cmd/tusd/cli/serve.go +++ b/cmd/tusd/cli/serve.go @@ -26,6 +26,7 @@ func Serve() { config := handler.Config{ MaxSize: Flags.MaxSize, BasePath: Flags.Basepath, + CorsOrigin: Flags.CorsOrigin, RespectForwardedHeaders: Flags.BehindProxy, DisableDownload: Flags.DisableDownload, DisableTermination: Flags.DisableTermination, @@ -105,6 +106,10 @@ func Serve() { protocol = "https" } + if Flags.CorsOrigin != "" { + stdout.Printf("CORS origin header is %s", Flags.CorsOrigin) + } + if Flags.HttpSock == "" { stdout.Printf("You can now upload files to: %s://%s%s", protocol, address, basepath) } diff --git a/pkg/handler/config.go b/pkg/handler/config.go index bc790fb..201ee26 100644 --- a/pkg/handler/config.go +++ b/pkg/handler/config.go @@ -45,6 +45,10 @@ type Config struct { NotifyCreatedUploads bool // Logger is the logger to use internally, mostly for printing requests. Logger *log.Logger + // Explicitly set Access-Control-Allow-Origin in cases where RespectForwardedHeaders + // doesn't give you the desired result. This can be the case with some reverse proxies + // or a kubernetes setup with complex network routing rules + CorsOrigin string // Respect the X-Forwarded-Host, X-Forwarded-Proto and Forwarded headers // potentially set by proxies when generating an absolute URL in the // response to POST requests. @@ -91,5 +95,12 @@ func (config *Config) validate() error { return errors.New("tusd: StoreComposer in Config needs to contain a non-nil core") } + if config.CorsOrigin != "" && config.CorsOrigin != "*" && config.CorsOrigin != "null" { + _, err := url.ParseRequestURI(config.CorsOrigin) + if err != nil { + errors.New("tusd: CorsOrigin is not a valid URL") + } + } + return nil } diff --git a/pkg/handler/unrouted_handler.go b/pkg/handler/unrouted_handler.go index 378a18d..76ce951 100644 --- a/pkg/handler/unrouted_handler.go +++ b/pkg/handler/unrouted_handler.go @@ -224,7 +224,12 @@ func (handler *UnroutedHandler) Middleware(h http.Handler) http.Handler { header := w.Header() if origin := r.Header.Get("Origin"); !handler.config.DisableCors && origin != "" { + var configuredOrigin = handler.config.CorsOrigin + if configuredOrigin != "" { + origin = configuredOrigin + } header.Set("Access-Control-Allow-Origin", origin) + header.Set("Vary", "Origin") if r.Method == "OPTIONS" { allowedMethods := "POST, HEAD, PATCH, OPTIONS"