From adb719ea4cfa538dd5c25333230ae935970e2df3 Mon Sep 17 00:00:00 2001 From: phartenfeller Date: Wed, 23 Sep 2020 18:09:44 +0200 Subject: [PATCH 1/7] custom header test --- main.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/main.go b/main.go index cb171a6..7b242a6 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,9 @@ import ( "strconv" "strings" "sync" + "encoding/json" + "os" + "path/filepath" ) var ( @@ -69,6 +72,11 @@ func (w *gzipResponseWriter) Write(b []byte) (int, error) { func handleReq(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Println("======================") + log.Println("path =>", r.URL.Path) + log.Println("extension =>", filepath.Ext(r.URL.Path)) + log.Println("pagedata =>", strings.HasPrefix(r.URL.Path, "/page-data")) + log.Println("======================") if *httpsPromote && r.Header.Get("X-Forwarded-Proto") == "http" { http.Redirect(w, r, "https://"+r.Host+r.RequestURI, http.StatusMovedPermanently) if *logRequest { @@ -80,14 +88,58 @@ func handleReq(h http.Handler) http.Handler { if *logRequest { log.Println(r.Method, r.URL.Path) } + + fileExtension := filepath.Ext(r.URL.Path) + if fileExtension == ".json" && strings.HasPrefix(r.URL.Path, "/page-data") { + log.Println("add header") + w.Header().Set("cache-control", "public, max-age=0, must-revalidate") + } + h.ServeHTTP(w, r) }) } +type HeaderConfigs struct { + Configs []HConfig `json:"configs"` +} + +type HConfig struct { + Path string `json:"path"` + FileExtension string `json:"fileExtension"` + Header string `json:"header"` +} + + +func initHeaderConfig() { + // Open our jsonFile + jsonFile, err := os.Open("/config/headerConfig.json") + // if we os.Open returns an error then handle it + if err != nil { + fmt.Println(err) + } + fmt.Println("Successfully Opened headerConfig.json") + + byteValue, _ := ioutil.ReadAll(jsonFile) + + var headerConfigs HeaderConfigs + + json.Unmarshal(byteValue, &headerConfigs) + + for i := 0; i < len(headerConfigs.Configs); i++ { + fmt.Println("Path: " + headerConfigs.Configs[i].Path) + fmt.Println("FileExtension: " + headerConfigs.Configs[i].FileExtension) + fmt.Println("Header: " + headerConfigs.Configs[i].Header) + } + + jsonFile.Close() +} + func main() { flag.Parse() + initHeaderConfig() + // sanity check if len(*setBasicAuth) != 0 && !*basicAuth { *basicAuth = true From 2c00fb0d38c0d06afdba721a729e826b50e783c1 Mon Sep 17 00:00:00 2001 From: phartenfeller Date: Wed, 23 Sep 2020 20:58:22 +0200 Subject: [PATCH 2/7] use json config + changed headers to key value array --- main.go | 94 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 29 deletions(-) diff --git a/main.go b/main.go index 7b242a6..40480b9 100644 --- a/main.go +++ b/main.go @@ -70,13 +70,15 @@ func (w *gzipResponseWriter) Write(b []byte) (int, error) { return w.Writer.Write(b) } -func handleReq(h http.Handler) http.Handler { +func handleReq(h http.Handler, headerConfigs HeaderConfigs) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + /* log.Println("======================") log.Println("path =>", r.URL.Path) log.Println("extension =>", filepath.Ext(r.URL.Path)) log.Println("pagedata =>", strings.HasPrefix(r.URL.Path, "/page-data")) log.Println("======================") + */ if *httpsPromote && r.Header.Get("X-Forwarded-Proto") == "http" { http.Redirect(w, r, "https://"+r.Host+r.RequestURI, http.StatusMovedPermanently) if *logRequest { @@ -89,10 +91,29 @@ func handleReq(h http.Handler) http.Handler { log.Println(r.Method, r.URL.Path) } - fileExtension := filepath.Ext(r.URL.Path) - if fileExtension == ".json" && strings.HasPrefix(r.URL.Path, "/page-data") { - log.Println("add header") - w.Header().Set("cache-control", "public, max-age=0, must-revalidate") + // apply custom header config + if (len(headerConfigs.Configs) > 0) { + reqFileExtension := filepath.Ext(r.URL.Path) + + for i := 0; i < len(headerConfigs.Configs); i++ { + configEntry := headerConfigs.Configs[i] + + fileMatch := configEntry.FileExtension == "*" || reqFileExtension == "."+ configEntry.FileExtension + pathMatch := configEntry.Path == "*" || strings.HasPrefix(r.URL.Path, configEntry.Path) + + // log.Println("fileMatch", reqFileExtension, configEntry.FileExtension) + // log.Println("pathMatch", r.URL.Path, configEntry.Path) + + if fileMatch && pathMatch { + log.Println(r.URL.Path, configEntry.FileExtension, configEntry.Path) + for j := 0; j < len(configEntry.Headers); j++ { + headerEntry := configEntry.Headers[j] + + log.Println("add header", headerEntry.Key, headerEntry.Value, "to", r.URL.Path) + w.Header().Set(headerEntry.Key, headerEntry.Value) + } + } + } } h.ServeHTTP(w, r) @@ -106,39 +127,54 @@ type HeaderConfigs struct { type HConfig struct { Path string `json:"path"` FileExtension string `json:"fileExtension"` - Header string `json:"header"` + Headers []Header `json:"headers"` +} + +type Header struct { + Key string `json:"key"` + Value string `json:"value"` } -func initHeaderConfig() { - // Open our jsonFile - jsonFile, err := os.Open("/config/headerConfig.json") - // if we os.Open returns an error then handle it - if err != nil { - fmt.Println(err) +func initHeaderConfig() HeaderConfigs { + if fileExists("/config/headerConfig.json") { + jsonFile, err := os.Open("/config/headerConfig.json") + if err != nil { + fmt.Println(err) + } + + byteValue, _ := ioutil.ReadAll(jsonFile) + + var headerConfigs HeaderConfigs + + json.Unmarshal(byteValue, &headerConfigs) + + fmt.Println("Found header config file. Rules:") + + for i := 0; i < len(headerConfigs.Configs); i++ { + fmt.Println("==============================================================") + fmt.Println("Path: " + headerConfigs.Configs[i].Path) + fmt.Println("FileExtension: " + headerConfigs.Configs[i].FileExtension) + for j := 0; j < len(headerConfigs.Configs); j++ { + headerRule := headerConfigs.Configs[i].Headers[j] + fmt.Println(headerRule.Key, ":", headerRule.Value) + } + fmt.Println("==============================================================") + } + + jsonFile.Close() + + return headerConfigs + } else { + return nil } - fmt.Println("Successfully Opened headerConfig.json") - - byteValue, _ := ioutil.ReadAll(jsonFile) - - var headerConfigs HeaderConfigs - - json.Unmarshal(byteValue, &headerConfigs) - - for i := 0; i < len(headerConfigs.Configs); i++ { - fmt.Println("Path: " + headerConfigs.Configs[i].Path) - fmt.Println("FileExtension: " + headerConfigs.Configs[i].FileExtension) - fmt.Println("Header: " + headerConfigs.Configs[i].Header) - } - - jsonFile.Close() } func main() { flag.Parse() - initHeaderConfig() + headerConfigs := initHeaderConfig() // sanity check if len(*setBasicAuth) != 0 && !*basicAuth { @@ -156,7 +192,7 @@ func main() { } } - handler := handleReq(http.FileServer(fileSystem)) + handler := handleReq(http.FileServer(fileSystem), headerConfigs) pathPrefix := "/" if len(*context) > 0 { From 1557fd3591c840c2cfc58612fd72afdde563a1bd Mon Sep 17 00:00:00 2001 From: phartenfeller Date: Sun, 27 Sep 2020 18:15:09 +0200 Subject: [PATCH 3/7] split headerConfig logic to new file and middleware --- customHeaders.go | 100 +++++++++++++++++++++++++++++++++++++++++++++++ main.go | 96 ++++----------------------------------------- 2 files changed, 107 insertions(+), 89 deletions(-) create mode 100644 customHeaders.go diff --git a/customHeaders.go b/customHeaders.go new file mode 100644 index 0000000..0056021 --- /dev/null +++ b/customHeaders.go @@ -0,0 +1,100 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "strings" +) + +// HeaderConfigArray is the array which contains all the custom header rules +type HeaderConfigArray struct { + Configs []HeaderConfig `json:"configs"` +} + +// HeaderConfig is a single header rule specification +type HeaderConfig struct { + Path string `json:"path"` + FileExtension string `json:"fileExtension"` + Headers []HeaderDefiniton `json:"headers"` +} + +// HeaderDefiniton is a key value pair of a specified header rule +type HeaderDefiniton struct { + Key string `json:"key"` + Value string `json:"value"` +} + +var headerConfigs HeaderConfigArray + +func fileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} + +func initHeaderConfig() bool { + headerConfigValid := false + + if fileExists("/config/headerConfig.json") { + jsonFile, err := os.Open("/config/headerConfig.json") + if err != nil { + fmt.Println("Cant't read header config file. Error:") + fmt.Println(err) + } else { + byteValue, _ := ioutil.ReadAll(jsonFile) + + json.Unmarshal(byteValue, &headerConfigs) + + if len(headerConfigs.Configs) > 0 { + headerConfigValid = true + fmt.Println("Found header config file. Rules:") + + for i := 0; i < len(headerConfigs.Configs); i++ { + configEntry := headerConfigs.Configs[i] + fmt.Println("==============================================================") + fmt.Println("Path: " + configEntry.Path) + fmt.Println("FileExtension: " + configEntry.FileExtension) + for j := 0; j < len(configEntry.Headers); j++ { + headerRule := configEntry.Headers[j] + fmt.Println(headerRule.Key, ":", headerRule.Value) + } + fmt.Println("==============================================================") + } + } else { + fmt.Println("No rules found in header config file.") + } + + } + jsonFile.Close() + } + + return headerConfigValid +} + +func customHeadersMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + reqFileExtension := filepath.Ext(r.URL.Path) + + for i := 0; i < len(headerConfigs.Configs); i++ { + configEntry := headerConfigs.Configs[i] + + fileMatch := configEntry.FileExtension == "*" || reqFileExtension == "."+configEntry.FileExtension + pathMatch := configEntry.Path == "*" || strings.HasPrefix(r.URL.Path, configEntry.Path) + + if fileMatch && pathMatch { + for j := 0; j < len(configEntry.Headers); j++ { + headerEntry := configEntry.Headers[j] + w.Header().Set(headerEntry.Key, headerEntry.Value) + } + } + } + + next.ServeHTTP(w, r) + }) +} diff --git a/main.go b/main.go index 40480b9..b2617e6 100644 --- a/main.go +++ b/main.go @@ -14,9 +14,6 @@ import ( "strconv" "strings" "sync" - "encoding/json" - "os" - "path/filepath" ) var ( @@ -70,15 +67,8 @@ func (w *gzipResponseWriter) Write(b []byte) (int, error) { return w.Writer.Write(b) } -func handleReq(h http.Handler, headerConfigs HeaderConfigs) http.Handler { +func handleReq(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - /* - log.Println("======================") - log.Println("path =>", r.URL.Path) - log.Println("extension =>", filepath.Ext(r.URL.Path)) - log.Println("pagedata =>", strings.HasPrefix(r.URL.Path, "/page-data")) - log.Println("======================") - */ if *httpsPromote && r.Header.Get("X-Forwarded-Proto") == "http" { http.Redirect(w, r, "https://"+r.Host+r.RequestURI, http.StatusMovedPermanently) if *logRequest { @@ -91,91 +81,14 @@ func handleReq(h http.Handler, headerConfigs HeaderConfigs) http.Handler { log.Println(r.Method, r.URL.Path) } - // apply custom header config - if (len(headerConfigs.Configs) > 0) { - reqFileExtension := filepath.Ext(r.URL.Path) - - for i := 0; i < len(headerConfigs.Configs); i++ { - configEntry := headerConfigs.Configs[i] - - fileMatch := configEntry.FileExtension == "*" || reqFileExtension == "."+ configEntry.FileExtension - pathMatch := configEntry.Path == "*" || strings.HasPrefix(r.URL.Path, configEntry.Path) - - // log.Println("fileMatch", reqFileExtension, configEntry.FileExtension) - // log.Println("pathMatch", r.URL.Path, configEntry.Path) - - if fileMatch && pathMatch { - log.Println(r.URL.Path, configEntry.FileExtension, configEntry.Path) - for j := 0; j < len(configEntry.Headers); j++ { - headerEntry := configEntry.Headers[j] - - log.Println("add header", headerEntry.Key, headerEntry.Value, "to", r.URL.Path) - w.Header().Set(headerEntry.Key, headerEntry.Value) - } - } - } - } - h.ServeHTTP(w, r) }) } -type HeaderConfigs struct { - Configs []HConfig `json:"configs"` -} - -type HConfig struct { - Path string `json:"path"` - FileExtension string `json:"fileExtension"` - Headers []Header `json:"headers"` -} - -type Header struct { - Key string `json:"key"` - Value string `json:"value"` -} - - -func initHeaderConfig() HeaderConfigs { - if fileExists("/config/headerConfig.json") { - jsonFile, err := os.Open("/config/headerConfig.json") - if err != nil { - fmt.Println(err) - } - - byteValue, _ := ioutil.ReadAll(jsonFile) - - var headerConfigs HeaderConfigs - - json.Unmarshal(byteValue, &headerConfigs) - - fmt.Println("Found header config file. Rules:") - - for i := 0; i < len(headerConfigs.Configs); i++ { - fmt.Println("==============================================================") - fmt.Println("Path: " + headerConfigs.Configs[i].Path) - fmt.Println("FileExtension: " + headerConfigs.Configs[i].FileExtension) - for j := 0; j < len(headerConfigs.Configs); j++ { - headerRule := headerConfigs.Configs[i].Headers[j] - fmt.Println(headerRule.Key, ":", headerRule.Value) - } - fmt.Println("==============================================================") - } - - jsonFile.Close() - - return headerConfigs - } else { - return nil - } -} - func main() { flag.Parse() - headerConfigs := initHeaderConfig() - // sanity check if len(*setBasicAuth) != 0 && !*basicAuth { *basicAuth = true @@ -192,7 +105,7 @@ func main() { } } - handler := handleReq(http.FileServer(fileSystem), headerConfigs) + handler := handleReq(http.FileServer(fileSystem)) pathPrefix := "/" if len(*context) > 0 { @@ -210,6 +123,11 @@ func main() { handler = authMiddleware(handler) } + headerConfigValid := initHeaderConfig() + if headerConfigValid { + handler = customHeadersMiddleware(handler) + } + // Extra headers. if len(*headerFlag) > 0 { header, headerValue := parseHeaderFlag(*headerFlag) From dbdda5ed3d58e2d97fd0de0c765ecafc3ac7b339 Mon Sep 17 00:00:00 2001 From: phartenfeller Date: Mon, 28 Sep 2020 11:59:03 +0200 Subject: [PATCH 4/7] custom header documentation --- docs/header-config.md | 74 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 docs/header-config.md diff --git a/docs/header-config.md b/docs/header-config.md new file mode 100644 index 0000000..79840c9 --- /dev/null +++ b/docs/header-config.md @@ -0,0 +1,74 @@ +# Header Config + +With the header config, you can specify custom [HTTP Header](https://developer.mozilla.org/de/docs/Web/HTTP/Headers) for the responses of certain file types and paths. + +## Config + +You have to create a JSON file that serves as a config. The JSON must contain a `configs` array. For every entry, you can specify a certain path that must be matched as well as a file extension. You can use the `*` symbol to use the config entry for any path or filename. Note that the path option only matches the requested path from the start. Thatswhy you have to start with a `/` and can use paths like `/files/static/css`. The `headers` array includes a key-value pair of the actual header rule. The headers are not parsed so double check your spelling and test your site. + +The created JSON config has to be mounted into the container via a volume into `/config/headerConfig.json`. When this file does not exist inside the container, the header middleware will not be active. + +Example command to add to the docker run command: + +``` +-v /your/path/to/the/config/myConfig.json:/config/headerConfig.json +``` + +On startup, the container will log the found header rules. + +## Example headerConfig.json + +```json +{ + "configs": [ + { + "path": "*", + "fileExtension": "html", + "headers": [ + { + "key": "cache-control", + "value": "public, max-age=0, must-revalidate" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=31536000; includeSubDomains;" + } + ] + }, + { + "path": "*", + "fileExtension": "css", + "headers": [ + { + "key": "cache-control", + "value": "public, max-age=31536000, immutable" + } + ] + }, + { + "path": "/page-data", + "fileExtension": "json", + "headers": [ + { + "key": "cache-control", + "value": "public, max-age=0, must-revalidate" + }, + { + "key": "content-language", + "value": "en" + } + ] + }, + { + "path": "/static/", + "fileExtension": "*", + "headers": [ + { + "key": "cache-control", + "value": "public, max-age=31536000, immutable" + } + ] + } + ] +} +``` From 73eac2e1a690f9b5994a60d7ee80441141df5018 Mon Sep 17 00:00:00 2001 From: phartenfeller Date: Mon, 28 Sep 2020 12:09:00 +0200 Subject: [PATCH 5/7] improved found rules logging --- customHeaders.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/customHeaders.go b/customHeaders.go index 0056021..6d17d16 100644 --- a/customHeaders.go +++ b/customHeaders.go @@ -38,6 +38,18 @@ func fileExists(filename string) bool { return !info.IsDir() } +func logHeaderConfig(config HeaderConfig) { + fmt.Println("Path: " + config.Path) + fmt.Println("FileExtension: " + config.FileExtension) + + for j := 0; j < len(config.Headers); j++ { + headerRule := config.Headers[j] + fmt.Println(headerRule.Key, ":", headerRule.Value) + } + + fmt.Println("------------------------------") +} + func initHeaderConfig() bool { headerConfigValid := false @@ -54,17 +66,11 @@ func initHeaderConfig() bool { if len(headerConfigs.Configs) > 0 { headerConfigValid = true fmt.Println("Found header config file. Rules:") + fmt.Println("------------------------------") for i := 0; i < len(headerConfigs.Configs); i++ { configEntry := headerConfigs.Configs[i] - fmt.Println("==============================================================") - fmt.Println("Path: " + configEntry.Path) - fmt.Println("FileExtension: " + configEntry.FileExtension) - for j := 0; j < len(configEntry.Headers); j++ { - headerRule := configEntry.Headers[j] - fmt.Println(headerRule.Key, ":", headerRule.Value) - } - fmt.Println("==============================================================") + logHeaderConfig(configEntry) } } else { fmt.Println("No rules found in header config file.") From 64bc411fc7ff2803567a86a8db61a9bcc12a1f80 Mon Sep 17 00:00:00 2001 From: phartenfeller Date: Mon, 28 Sep 2020 12:11:01 +0200 Subject: [PATCH 6/7] updated readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0c36bfb..72a8add 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Yeah, decided to drop support of unsecured HTTPS. Two-years ago, when I started * Light container * More secure than official images (see below) * Log enabled + * Specify custom response headers per path and filetype [(info)](./docs/header-config.md) ### Why? Because the official Golang image is wayyyy too big (around 1/2Gb as you can see below) and could be insecure. From 3438532c3fbfcd8b27f32515453232276f6f963d Mon Sep 17 00:00:00 2001 From: phartenfeller Date: Mon, 28 Sep 2020 19:47:48 +0200 Subject: [PATCH 7/7] Config path can be specified with a parameter --- README.md | 14 ++++++++------ customHeaders.go | 6 +++--- docs/header-config.md | 10 ++++++++-- main.go | 3 ++- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 72a8add..36d842b 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ docker run -d -p 80:8043 -v path/to/website:/srv/http --name goStatic pierrezemb ``` ./goStatic --help -Usage of /goStatic: +Usage of ./goStatic: -append-header HeaderName:Value HTTP response header, specified as HeaderName:Value that should be added to all responses. -context string @@ -51,8 +51,14 @@ Usage of /goStatic: Enable basic auth. By default, password are randomly generated. Use --set-basic-auth to set it. -enable-health Enable health check endpoint. You can call /health to get a 200 response. Useful for Kubernetes, OpenFaas, etc. + -enable-logging + Enable log request -fallback string - Default fallback file. Either absolute for a specific asset (/index.html), or relative to recursively resolve (index.html). + Default fallback file. Either absolute for a specific asset (/index.html), or relative to recursively resolve (index.html) + -header-config-path string + Path to the config file for custom response headers (default "/config/headerConfig.json") + -https-promote + All HTTP requests should be redirected to HTTPS -password-length int Size of the randomized password (default 16) -path string @@ -61,10 +67,6 @@ Usage of /goStatic: The listening port (default 8043) -set-basic-auth string Define the basic auth. Form must be user:password - -https-promote - Connections to http: are redirected to https: - -enable-logging - Writes a simple log entry for requests to the server ``` #### Fallback diff --git a/customHeaders.go b/customHeaders.go index 6d17d16..1e819bf 100644 --- a/customHeaders.go +++ b/customHeaders.go @@ -50,11 +50,11 @@ func logHeaderConfig(config HeaderConfig) { fmt.Println("------------------------------") } -func initHeaderConfig() bool { +func initHeaderConfig(headerConfigPath string) bool { headerConfigValid := false - if fileExists("/config/headerConfig.json") { - jsonFile, err := os.Open("/config/headerConfig.json") + if fileExists(headerConfigPath) { + jsonFile, err := os.Open(headerConfigPath) if err != nil { fmt.Println("Cant't read header config file. Error:") fmt.Println(err) diff --git a/docs/header-config.md b/docs/header-config.md index 79840c9..b97255d 100644 --- a/docs/header-config.md +++ b/docs/header-config.md @@ -6,12 +6,18 @@ With the header config, you can specify custom [HTTP Header](https://developer.m You have to create a JSON file that serves as a config. The JSON must contain a `configs` array. For every entry, you can specify a certain path that must be matched as well as a file extension. You can use the `*` symbol to use the config entry for any path or filename. Note that the path option only matches the requested path from the start. Thatswhy you have to start with a `/` and can use paths like `/files/static/css`. The `headers` array includes a key-value pair of the actual header rule. The headers are not parsed so double check your spelling and test your site. -The created JSON config has to be mounted into the container via a volume into `/config/headerConfig.json`. When this file does not exist inside the container, the header middleware will not be active. +The created JSON config has to be mounted into the container via a volume into `/config/headerConfig.json` per default. When this file does not exist inside the container, the header middleware will not be active. Example command to add to the docker run command: ``` --v /your/path/to/the/config/myConfig.json:/config/headerConfig.json +docker run ... -v /your/path/to/the/config/myConfig.json:/config/headerConfig.json +``` + +You can also specify where you want to mount your config into with the `header-config-path` flag: + +``` +docker run ... -v /your/path/to/the/config/myConfig.json:/other/path/myConfig.json -header-config-path=/other/path/myConfig.json ``` On startup, the container will log the found header rules. diff --git a/main.go b/main.go index b2617e6..2590263 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,7 @@ var ( sizeRandom = flag.Int("password-length", 16, "Size of the randomized password") logRequest = flag.Bool("enable-logging", false, "Enable log request") httpsPromote = flag.Bool("https-promote", false, "All HTTP requests should be redirected to HTTPS") + headerConfigPath = flag.String("header-config-path", "/config/headerConfig.json", "Path to the config file for custom response headers") username string password string @@ -123,7 +124,7 @@ func main() { handler = authMiddleware(handler) } - headerConfigValid := initHeaderConfig() + headerConfigValid := initHeaderConfig(*headerConfigPath) if headerConfigValid { handler = customHeadersMiddleware(handler) }