mirror of
https://github.com/tarampampam/error-pages.git
synced 2024-08-30 18:22:40 +00:00
Added possibility to disable error pages auto-localization (#94)
This commit is contained in:
parent
a3389aaafa
commit
d21a6f2797
@ -6,11 +6,16 @@ The format is based on [Keep a Changelog][keepachangelog] and this project adher
|
||||
|
||||
## UNRELEASED
|
||||
|
||||
### Added
|
||||
|
||||
- Possibility to disable error pages auto-localization (using `--disable-l10n` flag for the `serve` & `build` commands or environment variable `DISABLE_L10N`) [#91]
|
||||
|
||||
### Fixed
|
||||
|
||||
- User UID/GID changed to the numeric values in the dockerfile [#92]
|
||||
|
||||
[#92]:https://github.com/tarampampam/error-pages/issues/92
|
||||
[#91]:https://github.com/tarampampam/error-pages/issues/91
|
||||
|
||||
## v2.12.1
|
||||
|
||||
|
@ -68,7 +68,8 @@ ENV LISTEN_PORT="8080" \
|
||||
TEMPLATE_NAME="ghost" \
|
||||
DEFAULT_ERROR_PAGE="404" \
|
||||
DEFAULT_HTTP_CODE="404" \
|
||||
SHOW_DETAILS="false"
|
||||
SHOW_DETAILS="false" \
|
||||
DISABLE_L10N="false"
|
||||
|
||||
# Docs: <https://docs.docker.com/engine/reference/builder/#healthcheck>
|
||||
HEALTHCHECK --interval=7s --timeout=2s CMD ["/bin/error-pages", "healthcheck", "--log-json"]
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
func NewCommand(log *zap.Logger, configFile *string) *cobra.Command {
|
||||
var (
|
||||
generateIndex bool
|
||||
disableL10n bool
|
||||
cfg *config.Config
|
||||
)
|
||||
|
||||
@ -39,7 +40,7 @@ func NewCommand(log *zap.Logger, configFile *string) *cobra.Command {
|
||||
return errors.New("wrong arguments count")
|
||||
}
|
||||
|
||||
return run(log, cfg, args[0], generateIndex)
|
||||
return run(log, cfg, args[0], generateIndex, disableL10n)
|
||||
},
|
||||
}
|
||||
|
||||
@ -50,6 +51,13 @@ func NewCommand(log *zap.Logger, configFile *string) *cobra.Command {
|
||||
"generate index page",
|
||||
)
|
||||
|
||||
cmd.Flags().BoolVarP(
|
||||
&disableL10n,
|
||||
"disable-l10n", "",
|
||||
false,
|
||||
"disable error pages localization",
|
||||
)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -60,7 +68,7 @@ const (
|
||||
outDirPerm = os.FileMode(0775)
|
||||
)
|
||||
|
||||
func run(log *zap.Logger, cfg *config.Config, outDirectoryPath string, generateIndex bool) error { //nolint:funlen
|
||||
func run(log *zap.Logger, cfg *config.Config, outDirectoryPath string, generateIndex, disableL10n bool) error { //nolint:funlen,lll
|
||||
if len(cfg.Templates) == 0 {
|
||||
return errors.New("no loaded templates")
|
||||
}
|
||||
@ -92,6 +100,7 @@ func run(log *zap.Logger, cfg *config.Config, outDirectoryPath string, generateI
|
||||
Message: page.Message(),
|
||||
Description: page.Description(),
|
||||
ShowRequestDetails: false,
|
||||
L10nDisabled: disableL10n,
|
||||
})
|
||||
if renderingErr != nil {
|
||||
return renderingErr
|
||||
|
@ -30,7 +30,7 @@ func NewCommand(ctx context.Context, log *zap.Logger, configFile *string) *cobra
|
||||
return errors.New("path to the config file is required for this command")
|
||||
}
|
||||
|
||||
if err = f.overrideUsingEnv(cmd.Flags()); err != nil {
|
||||
if err = f.OverrideUsingEnv(cmd.Flags()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -38,18 +38,18 @@ func NewCommand(ctx context.Context, log *zap.Logger, configFile *string) *cobra
|
||||
return err
|
||||
}
|
||||
|
||||
return f.validate()
|
||||
return f.Validate()
|
||||
},
|
||||
RunE: func(*cobra.Command, []string) error { return run(ctx, log, f, cfg) },
|
||||
RunE: func(*cobra.Command, []string) error { return run(ctx, log, cfg, f) },
|
||||
}
|
||||
|
||||
f.init(cmd.Flags())
|
||||
f.Init(cmd.Flags())
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// run current command.
|
||||
func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config) error { //nolint:funlen
|
||||
func run(parentCtx context.Context, log *zap.Logger, cfg *config.Config, f flags) error { //nolint:funlen
|
||||
var (
|
||||
ctx, cancel = context.WithCancel(parentCtx) // serve context creation
|
||||
oss = breaker.NewOSSignals(ctx) // OS signals listener
|
||||
@ -70,9 +70,11 @@ func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config
|
||||
var (
|
||||
templateNames = cfg.TemplateNames()
|
||||
picker interface{ Pick() string }
|
||||
|
||||
opt = f.ToOptions()
|
||||
)
|
||||
|
||||
switch f.template.name {
|
||||
switch opt.Template.Name {
|
||||
case useRandomTemplate:
|
||||
log.Info("A random template will be used")
|
||||
|
||||
@ -99,28 +101,19 @@ func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config
|
||||
picker = pick.NewStringsSlice(templateNames, pick.First)
|
||||
|
||||
default:
|
||||
if t, found := cfg.Template(f.template.name); found {
|
||||
if t, found := cfg.Template(opt.Template.Name); found {
|
||||
log.Info("We will use the requested template", zap.String("name", t.Name()))
|
||||
picker = pick.NewStringsSlice([]string{t.Name()}, pick.First)
|
||||
} else {
|
||||
return errors.New("requested nonexistent template: " + f.template.name)
|
||||
return errors.New("requested nonexistent template: " + opt.Template.Name)
|
||||
}
|
||||
}
|
||||
|
||||
var proxyHTTPHeaders = f.HeadersToProxy()
|
||||
|
||||
// create HTTP server
|
||||
server := appHttp.NewServer(log)
|
||||
|
||||
// register server routes, middlewares, etc.
|
||||
if err := server.Register(
|
||||
cfg,
|
||||
picker,
|
||||
f.defaultErrorPage,
|
||||
f.defaultHTTPCode,
|
||||
f.showDetails,
|
||||
proxyHTTPHeaders,
|
||||
); err != nil {
|
||||
if err := server.Register(cfg, picker, opt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -131,15 +124,16 @@ func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config
|
||||
defer close(errCh)
|
||||
|
||||
log.Info("Server starting",
|
||||
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),
|
||||
zap.Strings("proxy headers", proxyHTTPHeaders),
|
||||
zap.Bool("show request details", f.showDetails),
|
||||
zap.String("addr", f.Listen.IP),
|
||||
zap.Uint16("port", f.Listen.Port),
|
||||
zap.String("default error page", opt.Default.PageCode),
|
||||
zap.Uint16("default HTTP response code", opt.Default.HTTPCode),
|
||||
zap.Strings("proxy headers", opt.ProxyHTTPHeaders),
|
||||
zap.Bool("show request details", opt.ShowDetails),
|
||||
zap.Bool("localization disabled", opt.L10n.Disabled),
|
||||
)
|
||||
|
||||
if err := server.Start(f.listen.ip, f.listen.port); err != nil {
|
||||
if err := server.Start(f.Listen.IP, f.Listen.Port); err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
}(startingErrCh)
|
||||
|
@ -9,60 +9,26 @@ import (
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/tarampampam/error-pages/internal/env"
|
||||
"github.com/tarampampam/error-pages/internal/options"
|
||||
)
|
||||
|
||||
type flags struct {
|
||||
listen struct {
|
||||
ip string
|
||||
port uint16
|
||||
Listen struct {
|
||||
IP string
|
||||
Port uint16
|
||||
}
|
||||
template struct {
|
||||
name string
|
||||
}
|
||||
l10n struct {
|
||||
disabled bool
|
||||
}
|
||||
defaultErrorPage string
|
||||
defaultHTTPCode uint16
|
||||
showDetails bool
|
||||
proxyHTTPHeaders string // comma-separated
|
||||
}
|
||||
|
||||
// HeadersToProxy converts a comma-separated string with headers list into strings slice (with a sorting and without
|
||||
// duplicates).
|
||||
func (f *flags) HeadersToProxy() []string {
|
||||
var raw = strings.Split(f.proxyHTTPHeaders, ",")
|
||||
|
||||
if len(raw) == 0 {
|
||||
return []string{}
|
||||
} else if len(raw) == 1 {
|
||||
if h := strings.TrimSpace(raw[0]); h != "" {
|
||||
return []string{h}
|
||||
} else {
|
||||
return []string{}
|
||||
}
|
||||
}
|
||||
|
||||
var m = make(map[string]struct{}, len(raw))
|
||||
|
||||
// make unique and ignore empty strings
|
||||
for _, h := range raw {
|
||||
if h = strings.TrimSpace(h); h != "" {
|
||||
if _, ok := m[h]; !ok {
|
||||
m[h] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// convert map into slice
|
||||
var headers = make([]string, 0, len(m))
|
||||
for h := range m {
|
||||
headers = append(headers, h)
|
||||
}
|
||||
|
||||
// make sort
|
||||
sort.Strings(headers)
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
const (
|
||||
listenFlagName = "listen"
|
||||
portFlagName = "port"
|
||||
@ -71,6 +37,7 @@ const (
|
||||
defaultHTTPCodeFlagName = "default-http-code"
|
||||
showDetailsFlagName = "show-details"
|
||||
proxyHTTPHeadersFlagName = "proxy-headers"
|
||||
disableL10nFlagName = "disable-l10n"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -80,18 +47,18 @@ const (
|
||||
useRandomTemplateHourly = "random-hourly"
|
||||
)
|
||||
|
||||
func (f *flags) init(flagSet *pflag.FlagSet) {
|
||||
func (f *flags) Init(flagSet *pflag.FlagSet) {
|
||||
flagSet.StringVarP(
|
||||
&f.listen.ip,
|
||||
&f.Listen.IP,
|
||||
listenFlagName, "l",
|
||||
"0.0.0.0",
|
||||
fmt.Sprintf("IP address to listen on [$%s]", env.ListenAddr),
|
||||
fmt.Sprintf("IP address to Listen on [$%s]", env.ListenAddr),
|
||||
)
|
||||
flagSet.Uint16VarP(
|
||||
&f.listen.port,
|
||||
&f.Listen.Port,
|
||||
portFlagName, "p",
|
||||
8080, //nolint:gomnd // must be same as default healthcheck `--port` flag value
|
||||
fmt.Sprintf("TCP port number [$%s]", env.ListenPort),
|
||||
fmt.Sprintf("TCP prt number [$%s]", env.ListenPort),
|
||||
)
|
||||
flagSet.StringVarP(
|
||||
&f.template.name,
|
||||
@ -131,22 +98,28 @@ func (f *flags) init(flagSet *pflag.FlagSet) {
|
||||
"",
|
||||
fmt.Sprintf("proxy HTTP request headers list (comma-separated) [$%s]", env.ProxyHTTPHeaders),
|
||||
)
|
||||
flagSet.BoolVarP(
|
||||
&f.l10n.disabled,
|
||||
disableL10nFlagName, "",
|
||||
false,
|
||||
fmt.Sprintf("disable error pages localization [$%s]", env.DisableL10n),
|
||||
)
|
||||
}
|
||||
|
||||
func (f *flags) overrideUsingEnv(flagSet *pflag.FlagSet) (lastErr error) { //nolint:gocognit,gocyclo
|
||||
func (f *flags) OverrideUsingEnv(flagSet *pflag.FlagSet) (lastErr error) { //nolint:gocognit,gocyclo
|
||||
flagSet.VisitAll(func(flag *pflag.Flag) {
|
||||
// flag was NOT defined using CLI (flags should have maximal priority)
|
||||
if !flag.Changed { //nolint:nestif
|
||||
switch flag.Name {
|
||||
case listenFlagName:
|
||||
if envVar, exists := env.ListenAddr.Lookup(); exists {
|
||||
f.listen.ip = strings.TrimSpace(envVar)
|
||||
f.Listen.IP = strings.TrimSpace(envVar)
|
||||
}
|
||||
|
||||
case portFlagName:
|
||||
if envVar, exists := env.ListenPort.Lookup(); exists {
|
||||
if p, err := strconv.ParseUint(envVar, 10, 16); err == nil { //nolint:gomnd
|
||||
f.listen.port = uint16(p)
|
||||
f.Listen.Port = uint16(p)
|
||||
} else {
|
||||
lastErr = fmt.Errorf("wrong TCP port environment variable [%s] value", envVar)
|
||||
}
|
||||
@ -182,6 +155,13 @@ func (f *flags) overrideUsingEnv(flagSet *pflag.FlagSet) (lastErr error) { //nol
|
||||
if envVar, exists := env.ProxyHTTPHeaders.Lookup(); exists {
|
||||
f.proxyHTTPHeaders = strings.TrimSpace(envVar)
|
||||
}
|
||||
|
||||
case disableL10nFlagName:
|
||||
if envVar, exists := env.DisableL10n.Lookup(); exists {
|
||||
if b, err := strconv.ParseBool(envVar); err == nil {
|
||||
f.l10n.disabled = b
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -189,9 +169,9 @@ func (f *flags) overrideUsingEnv(flagSet *pflag.FlagSet) (lastErr error) { //nol
|
||||
return lastErr
|
||||
}
|
||||
|
||||
func (f *flags) validate() error {
|
||||
if net.ParseIP(f.listen.ip) == nil {
|
||||
return fmt.Errorf("wrong IP address [%s] for listening", f.listen.ip)
|
||||
func (f *flags) Validate() error {
|
||||
if net.ParseIP(f.Listen.IP) == nil {
|
||||
return fmt.Errorf("wrong IP address [%s] for listening", f.Listen.IP)
|
||||
}
|
||||
|
||||
if f.defaultHTTPCode > 599 { //nolint:gomnd
|
||||
@ -204,3 +184,52 @@ func (f *flags) validate() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// headersToProxy converts a comma-separated string with headers list into strings slice (with a sorting and without
|
||||
// duplicates).
|
||||
func (f *flags) headersToProxy() []string {
|
||||
var raw = strings.Split(f.proxyHTTPHeaders, ",")
|
||||
|
||||
if len(raw) == 0 {
|
||||
return []string{}
|
||||
} else if len(raw) == 1 {
|
||||
if h := strings.TrimSpace(raw[0]); h != "" {
|
||||
return []string{h}
|
||||
} else {
|
||||
return []string{}
|
||||
}
|
||||
}
|
||||
|
||||
var m = make(map[string]struct{}, len(raw))
|
||||
|
||||
// make unique and ignore empty strings
|
||||
for _, h := range raw {
|
||||
if h = strings.TrimSpace(h); h != "" {
|
||||
if _, ok := m[h]; !ok {
|
||||
m[h] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// convert map into slice
|
||||
var headers = make([]string, 0, len(m))
|
||||
for h := range m {
|
||||
headers = append(headers, h)
|
||||
}
|
||||
|
||||
// make sort
|
||||
sort.Strings(headers)
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
func (f *flags) ToOptions() (o options.ErrorPage) {
|
||||
o.Default.PageCode = f.defaultErrorPage
|
||||
o.Default.HTTPCode = f.defaultHTTPCode
|
||||
o.L10n.Disabled = f.l10n.disabled
|
||||
o.Template.Name = f.template.name
|
||||
o.ShowDetails = f.showDetails
|
||||
o.ProxyHTTPHeaders = f.headersToProxy()
|
||||
|
||||
return o
|
||||
}
|
||||
|
1
internal/env/env.go
vendored
1
internal/env/env.go
vendored
@ -14,6 +14,7 @@ const (
|
||||
DefaultHTTPCode envVariable = "DEFAULT_HTTP_CODE" // default HTTP response code
|
||||
ShowDetails envVariable = "SHOW_DETAILS" // show request details in response
|
||||
ProxyHTTPHeaders envVariable = "PROXY_HTTP_HEADERS" // proxy HTTP request headers list (request -> response)
|
||||
DisableL10n envVariable = "DISABLE_L10N" // disable pages localization
|
||||
)
|
||||
|
||||
// String returns environment variable name in the string representation.
|
||||
|
2
internal/env/env_test.go
vendored
2
internal/env/env_test.go
vendored
@ -16,6 +16,7 @@ func TestConstants(t *testing.T) {
|
||||
assert.Equal(t, "DEFAULT_HTTP_CODE", string(DefaultHTTPCode))
|
||||
assert.Equal(t, "SHOW_DETAILS", string(ShowDetails))
|
||||
assert.Equal(t, "PROXY_HTTP_HEADERS", string(ProxyHTTPHeaders))
|
||||
assert.Equal(t, "DISABLE_L10N", string(DisableL10n))
|
||||
}
|
||||
|
||||
func TestEnvVariable_Lookup(t *testing.T) {
|
||||
@ -30,6 +31,7 @@ func TestEnvVariable_Lookup(t *testing.T) {
|
||||
{giveEnv: DefaultHTTPCode},
|
||||
{giveEnv: ShowDetails},
|
||||
{giveEnv: ProxyHTTPHeaders},
|
||||
{giveEnv: DisableL10n},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/tarampampam/error-pages/internal/config"
|
||||
"github.com/tarampampam/error-pages/internal/options"
|
||||
"github.com/tarampampam/error-pages/internal/tpl"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
@ -24,8 +25,7 @@ func RespondWithErrorPage( //nolint:funlen,gocyclo
|
||||
rdr renderer,
|
||||
pageCode string,
|
||||
httpCode int,
|
||||
showRequestDetails bool,
|
||||
proxyHeaders []string,
|
||||
opt options.ErrorPage,
|
||||
) {
|
||||
ctx.Response.Header.Set("X-Robots-Tag", "noindex") // block Search indexing
|
||||
|
||||
@ -33,10 +33,14 @@ func RespondWithErrorPage( //nolint:funlen,gocyclo
|
||||
clientWant = ClientWantFormat(ctx)
|
||||
json, canJSON = cfg.JSONFormat()
|
||||
xml, canXML = cfg.XMLFormat()
|
||||
props = tpl.Properties{Code: pageCode, ShowRequestDetails: showRequestDetails}
|
||||
props = tpl.Properties{
|
||||
Code: pageCode,
|
||||
ShowRequestDetails: opt.ShowDetails,
|
||||
L10nDisabled: opt.L10n.Disabled,
|
||||
}
|
||||
)
|
||||
|
||||
if showRequestDetails {
|
||||
if opt.ShowDetails {
|
||||
props.OriginalURI = string(ctx.Request.Header.Peek(OriginalURI))
|
||||
props.Namespace = string(ctx.Request.Header.Peek(Namespace))
|
||||
props.IngressName = string(ctx.Request.Header.Peek(IngressName))
|
||||
@ -66,7 +70,7 @@ func RespondWithErrorPage( //nolint:funlen,gocyclo
|
||||
}
|
||||
|
||||
// proxy required HTTP headers from the request to the response
|
||||
for _, headerToProxy := range proxyHeaders {
|
||||
for _, headerToProxy := range opt.ProxyHTTPHeaders {
|
||||
if reqHeader := ctx.Request.Header.Peek(headerToProxy); len(reqHeader) > 0 {
|
||||
ctx.Response.Header.SetBytesV(headerToProxy, reqHeader)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package errorpage
|
||||
import (
|
||||
"github.com/tarampampam/error-pages/internal/config"
|
||||
"github.com/tarampampam/error-pages/internal/http/core"
|
||||
"github.com/tarampampam/error-pages/internal/options"
|
||||
"github.com/tarampampam/error-pages/internal/tpl"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
@ -19,18 +20,12 @@ type (
|
||||
)
|
||||
|
||||
// NewHandler creates handler for error pages serving.
|
||||
func NewHandler(
|
||||
cfg *config.Config,
|
||||
p templatePicker,
|
||||
rdr renderer,
|
||||
showRequestDetails bool,
|
||||
proxyHTTPHeaders []string,
|
||||
) fasthttp.RequestHandler {
|
||||
func NewHandler(cfg *config.Config, p templatePicker, rdr renderer, opt options.ErrorPage) fasthttp.RequestHandler {
|
||||
return func(ctx *fasthttp.RequestCtx) {
|
||||
core.SetClientFormat(ctx, core.PlainTextContentType) // default content type
|
||||
|
||||
if code, ok := ctx.UserValue("code").(string); ok {
|
||||
core.RespondWithErrorPage(ctx, cfg, p, rdr, code, fasthttp.StatusOK, showRequestDetails, proxyHTTPHeaders)
|
||||
core.RespondWithErrorPage(ctx, cfg, p, rdr, code, fasthttp.StatusOK, opt)
|
||||
} else { // will never occur
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
_, _ = ctx.WriteString("cannot extract requested code from the request")
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/tarampampam/error-pages/internal/config"
|
||||
"github.com/tarampampam/error-pages/internal/http/core"
|
||||
"github.com/tarampampam/error-pages/internal/options"
|
||||
"github.com/tarampampam/error-pages/internal/tpl"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
@ -21,23 +22,15 @@ type (
|
||||
)
|
||||
|
||||
// NewHandler creates handler for the index page serving.
|
||||
func NewHandler(
|
||||
cfg *config.Config,
|
||||
p templatePicker,
|
||||
rdr renderer,
|
||||
defaultPageCode string,
|
||||
defaultHTTPCode uint16,
|
||||
showRequestDetails bool,
|
||||
proxyHTTPHeaders []string,
|
||||
) fasthttp.RequestHandler {
|
||||
func NewHandler(cfg *config.Config, p templatePicker, rdr renderer, opt options.ErrorPage) fasthttp.RequestHandler {
|
||||
return func(ctx *fasthttp.RequestCtx) {
|
||||
pageCode, httpCode := defaultPageCode, int(defaultHTTPCode)
|
||||
pageCode, httpCode := opt.Default.PageCode, int(opt.Default.HTTPCode)
|
||||
|
||||
if returnCode, ok := extractCodeToReturn(ctx); ok {
|
||||
pageCode, httpCode = strconv.Itoa(returnCode), returnCode
|
||||
}
|
||||
|
||||
core.RespondWithErrorPage(ctx, cfg, p, rdr, pageCode, httpCode, showRequestDetails, proxyHTTPHeaders)
|
||||
core.RespondWithErrorPage(ctx, cfg, p, rdr, pageCode, httpCode, opt)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
notfoundHandler "github.com/tarampampam/error-pages/internal/http/handlers/notfound"
|
||||
versionHandler "github.com/tarampampam/error-pages/internal/http/handlers/version"
|
||||
"github.com/tarampampam/error-pages/internal/metrics"
|
||||
"github.com/tarampampam/error-pages/internal/options"
|
||||
"github.com/tarampampam/error-pages/internal/tpl"
|
||||
"github.com/tarampampam/error-pages/internal/version"
|
||||
"github.com/valyala/fasthttp"
|
||||
@ -66,14 +67,7 @@ type templatePicker interface {
|
||||
|
||||
// Register server routes, middlewares, etc.
|
||||
// Router docs: <https://github.com/fasthttp/router>
|
||||
func (s *Server) Register(
|
||||
cfg *config.Config,
|
||||
templatePicker templatePicker,
|
||||
defaultPageCode string,
|
||||
defaultHTTPCode uint16,
|
||||
showDetails bool,
|
||||
proxyHTTPHeaders []string,
|
||||
) error {
|
||||
func (s *Server) Register(cfg *config.Config, templatePicker templatePicker, opt options.ErrorPage) error {
|
||||
reg, m := metrics.NewRegistry(), metrics.NewMetrics()
|
||||
|
||||
if err := m.Register(reg); err != nil {
|
||||
@ -82,8 +76,9 @@ func (s *Server) Register(
|
||||
|
||||
s.fast.Handler = common.DurationMetrics(common.LogRequest(s.router.Handler, s.log), &m)
|
||||
|
||||
s.router.GET("/", indexHandler.NewHandler(cfg, templatePicker, s.rdr, defaultPageCode, defaultHTTPCode, showDetails, proxyHTTPHeaders)) //nolint:lll
|
||||
s.router.GET("/{code}.html", errorpageHandler.NewHandler(cfg, templatePicker, s.rdr, showDetails, proxyHTTPHeaders)) //nolint:lll
|
||||
s.router.GET("/", indexHandler.NewHandler(cfg, templatePicker, s.rdr, opt))
|
||||
s.router.GET("/{code}.html", errorpageHandler.NewHandler(cfg, templatePicker, s.rdr, opt))
|
||||
|
||||
s.router.GET("/version", versionHandler.NewHandler(version.Version()))
|
||||
|
||||
liveHandler := healthzHandler.NewHandler(checkers.NewLiveChecker())
|
||||
|
16
internal/options/errorpage.go
Normal file
16
internal/options/errorpage.go
Normal file
@ -0,0 +1,16 @@
|
||||
package options
|
||||
|
||||
type ErrorPage struct {
|
||||
Default struct {
|
||||
PageCode string // default error page code
|
||||
HTTPCode uint16 // default HTTP response code
|
||||
}
|
||||
L10n struct {
|
||||
Disabled bool // disable error pages localization
|
||||
}
|
||||
Template struct {
|
||||
Name string // template name
|
||||
}
|
||||
ShowDetails bool // show request details in response
|
||||
ProxyHTTPHeaders []string // proxy HTTP request headers list
|
||||
}
|
@ -16,6 +16,7 @@ type Properties struct { // only string properties with a "token" tag, please
|
||||
RequestID string `token:"request_id"`
|
||||
ForwardedFor string `token:"forwarded_for"`
|
||||
Host string `token:"host"`
|
||||
L10nDisabled bool
|
||||
ShowRequestDetails bool
|
||||
}
|
||||
|
||||
|
@ -142,6 +142,8 @@ func (tr *TemplateRenderer) Render(content []byte, props Properties) ([]byte, er
|
||||
var funcMap = template.FuncMap{
|
||||
"show_details": func() bool { return props.ShowRequestDetails },
|
||||
"hide_details": func() bool { return !props.ShowRequestDetails },
|
||||
"l10n_disabled": func() bool { return props.L10nDisabled },
|
||||
"l10n_enabled": func() bool { return !props.L10nDisabled },
|
||||
}
|
||||
|
||||
// make a copy of template functions map
|
||||
|
@ -56,6 +56,17 @@ func Test_Render(t *testing.T) {
|
||||
giveProps: tpl.Properties{Code: "201", Message: "lorem ipsum"},
|
||||
wantContent: `{"code": "201", "message": {"here":[ " Yeah " ]}}`,
|
||||
},
|
||||
|
||||
"fn l10n_enabled": {
|
||||
giveContent: "{{ if l10n_enabled }}Y{{ else }}N{{ end }}",
|
||||
giveProps: tpl.Properties{L10nDisabled: true},
|
||||
wantContent: "N",
|
||||
},
|
||||
"fn l10n_disabled": {
|
||||
giveContent: "{{ if l10n_disabled }}Y{{ else }}N{{ end }}",
|
||||
giveProps: tpl.Properties{L10nDisabled: true},
|
||||
wantContent: "Y",
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
content, err := renderer.Render([]byte(tt.giveContent), tt.giveProps)
|
||||
|
@ -225,6 +225,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
// {{ if l10n_enabled }}
|
||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
||||
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
|
||||
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
|
||||
@ -233,6 +234,7 @@
|
||||
p.appendChild(s);
|
||||
})(document.createElement('script'), document.body);
|
||||
}
|
||||
// {{ end }}
|
||||
</script>
|
||||
</body>
|
||||
<!--
|
||||
|
@ -104,6 +104,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// {{ if l10n_enabled }}
|
||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
||||
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
|
||||
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
|
||||
@ -112,6 +113,7 @@
|
||||
p.appendChild(s);
|
||||
})(document.createElement('script'), document.body);
|
||||
}
|
||||
// {{ end }}
|
||||
</script>
|
||||
</body>
|
||||
<!--
|
||||
|
@ -254,6 +254,7 @@
|
||||
console.warn('Cannot parse the error code:', errorCode);
|
||||
}
|
||||
|
||||
// {{ if l10n_enabled }}
|
||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
||||
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
|
||||
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
|
||||
@ -262,6 +263,7 @@
|
||||
p.appendChild(s);
|
||||
})(document.createElement('script'), document.body);
|
||||
}
|
||||
// {{ end }}
|
||||
</script>
|
||||
<!--
|
||||
Error {{ code }}: {{ message }}
|
||||
|
@ -98,6 +98,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// {{ if l10n_enabled }}
|
||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
||||
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
|
||||
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
|
||||
@ -106,6 +107,7 @@
|
||||
p.appendChild(s);
|
||||
})(document.createElement('script'), document.body);
|
||||
}
|
||||
// {{ end }}
|
||||
</script>
|
||||
</body>
|
||||
<!--
|
||||
|
@ -163,6 +163,7 @@
|
||||
{{ end }}
|
||||
</div>
|
||||
<script>
|
||||
// {{ if l10n_enabled }}
|
||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
||||
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
|
||||
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
|
||||
@ -171,6 +172,7 @@
|
||||
p.appendChild(s);
|
||||
})(document.createElement('script'), document.body);
|
||||
}
|
||||
// {{ end }}
|
||||
</script>
|
||||
</body>
|
||||
<!--
|
||||
|
@ -82,6 +82,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// {{ if l10n_enabled }}
|
||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
||||
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
|
||||
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
|
||||
@ -90,6 +91,7 @@
|
||||
p.appendChild(s);
|
||||
})(document.createElement('script'), document.body);
|
||||
}
|
||||
// {{ end }}
|
||||
</script>
|
||||
</body>
|
||||
<!--
|
||||
|
@ -84,6 +84,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// {{ if l10n_enabled }}
|
||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
||||
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
|
||||
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
|
||||
@ -92,6 +93,7 @@
|
||||
p.appendChild(s);
|
||||
})(document.createElement('script'), document.body);
|
||||
}
|
||||
// {{ end }}
|
||||
</script>
|
||||
</body>
|
||||
<!--
|
||||
|
@ -378,6 +378,7 @@
|
||||
console.warn('gsap library is not initialized (network error?)')
|
||||
}
|
||||
|
||||
// {{ if l10n_enabled }}
|
||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
||||
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
|
||||
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
|
||||
@ -386,6 +387,7 @@
|
||||
p.appendChild(s);
|
||||
})(document.createElement('script'), document.body);
|
||||
}
|
||||
// {{ end }}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
@ -262,6 +262,7 @@
|
||||
|
||||
(new Matrix(document.getElementById('matrix'))).run(document.getElementById('matrix-words'));
|
||||
|
||||
// {{ if l10n_enabled }}
|
||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
||||
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
|
||||
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
|
||||
@ -270,6 +271,7 @@
|
||||
p.appendChild(s);
|
||||
})(document.createElement('script'), document.body);
|
||||
}
|
||||
// {{ end }}
|
||||
</script>
|
||||
</body>
|
||||
<!--
|
||||
|
@ -175,6 +175,7 @@
|
||||
window.clearInterval(flickerInterval);
|
||||
});
|
||||
|
||||
// {{ if l10n_enabled }}
|
||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
||||
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
|
||||
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
|
||||
@ -183,6 +184,7 @@
|
||||
p.appendChild(s);
|
||||
})(document.createElement('script'), document.body);
|
||||
}
|
||||
// {{ end }}
|
||||
</script>
|
||||
</body>
|
||||
<!--
|
||||
|
@ -11,7 +11,7 @@ Creating templates is a very simple operation, even for those who know nothing a
|
||||
### Error page & request data
|
||||
|
||||
| Signature | Description | Example |
|
||||
|-------------------------------------|---------------------------------------------------------------|----------------------------------------------|
|
||||
|--------------------------------------|---------------------------------------------------------------|----------------------------------------------|
|
||||
| `{{ code }}` | Error page code | `404` |
|
||||
| `{{ message }}` | Error code message | `Not found` |
|
||||
| `{{ description }}` | Error code description | `The server can not find the requested page` |
|
||||
@ -28,6 +28,8 @@ Creating templates is a very simple operation, even for those who know nothing a
|
||||
| `{{ version }}` | Application version | `2.5.0` |
|
||||
| `{{ if show_details }}...{{ end }}` | Logical operator (server started with "show details" option?) | |
|
||||
| `{{ if hide_details }}...{{ end }}` | Same as above, but inverted | |
|
||||
| `{{ if l10n_enabled }}...{{ end }}` | Logical operator (l10n is enabled?) | |
|
||||
| `{{ if l10n_disabled }}...{{ end }}` | Same as above, but inverted | |
|
||||
|
||||
### Modifiers
|
||||
|
||||
|
@ -215,6 +215,7 @@
|
||||
}, 550);
|
||||
// {{ end }}
|
||||
|
||||
// {{ if l10n_enabled }}
|
||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
||||
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
|
||||
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
|
||||
@ -223,6 +224,7 @@
|
||||
p.appendChild(s);
|
||||
})(document.createElement('script'), document.body);
|
||||
}
|
||||
// {{ end }}
|
||||
</script>
|
||||
</body>
|
||||
<!--
|
||||
|
Loading…
Reference in New Issue
Block a user