From 79bbf3d71ee0069be44c15cb4eeb2ed7f9d3f9eb Mon Sep 17 00:00:00 2001
From: Paramtamtam <7326800+tarampampam@users.noreply.github.com>
Date: Mon, 3 Jan 2022 21:51:30 +0500
Subject: [PATCH] Flag `--default-http-code` for the `serve` subcommand added
 (#44)

---
 .github/workflows/tests.yml             |  4 ++--
 .golangci.yml                           |  2 ++
 CHANGELOG.md                            |  6 ++++++
 Dockerfile                              |  3 ++-
 internal/cli/serve/command.go           |  3 ++-
 internal/cli/serve/flags.go             | 23 ++++++++++++++++++++++-
 internal/env/env.go                     |  1 +
 internal/env/env_test.go                |  2 ++
 internal/http/handlers/index/handler.go |  9 +++++++--
 internal/http/server.go                 |  9 +++++++--
 10 files changed, 53 insertions(+), 9 deletions(-)

diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 25b7e9a..a217b3c 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -196,12 +196,12 @@ jobs: # Docs: <https://git.io/JvxXE>
         run: docker load < docker-image.tar
 
       - name: Run container with the app
-        run: docker run --rm -d -p "8080:8080/tcp" --name app app:ci
+        run: docker run --rm -d -p "8080:8080/tcp" -e "DEFAULT_HTTP_CODE=401" --name app app:ci
 
       - name: Wait for container "healthy" state
         run: until [[ "`docker inspect -f {{.State.Health.Status}} app`" == "healthy" ]]; do echo "wait 1 sec.."; sleep 1; done
 
-      - run: curl --fail http://127.0.0.1:8080/
+      - run: test $(curl --write-out %{http_code} --silent --output /dev/null http://127.0.0.1:8080/) -eq 401
       - run: curl --fail http://127.0.0.1:8080/500.html
       - run: curl --fail http://127.0.0.1:8080/400.html
       - run: curl --fail http://127.0.0.1:8080/health/live
diff --git a/.golangci.yml b/.golangci.yml
index fce316e..faea502 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -5,6 +5,8 @@ run:
   skip-dirs:
     - .github
     - .git
+    - tmp
+    - temp
   modules-download-mode: readonly
   allow-parallel-runners: true
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8523505..34bcf70 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,10 +6,16 @@ The format is based on [Keep a Changelog][keepachangelog] and this project adher
 
 ## UNRELEASED
 
+### Added
+
+- Flag `--default-http-code` for the `serve` subcommand (`404` is used by default instead of `200`, environment name `DEFAULT_HTTP_CODE`) [#41]
+
 ### Changed
 
 - Go updated from `1.17.1` up to `1.17.5`
 
+[#41]:https://github.com/tarampampam/error-pages/issues/41
+
 ## v2.2.0
 
 ### Added
diff --git a/Dockerfile b/Dockerfile
index 74c6bbf..ca10380 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -65,7 +65,8 @@ WORKDIR /opt
 
 ENV LISTEN_PORT="8080" \
     TEMPLATE_NAME="ghost" \
-    DEFAULT_ERROR_PAGE="404"
+    DEFAULT_ERROR_PAGE="404" \
+    DEFAULT_HTTP_CODE="404"
 
 # Docs: <https://docs.docker.com/engine/reference/builder/#healthcheck>
 HEALTHCHECK --interval=7s --timeout=2s CMD [ \
diff --git a/internal/cli/serve/command.go b/internal/cli/serve/command.go
index a757f67..6bc481b 100644
--- a/internal/cli/serve/command.go
+++ b/internal/cli/serve/command.go
@@ -144,7 +144,7 @@ func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config
 	server := appHttp.NewServer(log)
 
 	// register server routes, middlewares, etc.
-	server.Register(&errorPages, picker, f.defaultErrorPage)
+	server.Register(&errorPages, picker, f.defaultErrorPage, f.defaultHTTPCode)
 
 	startedAt, startingErrCh := time.Now(), make(chan error, 1) // channel for server starting error
 
@@ -156,6 +156,7 @@ func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config
 			zap.String("addr", f.listen.ip),
 			zap.Uint16("port", f.listen.port),
 			zap.String("default error page", f.defaultErrorPage),
+			zap.Uint16("default HTTP response code", f.defaultHTTPCode),
 		)
 
 		if err := server.Start(f.listen.ip, f.listen.port); err != nil {
diff --git a/internal/cli/serve/flags.go b/internal/cli/serve/flags.go
index 7117ea9..1c368bf 100644
--- a/internal/cli/serve/flags.go
+++ b/internal/cli/serve/flags.go
@@ -19,6 +19,7 @@ type flags struct {
 		name string
 	}
 	defaultErrorPage string
+	defaultHTTPCode  uint16
 }
 
 const (
@@ -26,6 +27,7 @@ const (
 	portFlagName             = "port"
 	templateNameFlagName     = "template-name"
 	defaultErrorPageFlagName = "default-error-page"
+	defaultHTTPCodeFlagName  = "default-http-code"
 )
 
 const (
@@ -61,9 +63,15 @@ func (f *flags) init(flagSet *pflag.FlagSet) {
 		"404",
 		fmt.Sprintf("default error page [$%s]", env.DefaultErrorPage),
 	)
+	flagSet.Uint16VarP(
+		&f.defaultHTTPCode,
+		defaultHTTPCodeFlagName, "",
+		404, //nolint:gomnd
+		fmt.Sprintf("default HTTP response code [$%s]", env.DefaultHTTPCode),
+	)
 }
 
-func (f *flags) overrideUsingEnv(flagSet *pflag.FlagSet) (lastErr error) {
+func (f *flags) overrideUsingEnv(flagSet *pflag.FlagSet) (lastErr error) { //nolint:gocognit
 	flagSet.VisitAll(func(flag *pflag.Flag) {
 		// flag was NOT defined using CLI (flags should have maximal priority)
 		if !flag.Changed { //nolint:nestif
@@ -91,6 +99,15 @@ func (f *flags) overrideUsingEnv(flagSet *pflag.FlagSet) (lastErr error) {
 				if envVar, exists := env.DefaultErrorPage.Lookup(); exists {
 					f.defaultErrorPage = strings.TrimSpace(envVar)
 				}
+
+			case defaultHTTPCodeFlagName:
+				if envVar, exists := env.DefaultHTTPCode.Lookup(); exists {
+					if code, err := strconv.ParseUint(envVar, 10, 16); err == nil { //nolint:gomnd
+						f.defaultHTTPCode = uint16(code)
+					} else {
+						lastErr = fmt.Errorf("wrong default HTTP response code environment variable [%s] value", envVar)
+					}
+				}
 			}
 		}
 	})
@@ -103,5 +120,9 @@ func (f *flags) validate() error {
 		return fmt.Errorf("wrong IP address [%s] for listening", f.listen.ip)
 	}
 
+	if f.defaultHTTPCode > 599 { //nolint:gomnd
+		return fmt.Errorf("wrong default HTTP response code [%d]", f.defaultHTTPCode)
+	}
+
 	return nil
 }
diff --git a/internal/env/env.go b/internal/env/env.go
index 6c638f5..1088e27 100644
--- a/internal/env/env.go
+++ b/internal/env/env.go
@@ -11,6 +11,7 @@ const (
 	TemplateName     envVariable = "TEMPLATE_NAME"      // template name
 	ConfigFilePath   envVariable = "CONFIG_FILE"        // path to the config file
 	DefaultErrorPage envVariable = "DEFAULT_ERROR_PAGE" // default error page (code)
+	DefaultHTTPCode  envVariable = "DEFAULT_HTTP_CODE"  // default HTTP response code
 )
 
 // String returns environment variable name in the string representation.
diff --git a/internal/env/env_test.go b/internal/env/env_test.go
index e249f99..018896c 100644
--- a/internal/env/env_test.go
+++ b/internal/env/env_test.go
@@ -13,6 +13,7 @@ func TestConstants(t *testing.T) {
 	assert.Equal(t, "TEMPLATE_NAME", string(TemplateName))
 	assert.Equal(t, "CONFIG_FILE", string(ConfigFilePath))
 	assert.Equal(t, "DEFAULT_ERROR_PAGE", string(DefaultErrorPage))
+	assert.Equal(t, "DEFAULT_HTTP_CODE", string(DefaultHTTPCode))
 }
 
 func TestEnvVariable_Lookup(t *testing.T) {
@@ -24,6 +25,7 @@ func TestEnvVariable_Lookup(t *testing.T) {
 		{giveEnv: TemplateName},
 		{giveEnv: ConfigFilePath},
 		{giveEnv: DefaultErrorPage},
+		{giveEnv: DefaultHTTPCode},
 	}
 
 	for _, tt := range cases {
diff --git a/internal/http/handlers/index/handler.go b/internal/http/handlers/index/handler.go
index fceff42..652f627 100644
--- a/internal/http/handlers/index/handler.go
+++ b/internal/http/handlers/index/handler.go
@@ -17,13 +17,18 @@ type (
 )
 
 // NewHandler creates handler for the index page serving.
-func NewHandler(e errorsPager, p templatePicker, defaultPageCode string) fasthttp.RequestHandler {
+func NewHandler(
+	e errorsPager,
+	p templatePicker,
+	defaultPageCode string,
+	defaultHTTPCode uint16,
+) fasthttp.RequestHandler {
 	return func(ctx *fasthttp.RequestCtx) {
 		content, err := e.GetPage(p.Pick(), defaultPageCode)
 
 		if err == nil {
 			ctx.SetContentType("text/html; charset=utf-8")
-			ctx.SetStatusCode(fasthttp.StatusOK)
+			ctx.SetStatusCode(int(defaultHTTPCode))
 			_, _ = ctx.Write(content)
 
 			return
diff --git a/internal/http/server.go b/internal/http/server.go
index 5b1da05..791599f 100644
--- a/internal/http/server.go
+++ b/internal/http/server.go
@@ -66,8 +66,13 @@ type (
 
 // Register server routes, middlewares, etc.
 // Router docs: <https://github.com/fasthttp/router>
-func (s *Server) Register(errorsPager errorsPager, templatePicker templatePicker, defaultPageCode string) {
-	s.router.GET("/", indexHandler.NewHandler(errorsPager, templatePicker, defaultPageCode))
+func (s *Server) Register(
+	errorsPager errorsPager,
+	templatePicker templatePicker,
+	defaultPageCode string,
+	defaultHTTPCode uint16,
+) {
+	s.router.GET("/", indexHandler.NewHandler(errorsPager, templatePicker, defaultPageCode, defaultHTTPCode))
 	s.router.GET("/version", versionHandler.NewHandler(version.Version()))
 	s.router.ANY("/health/live", healthzHandler.NewHandler(checkers.NewLiveChecker()))
 	s.router.GET("/{code}.html", errorpageHandler.NewHandler(errorsPager, templatePicker))