Compare commits

...

21 Commits

Author SHA1 Message Date
e8fa8896c9 Update CHANGELOG.md 2022-05-06 22:28:42 +05:00
c9bd47618d adding translation to Portuguese language (#103)
Co-authored-by: Fabio Correia <fabiocorreia@trixlog.com>
Co-authored-by: Paramtamtam <7326800+tarampampam@users.noreply.github.com>
2022-05-06 22:28:12 +05:00
3ffb952cdd Bump golang from 1.18.0-alpine to 1.18.1-alpine (#95) 2022-05-02 06:54:34 +00:00
b5892f44d9 Bump github.com/valyala/fasthttp from 1.34.0 to 1.36.0 (#96) 2022-05-02 04:24:25 +00:00
769b0cebb6 Bump github.com/fasthttp/router from 1.4.7 to 1.4.8 (#98) 2022-05-02 04:18:32 +00:00
8f49ff7204 Bump github/codeql-action from 1 to 2 (#99) 2022-05-02 04:18:12 +00:00
f89bdfbd51 Bump aquasecurity/trivy-action from 0.2.2 to 0.2.5 (#97) 2022-05-02 04:17:53 +00:00
1b2e899201 Bump actions/download-artifact from 2 to 3 (#100) 2022-05-02 04:17:31 +00:00
6c0c85544e Bump actions/upload-artifact from 2 to 3 (#101) 2022-05-02 04:17:11 +00:00
d3d1c62411 Bump codecov/codecov-action from 2 to 3 (#102) 2022-05-02 04:16:54 +00:00
8019d07cab Update CHANGELOG.md 2022-04-12 15:35:19 +05:00
d21a6f2797 Added possibility to disable error pages auto-localization (#94) 2022-04-12 15:34:35 +05:00
a3389aaafa Changing UID/GID to the numeric values (#93) 2022-04-09 20:39:52 +05:00
c6a7e30609 Bump github.com/fasthttp/router from 1.4.6 to 1.4.7 (#90) 2022-04-01 22:07:18 +00:00
01abc48a01 CI updated 2022-04-01 13:14:16 +05:00
d6374d7edf Bump actions/setup-go from 2 to 3 2022-04-01 13:01:22 +05:00
7ebfac9dc2 Bump actions/cache from 2 to 3.0.1 (#89) 2022-04-01 07:51:10 +00:00
64d4798156 Bump peter-evans/dockerhub-description from 2 to 3 (#88) 2022-04-01 07:48:54 +00:00
4adad3df10 CI updated (#87) 2022-03-30 21:23:42 +05:00
30a7b2793f Fix translation FR (#86) 2022-03-30 18:00:32 +05:00
2d9deb7370 CI now purges the CDN cache (#84) 2022-03-28 22:13:19 +05:00
35 changed files with 375 additions and 181 deletions

View File

@ -12,7 +12,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: peter-evans/dockerhub-description@v2 # Action page: <https://github.com/peter-evans/dockerhub-description>
- uses: peter-evans/dockerhub-description@v3 # Action page: <https://github.com/peter-evans/dockerhub-description>
with:
username: ${{ secrets.DOCKER_LOGIN }}
password: ${{ secrets.DOCKER_USER_PASSWORD }}

View File

@ -5,6 +5,18 @@ on:
types: [published]
jobs:
purge-cdn-cache:
name: Purge jsDelivr CDN cache
runs-on: ubuntu-20.04
steps:
- uses: gacts/purge-jsdelivr-cache@v1 # Action page: <https://github.com/gacts/purge-jsdelivr-cache>
with:
url: |
https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.js
https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js
https://cdn.jsdelivr.net/gh/tarampampam/error-pages@latest/l10n/l10n.js
https://cdn.jsdelivr.net/gh/tarampampam/error-pages@latest/l10n/l10n.min.js
build:
name: Build for ${{ matrix.os }} (${{ matrix.arch }})
runs-on: ubuntu-20.04
@ -14,8 +26,8 @@ jobs:
os: [linux, darwin] # linux, freebsd, darwin, windows
arch: [amd64] # amd64, 386
steps:
- uses: actions/setup-go@v2
with: {go-version: 1.18.0}
- uses: actions/setup-go@v3
with: {go-version: 1.18.1}
- uses: actions/checkout@v3
@ -75,8 +87,12 @@ jobs:
build-args: "APP_VERSION=${{ steps.slug.outputs.version }}"
tags: |
tarampampam/error-pages:${{ steps.slug.outputs.version }}
tarampampam/error-pages:${{ steps.slug.outputs.version-major }}.${{ steps.slug.outputs.version-minor }}
tarampampam/error-pages:${{ steps.slug.outputs.version-major }}
tarampampam/error-pages:latest
ghcr.io/${{ github.actor }}/${{ github.event.repository.name }}:${{ steps.slug.outputs.version }}
ghcr.io/${{ github.actor }}/${{ github.event.repository.name }}:${{ steps.slug.outputs.version-major }}.${{ steps.slug.outputs.version-minor }}
ghcr.io/${{ github.actor }}/${{ github.event.repository.name }}:${{ steps.slug.outputs.version-major }}
ghcr.io/${{ github.actor }}/${{ github.event.repository.name }}:latest
demo:

View File

@ -24,7 +24,7 @@ jobs: # Docs: <https://git.io/JvxXE>
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v2
- uses: actions/setup-go@v3
with: {go-version: 1.17} # On v1.18 I had an error "panic: load embedded ruleguard rules: rules/rules.go:13: can't load fmt"
- name: Run linter
@ -68,14 +68,14 @@ jobs: # Docs: <https://git.io/JvxXE>
name: Unit tests
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v2
- uses: actions/setup-go@v3
with: {go-version: 1.18}
- uses: actions/checkout@v3
with: {fetch-depth: 2} # Fixes codecov error 'Issue detecting commit SHA'
- name: Go modules Cache # Docs: <https://git.io/JfAKn#go---modules>
uses: actions/cache@v2
uses: actions/cache@v3
id: go-cache
with:
path: ~/go/pkg/mod
@ -88,7 +88,7 @@ jobs: # Docs: <https://git.io/JvxXE>
- name: Run Unit tests
run: go test -race -covermode=atomic -coverprofile /tmp/coverage.txt ./...
- uses: codecov/codecov-action@v2 # https://github.com/codecov/codecov-action
- uses: codecov/codecov-action@v3 # https://github.com/codecov/codecov-action
continue-on-error: true
with:
file: /tmp/coverage.txt
@ -104,7 +104,7 @@ jobs: # Docs: <https://git.io/JvxXE>
arch: [amd64] # amd64, 386
needs: [golangci-lint, go-test, validate-config-file]
steps:
- uses: actions/setup-go@v2
- uses: actions/setup-go@v3
with: {go-version: 1.18}
- uses: actions/checkout@v3
@ -113,7 +113,7 @@ jobs: # Docs: <https://git.io/JvxXE>
id: slug
- name: Go modules Cache # Docs: <https://git.io/JfAKn#go---modules>
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
@ -133,7 +133,7 @@ jobs: # Docs: <https://git.io/JvxXE>
if: matrix.os == 'linux'
run: ./error-pages version && ./error-pages -h
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v3
with:
name: error-pages-${{ matrix.os }}-${{ matrix.arch }}
path: error-pages
@ -147,7 +147,7 @@ jobs: # Docs: <https://git.io/JvxXE>
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v2
- uses: actions/download-artifact@v3
with:
name: error-pages-linux-amd64
path: .artifact
@ -194,7 +194,7 @@ jobs: # Docs: <https://git.io/JvxXE>
- run: docker save app:ci > ./docker-image.tar
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v3
with:
name: docker-image
path: ./docker-image.tar
@ -207,12 +207,12 @@ jobs: # Docs: <https://git.io/JvxXE>
steps:
- uses: actions/checkout@v3 # is needed for `upload-sarif` action
- uses: actions/download-artifact@v2
- uses: actions/download-artifact@v3
with:
name: docker-image
path: .artifact
- uses: aquasecurity/trivy-action@0.2.2 # action page: <https://github.com/aquasecurity/trivy-action>
- uses: aquasecurity/trivy-action@0.2.5 # action page: <https://github.com/aquasecurity/trivy-action>
with:
input: .artifact/docker-image.tar
format: sarif
@ -220,7 +220,7 @@ jobs: # Docs: <https://git.io/JvxXE>
exit-code: 1
output: trivy-results.sarif
- uses: github/codeql-action/upload-sarif@v1
- uses: github/codeql-action/upload-sarif@v2
if: always()
continue-on-error: true
with: {sarif_file: trivy-results.sarif}
@ -233,7 +233,7 @@ jobs: # Docs: <https://git.io/JvxXE>
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v2
- uses: actions/download-artifact@v3
with:
name: docker-image
path: .artifact

View File

@ -4,6 +4,39 @@ All notable changes to this package will be documented in this file.
The format is based on [Keep a Changelog][keepachangelog] and this project adheres to [Semantic Versioning][semver].
## v2.14.0
### Added
- Error pages now translated in portuguese 🇵🇹 [#103]
### Changed
- Go updated from `1.18.0` up to `1.18.1`
[#103]:https://github.com/tarampampam/error-pages/pull/103
## v2.13.0
### 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
### Fixed
- Fix translation 🇫🇷 [#86]
[#85]:https://github.com/tarampampam/error-pages/pull/86
## v2.12.0
### Changed

View File

@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1.2
# Image page: <https://hub.docker.com/_/golang>
FROM golang:1.18.0-alpine as builder
FROM golang:1.18.1-alpine as builder
# can be passed with any prefix (like `v1.2.3@GITHASH`), e.g.: `docker build --build-arg "APP_VERSION=v1.2.3@GITHASH" .`
ARG APP_VERSION="undefined@docker"
@ -60,7 +60,7 @@ LABEL \
COPY --from=builder /tmp/rootfs /
# Use an unprivileged user
USER appuser:appuser
USER 10001:10001
WORKDIR /opt
@ -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"]

View File

@ -34,7 +34,7 @@ One day you may want to replace the standard error pages of your HTTP server wit
- Error pages can be [embedded into your own `nginx`][wiki-usage-with-nginx] docker image
- Fully configurable (take a look at the [configuration file](https://github.com/tarampampam/error-pages/blob/master/error-pages.yml) and [project Wiki][wiki])
- Distributed using docker image and compiled binary files
- Localized (🇺🇸, 🇫🇷, 🇺🇦, 🇷🇺) HTML error pages (translation process [described here](https://github.com/tarampampam/error-pages/tree/master/l10n) - other translations are welcome!)
- Localized (🇺🇸, 🇫🇷, 🇺🇦, 🇷🇺, 🇵🇹) HTML error pages (translation process [described here](https://github.com/tarampampam/error-pages/tree/master/l10n) - other translations are welcome!)
## 🧩 Install

View File

@ -8,7 +8,7 @@ volumes:
services:
app: &app-service
image: golang:1.18.0-buster # Image page: <https://hub.docker.com/_/golang>
image: golang:1.18.1-buster # Image page: <https://hub.docker.com/_/golang>
working_dir: /src
environment:
HOME: /tmp

6
go.mod
View File

@ -4,7 +4,7 @@ go 1.18
require (
github.com/a8m/envsubst v1.3.0
github.com/fasthttp/router v1.4.6
github.com/fasthttp/router v1.4.8
github.com/fatih/color v1.13.0
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d
github.com/pkg/errors v0.9.1
@ -13,7 +13,7 @@ require (
github.com/spf13/cobra v1.4.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.1
github.com/valyala/fasthttp v1.34.0
github.com/valyala/fasthttp v1.36.0
go.uber.org/zap v1.21.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)
@ -32,7 +32,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/savsgio/gotils v0.0.0-20211223103454-d0aaa54c5899 // indirect
github.com/savsgio/gotils v0.0.0-20220401102855-e56b59f40436 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect

18
go.sum
View File

@ -65,8 +65,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fasthttp/router v1.4.6 h1:KfETdHGBnvoBfBHeRe/8TVYz8Bp/mASBVC5UXO9CpZI=
github.com/fasthttp/router v1.4.6/go.mod h1:Iv800u3hYFNuBBcmJNs/VBVpub+JfBihGBp5spSocbw=
github.com/fasthttp/router v1.4.8 h1:4zj4sAzXibjA6ZW19MdMe3GaYD1SM+TXrMLzHcVMBOI=
github.com/fasthttp/router v1.4.8/go.mod h1:UUtJdXFYlqYRQ32EAtWOvNYIZ1XfyC5JJIknWai6foI=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@ -151,7 +151,6 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d h1:cVtBfNW5XTHiKQe7jDaDBSh/EVM4XLPutLAGboIXuM0=
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.14.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U=
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -207,8 +206,8 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/savsgio/gotils v0.0.0-20211223103454-d0aaa54c5899 h1:Orn7s+r1raRTBKLSc9DmbktTT04sL+vkzsbRD2Q8rOI=
github.com/savsgio/gotils v0.0.0-20211223103454-d0aaa54c5899/go.mod h1:oejLrk1Y/5zOF+c/aHtXqn3TFlzzbAgPWg8zBiAHDas=
github.com/savsgio/gotils v0.0.0-20220401102855-e56b59f40436 h1:sfTahD3f2BSjx9U3R4K09PkNuZZWthT7g6vzTIXNWkM=
github.com/savsgio/gotils v0.0.0-20220401102855-e56b59f40436/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
@ -226,9 +225,9 @@ github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMT
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.33.0/go.mod h1:KJRK/MXx0J+yd0c5hlR+s1tIHD72sniU8ZJjl97LIw4=
github.com/valyala/fasthttp v1.34.0 h1:d3AAQJ2DRcxJYHm7OXNXtXt2as1vMDfxeIcFvhmGGm4=
github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0=
github.com/valyala/fasthttp v1.35.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
github.com/valyala/fasthttp v1.36.0 h1:NhqfO/cB7Ajn1czkKnWkMHyPYr5nyND14ZGPk23g0/c=
github.com/valyala/fasthttp v1.36.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -253,7 +252,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -317,7 +315,6 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -377,7 +374,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@ -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

View File

@ -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)

View File

@ -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
View File

@ -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.

View File

@ -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 {

View File

@ -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)
}

View File

@ -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")

View File

@ -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)
}
}

View File

@ -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())

View 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
}

View File

@ -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
}

View File

@ -140,8 +140,10 @@ 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 },
"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

View File

@ -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)

View File

@ -6,365 +6,437 @@ Object.defineProperty(window, 'l10n', {
fr: 'Erreur',
ru: 'Ошибка',
uk: 'Помилка',
pt: 'Erro',
},
'Good luck': {
fr: 'Bonne chance',
ru: 'Удачи',
uk: 'Успіхів',
pt: 'Boa sorte',
},
'UH OH': {
fr: 'Oups',
ru: 'Ох',
uk: 'Ох',
pt: 'Ops',
},
'Request details': {
fr: 'Détails de la demande',
fr: 'Détails de la requête',
ru: 'Детали запроса',
uk: 'Деталі запиту',
pt: 'Detalhes da solicitação',
},
'Double-check the URL': {
fr: 'Vérifiez lURL',
ru: 'Дважды проверьте URL',
uk: 'Двічі перевіряйте URL-адресу',
pt: 'Verifique novamente a URL',
},
'Alternatively, go back': {
fr: 'Essayer de revenir en arrière',
ru: 'Или можете вернуться назад',
uk: 'Або ви можете повернутися',
pt: "Como alternativa, tente voltar",
},
'Here\'s what might have happened': {
fr: 'Voici ce qui aurait pu se passer',
ru: 'Из-за чего это могло случиться',
uk: 'Що це може статися',
pt: 'Aqui está o que pode ter acontecido',
},
'You may have mistyped the URL': {
fr: 'Vous avez peut-être mal tapé lURL',
ru: 'Вы могли ошибиться в URL',
uk: 'Ви можете зробити помилку в URL-адресі',
pt: 'Você pode ter digitado incorretamente a URL',
},
'The site was moved': {
fr: 'Le site a été déplacé',
ru: 'Сайт был перемещён',
uk: 'Сайт був переміщений',
pt: 'O site foi movido',
},
'It was never here': {
fr: 'Il na jamais été ici',
ru: 'Он никогда не был здесь',
uk: 'Він ніколи не був тут',
pt: 'Nunca esteve aqui',
},
'Bad Request': {
fr: 'Mauvaise demande',
fr: 'Mauvaise requête',
ru: 'Некорректный запрос',
uk: 'Неправильний запит',
pt: 'Requisição inválida',
},
'The server did not understand the request': {
fr: 'Le serveur ne comprend pas la demande',
fr: 'Le serveur ne comprend pas la requête',
ru: 'Сервер не смог обработать запрос из-за ошибки в нём',
uk: 'Сервер не міг обробити запит через помилку в ньому',
pt: 'O servidor não entendeu a solicitação',
},
'Unauthorized': {
fr: 'Non autorisé',
ru: 'Запрос не авторизован',
uk: 'Несанкціонований доступ',
pt: 'Não autorizado',
},
'The requested page needs a username and a password': {
fr: 'La page demandée nécessite un nom dutilisateur et un mot de passe',
ru: 'Для доступа к странице требуется логин и пароль',
uk: 'Щоб отримати доступ до сторінки, потрібний логін та пароль',
pt: 'A página solicitada precisa de um nome de usuário e uma senha',
},
'Forbidden': {
fr: 'Interdit',
ru: 'Запрещено',
uk: 'Заборонено',
pt: 'Proibido',
},
'Access is forbidden to the requested page': {
fr: 'Accès interdit à la page demandée',
ru: 'Доступ к странице запрещён',
uk: 'Доступ до сторінки заборонено',
pt: 'É proibido o acesso à página solicitada',
},
'Not Found': {
fr: 'Pas trouvé',
fr: 'Introuvable',
ru: 'Страница не найдена',
uk: 'Сторінка не знайдена',
pt: 'Não encontrado',
},
'The server can not find the requested page': {
fr: 'Le serveur ne peut trouver la page demandée',
ru: 'Сервер не смог найти запрашиваемую страницу',
uk: 'Сервер не міг знайти запитану сторінку',
pt: 'O servidor não consegue encontrar a página solicitada',
},
'Method Not Allowed': {
fr: 'Méthode Non Autorisée',
ru: 'Метод не поддерживается',
uk: 'Неприпустимий метод',
pt: 'Método não permitido',
},
'The method specified in the request is not allowed': {
fr: 'La méthode spécifiée dans la requête nest pas autorisée',
ru: 'Указанный в запросе метод не поддерживается',
uk: 'Метод, зазначений у запиті, не підтримується',
pt: 'O método especificado na solicitação não é permitido',
},
'Proxy Authentication Required': {
fr: 'Authentification proxy requise',
ru: 'Нужна аутентификация прокси',
uk: 'Потрібна ідентифікація проксі',
pt: 'Autenticação de proxy necessária',
},
'You must authenticate with a proxy server before this request can be served': {
fr: 'Vous devez vous authentifier avec un serveur proxy avant que cette requête puisse être servie',
ru: 'Вы должны быть авторизованы на прокси сервере для обработки этого запроса',
uk: 'Ви повинні увійти до проксі-сервера для обробки цього запиту',
pt: 'Você deve se autenticar com um servidor proxy antes que esta solicitação possa ser atendida',
},
'Request Timeout': {
fr: 'Demande expiré',
fr: 'Requête expiré',
ru: 'Истекло время ожидания',
uk: 'Час запиту закінчився',
pt: 'Tempo limite de solicitação excedido',
},
'The request took longer than the server was prepared to wait': {
fr: 'La requête prend plus de temps que prévu',
ru: 'Отправка запроса заняла слишком много времени',
uk: 'Надсилання запиту зайняв занадто багато часу',
pt: 'A solicitação demorou mais do que o servidor estava preparado para esperar',
},
'Conflict': {
fr: 'Conflit',
ru: 'Конфликт',
uk: 'Конфлікт',
pt: 'Conflito',
},
'The request could not be completed because of a conflict': {
fr: 'La requête na pas pu être complétée à cause dun conflit',
ru: 'Запрос не может быть обработан из-за конфликта',
uk: 'Запит не може бути оброблений через конфлікт',
pt: 'A solicitação não pôde ser concluída devido a um conflito',
},
'Gone': {
fr: 'Supprimé',
ru: 'Удалено',
uk: 'Вилучений',
pt: 'Removido',
},
'The requested page is no longer available': {
fr: 'La page demandée nest plus disponible',
ru: 'Запрошенная страница была удалена',
uk: 'Запитана сторінка була видалена',
pt: 'A página solicitada não está mais disponível',
},
'Length Required': {
fr: 'Longueur requise',
ru: 'Необходима длина',
uk: 'Потрібно вказати розмір',
pt: 'Content-Length necessário',
},
'The "Content-Length" is not defined. The server will not accept the request without it': {
fr: 'Le "Content-Length" nest pas défini. Le serveur ne prendra pas en compte la requête sans',
fr: 'Le "Content-Length" nest pas défini. Le serveur ne prendra pas en compte la requête',
ru: 'Заголовок "Content-Length" не был передан. Сервер не может обработать запрос без него',
uk: 'Заголовок "Content-Length" не був переданий. Сервер не може обробити запит без нього',
pt: 'O "Content-Length" não está definido. O servidor não aceitará a solicitação sem ele',
},
'Precondition Failed': {
fr: 'Échec de la condition préalable',
ru: 'Условие ложно',
uk: 'Збій під час обробки попередньої умови',
pt: 'Falha na pré-condição',
},
'The pre condition given in the request evaluated to false by the server': {
fr: 'La précondition donnée dans la requête a été évaluée comme étant fausse par le serveur',
ru: 'Ни одно из условных полей заголовка запроса не было выполнено',
uk: 'Жодна з умовних полів заголовка запиту не була виконана',
pt: 'A pré-condição dada na solicitação avaliada como falsa pelo servidor',
},
'Payload Too Large': {
fr: 'Charge trop volumineuse',
ru: 'Слишком большой запрос',
uk: 'Занадто великий запит',
pt: 'Payload muito grande',
},
'The server will not accept the request, because the request entity is too large': {
fr: 'Le serveur ne prendra pas en compte la requête, car lentité de la requête est trop volumineuse',
ru: 'Сервер не может обработать запрос, так как он слишком большой',
uk: 'Сервер не може обробити запит, оскільки він занадто великий',
pt: 'O servidor não aceitará a solicitação porque a entidade da solicitação é muito grande',
},
'Requested Range Not Satisfiable': {
fr: 'Demande non satisfaisante',
fr: 'Requête non satisfaisante',
ru: 'Диапазон не достижим',
uk: 'Запитуваний діапазон недосяжний',
pt: 'Intervalo Solicitado Não Satisfatório',
},
'The requested byte range is not available and is out of bounds': {
fr: 'Le byte range demandé nest pas disponible et est hors des limites',
ru: 'Запрошенный диапазон данных недоступен или вне допустимых пределов',
uk: 'Описаний діапазон даних недоступний або з допустимих меж',
pt: 'O intervalo de bytes solicitado não está disponível e está fora dos limites',
},
'I\'m a teapot': {
fr: 'Je suis une théière',
ru: 'Я чайник',
uk: 'Я чайник',
pt: 'Eu sou um bule',
},
'Attempt to brew coffee with a teapot is not supported': {
fr: 'Tenter de préparer du café avec une théière nest pas pris en charge',
ru: 'Попытка заварить кофе в чайнике обречена на фиаско',
uk: 'Спроба виварити каву в чайник приречена на фіаско',
pt: 'A tentativa de preparar café com um bule não é suportada',
},
'Too Many Requests': {
fr: 'Trop de demandes',
fr: 'Trop de requêtes',
ru: 'Слишком много запросов',
uk: 'Занадто багато запитів',
pt: 'Excesso de solicitações',
},
'Too many requests in a given amount of time': {
fr: 'Trop de requêtes dans un délai donné',
ru: 'Отправлено слишком много запросов за короткое время',
uk: 'Надіслано занадто багато запитів на короткий час',
pt: 'Excesso de solicitações em um determinado período de tempo',
},
'Internal Server Error': {
fr: 'Erreur interne du serveur',
ru: 'Внутренняя ошибка сервера',
uk: 'Внутрішня помилка сервера',
pt: 'Erro do Servidor Interno',
},
'The server met an unexpected condition': {
fr: 'Le serveur a rencontré une condition inattendue',
ru: 'Произошло что-то неожиданное на сервере',
uk: 'На сервері було щось несподіване',
pt: 'O servidor encontrou uma condição inesperada',
},
'Bad Gateway': {
fr: 'Mauvaise passerelle',
ru: 'Ошибка шлюза',
uk: 'Помилка шлюзу',
pt: 'Gateway inválido',
},
'The server received an invalid response from the upstream server': {
fr: 'Le serveur a reçu une réponse invalide du serveur distant',
ru: 'Сервер получил некорректный ответ от вышестоящего сервера',
uk: 'Сервер отримав неправильну відповідь з сервера Upstream',
pt: 'O servidor recebeu uma resposta inválida do servidor upstream',
},
'Service Unavailable': {
fr: 'Service indisponible',
ru: 'Сервис недоступен',
uk: 'Сервіс недоступний',
pt: 'Serviço não disponível',
},
'The server is temporarily overloading or down': {
fr: 'Le serveur est temporairement en surcharge ou indisponible',
ru: 'Сервер временно не может обрабатывать запросы по техническим причинам',
uk: 'Сервер тимчасово не може обробляти запити з технічних причин',
pt: 'O servidor está temporariamente sobrecarregado ou inativo',
},
'Gateway Timeout': {
fr: 'Expiration Passerelle',
ru: 'Шлюз не отвечает',
uk: 'Шлюз не відповідає',
pt: 'Tempo limite do gateway excedido',
},
'The gateway has timed out': {
fr: 'Le temps dattente de la passerelle est dépassé',
ru: 'Сервер не дождался ответа от вышестоящего сервера',
uk: 'Сервер не чекав відповіді від сервера Upstream',
pt: 'O gateway esgotou o tempo limite',
},
'HTTP Version Not Supported': {
fr: 'Version HTTP non prise en charge',
ru: 'Версия HTTP не поддерживается',
uk: 'Версія НТТР не підтримується',
pt: 'Versão HTTP não suportada',
},
'The server does not support the "http protocol" version': {
fr: 'Le serveur ne supporte pas la version du protocole HTTP"',
fr: 'Le serveur ne supporte pas la version du protocole HTTP',
ru: 'Сервер не поддерживает запрошенную версию HTTP протокола',
uk: 'Сервер не підтримує запитану версію HTTP-протоколу',
pt: 'O servidor não suporta a versão do protocolo HTTP',
},
'Host': {
fr: 'Hôte',
ru: 'Хост',
uk: 'Хост',
pt: 'Hospedeiro',
},
'Original URI': {
fr: 'URI dorigine',
ru: 'Исходный URI',
uk: 'Вихідний URI',
pt: 'URI original',
},
'Forwarded for': {
fr: 'Transmis pour',
ru: 'Перенаправлен',
uk: 'Перенаправлений',
pt: 'Encaminhado para',
},
'Namespace': {
fr: 'Espace de noms',
ru: 'Пространство имён',
uk: 'Простір імен',
pt: 'Namespace',
},
'Ingress name': {
fr: 'Nom ingress',
ru: 'Имя Ingress',
uk: 'Ім\'я Ingress',
pt: 'Nome Ingress',
},
'Service name': {
fr: 'Nom du service',
ru: 'Имя сервиса',
uk: 'Ім\'я сервісу',
pt: 'Nome do Serviço',
},
'Service port': {
fr: 'Port du service',
ru: 'Порт сервиса',
uk: 'Порт сервісу',
pt: 'Porta do serviço',
},
'Request ID': {
fr: 'Identifiant de la demande',
fr: 'Identifiant de la requête',
ru: 'ID запроса',
uk: 'ID запиту',
pt: 'ID da solicitação',
},
'Timestamp': {
fr: 'Horodatage',
ru: 'Временная метка',
uk: 'Тимчасова мітка',
pt: 'Timestamp',
},
'client-side error': {
fr: 'Erreur du client',
fr: 'Erreur Client',
ru: 'ошибка на стороне клиента',
uk: 'помилка на стороні клієнта',
pt: 'erro do lado do cliente',
},
'server-side error': {
fr: 'Erreur du serveur',
fr: 'Erreur Serveur',
ru: 'ошибка на стороне сервера',
uk: 'помилка на стороні сервера',
pt: 'erro do lado do servidor',
},
'Your Client': {
fr: 'Votre client',
fr: 'Votre Client',
ru: 'Ваш Браузер',
uk: 'Ваш Браузер',
pt: 'Seu Cliente',
},
'Network': {
fr: 'Réseau',
ru: 'Сеть',
uk: 'Сіть',
pt: 'Rede',
},
'Web Server': {
fr: 'Serveur Web',
ru: 'Web Сервер',
uk: 'Web Сервер',
pt: 'Servidor web',
},
'What happened?': {
fr: 'Que sest-il passé ?',
ru: 'Что произошло?',
uk: 'Що сталося?',
pt: 'O que aconteceu?',
},
'What can i do?': {
fr: 'Que puis-je faire ?',
ru: 'Что можно сделать?',
uk: 'Що можна зробити?',
pt: 'O que eu posso fazer?',
},
'Please try again in a few minutes': {
fr: 'Veuillez réessayer dans quelques minutes',
ru: 'Пожалуйста, попробуйте повторить запрос ещё раз чуть позже',
uk: 'Будь ласка, спробуйте повторити запит ще раз трохи пізніше',
pt: 'Por favor, tente novamente em alguns minutos',
},
'Working': {
fr: 'Opérationnel',
ru: 'Работает',
uk: 'Працює',
pt: 'Funcionando',
},
'Unknown': {
fr: 'Inconnu',
ru: 'Неизвестно',
uk: 'Невідомо',
pt: 'Desconhecido',
},
'Please try to change the request method, headers, payload, or URL': {
fr: 'Veuillez essayer de changer la méthode de requête, les en-têtes, le contenu ou lURL',
ru: 'Пожалуйста, попробуйте изменить метод запроса, заголовки, его содержимое или URL',
uk: 'Будь ласка, спробуйте змінити метод запиту, заголовки, його вміст або URL-адресу',
pt: 'Tente alterar o método de solicitação, cabeçalhos, payload ou URL',
},
'Please check your authorization data': {
fr: 'Veuillez vérifier vos données dautorisation',
ru: 'Пожалуйста, проверьте данные авторизации',
uk: 'Будь ласка, перевірте дані авторизації',
pt: 'Verifique seus dados de autorização',
},
'Please double-check the URL and try again': {
fr: 'Veuillez vérifier lURL et réessayer',
ru: 'Пожалуйста, дважды проверьте URL и попробуйте снова',
uk: 'Будь ласка, двічі перевірте URL-адресу і спробуйте знову',
pt: 'Verifique novamente o URL e tente novamente',
},
};

View File

@ -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>
<!--

View File

@ -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>
<!--

View File

@ -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 }}

View File

@ -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>
<!--

View File

@ -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>
<!--

View File

@ -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>
<!--

View File

@ -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>
<!--

View File

@ -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>

View File

@ -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>
<!--

View File

@ -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>
<!--

View File

@ -10,24 +10,26 @@ 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` |
| `{{ original_uri }}` | `X-Original-URI` header value | `/foo1/bar2` |
| `{{ namespace }}` | `X-Namespace` header value | `foo` |
| `{{ ingress_name }}` | `X-Ingress-Name` header value | `bar` |
| `{{ service_name }}` | `X-Service-Name` header value | `baz` |
| `{{ service_port }}` | `X-Service-Port` header value | `8080` |
| `{{ request_id }}` | `X-Request-ID` header value | `12AB34CD56EF78` |
| `{{ forwarded_for }}` | `X-Forwarded-For` header value | `203.0.113.195, 70.41.3.18` |
| `{{ host }}` | `Host` header value | `example.com` |
| `{{ now.Unix }}` | Current timestamp (e.g. in Unix format) | `1643621927` |
| `{{ hostname }}` | OS hostname | `ab12cd34ef56` |
| `{{ 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 | |
| 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` |
| `{{ original_uri }}` | `X-Original-URI` header value | `/foo1/bar2` |
| `{{ namespace }}` | `X-Namespace` header value | `foo` |
| `{{ ingress_name }}` | `X-Ingress-Name` header value | `bar` |
| `{{ service_name }}` | `X-Service-Name` header value | `baz` |
| `{{ service_port }}` | `X-Service-Port` header value | `8080` |
| `{{ request_id }}` | `X-Request-ID` header value | `12AB34CD56EF78` |
| `{{ forwarded_for }}` | `X-Forwarded-For` header value | `203.0.113.195, 70.41.3.18` |
| `{{ host }}` | `Host` header value | `example.com` |
| `{{ now.Unix }}` | Current timestamp (e.g. in Unix format) | `1643621927` |
| `{{ hostname }}` | OS hostname | `ab12cd34ef56` |
| `{{ 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

View File

@ -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>
<!--