forked from gofiber/fiber
/
etag.go
116 lines (94 loc) · 2.59 KB
/
etag.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
107
108
109
110
111
112
113
114
115
116
package etag
import (
"bytes"
"hash/crc32"
"github.com/Nota-ITS/fiber"
"github.com/valyala/bytebufferpool"
)
// New creates a new middleware handler
func New(config ...Config) fiber.Handler {
// Set default config
cfg := configDefault(config...)
var (
normalizedHeaderETag = []byte("Etag")
weakPrefix = []byte("W/")
)
const crcPol = 0xD5828281
crc32q := crc32.MakeTable(crcPol)
// Return new handler
return func(c *fiber.Ctx) error {
// Don't execute middleware if Next returns true
if cfg.Next != nil && cfg.Next(c) {
return c.Next()
}
// Return err if next handler returns one
if err := c.Next(); err != nil {
return err
}
// Don't generate ETags for invalid responses
if c.Response().StatusCode() != fiber.StatusOK {
return nil
}
body := c.Response().Body()
// Skips ETag if no response body is present
if len(body) == 0 {
return nil
}
// Skip ETag if header is already present
if c.Response().Header.PeekBytes(normalizedHeaderETag) != nil {
return nil
}
// Generate ETag for response
bb := bytebufferpool.Get()
defer bytebufferpool.Put(bb)
// Enable weak tag
if cfg.Weak {
_, _ = bb.Write(weakPrefix) //nolint:errcheck // This will never fail
}
_ = bb.WriteByte('"') //nolint:errcheck // This will never fail
bb.B = appendUint(bb.Bytes(), uint32(len(body)))
_ = bb.WriteByte('-') //nolint:errcheck // This will never fail
bb.B = appendUint(bb.Bytes(), crc32.Checksum(body, crc32q))
_ = bb.WriteByte('"') //nolint:errcheck // This will never fail
etag := bb.Bytes()
// Get ETag header from request
clientEtag := c.Request().Header.Peek(fiber.HeaderIfNoneMatch)
// Check if client's ETag is weak
if bytes.HasPrefix(clientEtag, weakPrefix) {
// Check if server's ETag is weak
if bytes.Equal(clientEtag[2:], etag) || bytes.Equal(clientEtag[2:], etag[2:]) {
// W/1 == 1 || W/1 == W/1
c.Context().ResetBody()
return c.SendStatus(fiber.StatusNotModified)
}
// W/1 != W/2 || W/1 != 2
c.Response().Header.SetCanonical(normalizedHeaderETag, etag)
return nil
}
if bytes.Contains(clientEtag, etag) {
// 1 == 1
c.Context().ResetBody()
return c.SendStatus(fiber.StatusNotModified)
}
// 1 != 2
c.Response().Header.SetCanonical(normalizedHeaderETag, etag)
return nil
}
}
// appendUint appends n to dst and returns the extended dst.
func appendUint(dst []byte, n uint32) []byte {
var b [20]byte
buf := b[:]
i := len(buf)
var q uint32
for n >= 10 {
i--
q = n / 10
buf[i] = '0' + byte(n-q*10)
n = q
}
i--
buf[i] = '0' + byte(n)
dst = append(dst, buf[i:]...)
return dst
}