register/handlers: remove context manager

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2017-04-07 15:19:53 -07:00
parent a73ed75f5a
commit 1f0a9dbca0
No known key found for this signature in database
GPG key ID: 67B3DED84EDC823F
2 changed files with 11 additions and 73 deletions

View file

@ -596,24 +596,19 @@ func (app *App) configureSecret(configuration *configuration.Configuration) {
func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close() // ensure that request body is always closed. defer r.Body.Close() // ensure that request body is always closed.
// Instantiate an http context here so we can track the error codes // Prepare the context with our own little decorations.
// returned by the request router. ctx := r.Context()
ctx := defaultContextManager.context(app, w, r) ctx = ctxu.WithRequest(ctx, r)
ctx, w = ctxu.WithResponseWriter(ctx, w)
ctx = ctxu.WithLogger(ctx, ctxu.GetRequestLogger(ctx))
r = r.WithContext(ctx)
defer func() { defer func() {
status, ok := ctx.Value("http.response.status").(int) status, ok := ctx.Value("http.response.status").(int)
if ok && status >= 200 && status <= 399 { if ok && status >= 200 && status <= 399 {
ctxu.GetResponseLogger(ctx).Infof("response completed") ctxu.GetResponseLogger(r.Context()).Infof("response completed")
} }
}() }()
defer defaultContextManager.release(ctx)
// NOTE(stevvooe): Total hack to get instrumented responsewriter from context.
var err error
w, err = ctxu.GetResponseWriter(ctx)
if err != nil {
ctxu.GetLogger(ctx).Warnf("response writer not found in context")
}
// Set a header with the Docker Distribution API Version for all responses. // Set a header with the Docker Distribution API Version for all responses.
w.Header().Add("Docker-Distribution-API-Version", "registry/2.0") w.Header().Add("Docker-Distribution-API-Version", "registry/2.0")
@ -649,6 +644,9 @@ func (app *App) dispatcher(dispatch dispatchFunc) http.Handler {
// Add username to request logging // Add username to request logging
context.Context = ctxu.WithLogger(context.Context, ctxu.GetLogger(context.Context, auth.UserNameKey)) context.Context = ctxu.WithLogger(context.Context, ctxu.GetLogger(context.Context, auth.UserNameKey))
// sync up context on the request.
r = r.WithContext(context)
if app.nameRequired(r) { if app.nameRequired(r) {
nameRef, err := reference.WithName(getName(context)) nameRef, err := reference.WithName(getName(context))
if err != nil { if err != nil {
@ -756,7 +754,7 @@ func (app *App) logError(context context.Context, errors errcode.Errors) {
// context constructs the context object for the application. This only be // context constructs the context object for the application. This only be
// called once per request. // called once per request.
func (app *App) context(w http.ResponseWriter, r *http.Request) *Context { func (app *App) context(w http.ResponseWriter, r *http.Request) *Context {
ctx := defaultContextManager.context(app, w, r) ctx := r.Context()
ctx = ctxu.WithVars(ctx, r) ctx = ctxu.WithVars(ctx, r)
ctx = ctxu.WithLogger(ctx, ctxu.GetLogger(ctx, ctx = ctxu.WithLogger(ctx, ctxu.GetLogger(ctx,
"vars.name", "vars.name",

View file

@ -3,7 +3,6 @@ package handlers
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"sync"
"github.com/docker/distribution" "github.com/docker/distribution"
ctxu "github.com/docker/distribution/context" ctxu "github.com/docker/distribution/context"
@ -91,62 +90,3 @@ func getUserName(ctx context.Context, r *http.Request) string {
return username return username
} }
// contextManager allows us to associate net/context.Context instances with a
// request, based on the memory identity of http.Request. This prepares http-
// level context, which is not application specific. If this is called,
// (*contextManager).release must be called on the context when the request is
// completed.
//
// Providing this circumvents a lot of necessity for dispatchers with the
// benefit of instantiating the request context much earlier.
//
// TODO(stevvooe): Consider making this facility a part of the context package.
type contextManager struct {
contexts map[*http.Request]context.Context
mu sync.Mutex
}
// defaultContextManager is just a global instance to register request contexts.
var defaultContextManager = newContextManager()
func newContextManager() *contextManager {
return &contextManager{
contexts: make(map[*http.Request]context.Context),
}
}
// context either returns a new context or looks it up in the manager.
func (cm *contextManager) context(parent context.Context, w http.ResponseWriter, r *http.Request) context.Context {
cm.mu.Lock()
defer cm.mu.Unlock()
ctx, ok := cm.contexts[r]
if ok {
return ctx
}
if parent == nil {
parent = ctxu.Background()
}
ctx = ctxu.WithRequest(parent, r)
ctx, w = ctxu.WithResponseWriter(ctx, w)
ctx = ctxu.WithLogger(ctx, ctxu.GetRequestLogger(ctx))
cm.contexts[r] = ctx
return ctx
}
// releases frees any associated with resources from request.
func (cm *contextManager) release(ctx context.Context) {
cm.mu.Lock()
defer cm.mu.Unlock()
r, err := ctxu.GetRequest(ctx)
if err != nil {
ctxu.GetLogger(ctx).Errorf("no request found in context during release")
return
}
delete(cm.contexts, r)
}