From cbb2ce6d0732bcf2372cbc201fc1c1f2733aadba Mon Sep 17 00:00:00 2001 From: crapStone Date: Thu, 16 Nov 2023 17:11:35 +0000 Subject: [PATCH] add go templating engine for error page and make errors more clear (#260) ping #199 closes #213 Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/260 Co-authored-by: crapStone Co-committed-by: crapStone --- .woodpecker.yml | 2 +- README.md | 2 +- go.mod | 15 ++++-- go.sum | 30 +++++++---- html/404.html | 37 ------------- html/error.go | 50 ------------------ html/error.html | 38 -------------- html/error_test.go | 38 -------------- html/html.go | 54 +++++++++++++++++-- html/html_test.go | 54 +++++++++++++++++++ html/templates/error.html | 69 +++++++++++++++++++++++++ server/handler/handler.go | 2 +- server/handler/handler_custom_domain.go | 2 +- server/handler/handler_raw_domain.go | 2 +- server/handler/handler_sub_domain.go | 22 +++++--- server/handler/try.go | 2 +- server/upstream/upstream.go | 16 +++--- 17 files changed, 232 insertions(+), 203 deletions(-) delete mode 100644 html/404.html delete mode 100644 html/error.go delete mode 100644 html/error.html delete mode 100644 html/error_test.go create mode 100644 html/html_test.go create mode 100644 html/templates/error.html diff --git a/.woodpecker.yml b/.woodpecker.yml index 7de8ac8..759e2f1 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,7 +1,7 @@ steps: # use vendor to cache dependencies vendor: - image: golang:1.20 + image: golang:1.21 commands: - go mod vendor diff --git a/README.md b/README.md index 39caa24..fb2a4b9 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ Thank you very much. ### Test Server -Make sure you have [golang](https://go.dev) v1.20 or newer and [just](https://just.systems/man/en/) installed. +Make sure you have [golang](https://go.dev) v1.21 or newer and [just](https://just.systems/man/en/) installed. run `just dev` now this pages should work: diff --git a/go.mod b/go.mod index 72eb289..eba292e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module codeberg.org/codeberg/pages -go 1.20 +go 1.21 + +toolchain go1.21.4 require ( code.gitea.io/sdk/gitea v0.16.1-0.20231115014337-e23e8aa3004f @@ -10,6 +12,7 @@ require ( github.com/joho/godotenv v1.4.0 github.com/lib/pq v1.10.7 github.com/mattn/go-sqlite3 v1.14.16 + github.com/microcosm-cc/bluemonday v1.0.26 github.com/reugn/equalizer v0.0.0-20210216135016-a959c509d7ad github.com/rs/zerolog v1.27.0 github.com/stretchr/testify v1.7.0 @@ -35,6 +38,7 @@ require ( github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1 // indirect github.com/aliyun/alibaba-cloud-sdk-go v1.61.1183 // indirect github.com/aws/aws-sdk-go v1.39.0 // indirect + github.com/aymerick/douceur v0.2.0 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/cenkalti/backoff/v4 v4.1.1 // indirect github.com/cloudflare/cloudflare-go v0.20.0 // indirect @@ -61,6 +65,7 @@ require ( github.com/googleapis/gax-go/v2 v2.0.5 // indirect github.com/gophercloud/gophercloud v0.16.0 // indirect github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae // indirect + github.com/gorilla/css v1.0.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect @@ -115,11 +120,11 @@ require ( github.com/vultr/govultr/v2 v2.7.1 // indirect go.opencensus.io v0.22.3 // indirect go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277 // indirect - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect - golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect - golang.org/x/sys v0.1.0 // indirect - golang.org/x/text v0.3.6 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect google.golang.org/api v0.20.0 // indirect google.golang.org/appengine v1.6.5 // indirect diff --git a/go.sum b/go.sum index f78ae18..7ea8b78 100644 --- a/go.sum +++ b/go.sum @@ -88,6 +88,8 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go v1.39.0 h1:74BBwkEmiqBbi2CGflEh34l0YNtIibTjZsibGarkNjo= github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -251,6 +253,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -278,6 +281,8 @@ github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae/go.mod h1:wx8HMD github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= @@ -477,6 +482,8 @@ github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= +github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= @@ -756,8 +763,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 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= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -790,7 +797,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -826,8 +834,9 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 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= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -899,11 +908,12 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/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-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -911,8 +921,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -963,7 +974,8 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/html/404.html b/html/404.html deleted file mode 100644 index 7c721b5..0000000 --- a/html/404.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - %status% - - - - - - - - - -

- Page not found! -

-
- Sorry, but this page couldn't be found or is inaccessible (%status%).
- We hope this isn't a problem on our end ;) - Make sure to check the troubleshooting section in the Docs! -
- - - Static pages made easy - Codeberg Pages - - - diff --git a/html/error.go b/html/error.go deleted file mode 100644 index 206b123..0000000 --- a/html/error.go +++ /dev/null @@ -1,50 +0,0 @@ -package html - -import ( - "html/template" - "net/http" - "strconv" - "strings" - - "codeberg.org/codeberg/pages/server/context" -) - -// ReturnErrorPage sets the response status code and writes NotFoundPage to the response body, -// with "%status%" and %message% replaced with the provided statusCode and msg -func ReturnErrorPage(ctx *context.Context, msg string, statusCode int) { - ctx.RespWriter.Header().Set("Content-Type", "text/html; charset=utf-8") - ctx.RespWriter.WriteHeader(statusCode) - - msg = generateResponse(msg, statusCode) - - _, _ = ctx.RespWriter.Write([]byte(msg)) -} - -// TODO: use template engine -func generateResponse(msg string, statusCode int) string { - if msg == "" { - msg = strings.ReplaceAll(NotFoundPage, - "%status%", - strconv.Itoa(statusCode)+" "+errorMessage(statusCode)) - } else { - msg = strings.ReplaceAll( - strings.ReplaceAll(ErrorPage, "%message%", template.HTMLEscapeString(msg)), - "%status%", - http.StatusText(statusCode)) - } - - return msg -} - -func errorMessage(statusCode int) string { - message := http.StatusText(statusCode) - - switch statusCode { - case http.StatusMisdirectedRequest: - message += " - domain not specified in .domains file" - case http.StatusFailedDependency: - message += " - target repo/branch doesn't exist or is private" - } - - return message -} diff --git a/html/error.html b/html/error.html deleted file mode 100644 index f1975f7..0000000 --- a/html/error.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - %status% - - - - - - - - - -

- %status%! -

-
- Sorry, but this page couldn't be served.
- We got an "%message%"
- We hope this isn't a problem on our end ;) - Make sure to check the troubleshooting section in the Docs! -
- - - Static pages made easy - Codeberg Pages - - - diff --git a/html/error_test.go b/html/error_test.go deleted file mode 100644 index f5da08c..0000000 --- a/html/error_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package html - -import ( - "net/http" - "strings" - "testing" -) - -func TestValidMessage(t *testing.T) { - testString := "requested blacklisted path" - statusCode := http.StatusForbidden - - expected := strings.ReplaceAll( - strings.ReplaceAll(ErrorPage, "%message%", testString), - "%status%", - http.StatusText(statusCode)) - actual := generateResponse(testString, statusCode) - - if expected != actual { - t.Errorf("generated response did not match: expected: '%s', got: '%s'", expected, actual) - } -} - -func TestMessageWithHtml(t *testing.T) { - testString := `abc +func ReturnErrorPage(ctx *context.Context, msg string, statusCode int) { + ctx.RespWriter.Header().Set("Content-Type", "text/html; charset=utf-8") + ctx.RespWriter.WriteHeader(statusCode) + + templateContext := TemplateContext{ + StatusCode: statusCode, + StatusText: http.StatusText(statusCode), + Message: sanitizer.Sanitize(msg), + } + + err := errorTemplate.Execute(ctx.RespWriter, templateContext) + if err != nil { + log.Err(err).Str("message", msg).Int("status", statusCode).Msg("could not write response") + } +} + +func createBlueMondayPolicy() *bluemonday.Policy { + p := bluemonday.NewPolicy() + + p.AllowElements("code") + + return p +} diff --git a/html/html_test.go b/html/html_test.go new file mode 100644 index 0000000..b395bb2 --- /dev/null +++ b/html/html_test.go @@ -0,0 +1,54 @@ +package html + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSanitizerSimpleString(t *testing.T) { + str := "simple text message without any html elements" + + assert.Equal(t, str, sanitizer.Sanitize(str)) +} + +func TestSanitizerStringWithCodeTag(t *testing.T) { + str := "simple text message with html tag" + + assert.Equal(t, str, sanitizer.Sanitize(str)) +} + +func TestSanitizerStringWithCodeTagWithAttribute(t *testing.T) { + str := "simple text message with html tag" + expected := "simple text message with html tag" + + assert.Equal(t, expected, sanitizer.Sanitize(str)) +} + +func TestSanitizerStringWithATag(t *testing.T) { + str := "simple text message with a link to another page" + expected := "simple text message with a link to another page" + + assert.Equal(t, expected, sanitizer.Sanitize(str)) +} + +func TestSanitizerStringWithATagAndHref(t *testing.T) { + str := "simple text message with a link to another page" + expected := "simple text message with a link to another page" + + assert.Equal(t, expected, sanitizer.Sanitize(str)) +} + +func TestSanitizerStringWithImgTag(t *testing.T) { + str := "simple text message with a \"not" + expected := "simple text message with a " + + assert.Equal(t, expected, sanitizer.Sanitize(str)) +} + +func TestSanitizerStringWithImgTagAndOnerrorAttribute(t *testing.T) { + str := "simple text message with a \"not" + expected := "simple text message with a " + + assert.Equal(t, expected, sanitizer.Sanitize(str)) +} diff --git a/html/templates/error.html b/html/templates/error.html new file mode 100644 index 0000000..6094a26 --- /dev/null +++ b/html/templates/error.html @@ -0,0 +1,69 @@ + + + + + + {{.StatusText}} + + + + + + + + + + +

{{.StatusText}} ({{.StatusCode}})!

+
+

Sorry, but this page couldn't be served.

+

"{{.Message}}"

+

+ We hope this isn't a problem on our end ;) - Make sure to check the + troubleshooting section in the Docs! +

+
+ + + Static pages made easy - + Codeberg Pages + + + diff --git a/server/handler/handler.go b/server/handler/handler.go index fbdafd7..a3011f3 100644 --- a/server/handler/handler.go +++ b/server/handler/handler.go @@ -65,7 +65,7 @@ func Handler(mainDomainSuffix, rawDomain string, // Block blacklisted paths (like ACME challenges) for _, blacklistedPath := range blacklistedPaths { if strings.HasPrefix(ctx.Path(), blacklistedPath) { - html.ReturnErrorPage(ctx, "requested blacklisted path", http.StatusForbidden) + html.ReturnErrorPage(ctx, "requested path is blacklisted", http.StatusForbidden) return } } diff --git a/server/handler/handler_custom_domain.go b/server/handler/handler_custom_domain.go index 299d7cf..8742be4 100644 --- a/server/handler/handler_custom_domain.go +++ b/server/handler/handler_custom_domain.go @@ -49,7 +49,7 @@ func handleCustomDomain(log zerolog.Logger, ctx *context.Context, giteaClient *g }, canonicalLink); works { canonicalDomain, valid := targetOpt.CheckCanonicalDomain(giteaClient, trimmedHost, mainDomainSuffix, canonicalDomainCache) if !valid { - html.ReturnErrorPage(ctx, "", http.StatusMisdirectedRequest) + html.ReturnErrorPage(ctx, "domain not specified in .domains file", http.StatusMisdirectedRequest) return } else if canonicalDomain != trimmedHost { // only redirect if the target is also a codeberg page! diff --git a/server/handler/handler_raw_domain.go b/server/handler/handler_raw_domain.go index aa41c52..b87991e 100644 --- a/server/handler/handler_raw_domain.go +++ b/server/handler/handler_raw_domain.go @@ -61,7 +61,7 @@ func handleRaw(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Clie tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache) } else { html.ReturnErrorPage(ctx, - fmt.Sprintf("raw domain could not find repo '%s/%s' or repo is empty", targetOpt.TargetOwner, targetOpt.TargetRepo), + fmt.Sprintf("raw domain could not find repo %s/%s or repo is empty", targetOpt.TargetOwner, targetOpt.TargetRepo), http.StatusNotFound) } } diff --git a/server/handler/handler_sub_domain.go b/server/handler/handler_sub_domain.go index 8731bec..e7cb3a6 100644 --- a/server/handler/handler_sub_domain.go +++ b/server/handler/handler_sub_domain.go @@ -55,9 +55,11 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite log.Trace().Msg("tryUpstream: serve with specified repo and branch") tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache) } else { - html.ReturnErrorPage(ctx, - fmt.Sprintf("explizite set branch %q do not exist at '%s/%s'", targetOpt.TargetBranch, targetOpt.TargetOwner, targetOpt.TargetRepo), - http.StatusFailedDependency) + html.ReturnErrorPage( + ctx, + formatSetBranchNotFoundMessage(targetOpt.TargetBranch, targetOpt.TargetOwner, targetOpt.TargetRepo), + http.StatusFailedDependency, + ) } return } @@ -85,9 +87,11 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite log.Trace().Msg("tryUpstream: serve default pages repo with specified branch") tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache) } else { - html.ReturnErrorPage(ctx, - fmt.Sprintf("explizite set branch %q do not exist at '%s/%s'", targetOpt.TargetBranch, targetOpt.TargetOwner, targetOpt.TargetRepo), - http.StatusFailedDependency) + html.ReturnErrorPage( + ctx, + formatSetBranchNotFoundMessage(targetOpt.TargetBranch, targetOpt.TargetOwner, targetOpt.TargetRepo), + http.StatusFailedDependency, + ) } return } @@ -143,6 +147,10 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite // Couldn't find a valid repo/branch html.ReturnErrorPage(ctx, - fmt.Sprintf("could not find a valid repository[%s]", targetRepo), + fmt.Sprintf("could not find a valid repository or branch for repository: %s", targetRepo), http.StatusNotFound) } + +func formatSetBranchNotFoundMessage(branch, owner, repo string) string { + return fmt.Sprintf("explicitly set branch %q does not exist at %s/%s", branch, owner, repo) +} diff --git a/server/handler/try.go b/server/handler/try.go index 6cfe08e..838ae27 100644 --- a/server/handler/try.go +++ b/server/handler/try.go @@ -41,7 +41,7 @@ func tryUpstream(ctx *context.Context, giteaClient *gitea.Client, // Try to request the file from the Gitea API if !options.Upstream(ctx, giteaClient, redirectsCache) { - html.ReturnErrorPage(ctx, "", ctx.StatusCode) + html.ReturnErrorPage(ctx, "gitea client failed", ctx.StatusCode) } } diff --git a/server/upstream/upstream.go b/server/upstream/upstream.go index f97c6ae..1a444e4 100644 --- a/server/upstream/upstream.go +++ b/server/upstream/upstream.go @@ -53,11 +53,11 @@ type Options struct { } // Upstream requests a file from the Gitea API at GiteaRoot and writes it to the request context. -func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redirectsCache cache.SetGetKey) (final bool) { +func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redirectsCache cache.SetGetKey) bool { log := log.With().Strs("upstream", []string{o.TargetOwner, o.TargetRepo, o.TargetBranch, o.TargetPath}).Logger() if o.TargetOwner == "" || o.TargetRepo == "" { - html.ReturnErrorPage(ctx, "either repo owner or name info is missing", http.StatusBadRequest) + html.ReturnErrorPage(ctx, "gitea client: either repo owner or name info is missing", http.StatusBadRequest) return true } @@ -67,7 +67,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redi // handle 404 if err != nil && errors.Is(err, gitea.ErrorNotFound) || !branchExist { html.ReturnErrorPage(ctx, - fmt.Sprintf("branch %q for '%s/%s' not found", o.TargetBranch, o.TargetOwner, o.TargetRepo), + fmt.Sprintf("branch %q for %s/%s not found", o.TargetBranch, o.TargetOwner, o.TargetRepo), http.StatusNotFound) return true } @@ -75,7 +75,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redi // handle unexpected errors if err != nil { html.ReturnErrorPage(ctx, - fmt.Sprintf("could not get timestamp of branch %q: %v", o.TargetBranch, err), + fmt.Sprintf("could not get timestamp of branch %q: '%v'", o.TargetBranch, err), http.StatusFailedDependency) return true } @@ -153,16 +153,16 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redi var msg string if err != nil { - msg = "gitea client returned unexpected error" + msg = "gitea client: returned unexpected error" log.Error().Err(err).Msg(msg) - msg = fmt.Sprintf("%s: %v", msg, err) + msg = fmt.Sprintf("%s: '%v'", msg, err) } if reader == nil { - msg = "gitea client returned no reader" + msg = "gitea client: returned no reader" log.Error().Msg(msg) } if statusCode != http.StatusOK { - msg = fmt.Sprintf("Couldn't fetch contents (status code %d)", statusCode) + msg = fmt.Sprintf("gitea client: couldn't fetch contents: %d - %s", statusCode, http.StatusText(statusCode)) log.Error().Msg(msg) }