From 3434133796be03563c300c479ffdf3c0e7f9a796 Mon Sep 17 00:00:00 2001 From: "Demi [Alvaro Martinez de Miguel]" Date: Tue, 15 Oct 2019 20:06:56 +0200 Subject: [PATCH 1/9] create handler to add cors headers to response --- handle/handle.go | 9 +++++++++ handle/handle_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/handle/handle.go b/handle/handle.go index babedd3..f0d3e91 100644 --- a/handle/handle.go +++ b/handle/handle.go @@ -109,6 +109,15 @@ func IgnoreIndex(serve http.HandlerFunc) http.HandlerFunc { } } +func AddCorsHeaders(serve http.HandlerFunc) http.HandlerFunc { + return func(writer http.ResponseWriter, request *http.Request) { + writer.Header().Set("Access-Control-Allow-Origin", "*") + writer.Header().Set("Access-Control-Allow-Headers", "*") + + serve(writer, request) + } +} + // Listening function for serving the handler function. func Listening() ListenerFunc { return func(binding string, handler http.HandlerFunc) error { diff --git a/handle/handle_test.go b/handle/handle_test.go index 11dd6d7..2ad5eb4 100644 --- a/handle/handle_test.go +++ b/handle/handle_test.go @@ -9,6 +9,7 @@ import ( "os" "path" "testing" + "strings" ) var ( @@ -458,3 +459,32 @@ func TestValidReferrer(t *testing.T) { }) } } + +func TestAddsCorsHeaders(t *testing.T) { + testCases := []struct { + name string + header string + value string + }{ + {"Add Access-Control-Allow-Origin header", "Access-Control-Allow-Origin", "*"}, + {"Add Access-Control-Allow-Headers header", "Access-Control-Allow-Headers", "*"}, + } + + for _, serveFile := range serveFileFuncs { + handler := AddCorsHeaders(Basic(serveFile, baseDir)) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + req := httptest.NewRequest("GET", "http://localhost/", nil) + w := httptest.NewRecorder() + + handler(w, req) + + resp := w.Result() + headerValue := strings.Join(resp.Header[tc.header], ", ") + if headerValue != tc.value { + t.Errorf("Response header %q = %q, want %q", tc.header, headerValue, tc.value) + } + }) + } + } +} From 91c955e52e5fb50ad5d0ea62f89d74bf0a51944e Mon Sep 17 00:00:00 2001 From: "Demi [Alvaro Martinez de Miguel]" Date: Wed, 16 Oct 2019 14:25:20 +0200 Subject: [PATCH 2/9] Update congif to support CORS --- config/config.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/config.go b/config/config.go index 1694e33..1f3d7a6 100644 --- a/config/config.go +++ b/config/config.go @@ -23,6 +23,7 @@ var ( TLSKey string `yaml:"tls-key"` URLPrefix string `yaml:"url-prefix"` Referrers []string `yaml:"referrers"` + Cors bool `yaml:cors` } ) @@ -36,6 +37,7 @@ const ( tlsCertKey = "TLS_CERT" tlsKeyKey = "TLS_KEY" urlPrefixKey = "URL_PREFIX" + corsKey = "CORS" ) var ( @@ -48,6 +50,7 @@ var ( defaultTLSCert = "" defaultTLSKey = "" defaultURLPrefix = "" + defaultCors = false ) func init() { @@ -65,6 +68,7 @@ func setDefaults() { Get.TLSCert = defaultTLSCert Get.TLSKey = defaultTLSKey Get.URLPrefix = defaultURLPrefix + Get.Cors = defaultCors } // Load the configuration file. @@ -113,6 +117,7 @@ func overrideWithEnvVars() { Get.TLSKey = envAsStr(tlsKeyKey, Get.TLSKey) Get.URLPrefix = envAsStr(urlPrefixKey, Get.URLPrefix) Get.Referrers = envAsStrSlice(referrersKey, Get.Referrers) + Get.Cors = envAsBool(corsKey, Get.Cors) } // validate the configuration. From f3f9442821ecbaa78362ef1897878248277a810b Mon Sep 17 00:00:00 2001 From: "Demi [Alvaro Martinez de Miguel]" Date: Wed, 16 Oct 2019 14:26:09 +0200 Subject: [PATCH 3/9] Add cors headers if config is set to true --- cli/server/server.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cli/server/server.go b/cli/server/server.go index 31d98d1..2393cd7 100644 --- a/cli/server/server.go +++ b/cli/server/server.go @@ -61,6 +61,11 @@ func handlerSelector() (handler http.HandlerFunc) { if !config.Get.ShowListing { handler = handle.IgnoreIndex(handler) } + + if config.Get.Cors { + handler = handle.AddCorsHeaders(handler) + } + return } From d55f887d9c5de0f618b7178dc4e114116c5b949e Mon Sep 17 00:00:00 2001 From: "Demi [Alvaro Martinez de Miguel]" Date: Wed, 16 Oct 2019 14:26:36 +0200 Subject: [PATCH 4/9] update documentation for cors option --- README.md | 4 ++++ cli/help/help.go | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/README.md b/README.md index 1fad068..9ae1048 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ Install from any of the following locations: Default values are shown with the associated environment variable. ```bash +# Enables resource access from any domain. +CORS=false + # Enable debugging for troubleshooting. If set to 'true' this prints extra # information during execution. IMPORTANT NOTE: The configuration summary is # printed to stdout while logs generated during execution are printed to stderr. @@ -69,6 +72,7 @@ show-listing: true tls-cert: "" tls-key: "" url-prefix: "" +cors: false ``` Example configuration with possible alternative values: diff --git a/cli/help/help.go b/cli/help/help.go index 6f8a3fa..d8faff1 100644 --- a/cli/help/help.go +++ b/cli/help/help.go @@ -33,6 +33,10 @@ DEPENDENCIES None... not even libc! ENVIRONMENT VARIABLES + CORS + When set to 'true' it enables resource access from any domain. All responses + will include the headers 'Access-Control-Allow-Origin' and 'Access-Control-Allow-Headers' + with a wildcard value ('*'). DEBUG When set to 'true' enables additional logging, including the configuration used and an access log for each request. IMPORTANT NOTE: @@ -94,6 +98,7 @@ CONFIGURATION FILE tls-cert: "" tls-key: "" url-prefix: "" + cors: false ---------------------------------------------------------------------------- Example config.yml with possible alternative values: From 8d38b2fd8059db53786d98fbf6ea0a4d3d5b3a77 Mon Sep 17 00:00:00 2001 From: "Demi [Alvaro Martinez de Miguel]" Date: Wed, 16 Oct 2019 14:34:53 +0200 Subject: [PATCH 5/9] tests cors in server --- cli/server/server_test.go | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/cli/server/server_test.go b/cli/server/server_test.go index c0a2bb9..c297f93 100644 --- a/cli/server/server_test.go +++ b/cli/server/server_test.go @@ -42,23 +42,28 @@ func TestHandlerSelector(t *testing.T) { listing bool debug bool refer []string + cors bool }{ - {"Basic handler w/o debug", testFolder, "", true, false, ignoreReferrer}, - {"Prefix handler w/o debug", testFolder, testPrefix, true, false, ignoreReferrer}, - {"Basic and hide listing handler w/o debug", testFolder, "", false, false, ignoreReferrer}, - {"Prefix and hide listing handler w/o debug", testFolder, testPrefix, false, false, ignoreReferrer}, - {"Basic handler w/debug", testFolder, "", true, true, ignoreReferrer}, - {"Prefix handler w/debug", testFolder, testPrefix, true, true, ignoreReferrer}, - {"Basic and hide listing handler w/debug", testFolder, "", false, true, ignoreReferrer}, - {"Prefix and hide listing handler w/debug", testFolder, testPrefix, false, true, ignoreReferrer}, - {"Basic handler w/o debug w/refer", testFolder, "", true, false, testReferrer}, - {"Prefix handler w/o debug w/refer", testFolder, testPrefix, true, false, testReferrer}, - {"Basic and hide listing handler w/o debug w/refer", testFolder, "", false, false, testReferrer}, - {"Prefix and hide listing handler w/o debug w/refer", testFolder, testPrefix, false, false, testReferrer}, - {"Basic handler w/debug w/refer", testFolder, "", true, true, testReferrer}, - {"Prefix handler w/debug w/refer", testFolder, testPrefix, true, true, testReferrer}, - {"Basic and hide listing handler w/debug w/refer", testFolder, "", false, true, testReferrer}, - {"Prefix and hide listing handler w/debug w/refer", testFolder, testPrefix, false, true, testReferrer}, + {"Basic handler w/o debug", testFolder, "", true, false, ignoreReferrer, false}, + {"Prefix handler w/o debug", testFolder, testPrefix, true, false, ignoreReferrer, false}, + {"Basic and hide listing handler w/o debug", testFolder, "", false, false, ignoreReferrer, false}, + {"Prefix and hide listing handler w/o debug", testFolder, testPrefix, false, false, ignoreReferrer, false}, + {"Basic handler w/debug", testFolder, "", true, true, ignoreReferrer, false}, + {"Prefix handler w/debug", testFolder, testPrefix, true, true, ignoreReferrer, false}, + {"Basic and hide listing handler w/debug", testFolder, "", false, true, ignoreReferrer, false}, + {"Prefix and hide listing handler w/debug", testFolder, testPrefix, false, true, ignoreReferrer, false}, + {"Basic handler w/o debug w/refer", testFolder, "", true, false, testReferrer, false}, + {"Prefix handler w/o debug w/refer", testFolder, testPrefix, true, false, testReferrer, false}, + {"Basic and hide listing handler w/o debug w/refer", testFolder, "", false, false, testReferrer, false}, + {"Prefix and hide listing handler w/o debug w/refer", testFolder, testPrefix, false, false, testReferrer, false}, + {"Basic handler w/debug w/refer w/o cors", testFolder, "", true, true, testReferrer, false}, + {"Prefix handler w/debug w/refer w/o cors", testFolder, testPrefix, true, true, testReferrer, false}, + {"Basic and hide listing handler w/debug w/refer w/o cors", testFolder, "", false, true, testReferrer, false}, + {"Prefix and hide listing handler w/debug w/refer w/o cors", testFolder, testPrefix, false, true, testReferrer, false}, + {"Basic handler w/debug w/refer w/cors", testFolder, "", true, true, testReferrer, true}, + {"Prefix handler w/debug w/refer w/cors", testFolder, testPrefix, true, true, testReferrer, true}, + {"Basic and hide listing handler w/debug w/refer w/cors", testFolder, "", false, true, testReferrer, true}, + {"Prefix and hide listing handler w/debug w/refer w/cors", testFolder, testPrefix, false, true, testReferrer, true}, } for _, tc := range testCases { @@ -68,6 +73,7 @@ func TestHandlerSelector(t *testing.T) { config.Get.ShowListing = tc.listing config.Get.URLPrefix = tc.prefix config.Get.Referrers = tc.refer + config.Get.Cors = tc.cors handlerSelector() }) From 6c5c2e83879d6b125b660d4edc2b462d63b3640e Mon Sep 17 00:00:00 2001 From: "Demi [Alvaro Martinez de Miguel]" Date: Wed, 16 Oct 2019 14:46:04 +0200 Subject: [PATCH 6/9] Rolled release version --- Dockerfile | 2 +- Dockerfile.all | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 782c9df..e7c8625 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ################################################################################ FROM golang:1.13.1 as builder -ENV VERSION 1.6.6 +ENV VERSION 1.7.6 ENV BUILD_DIR /build RUN mkdir -p ${BUILD_DIR} diff --git a/Dockerfile.all b/Dockerfile.all index 66d026e..351def9 100644 --- a/Dockerfile.all +++ b/Dockerfile.all @@ -1,6 +1,6 @@ FROM golang:1.13.1 as builder -ENV VERSION 1.6.6 +ENV VERSION 1.7.6 ENV BUILD_DIR /build RUN mkdir -p ${BUILD_DIR} @@ -21,5 +21,5 @@ LABEL life.apets.vendor="Halverneus" \ life.apets.url="https://github.com/halverneus/static-file-server" \ life.apets.name="Static File Server" \ life.apets.description="A tiny static file server" \ - life.apets.version="v1.6.6" \ + life.apets.version="v1.7.6" \ life.apets.schema-version="1.0" From b8819125821e3d140652b69c71a17f020f2d3597 Mon Sep 17 00:00:00 2001 From: Jeromy Streets Date: Wed, 16 Oct 2019 09:28:55 -0700 Subject: [PATCH 7/9] Set release version to 1.7.0. --- Dockerfile | 4 ++-- Dockerfile.all | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index e7c8625..f9a69e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ################################################################################ FROM golang:1.13.1 as builder -ENV VERSION 1.7.6 +ENV VERSION 1.7.0 ENV BUILD_DIR /build RUN mkdir -p ${BUILD_DIR} @@ -31,5 +31,5 @@ LABEL life.apets.vendor="Halverneus" \ life.apets.url="https://github.com/halverneus/static-file-server" \ life.apets.name="Static File Server" \ life.apets.description="A tiny static file server" \ - life.apets.version="v1.6.6" \ + life.apets.version="v1.7.0" \ life.apets.schema-version="1.0" diff --git a/Dockerfile.all b/Dockerfile.all index 351def9..3d696be 100644 --- a/Dockerfile.all +++ b/Dockerfile.all @@ -1,6 +1,6 @@ FROM golang:1.13.1 as builder -ENV VERSION 1.7.6 +ENV VERSION 1.7.0 ENV BUILD_DIR /build RUN mkdir -p ${BUILD_DIR} @@ -21,5 +21,5 @@ LABEL life.apets.vendor="Halverneus" \ life.apets.url="https://github.com/halverneus/static-file-server" \ life.apets.name="Static File Server" \ life.apets.description="A tiny static file server" \ - life.apets.version="v1.7.6" \ + life.apets.version="v1.7.0" \ life.apets.schema-version="1.0" From 0d80a644ff074224e6e869f79f70486eeef8d327 Mon Sep 17 00:00:00 2001 From: Jeromy Streets Date: Wed, 16 Oct 2019 09:30:47 -0700 Subject: [PATCH 8/9] Updated alphabetical ordering of flags and 80-column wordwrap. --- README.md | 2 +- cli/help/help.go | 8 ++++---- config/config.go | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9ae1048..86da89e 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ the path to the configuration file using the command line option ('-c', '-config', '--config'). ```yaml +cors: false debug: false folder: /web host: "" @@ -72,7 +73,6 @@ show-listing: true tls-cert: "" tls-key: "" url-prefix: "" -cors: false ``` Example configuration with possible alternative values: diff --git a/cli/help/help.go b/cli/help/help.go index d8faff1..e5bbb65 100644 --- a/cli/help/help.go +++ b/cli/help/help.go @@ -34,9 +34,9 @@ DEPENDENCIES ENVIRONMENT VARIABLES CORS - When set to 'true' it enables resource access from any domain. All responses - will include the headers 'Access-Control-Allow-Origin' and 'Access-Control-Allow-Headers' - with a wildcard value ('*'). + When set to 'true' it enables resource access from any domain. All + responses will include the headers 'Access-Control-Allow-Origin' and + 'Access-Control-Allow-Headers' with a wildcard value ('*'). DEBUG When set to 'true' enables additional logging, including the configuration used and an access log for each request. IMPORTANT NOTE: @@ -89,6 +89,7 @@ CONFIGURATION FILE Example config.yml with defaults: ---------------------------------------------------------------------------- + cors: false debug: false folder: /web host: "" @@ -98,7 +99,6 @@ CONFIGURATION FILE tls-cert: "" tls-key: "" url-prefix: "" - cors: false ---------------------------------------------------------------------------- Example config.yml with possible alternative values: diff --git a/config/config.go b/config/config.go index 1f3d7a6..58aee00 100644 --- a/config/config.go +++ b/config/config.go @@ -14,6 +14,7 @@ import ( var ( // Get the desired configuration value. Get struct { + Cors bool `yaml:"cors"` Debug bool `yaml:"debug"` Folder string `yaml:"folder"` Host string `yaml:"host"` @@ -23,11 +24,11 @@ var ( TLSKey string `yaml:"tls-key"` URLPrefix string `yaml:"url-prefix"` Referrers []string `yaml:"referrers"` - Cors bool `yaml:cors` } ) const ( + corsKey = "CORS" debugKey = "DEBUG" folderKey = "FOLDER" hostKey = "HOST" @@ -37,7 +38,6 @@ const ( tlsCertKey = "TLS_CERT" tlsKeyKey = "TLS_KEY" urlPrefixKey = "URL_PREFIX" - corsKey = "CORS" ) var ( @@ -108,6 +108,7 @@ func Log() { // overrideWithEnvVars the default values and the configuration file values. func overrideWithEnvVars() { // Assign envvars, if set. + Get.Cors = envAsBool(corsKey, Get.Cors) Get.Debug = envAsBool(debugKey, Get.Debug) Get.Folder = envAsStr(folderKey, Get.Folder) Get.Host = envAsStr(hostKey, Get.Host) @@ -117,7 +118,6 @@ func overrideWithEnvVars() { Get.TLSKey = envAsStr(tlsKeyKey, Get.TLSKey) Get.URLPrefix = envAsStr(urlPrefixKey, Get.URLPrefix) Get.Referrers = envAsStrSlice(referrersKey, Get.Referrers) - Get.Cors = envAsBool(corsKey, Get.Cors) } // validate the configuration. From 9a679fb2e9705f03bbb59da681cc9b0ce18eb218 Mon Sep 17 00:00:00 2001 From: Jeromy Streets Date: Wed, 16 Oct 2019 09:33:25 -0700 Subject: [PATCH 9/9] Added comments and renamed function to annotate that it will apply the wildcard to CORS (rather than list allowed domains). Modified CORS unit test. --- cli/server/server.go | 3 +- handle/handle.go | 13 +++++---- handle/handle_test.go | 67 +++++++++++++++++++++++++++++++++++-------- 3 files changed, 64 insertions(+), 19 deletions(-) diff --git a/cli/server/server.go b/cli/server/server.go index 2393cd7..447c90d 100644 --- a/cli/server/server.go +++ b/cli/server/server.go @@ -62,8 +62,9 @@ func handlerSelector() (handler http.HandlerFunc) { handler = handle.IgnoreIndex(handler) } + // If configured, apply wildcard CORS support. if config.Get.Cors { - handler = handle.AddCorsHeaders(handler) + handler = handle.AddCorsWildcardHeaders(handler) } return diff --git a/handle/handle.go b/handle/handle.go index f0d3e91..e869e3b 100644 --- a/handle/handle.go +++ b/handle/handle.go @@ -109,12 +109,13 @@ func IgnoreIndex(serve http.HandlerFunc) http.HandlerFunc { } } -func AddCorsHeaders(serve http.HandlerFunc) http.HandlerFunc { - return func(writer http.ResponseWriter, request *http.Request) { - writer.Header().Set("Access-Control-Allow-Origin", "*") - writer.Header().Set("Access-Control-Allow-Headers", "*") - - serve(writer, request) +// AddCorsWildcardHeaders wraps an HTTP request to notify client browsers that +// resources should be allowed to be retrieved by any other domain. +func AddCorsWildcardHeaders(serve http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Headers", "*") + serve(w, r) } } diff --git a/handle/handle_test.go b/handle/handle_test.go index 2ad5eb4..c165300 100644 --- a/handle/handle_test.go +++ b/handle/handle_test.go @@ -9,7 +9,6 @@ import ( "os" "path" "testing" - "strings" ) var ( @@ -460,29 +459,73 @@ func TestValidReferrer(t *testing.T) { } } -func TestAddsCorsHeaders(t *testing.T) { +func TestAddCorsWildcardHeaders(t *testing.T) { testCases := []struct { - name string - header string - value string + name string + corsEnabled bool }{ - {"Add Access-Control-Allow-Origin header", "Access-Control-Allow-Origin", "*"}, - {"Add Access-Control-Allow-Headers header", "Access-Control-Allow-Headers", "*"}, + {"CORS disabled", false}, + {"CORS enabled", true}, + } + + corsHeaders := map[string]string{ + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": "*", } for _, serveFile := range serveFileFuncs { - handler := AddCorsHeaders(Basic(serveFile, baseDir)) for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - req := httptest.NewRequest("GET", "http://localhost/", nil) + var handler http.HandlerFunc + if tc.corsEnabled { + handler = AddCorsWildcardHeaders(Basic(serveFile, baseDir)) + } else { + handler = Basic(serveFile, baseDir) + } + + fullpath := "http://localhost/" + tmpFileName + req := httptest.NewRequest("GET", fullpath, nil) w := httptest.NewRecorder() handler(w, req) resp := w.Result() - headerValue := strings.Join(resp.Header[tc.header], ", ") - if headerValue != tc.value { - t.Errorf("Response header %q = %q, want %q", tc.header, headerValue, tc.value) + body, err := ioutil.ReadAll(resp.Body) + if nil != err { + t.Errorf("While reading body got %v", err) + } + contents := string(body) + if ok != resp.StatusCode { + t.Errorf( + "While retrieving %s expected status code of %d but got %d", + fullpath, ok, resp.StatusCode, + ) + } + if tmpFile != contents { + t.Errorf( + "While retrieving %s expected contents '%s' but got '%s'", + fullpath, tmpFile, contents, + ) + } + + if tc.corsEnabled { + for k, v := range corsHeaders { + if v != resp.Header.Get(k) { + t.Errorf( + "With CORS enabled expect header '%s' to return '%s' but got '%s'", + k, v, resp.Header.Get(k), + ) + } + } + } else { + for k := range corsHeaders { + if "" != resp.Header.Get(k) { + t.Errorf( + "With CORS disabled expected header '%s' to return '' but got '%s'", + k, resp.Header.Get(k), + ) + } + } } }) }