Middleware writes to response with html meta tags go-import and go-source. nolint:gocognit
( maxRepoPathDepth int, repoCtrl *repo.Controller, urlProvider url.Provider, )
| 59 | // |
| 60 | //nolint:gocognit |
| 61 | func Middleware( |
| 62 | maxRepoPathDepth int, |
| 63 | repoCtrl *repo.Controller, |
| 64 | urlProvider url.Provider, |
| 65 | ) func(http.Handler) http.Handler { |
| 66 | return func(next http.Handler) http.Handler { |
| 67 | return http.HandlerFunc( |
| 68 | func(w http.ResponseWriter, r *http.Request) { |
| 69 | if r.Method != http.MethodGet || r.URL.Query().Get("go-get") != "1" { |
| 70 | next.ServeHTTP(w, r) |
| 71 | return |
| 72 | } |
| 73 | ctx := r.Context() |
| 74 | |
| 75 | session, _ := request.AuthSessionFrom(ctx) |
| 76 | importPath, err := request.GetRepoRefFromPath(r) |
| 77 | if err != nil { |
| 78 | render.TranslatedUserError(ctx, w, err) |
| 79 | return |
| 80 | } |
| 81 | |
| 82 | // go get can also be used with (sub)module suffixes (e.g 127.0.0.1/my-project/my-repo/v2) |
| 83 | // for which go expects us to return the import path corresponding to the repository root |
| 84 | // (e.g. 127.0.0.1/my-project/my-repo). |
| 85 | // |
| 86 | // WARNING: This can lead to ambiguities as we allow matching paths between spaces and repos: |
| 87 | // 1. (space)foo + (repo)bar + (sufix)v2 = 127.0.0.1/my-project/my-repo/v2 |
| 88 | // 2. (space)foo/bar + (repo)v2 = 127.0.0.1/my-project/my-repo/v2 |
| 89 | // |
| 90 | // We handle ambiguities by always choosing the repo with the longest path (e.g. 2. case above). |
| 91 | // To solve go get related ambiguities users would have to move their repositories. |
| 92 | var repository *repo.RepositoryOutput |
| 93 | var repoRef string |
| 94 | |
| 95 | pathSegments := paths.Segments(importPath) |
| 96 | if len(pathSegments) > maxRepoPathDepth { |
| 97 | pathSegments = pathSegments[:maxRepoPathDepth] |
| 98 | } |
| 99 | |
| 100 | for l := len(pathSegments); l >= 2; l-- { |
| 101 | repoRef = paths.Concatenate(pathSegments[:l]...) |
| 102 | |
| 103 | repository, err = repoCtrl.Find(ctx, session, repoRef) |
| 104 | if err == nil { |
| 105 | break |
| 106 | } |
| 107 | if errors.Is(err, store.ErrResourceNotFound) { |
| 108 | log.Ctx(ctx).Debug().Err(err). |
| 109 | Msgf("repository %q doesn't exist, assume submodule and try again", repoRef) |
| 110 | continue |
| 111 | } |
| 112 | if errors.Is(err, auth.ErrForbidden) { |
| 113 | // To avoid leaking information about repos' existence we continue as if it wasn't found. |
| 114 | // WARNING: This can lead to different import results depending on access (very unlikely) |
| 115 | log.Ctx(ctx).Debug().Err(err). |
| 116 | Msgf("user has no access on repository %q, assume submodule and try again", repoRef) |
| 117 | continue |
| 118 | } |
no test coverage detected
searching dependent graphs…