@@ -62,10 +62,11 @@ type Response struct {
6262
6363// Client data structure for HTTP cache middleware.
6464type 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.
222253func 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