-
Notifications
You must be signed in to change notification settings - Fork 1
/
dot_resp.go
106 lines (92 loc) · 2.45 KB
/
dot_resp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package xtemplate
import (
"errors"
"io"
"log/slog"
"maps"
"net/http"
"path"
"strings"
"time"
)
type dotRespProvider struct{}
func (dotRespProvider) Value(r Request) (any, error) {
return DotResp{
Header: make(http.Header),
status: http.StatusOK,
w: r.W, r: r.R,
log: GetLogger(r.R.Context()),
}, nil
}
func (dotRespProvider) Cleanup(v any, err error) error {
d := v.(DotResp)
var errSt ErrorStatus
if errors.As(err, &errSt) {
// headers?
d.w.WriteHeader(int(errSt))
} else if err == nil {
maps.Copy(d.w.Header(), d.Header)
d.w.WriteHeader(d.status)
}
return err
}
var _ CleanupDotProvider = dotRespProvider{}
// DotResp is used as the .Resp field in buffered template invocations.
type DotResp struct {
http.Header
status int
w http.ResponseWriter
r *http.Request
log *slog.Logger
}
// ServeContent aborts execution of the template and instead responds to the
// request with content with any headers set by AddHeader and SetHeader so far
// but ignoring SetStatus.
func (d *DotResp) ServeContent(path_ string, modtime time.Time, content any) (string, error) {
var reader io.ReadSeeker
switch c := content.(type) {
case string:
reader = strings.NewReader(c)
case io.ReadSeeker:
reader = c
}
path_ = path.Clean(path_)
d.log.Debug("serving content response", slog.String("path", path_))
maps.Copy(d.w.Header(), d.Header)
http.ServeContent(d.w, d.r, path_, modtime, reader)
return "", ReturnError{}
}
// AddHeader adds a header field value, appending val to
// existing values for that field. It returns an
// empty string.
func (h *DotResp) AddHeader(field, val string) string {
h.Header.Add(field, val)
return ""
}
// SetHeader sets a header field value, overwriting any
// other values for that field. It returns an
// empty string.
func (h *DotResp) SetHeader(field, val string) string {
h.Header.Set(field, val)
return ""
}
// DelHeader deletes a header field. It returns an empty string.
func (h *DotResp) DelHeader(field string) string {
h.Header.Del(field)
return ""
}
// SetStatus sets the HTTP response status. It returns an empty string.
func (h *DotResp) SetStatus(status int) string {
h.status = status
return ""
}
// ReturnStatus sets the HTTP response status and exits template rendering
// immediately.
func (h *DotResp) ReturnStatus(status int) (string, error) {
h.status = status
return "", ReturnError{}
}
type ErrorStatus int
func (e ErrorStatus) Error() string {
return http.StatusText(int(e))
}