Skip to content

Commit 4c515d0

Browse files
committed
Add Ability to provide non-cacheable headers
1 parent fe78e97 commit 4c515d0

3 files changed

Lines changed: 169 additions & 35 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ func main() {
4646
cache.ClientWithAdapter(memcached),
4747
cache.ClientWithTTL(10 * time.Minute),
4848
cache.ClientWithRefreshKey("opn"),
49+
cache.ClientWithNonCachedHeaders([]string{"geo-country"}),
4950
)
5051
if err != nil {
5152
fmt.Println(err)
@@ -137,4 +138,4 @@ http-cache memory adapter takes way less GC pause time, that means smaller GC ov
137138
- [Redis adapter](https://godoc.org/github.com/victorspringer/http-cache/adapter/redis)
138139

139140
## License
140-
http-cache is released under the [MIT License](https://github.com/victorspringer/http-cache/blob/master/LICENSE).
141+
http-cache is released under the [MIT License](https://github.com/victorspringer/http-cache/blob/master/LICENSE).

cache.go

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,11 @@ type Response struct {
6262

6363
// Client data structure for HTTP cache middleware.
6464
type Client struct {
65-
adapter Adapter
66-
ttl time.Duration
67-
refreshKey string
68-
methods []string
65+
adapter Adapter
66+
ttl time.Duration
67+
refreshKey string
68+
methods []string
69+
nonCacheableHeaders []string
6970
}
7071

7172
// ClientOption is used to set Client settings.
@@ -89,7 +90,9 @@ func (c *Client) Middleware(next http.Handler) http.Handler {
8990
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
9091
if c.cacheableMethod(r.Method) {
9192
sortURLParams(r.URL)
92-
key := generateKey(r.URL.String())
93+
headerValues := extractHeaders(c.nonCacheableHeaders, r.Header)
94+
95+
key := generateKey(r.URL.String(), headerValues)
9396
if r.Method == http.MethodPost && r.Body != nil {
9497
body, err := ioutil.ReadAll(r.Body)
9598
defer r.Body.Close()
@@ -98,7 +101,7 @@ func (c *Client) Middleware(next http.Handler) http.Handler {
98101
return
99102
}
100103
reader := ioutil.NopCloser(bytes.NewBuffer(body))
101-
key = generateKeyWithBody(r.URL.String(), body)
104+
key = generateKeyWithBody(r.URL.String(), headerValues, body)
102105
r.Body = reader
103106
}
104107

@@ -107,7 +110,7 @@ func (c *Client) Middleware(next http.Handler) http.Handler {
107110
delete(params, c.refreshKey)
108111

109112
r.URL.RawQuery = params.Encode()
110-
key = generateKey(r.URL.String())
113+
key = generateKey(r.URL.String(), headerValues)
111114

112115
c.adapter.Release(key)
113116
} else {
@@ -202,21 +205,49 @@ func KeyAsString(key uint64) string {
202205
return strconv.FormatUint(key, 36)
203206
}
204207

205-
func generateKey(URL string) uint64 {
208+
func generateKey(URL string, headerValues []string) uint64 {
209+
buffer := bytes.Buffer{}
210+
buffer.WriteString(URL)
211+
212+
for _, value := range headerValues {
213+
buffer.WriteString(value)
214+
}
215+
206216
hash := fnv.New64a()
207-
hash.Write([]byte(URL))
217+
hash.Write(buffer.Bytes())
208218

209219
return hash.Sum64()
210220
}
211221

212-
func generateKeyWithBody(URL string, body []byte) uint64 {
222+
func generateKeyWithBody(URL string, headerValues []string, body []byte) uint64 {
223+
buffer := bytes.Buffer{}
224+
buffer.WriteString(URL)
225+
226+
for _, value := range headerValues {
227+
buffer.WriteString(value)
228+
}
229+
230+
buffer.Write(body)
231+
213232
hash := fnv.New64a()
214-
body = append([]byte(URL), body...)
215-
hash.Write(body)
233+
hash.Write([]byte(buffer.String()))
216234

217235
return hash.Sum64()
218236
}
219237

238+
func extractHeaders(nonCachedHeaders []string, headers http.Header) []string {
239+
var headerValues []string
240+
241+
for _, nonCachedHeader := range nonCachedHeaders {
242+
headerValue, ok := headers[nonCachedHeader]
243+
if ok {
244+
headerValues = append(headerValues, headerValue...)
245+
}
246+
}
247+
248+
return headerValues
249+
}
250+
220251
// NewClient initializes the cache HTTP middleware client with the given
221252
// options.
222253
func NewClient(opts ...ClientOption) (*Client, error) {
@@ -285,3 +316,12 @@ func ClientWithMethods(methods []string) ClientOption {
285316
return nil
286317
}
287318
}
319+
320+
// ClientWithNonCacheableHeaders sets the un-cacheable headers.
321+
// If you provide []string{"geo-country"} cache will be missed with different "geo-country" header but same URL.
322+
func ClientWithNonCacheableHeaders(headers []string) ClientOption {
323+
return func(c *Client) error {
324+
c.nonCacheableHeaders = headers
325+
return nil
326+
}
327+
}

0 commit comments

Comments
 (0)