Refactor Layer interface to return a Handler
... Rather than ServeHTTP directly. Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
This commit is contained in:
parent
e062e66ee1
commit
db5689aa86
4 changed files with 39 additions and 13 deletions
|
@ -108,10 +108,10 @@ type Layer interface {
|
||||||
// CreatedAt returns the time this layer was created.
|
// CreatedAt returns the time this layer was created.
|
||||||
CreatedAt() time.Time
|
CreatedAt() time.Time
|
||||||
|
|
||||||
// ServeHTTP allows a layer to serve itself, whether by providing
|
// Handler returns an HTTP handler which serves the layer content, whether
|
||||||
// a redirect directly to the content, or by serving the content
|
// by providing a redirect directly to the content, or by serving the
|
||||||
// itself
|
// content itself.
|
||||||
ServeHTTP(w http.ResponseWriter, r *http.Request)
|
Handler(r *http.Request) (http.Handler, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LayerUpload provides a handle for working with in-progress uploads.
|
// LayerUpload provides a handle for working with in-progress uploads.
|
||||||
|
|
|
@ -63,5 +63,12 @@ func (lh *layerHandler) GetLayer(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
layer.ServeHTTP(w, r)
|
handler, err := layer.Handler(r)
|
||||||
|
if err != nil {
|
||||||
|
ctxu.GetLogger(lh).Debugf("unexpected error getting layer HTTP handler: %s", err)
|
||||||
|
lh.Errors.Push(v2.ErrorCodeUnknown, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ type StorageDriver interface {
|
||||||
|
|
||||||
// URLFor returns a URL which may be used to retrieve the content stored at
|
// URLFor returns a URL which may be used to retrieve the content stored at
|
||||||
// the given path, possibly using the given options.
|
// the given path, possibly using the given options.
|
||||||
// May return an UnsupportedMethodErr in certain StorageDriver
|
// May return an ErrUnsupportedMethod in certain StorageDriver
|
||||||
// implementations.
|
// implementations.
|
||||||
URLFor(path string, options map[string]interface{}) (string, error)
|
URLFor(path string, options map[string]interface{}) (string, error)
|
||||||
}
|
}
|
||||||
|
@ -85,8 +85,8 @@ type StorageDriver interface {
|
||||||
// hyphen.
|
// hyphen.
|
||||||
var PathRegexp = regexp.MustCompile(`^(/[a-z0-9._-]+)+$`)
|
var PathRegexp = regexp.MustCompile(`^(/[a-z0-9._-]+)+$`)
|
||||||
|
|
||||||
// UnsupportedMethodErr may be returned in the case where a StorageDriver implementation does not support an optional method.
|
// ErrUnsupportedMethod may be returned in the case where a StorageDriver implementation does not support an optional method.
|
||||||
var ErrUnsupportedMethod = errors.New("Unsupported method")
|
var ErrUnsupportedMethod = errors.New("unsupported method")
|
||||||
|
|
||||||
// PathNotFoundError is returned when operating on a nonexistent path.
|
// PathNotFoundError is returned when operating on a nonexistent path.
|
||||||
type PathNotFoundError struct {
|
type PathNotFoundError struct {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/docker/distribution/digest"
|
||||||
|
"github.com/docker/distribution/registry/storage/driver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// layerReader implements Layer and provides facilities for reading and
|
// layerReader implements Layer and provides facilities for reading and
|
||||||
|
@ -35,11 +36,29 @@ func (lr *layerReader) Close() error {
|
||||||
return lr.closeWithErr(distribution.ErrLayerClosed)
|
return lr.closeWithErr(distribution.ErrLayerClosed)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *layerReader) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (lr *layerReader) Handler(r *http.Request) (h http.Handler, err error) {
|
||||||
w.Header().Set("Docker-Content-Digest", lr.digest.String())
|
var handlerFunc http.HandlerFunc
|
||||||
|
|
||||||
if url, err := lr.fileReader.driver.URLFor(lr.path, map[string]interface{}{"method": r.Method}); err == nil {
|
redirectURL, err := lr.fileReader.driver.URLFor(lr.path, map[string]interface{}{"method": r.Method})
|
||||||
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
|
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
handlerFunc = func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Redirect to storage URL.
|
||||||
|
http.Redirect(w, r, redirectURL, http.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
|
case driver.ErrUnsupportedMethod:
|
||||||
|
handlerFunc = func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Fallback to serving the content directly.
|
||||||
http.ServeContent(w, r, lr.digest.String(), lr.CreatedAt(), lr)
|
http.ServeContent(w, r, lr.digest.String(), lr.CreatedAt(), lr)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Some unexpected error.
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Docker-Content-Digest", lr.digest.String())
|
||||||
|
handlerFunc.ServeHTTP(w, r)
|
||||||
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue