f1a1da58db8bec06b3e62dcda0a14e6389e7bb6f
- Author
- Ayman Bagabas <ayman.bagabas@gmail.com>
- Committer
- Ayman Bagabas <ayman.bagabas@gmail.com>
- Date
Message
Diff
This diff is truncated to protect this page.
1diff --git a/go.mod b/go.mod
2index 67d13c4c6dce2a7c8486ccb3c401e6f4f231f70a..c0a03a5ca8ae3c623ea2873a114eac9ee673ab65 100644
3--- a/go.mod
4+++ b/go.mod
5@@ -29,6 +29,8 @@ require (
6 github.com/gobwas/glob v0.2.3
7 github.com/gogs/git-module v1.8.2
8 github.com/golang-jwt/jwt/v5 v5.0.0
9+ github.com/gorilla/handlers v1.5.1
10+ github.com/gorilla/mux v1.8.0
11 github.com/hashicorp/golang-lru/v2 v2.0.4
12 github.com/jmoiron/sqlx v1.3.5
13 github.com/lib/pq v1.10.9
14@@ -41,7 +43,6 @@ require (
15 github.com/rubyist/tracerx v0.0.0-20170927163412-787959303086
16 github.com/spf13/cobra v1.7.0
17 go.uber.org/automaxprocs v1.5.3
18- goji.io v2.0.2+incompatible
19 golang.org/x/crypto v0.11.0
20 golang.org/x/sync v0.3.0
21 gopkg.in/yaml.v3 v3.0.1
22@@ -58,6 +59,7 @@ require (
23 github.com/cespare/xxhash/v2 v2.2.0 // indirect
24 github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
25 github.com/dlclark/regexp2 v1.4.0 // indirect
26+ github.com/felixge/httpsnoop v1.0.1 // indirect
27 github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect
28 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
29 github.com/go-logfmt/logfmt v0.6.0 // indirect
30diff --git a/go.sum b/go.sum
31index 92f81ebc3856d0d58fd58e6f806946de398e3e1d..6843898e79ea81515c6659f597e2239fcc8bb581 100644
32--- a/go.sum
33+++ b/go.sum
34@@ -49,6 +49,8 @@ github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E
35 github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
36 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
37 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
38+github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
39+github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
40 github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 h1:mtDjlmloH7ytdblogrMz1/8Hqua1y8B4ID+bh3rvod0=
41 github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1/go.mod h1:fenKRzpXDjNpsIBhuhUzvjCKlDjKam0boRAenTE0Q6A=
42 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
43@@ -80,6 +82,10 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
44 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
45 github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
46 github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
47+github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
48+github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
49+github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
50+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
51 github.com/hashicorp/golang-lru/v2 v2.0.4 h1:7GHuZcgid37q8o5i3QI9KMT4nCWQQ3Kx3Ov6bb9MfK0=
52 github.com/hashicorp/golang-lru/v2 v2.0.4/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
53 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
54@@ -192,8 +198,6 @@ github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18W
55 github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ=
56 go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
57 go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
58-goji.io v2.0.2+incompatible h1:uIssv/elbKRLznFUy3Xj4+2Mz/qKhek/9aZQDUMae7c=
59-goji.io v2.0.2+incompatible/go.mod h1:sbqFwrtqZACxLBTQcdgVjFh54yGVCvwq8+w49MVMMIk=
60 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
61 golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
62 golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
63diff --git a/server/web/git.go b/server/web/git.go
64index a2158f434edf64031ff5b1aaddb9c7deaf16db4a..bf2fbd6e37e9e7baad6b7890d0ab7c10b5fa0ff8 100644
65--- a/server/web/git.go
66+++ b/server/web/git.go
67@@ -10,7 +10,6 @@ import (
68 "net/http"
69 "os"
70 "path/filepath"
71- "regexp"
72 "strings"
73 "time"
74
75@@ -23,64 +22,19 @@ import (
76 "github.com/charmbracelet/soft-serve/server/lfs"
77 "github.com/charmbracelet/soft-serve/server/proto"
78 "github.com/charmbracelet/soft-serve/server/utils"
79+ "github.com/gorilla/mux"
80 "github.com/prometheus/client_golang/prometheus"
81 "github.com/prometheus/client_golang/prometheus/promauto"
82- "goji.io/pat"
83- "goji.io/pattern"
84 )
85
86 // GitRoute is a route for git services.
87 type GitRoute struct {
88 method []string
89- pattern *regexp.Regexp
90 handler http.HandlerFunc
91+ path string
92 }
93
94-var _ Route = GitRoute{}
95-
96-// Match implements goji.Pattern.
97-func (g GitRoute) Match(r *http.Request) *http.Request {
98- re := g.pattern
99- ctx := r.Context()
100- cfg := config.FromContext(ctx)
101- if m := re.FindStringSubmatch(r.URL.Path); m != nil {
102- // This finds the Git objects & packs filenames in the URL.
103- file := strings.Replace(r.URL.Path, m[1]+"/", "", 1)
104- repo := utils.SanitizeRepo(m[1])
105- // Add repo suffix (.git)
106- r.URL.Path = fmt.Sprintf("%s.git/%s", repo, file)
107-
108- var service git.Service
109- var oid string // LFS object ID
110- var lockID string // LFS lock ID
111- switch {
112- case strings.HasSuffix(r.URL.Path, git.UploadPackService.String()):
113- service = git.UploadPackService
114- case strings.HasSuffix(r.URL.Path, git.ReceivePackService.String()):
115- service = git.ReceivePackService
116- case len(m) > 2:
117- if strings.HasPrefix(file, "info/lfs/objects/basic/") {
118- oid = m[2]
119- } else if strings.HasPrefix(file, "info/lfs/locks/") && strings.HasSuffix(file, "/unlock") {
120- lockID = m[2]
121- }
122- fallthrough
123- case strings.HasPrefix(file, "info/lfs"):
124- service = gitLfsService
125- }
126-
127- ctx = context.WithValue(ctx, pattern.Variable("lock_id"), lockID)
128- ctx = context.WithValue(ctx, pattern.Variable("oid"), oid)
129- ctx = context.WithValue(ctx, pattern.Variable("service"), service.String())
130- ctx = context.WithValue(ctx, pattern.Variable("dir"), filepath.Join(cfg.DataPath, "repos", repo+".git"))
131- ctx = context.WithValue(ctx, pattern.Variable("repo"), repo)
132- ctx = context.WithValue(ctx, pattern.Variable("file"), file)
133-
134- return r.WithContext(ctx)
135- }
136-
137- return nil
138-}
139+var _ http.Handler = GitRoute{}
140
141 // ServeHTTP implements http.Handler.
142 func (g GitRoute) ServeHTTP(w http.ResponseWriter, r *http.Request) {
143@@ -118,18 +72,49 @@ var (
144 }, []string{"repo", "file"})
145 )
146
147-var (
148- serviceRpcMatcher = regexp.MustCompile("(.*?)/(?:git-upload-pack|git-receive-pack)$") // nolint: revive
149- getInfoRefsMatcher = regexp.MustCompile("(.*?)/info/refs$")
150- getTextFileMatcher = regexp.MustCompile("(.*?)/(?:HEAD|objects/info/alternates|objects/info/http-alternates|objects/info/[^/]*)$")
151- getInfoPacksMatcher = regexp.MustCompile("(.*?)/objects/info/packs$")
152- getLooseObjectMatcher = regexp.MustCompile("(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$")
153- getPackFileMatcher = regexp.MustCompile(`(.*?)/objects/pack/pack-[0-9a-f]{40}\.pack$`)
154- getIdxFileMatcher = regexp.MustCompile(`(.*?)/objects/pack/pack-[0-9a-f]{40}\.idx$`)
155- serviceLfsBatchMatcher = regexp.MustCompile("(.*?)/info/lfs/objects/batch$")
156- serviceLfsBasicMatcher = regexp.MustCompile("(.*?)/info/lfs/objects/basic/([0-9a-f]{64})$")
157- serviceLfsBasicVerifyMatcher = regexp.MustCompile("(.*?)/info/lfs/objects/basic/verify$")
158-)
159+func withParams(h http.Handler) http.Handler {
160+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
161+ ctx := r.Context()
162+ logger := log.FromContext(ctx)
163+ cfg := config.FromContext(ctx)
164+ vars := mux.Vars(r)
165+ repo := vars["repo"]
166+
167diff --git a/server/web/git_lfs.go b/server/web/git_lfs.go
168index e49ca18abc99a92f255bd19a7dd87661f0874f39..b00a2661bcd006927492533fc1b3c277b5a59d31 100644
169--- a/server/web/git_lfs.go
170+++ b/server/web/git_lfs.go
171@@ -19,17 +19,13 @@ import (
172 "github.com/charmbracelet/soft-serve/server/config"
173 "github.com/charmbracelet/soft-serve/server/db"
174 "github.com/charmbracelet/soft-serve/server/db/models"
175- "github.com/charmbracelet/soft-serve/server/git"
176 "github.com/charmbracelet/soft-serve/server/lfs"
177 "github.com/charmbracelet/soft-serve/server/proto"
178 "github.com/charmbracelet/soft-serve/server/storage"
179 "github.com/charmbracelet/soft-serve/server/store"
180- "goji.io/pat"
181+ "github.com/gorilla/mux"
182 )
183
184-// Place holder service to handle Git LFS requests.
185-const gitLfsService git.Service = "git-lfs-service"
186-
187 // serviceLfsBatch handles a Git LFS batch requests.
188 // https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md
189 // TODO: support refname
190@@ -80,7 +76,7 @@ func serviceLfsBatch(w http.ResponseWriter, r *http.Request) {
191 return
192 }
193
194- name := pat.Param(r, "repo")
195+ name := mux.Vars(r)["repo"]
196 repo := proto.RepositoryFromContext(ctx)
197 if repo == nil {
198 renderJSON(w, http.StatusNotFound, lfs.ErrorResponse{
199@@ -184,8 +180,8 @@ func serviceLfsBatch(w http.ResponseWriter, r *http.Request) {
200 accessLevel := access.FromContext(ctx)
201 if accessLevel < access.ReadWriteAccess {
202 askCredentials(w, r)
203- renderJSON(w, http.StatusUnauthorized, lfs.ErrorResponse{
204- Message: "credentials needed",
205+ renderJSON(w, http.StatusForbidden, lfs.ErrorResponse{
206+ Message: "write access required",
207 })
208 return
209 }
210@@ -255,7 +251,7 @@ func serviceLfsBasic(w http.ResponseWriter, r *http.Request) {
211 // GET: /<repo>.git/info/lfs/objects/basic/<oid>
212 func serviceLfsBasicDownload(w http.ResponseWriter, r *http.Request) {
213 ctx := r.Context()
214- oid := pat.Param(r, "oid")
215+ oid := mux.Vars(r)["oid"]
216 repo := proto.RepositoryFromContext(ctx)
217 cfg := config.FromContext(ctx)
218 logger := log.FromContext(ctx).WithPrefix("http.lfs-basic")
219@@ -304,14 +300,14 @@ func serviceLfsBasicUpload(w http.ResponseWriter, r *http.Request) {
220 }
221
222 ctx := r.Context()
223- oid := pat.Param(r, "oid")
224+ oid := mux.Vars(r)["oid"]
225 cfg := config.FromContext(ctx)
226 be := backend.FromContext(ctx)
227 dbx := db.FromContext(ctx)
228 datastore := store.FromContext(ctx)
229 logger := log.FromContext(ctx).WithPrefix("http.lfs-basic")
230 strg := storage.NewLocalStorage(filepath.Join(cfg.DataPath, "lfs"))
231- name := pat.Param(r, "repo")
232+ name := mux.Vars(r)["repo"]
233
234 defer r.Body.Close() // nolint: errcheck
235 repo, err := be.Repository(ctx, name)
236@@ -836,7 +832,7 @@ func serviceLfsLocksDelete(w http.ResponseWriter, r *http.Request) {
237
238 ctx := r.Context()
239 logger := log.FromContext(ctx).WithPrefix("http.lfs-locks")
240- lockIDStr := pat.Param(r, "lock_id")
241+ lockIDStr := mux.Vars(r)["lock_id"]
242 if lockIDStr == "" {
243 logger.Error("error getting lock id")
244 renderJSON(w, http.StatusBadRequest, lfs.ErrorResponse{
245diff --git a/server/web/goget.go b/server/web/goget.go
246index 7d9ec1466606b3a8e76d7f37dc9633411e6814d3..3e56f9db8cbcc0f06439c78abef46d9ea9c49fd0 100644
247--- a/server/web/goget.go
248+++ b/server/web/goget.go
249@@ -6,12 +6,13 @@ import (
250 "path"
251 "text/template"
252
253+ "github.com/charmbracelet/log"
254 "github.com/charmbracelet/soft-serve/server/backend"
255 "github.com/charmbracelet/soft-serve/server/config"
256 "github.com/charmbracelet/soft-serve/server/utils"
257+ "github.com/gorilla/mux"
258 "github.com/prometheus/client_golang/prometheus"
259 "github.com/prometheus/client_golang/prometheus/promauto"
260- "goji.io/pattern"
261 )
262
263 var goGetCounter = promauto.NewCounterVec(prometheus.CounterOpts{
264@@ -26,7 +27,7 @@ var repoIndexHTMLTpl = template.Must(template.New("index").Parse(`<!DOCTYPE html
265 <head>
266 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
267 <meta http-equiv="refresh" content="0; url=https://godoc.org/{{ .ImportRoot }}/{{.Repo}}">
268- <meta name="go-import" content="{{ .ImportRoot }}/{{ .Repo }} git {{ .Config.HTTP.PublicURL }}/{{ .Repo }}">
269+ <meta name="go-import" content="{{ .ImportRoot }}/{{ .Repo }} git {{ .Config.HTTP.PublicURL }}/{{ .Repo }}.git">
270 </head>
271 <body>
272 Redirecting to docs at <a href="https://godoc.org/{{ .ImportRoot }}/{{ .Repo }}">godoc.org/{{ .ImportRoot }}/{{ .Repo }}</a>...
273@@ -40,15 +41,17 @@ type GoGetHandler struct{}
274 var _ http.Handler = (*GoGetHandler)(nil)
275
276 func (g GoGetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
277- repo := pattern.Path(r.Context())
278- repo = utils.SanitizeRepo(repo)
279 ctx := r.Context()
280 cfg := config.FromContext(ctx)
281 be := backend.FromContext(ctx)
282+ logger := log.FromContext(ctx)
283+ repo := mux.Vars(r)["repo"]
284
285 // Handle go get requests.
286 //
287- // Always return a 200 status code, even if the repo doesn't exist.
288+ // Always return a 200 status code, even if the repo path doesn't exist.
289+ // It will try to find the repo by walking up the path until it finds one.
290+ // If it can't find one, it will return a 404.
291 //
292 // https://golang.org/cmd/go/#hdr-Remote_import_paths
293 // https://go.dev/ref/mod#vcs-branch
294@@ -78,11 +81,12 @@ func (g GoGetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
295 Config *config.Config
296 ImportRoot string
297 }{
298- Repo: url.PathEscape(repo),
299+ Repo: utils.SanitizeRepo(repo),
300 Config: cfg,
301 ImportRoot: importRoot.Host,
302 }); err != nil {
303- http.Error(w, err.Error(), http.StatusInternalServerError)
304+ logger.Error("failed to render go get template", "err", err)
305+ renderInternalServerError(w, r)
306 return
307 }
308
309@@ -90,5 +94,5 @@ func (g GoGetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
310 return
311 }
312
313- http.NotFound(w, r)
314+ renderNotFound(w, r)
315 }
316diff --git a/server/web/server.go b/server/web/server.go
317index af344e7a1bd6bfe67178881a78061b7783d5d9dc..73921e68bf953491bc60f7f6252e38de2e8fcdf2 100644
318--- a/server/web/server.go
319+++ b/server/web/server.go
320@@ -4,35 +4,25 @@ import (
321 "context"
322 "net/http"
323
324- "goji.io"
325- "goji.io/pat"
326+ "github.com/gorilla/handlers"
327+ "github.com/gorilla/mux"
328 )
329
330-// Route is an interface for a route.
331-type Route interface {
332- http.Handler
333- goji.Pattern
334-}
335-
336 // NewRouter returns a new HTTP router.
337-// TODO: use gorilla/mux and friends
338 func NewRouter(ctx context.Context) http.Handler {
339- mux := goji.NewMux()
340+ router := mux.NewRouter()
341
342 // Git routes
343- for _, service := range gitRoutes {
344- mux.Handle(service, withAccess(service))
345- }
346-
347- // go-get handler
348- mux.Handle(pat.Get("/*"), GoGetHandler{})
349+ GitController(ctx, router)
350
351- // Middlewares
352- mux.Use(NewLoggingMiddleware)
353+ router.PathPrefix("/").HandlerFunc(renderNotFound)
354
355 // Context handler
356 // Adds context to the request
357- ctxHandler := NewContextHandler(ctx)
358+ h := NewContextHandler(ctx)(router)
359+ h = handlers.CompressHandler(h)
360+ h = handlers.RecoveryHandler()(h)
361+ h = NewLoggingMiddleware(h)
362
363- return ctxHandler(mux)
364+ return h
365 }
366diff --git a/server/web/util.go b/server/web/util.go
367index 2c68d6991045ded3efa8ac8f8bb98c5e57eb7039..412d0e00ef14b545fc042462b63bf12626ea7cc5 100644
368--- a/server/web/util.go
369+++ b/server/web/util.go
370@@ -1,10 +1,14 @@
371 package web
372
373-import "net/http"
374+import (
375+ "fmt"
376+ "io"
377+ "net/http"
378+)
379
380 func renderStatus(code int) http.HandlerFunc {
381 return func(w http.ResponseWriter, _ *http.Request) {
382 w.WriteHeader(code)
383- w.Write([]byte(http.StatusText(code))) // nolint: errcheck
384+ io.WriteString(w, fmt.Sprintf("%d %s", code, http.StatusText(code))) // nolint: errcheck
385 }
386 }
387diff --git a/testscript/testdata/http.txtar b/testscript/testdata/http.txtar
388index e0710514607f58601415fb106aab459a6925d395..defc142d318781892a06ccf40309e9bfac4a4912 100644
389--- a/testscript/testdata/http.txtar
390+++ b/testscript/testdata/http.txtar
391@@ -35,6 +35,11 @@ git -C repo2 tag v0.1.0
392 git -C repo2 push origin HEAD
393 git -C repo2 push origin HEAD --tags
394
395+# dumb http git
396+exec curl -s -XGET http://localhost:$HTTP_PORT/repo2.git/info/refs
397+stdout '[0-9a-z]{40} refs/heads/master\n[0-9a-z]{40} refs/tags/v0.1.0'
398+
399+
400 # http errors
401 exec curl -s -XGET http://localhost:$HTTP_PORT/repo2111foobar.git/foo/bar
402 stdout '404.*'
403@@ -59,10 +64,23 @@ stdout '.*unsupported operation.*'
404 exec curl -s -XPOST -H 'Accept: application/vnd.git-lfs+json' -H 'Content-Type: application/vnd.git-lfs+json' -d '{"operation":"download","objects":[{}]}' http://$TOKEN@localhost:$HTTP_PORT/repo2.git/info/lfs/objects/batch
405 cmp stdout http1.txt
406 exec curl -s -XPOST -H 'Accept: application/vnd.git-lfs+json' -H 'Content-Type: application/vnd.git-lfs+json' -d '{"operation":"upload","objects":[{}]}' http://$UTOKEN@localhost:$HTTP_PORT/repo2.git/info/lfs/objects/batch
407-stdout '.*credentials needed.*'
408+stdout '.*write access required.*'
409 exec curl -s -XPOST -H 'Accept: application/vnd.git-lfs+json' -H 'Content-Type: application/vnd.git-lfs+json' -d '{"operation":"upload","objects":[{}]}' http://$TOKEN@localhost:$HTTP_PORT/repo2.git/info/lfs/objects/batch
410 cmp stdout http1.txt
411
412+
413+# go-get allow (public repo)
414+exec curl -s http://localhost:$HTTP_PORT/repo2.git?go-get=1
415+cmpenv stdout goget.txt
416+exec curl -s http://localhost:$HTTP_PORT/repo2.git/subpackage?go-get=1
417+cmpenv stdout goget.txt
418+exec curl -s http://localhost:$HTTP_PORT/repo2/subpackage?go-get=1
419+cmpenv stdout goget.txt
420+
421+# go-get not found (invalid method)
422+exec curl -s -XPOST http://localhost:$HTTP_PORT/repo2/subpackage?go-get=1
423+stdout '404.*'
424+
425 # set private
426 soft repo private repo2 true
427
428@@ -80,20 +98,32 @@ stdout '.*credentials needed.*'
429 exec curl -s http://0$UTOKEN@localhost:$HTTP_PORT/repo2.git/info/lfs/objects/batch
430 cmp stdout http3.txt
431
432+# deny dumb http git
433+exec curl -s -XGET http://localhost:$HTTP_PORT/repo2.git/info/refs
434+stdout '404.*'
435+
436 # deny access ask for credentials
437 # this means the server responded with a 401 and prompted for credentials
438 # but we disable git terminal prompting to we get a fatal instead of a 401 "Unauthorized"
439 ! git clone http://localhost:$HTTP_PORT/repo2 repo2_clone
440 cmpenv stderr gitclone.txt
441 ! git clone http://someuser:somepassword@localhost:$HTTP_PORT/repo2 repo2_clone
442-stderr '.*Forbidden.*'
443+stderr '.*403.*'
444
445-# go-get endpoints not found
446-exec curl -s http://localhost:$HTTP_PORT/repo2.git
447+# go-get not found (private repo)
448+exec curl -s http://localhost:$HTTP_PORT/repo2.git?go-get=1
449 stdout '404.*'
450
451-# go-get endpoints
452-exec curl -s http://localhost:$HTTP_PORT/repo2.git?go-get=1
453+# go-get forbidden (private repo & expired token)
454+exec curl -s http://$ETOKEN@localhost:$HTTP_PORT/repo2.git?go-get=1
455+stdout '403.*'
456+
457+# go-get not found (private repo & different user)
458+exec curl -s http://$UTOKEN@localhost:$HTTP_PORT/repo2.git?go-get=1
459+stdout '404.*'
460+
461+# go-get with creds
462+exec curl -s http://$TOKEN@localhost:$HTTP_PORT/repo2.git?go-get=1
463 cmpenv stdout goget.txt
464
465 -- http1.txt --
466@@ -108,7 +138,7 @@ cmpenv stdout goget.txt
467 <head>
468 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
469 <meta http-equiv="refresh" content="0; url=https://godoc.org/localhost:$HTTP_PORT/repo2">
470- <meta name="go-import" content="localhost:$HTTP_PORT/repo2 git http://localhost:$HTTP_PORT/repo2">
471+ <meta name="go-import" content="localhost:$HTTP_PORT/repo2 git http://localhost:$HTTP_PORT/repo2.git">
472 </head>
473 <body>
474 Redirecting to docs at <a href="https://godoc.org/localhost:$HTTP_PORT/repo2">godoc.org/localhost:$HTTP_PORT/repo2</a>...