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
|
## 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
|
### Fixed
|
||||||
|
|
||||||
- User UID/GID changed to the numeric values in the dockerfile [#92]
|
- User UID/GID changed to the numeric values in the dockerfile [#92]
|
||||||
|
|
||||||
[#92]:https://github.com/tarampampam/error-pages/issues/92
|
[#92]:https://github.com/tarampampam/error-pages/issues/92
|
||||||
|
[#91]:https://github.com/tarampampam/error-pages/issues/91
|
||||||
|
|
||||||
## v2.12.1
|
## v2.12.1
|
||||||
|
|
||||||
|
@ -68,7 +68,8 @@ ENV LISTEN_PORT="8080" \
|
|||||||
TEMPLATE_NAME="ghost" \
|
TEMPLATE_NAME="ghost" \
|
||||||
DEFAULT_ERROR_PAGE="404" \
|
DEFAULT_ERROR_PAGE="404" \
|
||||||
DEFAULT_HTTP_CODE="404" \
|
DEFAULT_HTTP_CODE="404" \
|
||||||
SHOW_DETAILS="false"
|
SHOW_DETAILS="false" \
|
||||||
|
DISABLE_L10N="false"
|
||||||
|
|
||||||
# Docs: <https://docs.docker.com/engine/reference/builder/#healthcheck>
|
# Docs: <https://docs.docker.com/engine/reference/builder/#healthcheck>
|
||||||
HEALTHCHECK --interval=7s --timeout=2s CMD ["/bin/error-pages", "healthcheck", "--log-json"]
|
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 {
|
func NewCommand(log *zap.Logger, configFile *string) *cobra.Command {
|
||||||
var (
|
var (
|
||||||
generateIndex bool
|
generateIndex bool
|
||||||
|
disableL10n bool
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,7 +40,7 @@ func NewCommand(log *zap.Logger, configFile *string) *cobra.Command {
|
|||||||
return errors.New("wrong arguments count")
|
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",
|
"generate index page",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cmd.Flags().BoolVarP(
|
||||||
|
&disableL10n,
|
||||||
|
"disable-l10n", "",
|
||||||
|
false,
|
||||||
|
"disable error pages localization",
|
||||||
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +68,7 @@ const (
|
|||||||
outDirPerm = os.FileMode(0775)
|
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 {
|
if len(cfg.Templates) == 0 {
|
||||||
return errors.New("no loaded templates")
|
return errors.New("no loaded templates")
|
||||||
}
|
}
|
||||||
@ -92,6 +100,7 @@ func run(log *zap.Logger, cfg *config.Config, outDirectoryPath string, generateI
|
|||||||
Message: page.Message(),
|
Message: page.Message(),
|
||||||
Description: page.Description(),
|
Description: page.Description(),
|
||||||
ShowRequestDetails: false,
|
ShowRequestDetails: false,
|
||||||
|
L10nDisabled: disableL10n,
|
||||||
})
|
})
|
||||||
if renderingErr != nil {
|
if renderingErr != nil {
|
||||||
return renderingErr
|
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")
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,18 +38,18 @@ func NewCommand(ctx context.Context, log *zap.Logger, configFile *string) *cobra
|
|||||||
return err
|
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
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// run current command.
|
// 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 (
|
var (
|
||||||
ctx, cancel = context.WithCancel(parentCtx) // serve context creation
|
ctx, cancel = context.WithCancel(parentCtx) // serve context creation
|
||||||
oss = breaker.NewOSSignals(ctx) // OS signals listener
|
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 (
|
var (
|
||||||
templateNames = cfg.TemplateNames()
|
templateNames = cfg.TemplateNames()
|
||||||
picker interface{ Pick() string }
|
picker interface{ Pick() string }
|
||||||
|
|
||||||
|
opt = f.ToOptions()
|
||||||
)
|
)
|
||||||
|
|
||||||
switch f.template.name {
|
switch opt.Template.Name {
|
||||||
case useRandomTemplate:
|
case useRandomTemplate:
|
||||||
log.Info("A random template will be used")
|
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)
|
picker = pick.NewStringsSlice(templateNames, pick.First)
|
||||||
|
|
||||||
default:
|
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()))
|
log.Info("We will use the requested template", zap.String("name", t.Name()))
|
||||||
picker = pick.NewStringsSlice([]string{t.Name()}, pick.First)
|
picker = pick.NewStringsSlice([]string{t.Name()}, pick.First)
|
||||||
} else {
|
} 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
|
// create HTTP server
|
||||||
server := appHttp.NewServer(log)
|
server := appHttp.NewServer(log)
|
||||||
|
|
||||||
// register server routes, middlewares, etc.
|
// register server routes, middlewares, etc.
|
||||||
if err := server.Register(
|
if err := server.Register(cfg, picker, opt); err != nil {
|
||||||
cfg,
|
|
||||||
picker,
|
|
||||||
f.defaultErrorPage,
|
|
||||||
f.defaultHTTPCode,
|
|
||||||
f.showDetails,
|
|
||||||
proxyHTTPHeaders,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,15 +124,16 @@ func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config
|
|||||||
defer close(errCh)
|
defer close(errCh)
|
||||||
|
|
||||||
log.Info("Server starting",
|
log.Info("Server starting",
|
||||||
zap.String("addr", f.listen.ip),
|
zap.String("addr", f.Listen.IP),
|
||||||
zap.Uint16("port", f.listen.port),
|
zap.Uint16("port", f.Listen.Port),
|
||||||
zap.String("default error page", f.defaultErrorPage),
|
zap.String("default error page", opt.Default.PageCode),
|
||||||
zap.Uint16("default HTTP response code", f.defaultHTTPCode),
|
zap.Uint16("default HTTP response code", opt.Default.HTTPCode),
|
||||||
zap.Strings("proxy headers", proxyHTTPHeaders),
|
zap.Strings("proxy headers", opt.ProxyHTTPHeaders),
|
||||||
zap.Bool("show request details", f.showDetails),
|
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
|
errCh <- err
|
||||||
}
|
}
|
||||||
}(startingErrCh)
|
}(startingErrCh)
|
||||||
|
@ -9,60 +9,26 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"github.com/tarampampam/error-pages/internal/env"
|
"github.com/tarampampam/error-pages/internal/env"
|
||||||
|
"github.com/tarampampam/error-pages/internal/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
type flags struct {
|
type flags struct {
|
||||||
listen struct {
|
Listen struct {
|
||||||
ip string
|
IP string
|
||||||
port uint16
|
Port uint16
|
||||||
}
|
}
|
||||||
template struct {
|
template struct {
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
l10n struct {
|
||||||
|
disabled bool
|
||||||
|
}
|
||||||
defaultErrorPage string
|
defaultErrorPage string
|
||||||
defaultHTTPCode uint16
|
defaultHTTPCode uint16
|
||||||
showDetails bool
|
showDetails bool
|
||||||
proxyHTTPHeaders string // comma-separated
|
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 (
|
const (
|
||||||
listenFlagName = "listen"
|
listenFlagName = "listen"
|
||||||
portFlagName = "port"
|
portFlagName = "port"
|
||||||
@ -71,6 +37,7 @@ const (
|
|||||||
defaultHTTPCodeFlagName = "default-http-code"
|
defaultHTTPCodeFlagName = "default-http-code"
|
||||||
showDetailsFlagName = "show-details"
|
showDetailsFlagName = "show-details"
|
||||||
proxyHTTPHeadersFlagName = "proxy-headers"
|
proxyHTTPHeadersFlagName = "proxy-headers"
|
||||||
|
disableL10nFlagName = "disable-l10n"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -80,18 +47,18 @@ const (
|
|||||||
useRandomTemplateHourly = "random-hourly"
|
useRandomTemplateHourly = "random-hourly"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f *flags) init(flagSet *pflag.FlagSet) {
|
func (f *flags) Init(flagSet *pflag.FlagSet) {
|
||||||
flagSet.StringVarP(
|
flagSet.StringVarP(
|
||||||
&f.listen.ip,
|
&f.Listen.IP,
|
||||||
listenFlagName, "l",
|
listenFlagName, "l",
|
||||||
"0.0.0.0",
|
"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(
|
flagSet.Uint16VarP(
|
||||||
&f.listen.port,
|
&f.Listen.Port,
|
||||||
portFlagName, "p",
|
portFlagName, "p",
|
||||||
8080, //nolint:gomnd // must be same as default healthcheck `--port` flag value
|
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(
|
flagSet.StringVarP(
|
||||||
&f.template.name,
|
&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),
|
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) {
|
flagSet.VisitAll(func(flag *pflag.Flag) {
|
||||||
// flag was NOT defined using CLI (flags should have maximal priority)
|
// flag was NOT defined using CLI (flags should have maximal priority)
|
||||||
if !flag.Changed { //nolint:nestif
|
if !flag.Changed { //nolint:nestif
|
||||||
switch flag.Name {
|
switch flag.Name {
|
||||||
case listenFlagName:
|
case listenFlagName:
|
||||||
if envVar, exists := env.ListenAddr.Lookup(); exists {
|
if envVar, exists := env.ListenAddr.Lookup(); exists {
|
||||||
f.listen.ip = strings.TrimSpace(envVar)
|
f.Listen.IP = strings.TrimSpace(envVar)
|
||||||
}
|
}
|
||||||
|
|
||||||
case portFlagName:
|
case portFlagName:
|
||||||
if envVar, exists := env.ListenPort.Lookup(); exists {
|
if envVar, exists := env.ListenPort.Lookup(); exists {
|
||||||
if p, err := strconv.ParseUint(envVar, 10, 16); err == nil { //nolint:gomnd
|
if p, err := strconv.ParseUint(envVar, 10, 16); err == nil { //nolint:gomnd
|
||||||
f.listen.port = uint16(p)
|
f.Listen.Port = uint16(p)
|
||||||
} else {
|
} else {
|
||||||
lastErr = fmt.Errorf("wrong TCP port environment variable [%s] value", envVar)
|
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 {
|
if envVar, exists := env.ProxyHTTPHeaders.Lookup(); exists {
|
||||||
f.proxyHTTPHeaders = strings.TrimSpace(envVar)
|
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
|
return lastErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *flags) validate() error {
|
func (f *flags) Validate() error {
|
||||||
if net.ParseIP(f.listen.ip) == nil {
|
if net.ParseIP(f.Listen.IP) == nil {
|
||||||
return fmt.Errorf("wrong IP address [%s] for listening", f.listen.ip)
|
return fmt.Errorf("wrong IP address [%s] for listening", f.Listen.IP)
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.defaultHTTPCode > 599 { //nolint:gomnd
|
if f.defaultHTTPCode > 599 { //nolint:gomnd
|
||||||
@ -204,3 +184,52 @@ func (f *flags) validate() error {
|
|||||||
|
|
||||||
return nil
|
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
|
DefaultHTTPCode envVariable = "DEFAULT_HTTP_CODE" // default HTTP response code
|
||||||
ShowDetails envVariable = "SHOW_DETAILS" // show request details in response
|
ShowDetails envVariable = "SHOW_DETAILS" // show request details in response
|
||||||
ProxyHTTPHeaders envVariable = "PROXY_HTTP_HEADERS" // proxy HTTP request headers list (request -> 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.
|
// 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, "DEFAULT_HTTP_CODE", string(DefaultHTTPCode))
|
||||||
assert.Equal(t, "SHOW_DETAILS", string(ShowDetails))
|
assert.Equal(t, "SHOW_DETAILS", string(ShowDetails))
|
||||||
assert.Equal(t, "PROXY_HTTP_HEADERS", string(ProxyHTTPHeaders))
|
assert.Equal(t, "PROXY_HTTP_HEADERS", string(ProxyHTTPHeaders))
|
||||||
|
assert.Equal(t, "DISABLE_L10N", string(DisableL10n))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEnvVariable_Lookup(t *testing.T) {
|
func TestEnvVariable_Lookup(t *testing.T) {
|
||||||
@ -30,6 +31,7 @@ func TestEnvVariable_Lookup(t *testing.T) {
|
|||||||
{giveEnv: DefaultHTTPCode},
|
{giveEnv: DefaultHTTPCode},
|
||||||
{giveEnv: ShowDetails},
|
{giveEnv: ShowDetails},
|
||||||
{giveEnv: ProxyHTTPHeaders},
|
{giveEnv: ProxyHTTPHeaders},
|
||||||
|
{giveEnv: DisableL10n},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range cases {
|
for _, tt := range cases {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/tarampampam/error-pages/internal/config"
|
"github.com/tarampampam/error-pages/internal/config"
|
||||||
|
"github.com/tarampampam/error-pages/internal/options"
|
||||||
"github.com/tarampampam/error-pages/internal/tpl"
|
"github.com/tarampampam/error-pages/internal/tpl"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
)
|
)
|
||||||
@ -24,8 +25,7 @@ func RespondWithErrorPage( //nolint:funlen,gocyclo
|
|||||||
rdr renderer,
|
rdr renderer,
|
||||||
pageCode string,
|
pageCode string,
|
||||||
httpCode int,
|
httpCode int,
|
||||||
showRequestDetails bool,
|
opt options.ErrorPage,
|
||||||
proxyHeaders []string,
|
|
||||||
) {
|
) {
|
||||||
ctx.Response.Header.Set("X-Robots-Tag", "noindex") // block Search indexing
|
ctx.Response.Header.Set("X-Robots-Tag", "noindex") // block Search indexing
|
||||||
|
|
||||||
@ -33,10 +33,14 @@ func RespondWithErrorPage( //nolint:funlen,gocyclo
|
|||||||
clientWant = ClientWantFormat(ctx)
|
clientWant = ClientWantFormat(ctx)
|
||||||
json, canJSON = cfg.JSONFormat()
|
json, canJSON = cfg.JSONFormat()
|
||||||
xml, canXML = cfg.XMLFormat()
|
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.OriginalURI = string(ctx.Request.Header.Peek(OriginalURI))
|
||||||
props.Namespace = string(ctx.Request.Header.Peek(Namespace))
|
props.Namespace = string(ctx.Request.Header.Peek(Namespace))
|
||||||
props.IngressName = string(ctx.Request.Header.Peek(IngressName))
|
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
|
// 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 {
|
if reqHeader := ctx.Request.Header.Peek(headerToProxy); len(reqHeader) > 0 {
|
||||||
ctx.Response.Header.SetBytesV(headerToProxy, reqHeader)
|
ctx.Response.Header.SetBytesV(headerToProxy, reqHeader)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package errorpage
|
|||||||
import (
|
import (
|
||||||
"github.com/tarampampam/error-pages/internal/config"
|
"github.com/tarampampam/error-pages/internal/config"
|
||||||
"github.com/tarampampam/error-pages/internal/http/core"
|
"github.com/tarampampam/error-pages/internal/http/core"
|
||||||
|
"github.com/tarampampam/error-pages/internal/options"
|
||||||
"github.com/tarampampam/error-pages/internal/tpl"
|
"github.com/tarampampam/error-pages/internal/tpl"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
)
|
)
|
||||||
@ -19,18 +20,12 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewHandler creates handler for error pages serving.
|
// NewHandler creates handler for error pages serving.
|
||||||
func NewHandler(
|
func NewHandler(cfg *config.Config, p templatePicker, rdr renderer, opt options.ErrorPage) fasthttp.RequestHandler {
|
||||||
cfg *config.Config,
|
|
||||||
p templatePicker,
|
|
||||||
rdr renderer,
|
|
||||||
showRequestDetails bool,
|
|
||||||
proxyHTTPHeaders []string,
|
|
||||||
) fasthttp.RequestHandler {
|
|
||||||
return func(ctx *fasthttp.RequestCtx) {
|
return func(ctx *fasthttp.RequestCtx) {
|
||||||
core.SetClientFormat(ctx, core.PlainTextContentType) // default content type
|
core.SetClientFormat(ctx, core.PlainTextContentType) // default content type
|
||||||
|
|
||||||
if code, ok := ctx.UserValue("code").(string); ok {
|
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
|
} else { // will never occur
|
||||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||||
_, _ = ctx.WriteString("cannot extract requested code from the request")
|
_, _ = 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/config"
|
||||||
"github.com/tarampampam/error-pages/internal/http/core"
|
"github.com/tarampampam/error-pages/internal/http/core"
|
||||||
|
"github.com/tarampampam/error-pages/internal/options"
|
||||||
"github.com/tarampampam/error-pages/internal/tpl"
|
"github.com/tarampampam/error-pages/internal/tpl"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
)
|
)
|
||||||
@ -21,23 +22,15 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewHandler creates handler for the index page serving.
|
// NewHandler creates handler for the index page serving.
|
||||||
func NewHandler(
|
func NewHandler(cfg *config.Config, p templatePicker, rdr renderer, opt options.ErrorPage) fasthttp.RequestHandler {
|
||||||
cfg *config.Config,
|
|
||||||
p templatePicker,
|
|
||||||
rdr renderer,
|
|
||||||
defaultPageCode string,
|
|
||||||
defaultHTTPCode uint16,
|
|
||||||
showRequestDetails bool,
|
|
||||||
proxyHTTPHeaders []string,
|
|
||||||
) fasthttp.RequestHandler {
|
|
||||||
return func(ctx *fasthttp.RequestCtx) {
|
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 {
|
if returnCode, ok := extractCodeToReturn(ctx); ok {
|
||||||
pageCode, httpCode = strconv.Itoa(returnCode), returnCode
|
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"
|
notfoundHandler "github.com/tarampampam/error-pages/internal/http/handlers/notfound"
|
||||||
versionHandler "github.com/tarampampam/error-pages/internal/http/handlers/version"
|
versionHandler "github.com/tarampampam/error-pages/internal/http/handlers/version"
|
||||||
"github.com/tarampampam/error-pages/internal/metrics"
|
"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/tpl"
|
||||||
"github.com/tarampampam/error-pages/internal/version"
|
"github.com/tarampampam/error-pages/internal/version"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
@ -66,14 +67,7 @@ type templatePicker interface {
|
|||||||
|
|
||||||
// Register server routes, middlewares, etc.
|
// Register server routes, middlewares, etc.
|
||||||
// Router docs: <https://github.com/fasthttp/router>
|
// Router docs: <https://github.com/fasthttp/router>
|
||||||
func (s *Server) Register(
|
func (s *Server) Register(cfg *config.Config, templatePicker templatePicker, opt options.ErrorPage) error {
|
||||||
cfg *config.Config,
|
|
||||||
templatePicker templatePicker,
|
|
||||||
defaultPageCode string,
|
|
||||||
defaultHTTPCode uint16,
|
|
||||||
showDetails bool,
|
|
||||||
proxyHTTPHeaders []string,
|
|
||||||
) error {
|
|
||||||
reg, m := metrics.NewRegistry(), metrics.NewMetrics()
|
reg, m := metrics.NewRegistry(), metrics.NewMetrics()
|
||||||
|
|
||||||
if err := m.Register(reg); err != nil {
|
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.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("/", indexHandler.NewHandler(cfg, templatePicker, s.rdr, opt))
|
||||||
s.router.GET("/{code}.html", errorpageHandler.NewHandler(cfg, templatePicker, s.rdr, showDetails, proxyHTTPHeaders)) //nolint:lll
|
s.router.GET("/{code}.html", errorpageHandler.NewHandler(cfg, templatePicker, s.rdr, opt))
|
||||||
|
|
||||||
s.router.GET("/version", versionHandler.NewHandler(version.Version()))
|
s.router.GET("/version", versionHandler.NewHandler(version.Version()))
|
||||||
|
|
||||||
liveHandler := healthzHandler.NewHandler(checkers.NewLiveChecker())
|
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"`
|
RequestID string `token:"request_id"`
|
||||||
ForwardedFor string `token:"forwarded_for"`
|
ForwardedFor string `token:"forwarded_for"`
|
||||||
Host string `token:"host"`
|
Host string `token:"host"`
|
||||||
|
L10nDisabled bool
|
||||||
ShowRequestDetails bool
|
ShowRequestDetails bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +142,8 @@ func (tr *TemplateRenderer) Render(content []byte, props Properties) ([]byte, er
|
|||||||
var funcMap = template.FuncMap{
|
var funcMap = template.FuncMap{
|
||||||
"show_details": func() bool { return props.ShowRequestDetails },
|
"show_details": func() bool { return props.ShowRequestDetails },
|
||||||
"hide_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
|
// 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"},
|
giveProps: tpl.Properties{Code: "201", Message: "lorem ipsum"},
|
||||||
wantContent: `{"code": "201", "message": {"here":[ " Yeah " ]}}`,
|
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) {
|
t.Run(name, func(t *testing.T) {
|
||||||
content, err := renderer.Render([]byte(tt.giveContent), tt.giveProps)
|
content, err := renderer.Render([]byte(tt.giveContent), tt.giveProps)
|
||||||
|
@ -225,6 +225,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// {{ if l10n_enabled }}
|
||||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
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, 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';
|
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);
|
p.appendChild(s);
|
||||||
})(document.createElement('script'), document.body);
|
})(document.createElement('script'), document.body);
|
||||||
}
|
}
|
||||||
|
// {{ end }}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
<!--
|
<!--
|
||||||
|
@ -104,6 +104,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// {{ if l10n_enabled }}
|
||||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
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, 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';
|
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);
|
p.appendChild(s);
|
||||||
})(document.createElement('script'), document.body);
|
})(document.createElement('script'), document.body);
|
||||||
}
|
}
|
||||||
|
// {{ end }}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
<!--
|
<!--
|
||||||
|
@ -254,6 +254,7 @@
|
|||||||
console.warn('Cannot parse the error code:', errorCode);
|
console.warn('Cannot parse the error code:', errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// {{ if l10n_enabled }}
|
||||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
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, 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';
|
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);
|
p.appendChild(s);
|
||||||
})(document.createElement('script'), document.body);
|
})(document.createElement('script'), document.body);
|
||||||
}
|
}
|
||||||
|
// {{ end }}
|
||||||
</script>
|
</script>
|
||||||
<!--
|
<!--
|
||||||
Error {{ code }}: {{ message }}
|
Error {{ code }}: {{ message }}
|
||||||
|
@ -98,6 +98,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// {{ if l10n_enabled }}
|
||||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
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, 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';
|
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);
|
p.appendChild(s);
|
||||||
})(document.createElement('script'), document.body);
|
})(document.createElement('script'), document.body);
|
||||||
}
|
}
|
||||||
|
// {{ end }}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
<!--
|
<!--
|
||||||
|
@ -163,6 +163,7 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// {{ if l10n_enabled }}
|
||||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
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, 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';
|
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);
|
p.appendChild(s);
|
||||||
})(document.createElement('script'), document.body);
|
})(document.createElement('script'), document.body);
|
||||||
}
|
}
|
||||||
|
// {{ end }}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
<!--
|
<!--
|
||||||
|
@ -82,6 +82,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// {{ if l10n_enabled }}
|
||||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
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, 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';
|
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);
|
p.appendChild(s);
|
||||||
})(document.createElement('script'), document.body);
|
})(document.createElement('script'), document.body);
|
||||||
}
|
}
|
||||||
|
// {{ end }}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
<!--
|
<!--
|
||||||
|
@ -84,6 +84,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// {{ if l10n_enabled }}
|
||||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
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, 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';
|
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);
|
p.appendChild(s);
|
||||||
})(document.createElement('script'), document.body);
|
})(document.createElement('script'), document.body);
|
||||||
}
|
}
|
||||||
|
// {{ end }}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
<!--
|
<!--
|
||||||
|
@ -378,6 +378,7 @@
|
|||||||
console.warn('gsap library is not initialized (network error?)')
|
console.warn('gsap library is not initialized (network error?)')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// {{ if l10n_enabled }}
|
||||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
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, 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';
|
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);
|
p.appendChild(s);
|
||||||
})(document.createElement('script'), document.body);
|
})(document.createElement('script'), document.body);
|
||||||
}
|
}
|
||||||
|
// {{ end }}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
@ -262,6 +262,7 @@
|
|||||||
|
|
||||||
(new Matrix(document.getElementById('matrix'))).run(document.getElementById('matrix-words'));
|
(new Matrix(document.getElementById('matrix'))).run(document.getElementById('matrix-words'));
|
||||||
|
|
||||||
|
// {{ if l10n_enabled }}
|
||||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
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, 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';
|
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);
|
p.appendChild(s);
|
||||||
})(document.createElement('script'), document.body);
|
})(document.createElement('script'), document.body);
|
||||||
}
|
}
|
||||||
|
// {{ end }}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
<!--
|
<!--
|
||||||
|
@ -175,6 +175,7 @@
|
|||||||
window.clearInterval(flickerInterval);
|
window.clearInterval(flickerInterval);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// {{ if l10n_enabled }}
|
||||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
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, 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';
|
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);
|
p.appendChild(s);
|
||||||
})(document.createElement('script'), document.body);
|
})(document.createElement('script'), document.body);
|
||||||
}
|
}
|
||||||
|
// {{ end }}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
<!--
|
<!--
|
||||||
|
@ -11,7 +11,7 @@ Creating templates is a very simple operation, even for those who know nothing a
|
|||||||
### Error page & request data
|
### Error page & request data
|
||||||
|
|
||||||
| Signature | Description | Example |
|
| Signature | Description | Example |
|
||||||
|-------------------------------------|---------------------------------------------------------------|----------------------------------------------|
|
|--------------------------------------|---------------------------------------------------------------|----------------------------------------------|
|
||||||
| `{{ code }}` | Error page code | `404` |
|
| `{{ code }}` | Error page code | `404` |
|
||||||
| `{{ message }}` | Error code message | `Not found` |
|
| `{{ message }}` | Error code message | `Not found` |
|
||||||
| `{{ description }}` | Error code description | `The server can not find the requested page` |
|
| `{{ 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` |
|
| `{{ version }}` | Application version | `2.5.0` |
|
||||||
| `{{ if show_details }}...{{ end }}` | Logical operator (server started with "show details" option?) | |
|
| `{{ if show_details }}...{{ end }}` | Logical operator (server started with "show details" option?) | |
|
||||||
| `{{ if hide_details }}...{{ end }}` | Same as above, but inverted | |
|
| `{{ 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
|
### Modifiers
|
||||||
|
|
||||||
|
@ -215,6 +215,7 @@
|
|||||||
}, 550);
|
}, 550);
|
||||||
// {{ end }}
|
// {{ end }}
|
||||||
|
|
||||||
|
// {{ if l10n_enabled }}
|
||||||
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
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, 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';
|
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);
|
p.appendChild(s);
|
||||||
})(document.createElement('script'), document.body);
|
})(document.createElement('script'), document.body);
|
||||||
}
|
}
|
||||||
|
// {{ end }}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
<!--
|
<!--
|
||||||
|
Loading…
Reference in New Issue
Block a user