Merge pull request #261 from jlhawn/url_for_method

Refactor Layer interface to return a Handler
This commit is contained in:
Stephen Day 2015-03-13 17:27:42 -07:00
commit af4f5aa7d2
3 changed files with 35 additions and 9 deletions

View file

@ -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)
} }

View file

@ -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 {

View file

@ -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
}