Repository: tus/tusd (Go)

Issue:
Option to disable CORS headers
**Is your feature request related to a problem? Please describe.**
I'm seeing that you guys are blindly setting `Access-Control-Allow-Origin` to match the `Origin` header of the request, regardless of what that Origin header is. That's nice for ease of use, but it isn't exactly a good idea on the public internet.

You don't provide any options for changing CORS behavior, and I'm seeing in #135 that the response to this is that in production you're going to want to put `tusd` behind a proxy of some kind, anyway, and should probably have the proxy handle the CORS headers instead. This is totally reasonable, but it can present some challenges and pitfalls.

In my case I'm using [haproxy][1], and I can have it conditionally set `Access-Control-Origin` only for Origins that match a Regex contained in a file with something like this:

```
capture request header origin len 128
http-response add-header Access-Control-Allow-Origin %[capture.req.hdr(0)] if { capture.req.hdr(0) -m reg -f /etc/haproxy/cors-origins.lst 
```

The problem here is that `add-header` appends to what is already there, so this header will be set to `${Origin}, ${Origin}` for requests that hit `tusd`, which is obviously will cause the request to be blocked by the browser.

If I change this configuration to use `set-header` instead, which overwrites what may or may not already be there, it will get rid of this problem. However, having this collision go undetected creates a more serious problem, which is that `tusd` is still setting the header for non-matching origins, and the proxy is not clearing this. So even though haproxy is checking against the regexes, I am still allowing requests from all origins if they terminate at `tusd`.

To fix this, I have to actively delete the header in my configuration for non-matching origins. This isn't too complicated, since it's just a matter of starting by deleting whatever might be there:

```
capture request header origin len 128
http-response delete-header Access-Control-Allow-Origin
http-response set-header Access-Control-Allow-Origin %[capture.req.hdr(0)] if { capture.req.hdr(0) -m reg -f /etc/haproxy/cors-origins.lst
http-
```

It would be nice if it were cleaner, though. Having to explicitly delete something that shouldn't even be there in the first place is a bit of a kludge, to the point where I feel the need to leave a comment in the config file making note of `tusd`'s behavior that causes this `delete header` line to be required.

**Describe the solution you'd like**
To handle this problem-- and other confusion arising from multiple processes being responsible for CORS headers-- it would be nice to have an option of disabling CORS headers completely in `tusd`. That way I can easily just say that CORS is handled completely by my proxy.

Something  like `tusd --no-cors`.

**Describe alternatives you've considered**
I've described the alternative of just deleting these headers in my proxy configuration, and while it works it feels a bit kludgy and requires explaining commments.

**Can you provide help with implementing this feature?**
I would be interested, but I'm not familiar with Go and I have very little time to spend on it at the moment. If I do end up pitching it in, it will have to wait for a month or two, I imagine.

[1]: http://www.haproxy.org/



Discussion: Thanks for the feedback, it's very helpful. We have been getting these comments a few times already now so we are open to adding a `--cors-origin-pattern` option, so users can configure what origins they want to allow. Since my times is also very restricted, I would be happy to assist with opening a PR.
I appreciate the response, though I will note that `--cors-origin-pattern` wouldn't be quite what I'm looking for. This request is really more about preventing tusd from doing anything whatsoever with CORS headers. I've got the origin pattern check implemented in HAProxy already and do not need or want tusd to repeat it.

It is understandable if you guys don't have time at the moment. It's not a huge priority for me, either. Just something that would slightly clean up my HAProxy configuration. :+1: 
Ok, so if I understand your proposal of `--no-cors` correctly, the flag would allow you to get rid of the `http-response delete-header Access-Control-Allow-Origin` (etc) instructions in HAProxy. Is this correct? If so, then it would be a little benefit for adding this flag, making it a low priority (but not useless) for us as well.
Hey Guys, Any update on this issue as I am looking for a way to whitelist the origins. Usually, we have a tus server running on a separate machine. So, It becomes necessary to whitelist some domains.
Unfortunately, there is no update. You still have to use a proxy if you want custom CORS headers. We are open for PRs, though :)
Hi @Acconut, I also stumbled over this issue. I have created a PR with a new flag `--disable-cors` which completely disables all CORS headers. Would be great if you could have a look.



Fix (patch):
diff --git a/cmd/tusd/cli/flags.go b/cmd/tusd/cli/flags.go
index 072d490a3..0c4a896df 100644
--- a/cmd/tusd/cli/flags.go
+++ b/cmd/tusd/cli/flags.go
@@ -23,6 +23,7 @@ var Flags struct {
 	ShowGreeting            bool
 	DisableDownload         bool
 	DisableTermination      bool
+	DisableCors             bool
 	Timeout                 int64
 	S3Bucket                string
 	S3ObjectPrefix          string
@@ -72,6 +73,7 @@ func ParseFlags() {
 	flag.BoolVar(&Flags.ShowGreeting, "show-greeting", true, "Show the greeting message")
 	flag.BoolVar(&Flags.DisableDownload, "disable-download", false, "Disable the download endpoint")
 	flag.BoolVar(&Flags.DisableTermination, "disable-termination", false, "Disable the termination endpoint")
+	flag.BoolVar(&Flags.DisableCors, "disable-cors", false, "Disable CORS headers")
 	flag.Int64Var(&Flags.Timeout, "timeout", 6*1000, "Read timeout for connections in milliseconds.  A zero value means that reads will not timeout")
 	flag.StringVar(&Flags.S3Bucket, "s3-bucket", "", "Use AWS S3 with this bucket as storage backend (requires the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_REGION environment variables to be set)")
 	flag.StringVar(&Flags.S3ObjectPrefix, "s3-object-prefix", "", "Prefix for S3 object names")
@@ -106,7 +108,6 @@ func ParseFlags() {
 	flag.StringVar(&Flags.TLSCertFile, "tls-certificate", "", "Path to the file containing the x509 TLS certificate to be used. The file should also contain any intermediate certificates and the CA certificate.")
 	flag.StringVar(&Flags.TLSKeyFile, "tls-key", "", "Path to the file containing the key for the TLS certificate.")
 	flag.StringVar(&Flags.TLSMode, "tls-mode", "tls12", "Specify which TLS mode to use; valid modes are tls13, tls12, and tls12-strong.")
-
 	flag.StringVar(&Flags.CPUProfile, "cpuprofile", "", "write cpu profile to file")
 	flag.Parse()
 
diff --git a/cmd/tusd/cli/serve.go b/cmd/tusd/cli/serve.go
index 30f1f738c..8449b6a41 100644
--- a/cmd/tusd/cli/serve.go
+++ b/cmd/tusd/cli/serve.go
@@ -29,6 +29,7 @@ func Serve() {
 		RespectForwardedHeaders: Flags.BehindProxy,
 		DisableDownload:         Flags.DisableDownload,
 		DisableTermination:      Flags.DisableTermination,
+		DisableCors:             Flags.DisableCors,
 		StoreComposer:           Composer,
 		NotifyCompleteUploads:   true,
 		NotifyTerminatedUploads: true,
diff --git a/docs/usage-binary.md b/docs/usage-binary.md
index 326f1820e..269f37431 100644
--- a/docs/usage-binary.md
+++ b/docs/usage-binary.md
@@ -172,6 +172,8 @@ $ tusd -help
       If set, will listen to a UNIX socket at this location instead of a TCP socket
   -upload-dir string
       Directory to store uploads in (default "./data")
+  -disable-cors
+      Disables CORS headers. If set to true, tusd will not send any CORS related header. This is useful if you have a proxy sitting in front of tusd that handles CORS (default false)
   -verbose
       Enable verbose logging output (default true)
   -version
diff --git a/pkg/handler/config.go b/pkg/handler/config.go
index 9b729b817..bc790fbf7 100644
--- a/pkg/handler/config.go
+++ b/pkg/handler/config.go
@@ -28,6 +28,9 @@ type Config struct {
 	// DisableTermination indicates whether the server will refuse termination
 	// requests of the uploaded file, by not mounting the DELETE handler.
 	DisableTermination bool
+	// Disable cors headers. If set to true, tusd will not send any CORS related header.
+	// This is useful if you have a proxy sitting in front of tusd that handles CORS.
+	DisableCors bool
 	// NotifyCompleteUploads indicates whether sending notifications about
 	// completed uploads using the CompleteUploads channel should be enabled.
 	NotifyCompleteUploads bool
diff --git a/pkg/handler/unrouted_handler.go b/pkg/handler/unrouted_handler.go
index 55e7ccc3f..e798fc193 100644
--- a/pkg/handler/unrouted_handler.go
+++ b/pkg/handler/unrouted_handler.go
@@ -217,7 +217,7 @@ func (handler *UnroutedHandler) Middleware(h http.Handler) http.Handler {
 
 		header := w.Header()
 
-		if origin := r.Header.Get("Origin"); origin != "" {
+		if origin := r.Header.Get("Origin"); !handler.config.DisableCors && origin != "" {
 			header.Set("Access-Control-Allow-Origin", origin)
 
 			if r.Method == "OPTIONS" {