mirror of
https://github.com/tarampampam/error-pages.git
synced 2024-08-30 18:22:40 +00:00
wip: 🔕 temporary commit
This commit is contained in:
parent
1b94bc367c
commit
a52dbde00c
30
README.md
30
README.md
@ -27,21 +27,21 @@ $ error-pages [GLOBAL FLAGS] serve [COMMAND FLAGS] [ARGUMENTS...]
|
|||||||
|
|
||||||
The following flags are supported:
|
The following flags are supported:
|
||||||
|
|
||||||
| Name | Description | Default value | Environment variables |
|
| Name | Description | Default value | Environment variables |
|
||||||
|------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------:|:----------------------:|
|
|------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------:|:-------------------------:|
|
||||||
| `--listen="…"` (`-l`) | IP (v4 or v6) address to listen on | `0.0.0.0` | `LISTEN_ADDR` |
|
| `--listen="…"` (`-l`) | IP (v4 or v6) address to listen on | `0.0.0.0` | `LISTEN_ADDR` |
|
||||||
| `--port="…"` (`-p`) | TCP port number | `8080` | `LISTEN_PORT` |
|
| `--port="…"` (`-p`) | TCP port number | `8080` | `LISTEN_PORT` |
|
||||||
| `--add-template="…"` | to add a new template, provide the path to the file using this flag (the filename without the extension will be used as the template name) | `[]` | *none* |
|
| `--add-template="…"` | to add a new template, provide the path to the file using this flag (the filename without the extension will be used as the template name) | `[]` | *none* |
|
||||||
| `--add-http-code="…"` | to add a new HTTP status code, provide the code and its message/description using this flag (the format should be '%code%=%message%/%description%'; the code may contain a wildcard '*' to cover multiple codes at once, for example, '4**' will cover all 4xx codes, unless a more specific code was described previously) | `map[]` | *none* |
|
| `--add-http-code="…"` | to add a new HTTP status code, provide the code and its message/description using this flag (the format should be '%code%=%message%/%description%'; the code may contain a wildcard '*' to cover multiple codes at once, for example, '4**' will cover all 4xx codes, unless a more specific code was described previously) | `map[]` | *none* |
|
||||||
| `--json-format="…"` | override the default error page response in JSON format (Go templates are supported) | | `RESPONSE_JSON_FORMAT` |
|
| `--json-format="…"` | override the default error page response in JSON format (Go templates are supported) | | `RESPONSE_JSON_FORMAT` |
|
||||||
| `--xml-format="…"` | override the default error page response in XML format (Go templates are supported) | | `RESPONSE_XML_FORMAT` |
|
| `--xml-format="…"` | override the default error page response in XML format (Go templates are supported) | | `RESPONSE_XML_FORMAT` |
|
||||||
| `--template-name="…"` (`-t`) | name of the template to use for rendering error pages | `template-1` | `TEMPLATE_NAME` |
|
| `--template-name="…"` (`-t`) | name of the template to use for rendering error pages | `template-1` | `TEMPLATE_NAME` |
|
||||||
| `--disable-l10n` | disable localization of error pages (if the template supports localization) | `false` | `DISABLE_L10N` |
|
| `--disable-l10n` | disable localization of error pages (if the template supports localization) | `false` | `DISABLE_L10N` |
|
||||||
| `--default-error-page="…"` | the code of the default (index page, when a code is not specified) error page to render | `404` | `DEFAULT_ERROR_PAGE` |
|
| `--default-error-page="…"` | the code of the default (index page, when a code is not specified) error page to render | `404` | `DEFAULT_ERROR_PAGE` |
|
||||||
| `--default-http-code="…"` | the default (index page, when a code is not specified) HTTP response code | `404` | `DEFAULT_HTTP_CODE` |
|
| `--send-same-http-code` | the HTTP response should have the same status code as the requested error page (by default, every response with an error page will have a status code of 200) | `false` | `SEND_SAME_HTTP_CODE` |
|
||||||
| `--show-details` | show request details in the error page response (if supported by the template) | `false` | `SHOW_DETAILS` |
|
| `--show-details` | show request details in the error page response (if supported by the template) | `false` | `SHOW_DETAILS` |
|
||||||
| `--proxy-headers="…"` | listed here HTTP headers will be proxied from the original request to the error page response (comma-separated list) | `X-Request-Id,X-Trace-Id,X-Amzn-Trace-Id` | `PROXY_HTTP_HEADERS` |
|
| `--proxy-headers="…"` | listed here HTTP headers will be proxied from the original request to the error page response (comma-separated list) | `X-Request-Id,X-Trace-Id,X-Amzn-Trace-Id` | `PROXY_HTTP_HEADERS` |
|
||||||
| `--read-buffer-size="…"` | customize the HTTP read buffer size (set per connection for reading requests, also limits the maximum header size; consider increasing it if your clients send multi-KB request URIs or multi-KB headers, such as large cookies) | `0` | `READ_BUFFER_SIZE` |
|
| `--rotation-mode="…"` | templates automatic rotation mode (disabled/random-on-startup/random-on-each-request/random-daily/random-hourly) | `disabled` | `TEMPLATES_ROTATION_MODE` |
|
||||||
|
|
||||||
### `healthcheck` command (aliases: `chk`, `health`, `check`)
|
### `healthcheck` command (aliases: `chk`, `health`, `check`)
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ func NewCommand(log *zap.Logger) *cli.Command { //nolint:funlen,gocognit,gocyclo
|
|||||||
defaultCodeToRenderFlag = cli.UintFlag{
|
defaultCodeToRenderFlag = cli.UintFlag{
|
||||||
Name: "default-error-page",
|
Name: "default-error-page",
|
||||||
Usage: "the code of the default (index page, when a code is not specified) error page to render",
|
Usage: "the code of the default (index page, when a code is not specified) error page to render",
|
||||||
Value: uint64(cfg.Default.CodeToRender),
|
Value: uint64(cfg.DefaultCodeToRender),
|
||||||
Sources: env("DEFAULT_ERROR_PAGE"),
|
Sources: env("DEFAULT_ERROR_PAGE"),
|
||||||
Validator: func(code uint64) error {
|
Validator: func(code uint64) error {
|
||||||
if code > 999 { //nolint:mnd
|
if code > 999 { //nolint:mnd
|
||||||
@ -85,13 +85,13 @@ func NewCommand(log *zap.Logger) *cli.Command { //nolint:funlen,gocognit,gocyclo
|
|||||||
},
|
},
|
||||||
OnlyOnce: true,
|
OnlyOnce: true,
|
||||||
}
|
}
|
||||||
defaultHTTPCodeFlag = cli.UintFlag{
|
sendSameHTTPCodeFlag = cli.BoolFlag{
|
||||||
Name: "default-http-code",
|
Name: "send-same-http-code",
|
||||||
Usage: "the default (index page, when a code is not specified) HTTP response code",
|
Usage: "the HTTP response should have the same status code as the requested error page (by default, " +
|
||||||
Value: uint64(cfg.Default.HttpCode),
|
"every response with an error page will have a status code of 200)",
|
||||||
Sources: env("DEFAULT_HTTP_CODE"),
|
Value: cfg.RespondWithSameHTTPCode,
|
||||||
Validator: defaultCodeToRenderFlag.Validator,
|
Sources: env("SEND_SAME_HTTP_CODE"),
|
||||||
OnlyOnce: true,
|
OnlyOnce: true,
|
||||||
}
|
}
|
||||||
showDetailsFlag = cli.BoolFlag{
|
showDetailsFlag = cli.BoolFlag{
|
||||||
Name: "show-details",
|
Name: "show-details",
|
||||||
@ -157,8 +157,8 @@ func NewCommand(log *zap.Logger) *cli.Command { //nolint:funlen,gocognit,gocyclo
|
|||||||
|
|
||||||
cfg.TemplateName = c.String(templateNameFlag.Name)
|
cfg.TemplateName = c.String(templateNameFlag.Name)
|
||||||
cfg.L10n.Disable = c.Bool(disableL10nFlag.Name)
|
cfg.L10n.Disable = c.Bool(disableL10nFlag.Name)
|
||||||
cfg.Default.CodeToRender = uint16(c.Uint(defaultCodeToRenderFlag.Name))
|
cfg.DefaultCodeToRender = uint16(c.Uint(defaultCodeToRenderFlag.Name))
|
||||||
cfg.Default.HttpCode = uint16(c.Uint(defaultHTTPCodeFlag.Name))
|
cfg.RespondWithSameHTTPCode = c.Bool(sendSameHTTPCodeFlag.Name)
|
||||||
cfg.RotationMode, _ = config.ParseRotationMode(c.String(rotationModeFlag.Name))
|
cfg.RotationMode, _ = config.ParseRotationMode(c.String(rotationModeFlag.Name))
|
||||||
cfg.ShowDetails = c.Bool(showDetailsFlag.Name)
|
cfg.ShowDetails = c.Bool(showDetailsFlag.Name)
|
||||||
|
|
||||||
@ -231,8 +231,8 @@ func NewCommand(log *zap.Logger) *cli.Command { //nolint:funlen,gocognit,gocyclo
|
|||||||
zap.String("XML format", cfg.Formats.XML),
|
zap.String("XML format", cfg.Formats.XML),
|
||||||
zap.String("template name", cfg.TemplateName),
|
zap.String("template name", cfg.TemplateName),
|
||||||
zap.Bool("disable localization", cfg.L10n.Disable),
|
zap.Bool("disable localization", cfg.L10n.Disable),
|
||||||
zap.Uint16("default code to render", cfg.Default.CodeToRender),
|
zap.Uint16("default code to render", cfg.DefaultCodeToRender),
|
||||||
zap.Uint16("default HTTP code", cfg.Default.HttpCode),
|
zap.Bool("respond with the same HTTP code", cfg.RespondWithSameHTTPCode),
|
||||||
zap.Bool("show details", cfg.ShowDetails),
|
zap.Bool("show details", cfg.ShowDetails),
|
||||||
zap.Strings("proxy HTTP headers", cfg.ProxyHeaders),
|
zap.Strings("proxy HTTP headers", cfg.ProxyHeaders),
|
||||||
)
|
)
|
||||||
@ -249,7 +249,7 @@ func NewCommand(log *zap.Logger) *cli.Command { //nolint:funlen,gocognit,gocyclo
|
|||||||
&templateNameFlag,
|
&templateNameFlag,
|
||||||
&disableL10nFlag,
|
&disableL10nFlag,
|
||||||
&defaultCodeToRenderFlag,
|
&defaultCodeToRenderFlag,
|
||||||
&defaultHTTPCodeFlag,
|
&sendSameHTTPCodeFlag,
|
||||||
&showDetailsFlag,
|
&showDetailsFlag,
|
||||||
&proxyHeadersListFlag,
|
&proxyHeadersListFlag,
|
||||||
&rotationModeFlag,
|
&rotationModeFlag,
|
||||||
|
@ -37,15 +37,16 @@ type Config struct {
|
|||||||
Disable bool
|
Disable bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default contains default settings.
|
// DefaultCodeToRender is the code for the default error page to be displayed. It is used when the requested
|
||||||
Default struct {
|
// code is not defined in the incoming request (i.e., the code to render as the index page).
|
||||||
// CodeToRender is the code for the default error page to be displayed. It is used when the requested
|
DefaultCodeToRender uint16
|
||||||
// code is not defined in the incoming request (i.e., the code to render as the index page).
|
|
||||||
CodeToRender uint16
|
|
||||||
|
|
||||||
// HTTPCode is the HTTP code to return when the requested code is not defined in the incoming request.
|
// RespondWithSameHTTPCode determines whether the response should have the same HTTP status code as the requested
|
||||||
HttpCode uint16
|
// error page.
|
||||||
}
|
// In other words, if set to true and the requested error page has a code of 404, the HTTP response will also have
|
||||||
|
// a status code of 404. If set to false, the HTTP response will have a status code of 200 regardless of the
|
||||||
|
// requested error page's status code.
|
||||||
|
RespondWithSameHTTPCode bool
|
||||||
|
|
||||||
// RotationMode allows to set the rotation mode for templates to switch between them automatically on startup,
|
// RotationMode allows to set the rotation mode for templates to switch between them automatically on startup,
|
||||||
// on each request, daily, hourly and so on.
|
// on each request, daily, hourly and so on.
|
||||||
@ -150,8 +151,7 @@ func New() Config {
|
|||||||
cfg.ProxyHeaders = slices.Clone(defaultProxyHeaders)
|
cfg.ProxyHeaders = slices.Clone(defaultProxyHeaders)
|
||||||
|
|
||||||
// set defaults
|
// set defaults
|
||||||
cfg.Default.CodeToRender = 404
|
cfg.DefaultCodeToRender = http.StatusNotFound
|
||||||
cfg.Default.HttpCode = http.StatusNotFound
|
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package config_test
|
package config_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -20,8 +21,7 @@ func TestNew(t *testing.T) {
|
|||||||
assert.True(t, len(cfg.Templates) >= 2)
|
assert.True(t, len(cfg.Templates) >= 2)
|
||||||
assert.NotEmpty(t, cfg.TemplateName)
|
assert.NotEmpty(t, cfg.TemplateName)
|
||||||
assert.True(t, cfg.Templates.Has(cfg.TemplateName))
|
assert.True(t, cfg.Templates.Has(cfg.TemplateName))
|
||||||
assert.Equal(t, uint16(404), cfg.Default.CodeToRender)
|
assert.Equal(t, uint16(http.StatusNotFound), cfg.DefaultCodeToRender)
|
||||||
assert.Equal(t, uint16(404), cfg.Default.HttpCode)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("changing cfg1 should not affect cfg2", func(t *testing.T) {
|
t.Run("changing cfg1 should not affect cfg2", func(t *testing.T) {
|
||||||
|
@ -1,12 +1,84 @@
|
|||||||
package error_page
|
package error_page
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
func New() http.Handler {
|
"gh.tarampamp.am/error-pages/internal/config"
|
||||||
var body = []byte("error page")
|
)
|
||||||
|
|
||||||
|
func New(cfg *config.Config) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
var code uint16
|
||||||
_, _ = w.Write(body)
|
|
||||||
|
if fromUrl, okUrl := ExtractCodeFromURL(r.URL.Path); okUrl {
|
||||||
|
code = fromUrl
|
||||||
|
} else if fromHeader, okHeaders := ExtractCodeFromHeaders(r.Header); okHeaders {
|
||||||
|
code = fromHeader
|
||||||
|
} else {
|
||||||
|
code = cfg.DefaultCodeToRender
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpCode int
|
||||||
|
|
||||||
|
if cfg.RespondWithSameHTTPCode {
|
||||||
|
httpCode = int(code)
|
||||||
|
} else {
|
||||||
|
httpCode = http.StatusOK
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8") // TODO: should depends on requested type
|
||||||
|
w.WriteHeader(httpCode)
|
||||||
|
_, _ = w.Write([]byte(fmt.Sprintf("<html>error page for the code %d</html>", code)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExtractCodeFromURL extracts the error code from the given URL.
|
||||||
|
func ExtractCodeFromURL(url string) (uint16, bool) {
|
||||||
|
var parts = strings.SplitN(strings.TrimLeft(url, "/"), "/", 1)
|
||||||
|
|
||||||
|
if len(parts) == 0 {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
fileName = parts[0]
|
||||||
|
ext = strings.ToLower(filepath.Ext(fileName)) // ".html", ".htm", ".%something%" or an empty string
|
||||||
|
)
|
||||||
|
|
||||||
|
if ext != "" && ext != ".html" && ext != ".htm" {
|
||||||
|
return 0, false
|
||||||
|
} else if ext != "" {
|
||||||
|
fileName = strings.TrimSuffix(fileName, ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
if code, err := strconv.ParseUint(fileName, 10, 16); err == nil && code > 0 && code < 999 {
|
||||||
|
return uint16(code), true
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLContainsCode checks if the given URL contains an error code.
|
||||||
|
func URLContainsCode(url string) (ok bool) { _, ok = ExtractCodeFromURL(url); return } //nolint:nlreturn
|
||||||
|
|
||||||
|
// ExtractCodeFromHeaders extracts the error code from the given headers.
|
||||||
|
func ExtractCodeFromHeaders(headers http.Header) (uint16, bool) {
|
||||||
|
if value := headers.Get("X-Code"); len(value) > 0 && len(value) <= 3 {
|
||||||
|
if code, err := strconv.ParseUint(value, 10, 16); err == nil && code > 0 && code < 999 {
|
||||||
|
return uint16(code), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeadersContainCode checks if the given headers contain an error code.
|
||||||
|
func HeadersContainCode(headers http.Header) (ok bool) {
|
||||||
|
_, ok = ExtractCodeFromHeaders(headers)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -13,7 +12,7 @@ import (
|
|||||||
|
|
||||||
"gh.tarampamp.am/error-pages/internal/appmeta"
|
"gh.tarampamp.am/error-pages/internal/appmeta"
|
||||||
"gh.tarampamp.am/error-pages/internal/config"
|
"gh.tarampamp.am/error-pages/internal/config"
|
||||||
"gh.tarampamp.am/error-pages/internal/http/handlers/error_page"
|
ep "gh.tarampamp.am/error-pages/internal/http/handlers/error_page"
|
||||||
"gh.tarampamp.am/error-pages/internal/http/handlers/live"
|
"gh.tarampamp.am/error-pages/internal/http/handlers/live"
|
||||||
"gh.tarampamp.am/error-pages/internal/http/handlers/version"
|
"gh.tarampamp.am/error-pages/internal/http/handlers/version"
|
||||||
"gh.tarampamp.am/error-pages/internal/http/middleware/logreq"
|
"gh.tarampamp.am/error-pages/internal/http/middleware/logreq"
|
||||||
@ -51,9 +50,7 @@ func (s *Server) Register(cfg *config.Config) error {
|
|||||||
var (
|
var (
|
||||||
liveHandler = live.New()
|
liveHandler = live.New()
|
||||||
versionHandler = version.New(appmeta.Version())
|
versionHandler = version.New(appmeta.Version())
|
||||||
errorPagesHandler = error_page.New()
|
errorPagesHandler = ep.New(cfg)
|
||||||
|
|
||||||
errorPageRegex = regexp.MustCompile(`^/(\d{3})(?:\.html|\.htm)?$`) // TODO: rewrite to function
|
|
||||||
)
|
)
|
||||||
|
|
||||||
s.server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
s.server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -63,16 +60,19 @@ func (s *Server) Register(cfg *config.Config) error {
|
|||||||
// live endpoints
|
// live endpoints
|
||||||
case url == "/health/live" || url == "/health" || url == "/healthz" || url == "/live":
|
case url == "/health/live" || url == "/health" || url == "/healthz" || url == "/live":
|
||||||
liveHandler.ServeHTTP(w, r)
|
liveHandler.ServeHTTP(w, r)
|
||||||
|
|
||||||
// version endpoint
|
// version endpoint
|
||||||
case url == "/version":
|
case url == "/version":
|
||||||
versionHandler.ServeHTTP(w, r)
|
versionHandler.ServeHTTP(w, r)
|
||||||
|
|
||||||
// error pages endpoints:
|
// error pages endpoints:
|
||||||
// - /
|
// - /
|
||||||
// - /{code}.html
|
// - /{code}.html
|
||||||
// - /{code}.htm
|
// - /{code}.htm
|
||||||
// - /{code}
|
// - /{code}
|
||||||
case method == http.MethodGet && (url == "/" || errorPageRegex.MatchString(url)):
|
case method == http.MethodGet && (url == "/" || ep.URLContainsCode(url) || ep.HeadersContainCode(r.Header)):
|
||||||
errorPagesHandler.ServeHTTP(w, r)
|
errorPagesHandler.ServeHTTP(w, r)
|
||||||
|
|
||||||
// wrong requests handling
|
// wrong requests handling
|
||||||
default:
|
default:
|
||||||
switch {
|
switch {
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -99,7 +100,133 @@ func TestRouting(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("error page", func(t *testing.T) {
|
t.Run("error page", func(t *testing.T) {
|
||||||
t.Skip("not implemented")
|
t.Run("success", func(t *testing.T) {
|
||||||
|
var assertErrorPage = func(t *testing.T, wantErrorPageCode int, body []byte, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
var bodyStr = string(body)
|
||||||
|
|
||||||
|
assert.NotEmpty(t, bodyStr)
|
||||||
|
assert.Contains(t, bodyStr, "error page") // FIXME
|
||||||
|
assert.Contains(t, bodyStr, strconv.Itoa(wantErrorPageCode)) // FIXME?
|
||||||
|
assert.Contains(t, headers.Get("Content-Type"), "text/html") // FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("index, default", func(t *testing.T) {
|
||||||
|
var status, body, headers = sendRequest(t, http.MethodGet, baseUrl+"/")
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, status)
|
||||||
|
assertErrorPage(t, int(cfg.DefaultCodeToRender), body, headers)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("index, code in HTTP header", func(t *testing.T) {
|
||||||
|
var status, body, headers = sendRequest(t, http.MethodGet, baseUrl+"/", map[string]string{"X-Code": "404"})
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, status) // because of [cfg.RespondWithSameHTTPCode] is false by default
|
||||||
|
assertErrorPage(t, 404, body, headers)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("code in URL, .html", func(t *testing.T) {
|
||||||
|
var status, body, headers = sendRequest(t, http.MethodGet, baseUrl+"/500.html")
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, status)
|
||||||
|
assertErrorPage(t, 500, body, headers)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("code in URL, .htm", func(t *testing.T) {
|
||||||
|
var status, body, headers = sendRequest(t, http.MethodGet, baseUrl+"/409.htm")
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, status)
|
||||||
|
assertErrorPage(t, 409, body, headers)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("code in URL, without extension", func(t *testing.T) {
|
||||||
|
var status, body, headers = sendRequest(t, http.MethodGet, baseUrl+"/405")
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, status)
|
||||||
|
assertErrorPage(t, 405, body, headers)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("code in the URL have higher priority than in the headers", func(t *testing.T) {
|
||||||
|
var status, body, headers = sendRequest(t, http.MethodGet, baseUrl+"/405", map[string]string{"X-Code": "404"})
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, status)
|
||||||
|
assertErrorPage(t, 405, body, headers)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid code in HTTP header (with a string)", func(t *testing.T) {
|
||||||
|
var status, body, headers = sendRequest(t, http.MethodGet, baseUrl+"/", map[string]string{"X-Code": "foobar"})
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, status)
|
||||||
|
assertErrorPage(t, int(cfg.DefaultCodeToRender), body, headers)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid code in HTTP header (too small)", func(t *testing.T) {
|
||||||
|
var status, body, headers = sendRequest(t, http.MethodGet, baseUrl+"/", map[string]string{"X-Code": "0"})
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, status)
|
||||||
|
assertErrorPage(t, int(cfg.DefaultCodeToRender), body, headers)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid code in HTTP header (too big)", func(t *testing.T) {
|
||||||
|
var status, body, headers = sendRequest(t, http.MethodGet, baseUrl+"/", map[string]string{"X-Code": "1000"})
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, status)
|
||||||
|
assertErrorPage(t, int(cfg.DefaultCodeToRender), body, headers)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("failure", func(t *testing.T) {
|
||||||
|
var assertIsNotErrorPage = func(t *testing.T, body []byte) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.NotContains(t, string(body), "error page") // FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("invalid code in URL (too small)", func(t *testing.T) {
|
||||||
|
var status, body, _ = sendRequest(t, http.MethodGet, baseUrl+"/0.html")
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusNotFound, status)
|
||||||
|
assertIsNotErrorPage(t, body)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid code in URL (too big)", func(t *testing.T) {
|
||||||
|
var status, body, _ = sendRequest(t, http.MethodGet, baseUrl+"/1000.html")
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusNotFound, status)
|
||||||
|
assertIsNotErrorPage(t, body)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid code in URL (with a string suffix)", func(t *testing.T) {
|
||||||
|
var status, body, _ = sendRequest(t, http.MethodGet, baseUrl+"/404foobar.html")
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusNotFound, status)
|
||||||
|
assertIsNotErrorPage(t, body)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid code in URL (with a string prefix)", func(t *testing.T) {
|
||||||
|
var status, body, _ = sendRequest(t, http.MethodGet, baseUrl+"/foobar404.html")
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusNotFound, status)
|
||||||
|
assertIsNotErrorPage(t, body)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid code in URL (with a string)", func(t *testing.T) {
|
||||||
|
var status, body, _ = sendRequest(t, http.MethodGet, baseUrl+"/foobar.html")
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusNotFound, status)
|
||||||
|
assertIsNotErrorPage(t, body)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid HTTP methods", func(t *testing.T) {
|
||||||
|
for _, method := range []string{http.MethodDelete, http.MethodPatch, http.MethodPost, http.MethodPut} {
|
||||||
|
var status, body, _ = sendRequest(t, method, baseUrl+"/404.html")
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusMethodNotAllowed, status)
|
||||||
|
assertIsNotErrorPage(t, body)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("errors handling", func(t *testing.T) {
|
t.Run("errors handling", func(t *testing.T) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user