func buildTheCachedResponseHeader(resp *http.Response, cachedResp cache.CachedResponse, origin string) {
	resp.Header.Add("Expires", cachedResp.CachedTime.String())
	resp.Header.Add(XFromHache, "true")
	resp.Header.Add(XHacheOrigin, origin)
}
buildTheCachedResponse will finalize the response header
package httpcache
import (
	"bufio"
	"bytes"
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"strings"
	"time"
	"github.com/bxcodec/httpcache/cache"
	cacheControl "github.com/bxcodec/httpcache/helper/cacheheader"
)
const (
	HeaderAuthorization = "Authorization"
	HeaderCacheControl  = "Cache-Control"
	XFromHache   = "X-HTTPCache"
	XHacheOrigin = "X-HTTPCache-Origin"
)
type CacheHandler struct {
	DefaultRoundTripper http.RoundTripper
	CacheInteractor     cache.ICacheInteractor
	ComplyRFC           bool
}
func NewCacheHandlerRoundtrip(defaultRoundTripper http.RoundTripper, rfcCompliance bool, cacheActor cache.ICacheInteractor) *CacheHandler {
	if cacheActor == nil {
		log.Fatal("cache storage is not well set")
	}
	return &CacheHandler{
		DefaultRoundTripper: defaultRoundTripper,
		CacheInteractor:     cacheActor,
		ComplyRFC:           rfcCompliance,
	}
}
func validateTheCacheControl(req *http.Request, resp *http.Response) (validationResult cacheControl.ObjectResults, err error) {
	reqDir, err := cacheControl.ParseRequestCacheControl(req.Header.Get("Cache-Control"))
	if err != nil {
		return
	}
	resDir, err := cacheControl.ParseResponseCacheControl(resp.Header.Get("Cache-Control"))
	if err != nil {
		return
	}
	expiry := resp.Header.Get("Expires")
	expiresHeader, err := http.ParseTime(expiry)
	if err != nil && expiry != "" &&
		expiry != "-1" && expiry != "0" {
		return
	}
	dateHeaderStr := resp.Header.Get("Date")
	dateHeader, err := http.ParseTime(dateHeaderStr)
	if err != nil && dateHeaderStr != "" {
		return
	}
	lastModifiedStr := resp.Header.Get("Last-Modified")
	lastModifiedHeader, err := http.ParseTime(lastModifiedStr)
	if err != nil && lastModifiedStr != "" {
		return
	}
	obj := cacheControl.Object{
		RespDirectives:         resDir,
		RespHeaders:            resp.Header,
		RespStatusCode:         resp.StatusCode,
		RespExpiresHeader:      expiresHeader,
		RespDateHeader:         dateHeader,
		RespLastModifiedHeader: lastModifiedHeader,
		ReqDirectives:          reqDir,
		ReqHeaders:             req.Header,
		ReqMethod:              req.Method,
		NowUTC:                 time.Now().UTC(),
	}
	validationResult = cacheControl.ObjectResults{}
	cacheControl.CachableObject(&obj, &validationResult)
	cacheControl.ExpirationObject(&obj, &validationResult)
	return validationResult, nil
}
func (r *CacheHandler) roundTripRFCCompliance(req *http.Request) (resp *http.Response, err error) {
	allowCache := allowedFromCache(req.Header)
	if allowCache {
		cachedResp, cachedItem, cachedErr := getCachedResponse(r.CacheInteractor, req)
		if cachedResp != nil && cachedErr == nil {
			buildTheCachedResponseHeader(cachedResp, cachedItem, r.CacheInteractor.Origin())
			return cachedResp, cachedErr
		}
		if cachedErr != nil {
			log.Println(cachedErr, "failed to retrieve from cache, trying with a live version")
		}
	}
	resp, err = r.DefaultRoundTripper.RoundTrip(req)
	if err != nil {
		return
	}
	validationResult, errValidation := validateTheCacheControl(req, resp)
	if errValidation != nil {
		log.Printf("Can't validate the response to RFC 7234, plase check. Err: %v\n", errValidation)
		return  
	}
	if validationResult.OutErr != nil {
		log.Printf("Can't validate the response to RFC 7234, plase check. Err: %v\n", validationResult.OutErr)
		return  
	}
	if len(validationResult.OutReasons) > 0 {
		log.Printf("Can't validate the response to RFC 7234, plase check. Err: %v\n", validationResult.OutReasons)
		return  
	}
	err = storeRespToCache(r.CacheInteractor, req, resp)
	if err != nil {
		log.Printf("Can't store the response to database, plase check. Err: %v\n", err)
		err = nil  
	}
	return
}
func (r *CacheHandler) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	if r.ComplyRFC {
		return r.roundTripRFCCompliance(req)
	}
	cachedResp, cachedItem, cachedErr := getCachedResponse(r.CacheInteractor, req)
	if cachedResp != nil && cachedErr == nil {
		buildTheCachedResponseHeader(cachedResp, cachedItem, r.CacheInteractor.Origin())
		return cachedResp, cachedErr
	}
	if cachedErr != nil {
		log.Println(cachedErr, "failed to retrieve from cache, trying with a live version")
	}
	resp, err = r.DefaultRoundTripper.RoundTrip(req)
	if err != nil {
		return
	}
	err = storeRespToCache(r.CacheInteractor, req, resp)
	if err != nil {
		log.Printf("Can't store the response to database, plase check. Err: %v\n", err)
		err = nil  
	}
	return
}
func (r *CacheHandler) RFC7234Compliance(val bool) *CacheHandler {
	r.ComplyRFC = val
	return r
}
func storeRespToCache(cacheInteractor cache.ICacheInteractor, req *http.Request, resp *http.Response) (err error) {
	cachedResp := cache.CachedResponse{
		RequestMethod: req.Method,
		RequestURI:    req.RequestURI,
		CachedTime:    time.Now(),
	}
	dumpedResponse, err := httputil.DumpResponse(resp, true)
	if err != nil {
		return
	}
	cachedResp.DumpedResponse = dumpedResponse
	err = cacheInteractor.Set(getCacheKey(req), cachedResp)
	return
}
func getCachedResponse(cacheInteractor cache.ICacheInteractor, req *http.Request) (resp *http.Response, cachedResp cache.CachedResponse, err error) {
	cachedResp, err = cacheInteractor.Get(getCacheKey(req))
	if err != nil {
		return
	}
	cachedResponse := bytes.NewBuffer(cachedResp.DumpedResponse)
	resp, err = http.ReadResponse(bufio.NewReader(cachedResponse), req)
	if err != nil {
		return
	}
	validationResult, err := validateTheCacheControl(req, resp)
	if err != nil {
		return
	}
	if validationResult.OutErr != nil {
		return
	}
	if time.Now().After(validationResult.OutExpirationTime) {
		err = fmt.Errorf("cached-item already expired")
		return
	}
	return
}
func getCacheKey(req *http.Request) (key string) {
	key = fmt.Sprintf("%s %s", req.Method, req.RequestURI)
	if (strings.ToLower(req.Header.Get(HeaderCacheControl)) == "private") &&
		req.Header.Get(HeaderAuthorization) != "" {
		key = fmt.Sprintf("%s %s", key, req.Header.Get(HeaderAuthorization))
	}
	return
}