commit
						aeda6f5f8f
					
				| 
						 | 
					@ -263,6 +263,43 @@ func TestLayerAPI(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	checkResponse(t, "fetching layer bad digest", resp, http.StatusBadRequest)
 | 
						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:
 | 
						// Missing tests:
 | 
				
			||||||
	// 	- Upload the same tarsum file under and different repository and
 | 
						// 	- Upload the same tarsum file under and different repository and
 | 
				
			||||||
	//       ensure the content remains uncorrupted.
 | 
						//       ensure the content remains uncorrupted.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
package storage
 | 
					package storage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"time"
 | 
						"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) {
 | 
						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())
 | 
							w.Header().Set("Docker-Content-Digest", lr.digest.String())
 | 
				
			||||||
		handlerFunc.ServeHTTP(w, r)
 | 
							handlerFunc.ServeHTTP(w, r)
 | 
				
			||||||
	}), nil
 | 
						}), 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