func()

in registry/handlers/app.go [1483:1571]


func (app *App) dispatcher(dispatch dispatchFunc) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		for headerName, headerValues := range app.Config.HTTP.Headers {
			for _, value := range headerValues {
				w.Header().Add(headerName, value)
			}
		}

		ctx := app.context(w, r)

		// attach CF-RayID header to context and pass the key to the logger
		ctx.Context = dcontext.WithCFRayID(ctx.Context, r)
		ctx.Context = dcontext.WithLogger(ctx.Context, dcontext.GetLogger(ctx.Context, dcontext.CFRayIDLogKey))

		if err := app.authorized(w, r, ctx); err != nil {
			var authErr auth.Challenge
			if !errors.As(err, &authErr) {
				dcontext.GetLogger(ctx).WithError(err).Warn("error authorizing context")
			}
			return
		}

		// Add extra context to request logging
		ctx.Context = dcontext.WithLogger(ctx.Context, dcontext.GetLogger(ctx.Context, auth.UserNameKey, auth.UserTypeKey, auth.ResourceProjectPathsKey))
		// sync up context on the request.
		r = r.WithContext(ctx)

		// get all metadata either from the database or from the filesystem
		if app.Config.Database.Enabled {
			ctx.useDatabase = true
		}

		if app.nameRequired(r) {
			bp, ok := app.registry.Blobs().(distribution.BlobProvider)
			if !ok {
				err := fmt.Errorf("unable to convert BlobEnumerator into BlobProvider")
				dcontext.GetLogger(ctx).Error(err)
				ctx.Errors = append(ctx.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
			}
			ctx.blobProvider = bp

			repository, err := app.repositoryFromContext(ctx, w)
			if err != nil {
				return
			}

			ctx.queueBridge = app.queueBridge(ctx, r)

			// assign and decorate the authorized repository with an event bridge.
			ctx.Repository, ctx.RepositoryRemover = notifications.Listen(
				repository,
				ctx.App.repoRemover,
				app.eventBridge(ctx, r),
				ctx.useDatabase)

			ctx.Repository, err = applyRepoMiddleware(app, ctx.Repository, app.Config.Middleware["repository"])
			if err != nil {
				dcontext.GetLogger(ctx).Errorf("error initializing repository middleware: %v", err)
				ctx.Errors = append(ctx.Errors, errcode.ErrorCodeUnknown.WithDetail(err))

				if err := errcode.ServeJSON(w, ctx.Errors); err != nil {
					dcontext.GetLogger(ctx).Errorf("error serving error json: %v (from %v)", err, ctx.Errors)
				}
				return
			}
		}

		if ctx.useDatabase {
			if app.redisCache != nil {
				ctx.repoCache = datastore.NewCentralRepositoryCache(app.redisCache)
			} else {
				ctx.repoCache = datastore.NewSingleRepositoryCache()
			}
		}

		dispatch(ctx, r).ServeHTTP(w, r)

		// Automated error response handling here. Handlers may return their
		// own errors if they need different behavior (such as range errors
		// for layer upload).
		if ctx.Errors.Len() > 0 {
			if err := errcode.ServeJSON(w, ctx.Errors); err != nil {
				dcontext.GetLogger(ctx).Errorf("error serving error json: %v (from %v)", err, ctx.Errors)
			}

			app.logError(ctx, r, ctx.Errors)
		}
	})
}