44 "bufio"
55 "bytes"
66 "fmt"
7- "io/ioutil "
7+ "log "
88 "net/http"
99 "net/http/httputil"
1010 "strings"
@@ -15,57 +15,13 @@ import (
1515
1616// Headers
1717const (
18- HeaderAccept = "Accept"
19- HeaderAcceptEncoding = "Accept-Encoding"
20- HeaderAllow = "Allow"
21- HeaderAuthorization = "Authorization"
22- HeaderContentDisposition = "Content-Disposition"
23- HeaderContentEncoding = "Content-Encoding"
24- HeaderContentLength = "Content-Length"
25- HeaderContentType = "Content-Type"
26- HeaderCookie = "Cookie"
27- HeaderCacheControl = "Cache-Control"
28- HeaderSetCookie = "Set-Cookie"
29- HeaderIfModifiedSince = "If-Modified-Since"
30- HeaderLastModified = "Last-Modified"
31- HeaderLocation = "Location"
32- HeaderUpgrade = "Upgrade"
33- HeaderVary = "Vary"
34- HeaderWWWAuthenticate = "WWW-Authenticate"
35- HeaderXForwardedFor = "X-Forwarded-For"
36- HeaderXForwardedProto = "X-Forwarded-Proto"
37- HeaderXForwardedProtocol = "X-Forwarded-Protocol"
38- HeaderXForwardedSsl = "X-Forwarded-Ssl"
39- HeaderXUrlScheme = "X-Url-Scheme"
40- HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
41- HeaderXRealIP = "X-Real-IP"
42- HeaderXRequestID = "X-Request-ID"
43- HeaderXRequestedWith = "X-Requested-With"
44- HeaderServer = "Server"
45- HeaderOrigin = "Origin"
46-
47- // Access control
48- HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
49- HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers"
50- HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin"
51- HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods"
52- HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers"
53- HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
54- HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers"
55- HeaderAccessControlMaxAge = "Access-Control-Max-Age"
56-
57- // Security
58- HeaderStrictTransportSecurity = "Strict-Transport-Security"
59- HeaderXContentTypeOptions = "X-Content-Type-Options"
60- HeaderXXSSProtection = "X-XSS-Protection"
61- HeaderXFrameOptions = "X-Frame-Options"
62- HeaderContentSecurityPolicy = "Content-Security-Policy"
63- HeaderXCSRFToken = "X-CSRF-Token"
18+ HeaderAuthorization = "Authorization"
19+ HeaderCacheControl = "Cache-Control"
6420)
6521
6622var (
67- // CachedAuthorizedRequest used for determine that a request with Authorization header should be cached or not
68- CachedAuthorizedRequest = false // TODO(bxcodec): Need to revised about this feature
23+ // CacheAuthorizedRequest used for determine that a request with Authorization header should be cached or not
24+ CacheAuthorizedRequest = false // TODO(bxcodec): Need to revised about this feature
6925)
7026
7127// RoundTrip custom plugable' struct of implementation of the http.RoundTripper
@@ -74,16 +30,24 @@ type RoundTrip struct {
7430 CacheInteractor cache.Interactor
7531}
7632
33+ // NewRoundtrip will create an implementations of cache http roundtripper
34+ func NewRoundtrip (defaultRoundTripper http.RoundTripper , cacheActor cache.Interactor ) http.RoundTripper {
35+ return & RoundTrip {
36+ DefaultRoundTripper : defaultRoundTripper ,
37+ CacheInteractor : cacheActor ,
38+ }
39+ }
40+
7741// RoundTrip the implementation of http.RoundTripper
7842func (r * RoundTrip ) RoundTrip (req * http.Request ) (resp * http.Response , err error ) {
7943 if allowedFromCache (req ) {
80- resp , err = getCachedResponse (r .CacheInteractor , req )
44+ resp , cachedItem , err : = getCachedResponse (r .CacheInteractor , req )
8145 if resp != nil && err == nil {
82- buildTheCachedResponseHeader (resp )
83- return
46+ buildTheCachedResponseHeader (resp , cachedItem )
47+ return resp , err
8448 }
8549 }
86-
50+ err = nil
8751 resp , err = r .DefaultRoundTripper .RoundTrip (req )
8852 if err != nil {
8953 return
@@ -93,25 +57,21 @@ func (r *RoundTrip) RoundTrip(req *http.Request) (resp *http.Response, err error
9357 return
9458 }
9559
96- storeRespToCache (r .CacheInteractor , req , resp )
60+ err = storeRespToCache (r .CacheInteractor , req , resp )
61+ if err != nil {
62+ log .Println (err )
63+ }
64+
9765 return
9866}
9967
10068func storeRespToCache (cacheInteractor cache.Interactor , req * http.Request , resp * http.Response ) (err error ) {
10169 cachedResp := cache.CachedResponse {
102- StatusCode : resp .StatusCode ,
10370 RequestMethod : req .Method ,
10471 RequestURI : req .RequestURI ,
10572 CachedTime : time .Now (),
10673 }
10774
108- bodyBytes , err := ioutil .ReadAll (resp .Body )
109- if err != nil {
110- return
111- }
112-
113- resp .Body = ioutil .NopCloser (bytes .NewBuffer (bodyBytes ))
114- cachedResp .DumpedBody = bodyBytes
11575 dumpedResponse , err := httputil .DumpResponse (resp , true )
11676 if err != nil {
11777 return
@@ -121,8 +81,8 @@ func storeRespToCache(cacheInteractor cache.Interactor, req *http.Request, resp
12181 return
12282}
12383
124- func getCachedResponse (cacheInteractor cache.Interactor , req * http.Request ) (resp * http.Response , err error ) {
125- cachedResp , err : = cacheInteractor .Get (getCacheKey (req ))
84+ func getCachedResponse (cacheInteractor cache.Interactor , req * http.Request ) (resp * http.Response , cachedResp cache. CachedResponse , err error ) {
85+ cachedResp , err = cacheInteractor .Get (getCacheKey (req ))
12686 if err != nil {
12787 return
12888 }
@@ -132,12 +92,13 @@ func getCachedResponse(cacheInteractor cache.Interactor, req *http.Request) (res
13292 if err != nil {
13393 return
13494 }
95+
13596 return
13697}
13798
13899func getCacheKey (req * http.Request ) (key string ) {
139100 key = fmt .Sprintf ("%s %s" , req .Method , req .RequestURI )
140- if (CachedAuthorizedRequest ||
101+ if (CacheAuthorizedRequest ||
141102 (strings .ToLower (req .Header .Get (HeaderCacheControl )) == "private" )) &&
142103 req .Header .Get (HeaderAuthorization ) != "" {
143104 key = fmt .Sprintf ("%s %s" , key , req .Header .Get (HeaderAuthorization ))
@@ -146,21 +107,22 @@ func getCacheKey(req *http.Request) (key string) {
146107}
147108
148109// buildTheCachedResponse will finalize the response header
149- func buildTheCachedResponseHeader (resp * http.Response ) {
150- panic ("TODO: (bxcodec) Add the header based on RFC 7234" )
110+ func buildTheCachedResponseHeader (resp * http.Response , cachedResp cache.CachedResponse ) {
111+ resp .Header .Add ("Expires" , cachedResp .CachedTime .String ())
112+ // TODO: (bxcodec) add more headers related to cache
151113}
152114
153115// check the header if the response will cached or not
154116func allowedToCache (req * http.Request , resp * http.Response ) (ok bool ) {
155117 // A request with authorization header must not be cached
156118 // https://tools.ietf.org/html/rfc7234#section-3.2
157119 // Unless configured by user to cache request by authorization
158- if ok = ! CachedAuthorizedRequest && req .Header .Get (HeaderAuthorization ) != "" ; ! ok {
120+ if ok = ( ! CacheAuthorizedRequest && req .Header .Get (HeaderAuthorization ) == "" ) ; ! ok {
159121 return
160122 }
161123
162124 // check if the request method allowed to be cached
163- if ok = ! requestMethodValid (req ); ! ok {
125+ if ok = requestMethodValid (req ); ! ok {
164126 return
165127 }
166128
@@ -176,7 +138,6 @@ func allowedToCache(req *http.Request, resp *http.Response) (ok bool) {
176138 if ok = resp .StatusCode == http .StatusOK ; ! ok {
177139 return
178140 }
179-
180141 return
181142}
182143
0 commit comments