set strong ETag for responses

This commit is contained in:
perennial 2024-12-04 01:37:11 +11:00
parent 15f3ad988a
commit 3ac20187ea
No known key found for this signature in database
GPG key ID: 826BC6E6B83E08E7
3 changed files with 43 additions and 6 deletions

View file

@ -137,6 +137,7 @@
"assets/views/fragments/small-tn.jet.html:yTQShm_bVeU": "Deleted or Private",
"assets/views/fragments/thumbnail-dt.jet.html:0wMo7aB_ylE": "{{ if .XRestrict == 1 }}R-18{{ else }}R-18G{{ end }}",
"assets/views/fragments/thumbnail-dt.jet.html:R20Dy5iCS58": "AI",
"assets/views/index.jet.html:6103Lobv_EM": "Trending!",
"assets/views/index.jet.html:8lMwxcLFwfQ": "R-18",
"assets/views/index.jet.html:Awt3bDxDL0U": "View more",
"assets/views/index.jet.html:D-LKBPd3-uc": "Today's illustration rankings",
@ -145,6 +146,7 @@
"assets/views/index.jet.html:Sccoo133FQI": "All",
"assets/views/index.jet.html:lEVH3Ram904": "Newest works",
"assets/views/index.jet.html:lv5wuj1vx98": "Latest works by followed",
"assets/views/index.jet.html:n-1FZQng9rs": "Popular tags",
"assets/views/index.jet.html:n7zdClpaR18": "Recommended illustrations tagged",
"assets/views/index.jet.html:s7Bp-mQhmg0": "Recommended users",
"assets/views/index.jet.html:v1aAHggOM7M": "Recommended works",

View file

@ -14,9 +14,20 @@ func RenderHTML[T any](w http.ResponseWriter, r *http.Request, data T) error {
}
func RenderWithContentType[T any](w http.ResponseWriter, r *http.Request, contentType string, data T) error {
w.Header().Set("content-type", contentType)
w.WriteHeader(request_context.Get(r).RenderStatusCode)
return template.Render(w, template.GetTemplatingVariables(r), data)
w.Header().Set("Content-Type", contentType)
// Render and get ETag
etag, err := template.Render(w, template.GetTemplatingVariables(r), data)
if err != nil {
return err
}
// Set strong ETag
w.Header().Set("ETag", `"`+etag+`"`)
w.WriteHeader(request_context.Get(r).RenderStatusCode)
return nil
}
// Tutorial: adding new types in this file

View file

@ -1,12 +1,17 @@
package template
import (
"bytes"
"encoding/base64"
"encoding/binary"
"io"
"log"
"net/http"
"reflect"
"strings"
"github.com/zeebo/xxh3"
"codeberg.org/vnpower/pixivfe/v2/server/session"
"codeberg.org/vnpower/pixivfe/v2/server/utils"
@ -32,7 +37,7 @@ func Init(DisableCache bool, assetsLocation string) {
}
}
func Render[T any](w io.Writer, variables jet.VarMap, data T) error {
func Render[T any](w io.Writer, variables jet.VarMap, data T) (string, error) {
template_name, found := strings.CutPrefix(reflect.TypeFor[T]().Name(), "Data_")
if !found {
log.Panicf("struct name does not start with 'Data_': %s", template_name)
@ -40,12 +45,31 @@ func Render[T any](w io.Writer, variables jet.VarMap, data T) error {
template, err := views.GetTemplate(template_name + ".jet.html")
if err != nil {
return err
return "", err
}
views.Parse(template_name+".jet.html", template.String())
return template.Execute(w, variables, data)
// Create buffer to capture rendered output
buf := &bytes.Buffer{}
// Execute template to buffer
if err := template.Execute(buf, variables, data); err != nil {
return "", err
}
// Generate ETag
hash := xxh3.Hash(buf.Bytes())
hash_bytes := make([]byte, 8)
binary.LittleEndian.PutUint64(hash_bytes, uint64(hash))
etag := template_name + ":" + base64.RawURLEncoding.EncodeToString(hash_bytes)
// Write buffer to original writer
if _, err := io.Copy(w, buf); err != nil {
return "", err
}
return etag, nil
}
func GetTemplatingVariables(r *http.Request) jet.VarMap {