commit
						dc348d720b
					
				| 
						 | 
				
			
			@ -263,6 +263,43 @@ func TestLayerAPI(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
	checkResponse(t, "fetching layer bad digest", resp, http.StatusBadRequest)
 | 
			
		||||
 | 
			
		||||
	// Cache headers
 | 
			
		||||
	resp, err = http.Get(layerURL)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("unexpected error fetching layer: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	checkResponse(t, "fetching layer", resp, http.StatusOK)
 | 
			
		||||
	checkHeaders(t, resp, http.Header{
 | 
			
		||||
		"Content-Length":        []string{fmt.Sprint(layerLength)},
 | 
			
		||||
		"Docker-Content-Digest": []string{layerDigest.String()},
 | 
			
		||||
		"ETag":                  []string{layerDigest.String()},
 | 
			
		||||
		"Cache-Control":         []string{"max-age=86400"},
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// Matching etag, gives 304
 | 
			
		||||
	etag := resp.Header.Get("Etag")
 | 
			
		||||
	req, err = http.NewRequest("GET", layerURL, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Error constructing request: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
	req.Header.Set("If-None-Match", etag)
 | 
			
		||||
	resp, err = http.DefaultClient.Do(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Error constructing request: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	checkResponse(t, "fetching layer with etag", resp, http.StatusNotModified)
 | 
			
		||||
 | 
			
		||||
	// Non-matching etag, gives 200
 | 
			
		||||
	req, err = http.NewRequest("GET", layerURL, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Error constructing request: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
	req.Header.Set("If-None-Match", "")
 | 
			
		||||
	resp, err = http.DefaultClient.Do(req)
 | 
			
		||||
	checkResponse(t, "fetching layer with invalid etag", resp, http.StatusOK)
 | 
			
		||||
 | 
			
		||||
	// Missing tests:
 | 
			
		||||
	// 	- Upload the same tarsum file under and different repository and
 | 
			
		||||
	//       ensure the content remains uncorrupted.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
package storage
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +74,31 @@ func (lr *layerReader) Handler(r *http.Request) (h http.Handler, err error) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		// If the registry is serving this content itself, check
 | 
			
		||||
		// the If-None-Match header and return 304 on match.  Redirected
 | 
			
		||||
		// storage implementations do the same.
 | 
			
		||||
 | 
			
		||||
		if etagMatch(r, lr.digest.String()) {
 | 
			
		||||
			w.WriteHeader(http.StatusNotModified)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		setCacheHeaders(w, 86400, lr.digest.String())
 | 
			
		||||
		w.Header().Set("Docker-Content-Digest", lr.digest.String())
 | 
			
		||||
		handlerFunc.ServeHTTP(w, r)
 | 
			
		||||
	}), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func etagMatch(r *http.Request, etag string) bool {
 | 
			
		||||
	for _, headerVal := range r.Header["If-None-Match"] {
 | 
			
		||||
		if headerVal == etag {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setCacheHeaders(w http.ResponseWriter, cacheAge int, etag string) {
 | 
			
		||||
	w.Header().Set("ETag", etag)
 | 
			
		||||
	w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", cacheAge))
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue