Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / mod@v0.3.0 / sumdb / server.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/mod@v0.3.0/sumdb/server.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/mod@v0.3.0/sumdb/server.go
new file mode 100644 (file)
index 0000000..28866f1
--- /dev/null
@@ -0,0 +1,181 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sumdb implements the HTTP protocols for serving or accessing a module checksum database.
+package sumdb
+
+import (
+       "context"
+       "net/http"
+       "os"
+       "strings"
+
+       "golang.org/x/mod/internal/lazyregexp"
+       "golang.org/x/mod/module"
+       "golang.org/x/mod/sumdb/tlog"
+)
+
+// A ServerOps provides the external operations
+// (underlying database access and so on) needed by the Server.
+type ServerOps interface {
+       // Signed returns the signed hash of the latest tree.
+       Signed(ctx context.Context) ([]byte, error)
+
+       // ReadRecords returns the content for the n records id through id+n-1.
+       ReadRecords(ctx context.Context, id, n int64) ([][]byte, error)
+
+       // Lookup looks up a record for the given module,
+       // returning the record ID.
+       Lookup(ctx context.Context, m module.Version) (int64, error)
+
+       // ReadTileData reads the content of tile t.
+       // It is only invoked for hash tiles (t.L ≥ 0).
+       ReadTileData(ctx context.Context, t tlog.Tile) ([]byte, error)
+}
+
+// A Server is the checksum database HTTP server,
+// which implements http.Handler and should be invoked
+// to serve the paths listed in ServerPaths.
+type Server struct {
+       ops ServerOps
+}
+
+// NewServer returns a new Server using the given operations.
+func NewServer(ops ServerOps) *Server {
+       return &Server{ops: ops}
+}
+
+// ServerPaths are the URL paths the Server can (and should) serve.
+//
+// Typically a server will do:
+//
+//     srv := sumdb.NewServer(ops)
+//     for _, path := range sumdb.ServerPaths {
+//             http.Handle(path, srv)
+//     }
+//
+var ServerPaths = []string{
+       "/lookup/",
+       "/latest",
+       "/tile/",
+}
+
+var modVerRE = lazyregexp.New(`^[^@]+@v[0-9]+\.[0-9]+\.[0-9]+(-[^@]*)?(\+incompatible)?$`)
+
+func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+       ctx := r.Context()
+
+       switch {
+       default:
+               http.NotFound(w, r)
+
+       case strings.HasPrefix(r.URL.Path, "/lookup/"):
+               mod := strings.TrimPrefix(r.URL.Path, "/lookup/")
+               if !modVerRE.MatchString(mod) {
+                       http.Error(w, "invalid module@version syntax", http.StatusBadRequest)
+                       return
+               }
+               i := strings.Index(mod, "@")
+               escPath, escVers := mod[:i], mod[i+1:]
+               path, err := module.UnescapePath(escPath)
+               if err != nil {
+                       reportError(w, err)
+                       return
+               }
+               vers, err := module.UnescapeVersion(escVers)
+               if err != nil {
+                       reportError(w, err)
+                       return
+               }
+               id, err := s.ops.Lookup(ctx, module.Version{Path: path, Version: vers})
+               if err != nil {
+                       reportError(w, err)
+                       return
+               }
+               records, err := s.ops.ReadRecords(ctx, id, 1)
+               if err != nil {
+                       // This should never happen - the lookup says the record exists.
+                       http.Error(w, err.Error(), http.StatusInternalServerError)
+                       return
+               }
+               if len(records) != 1 {
+                       http.Error(w, "invalid record count returned by ReadRecords", http.StatusInternalServerError)
+                       return
+               }
+               msg, err := tlog.FormatRecord(id, records[0])
+               if err != nil {
+                       http.Error(w, err.Error(), http.StatusInternalServerError)
+                       return
+               }
+               signed, err := s.ops.Signed(ctx)
+               if err != nil {
+                       http.Error(w, err.Error(), http.StatusInternalServerError)
+                       return
+               }
+               w.Header().Set("Content-Type", "text/plain; charset=UTF-8")
+               w.Write(msg)
+               w.Write(signed)
+
+       case r.URL.Path == "/latest":
+               data, err := s.ops.Signed(ctx)
+               if err != nil {
+                       http.Error(w, err.Error(), http.StatusInternalServerError)
+                       return
+               }
+               w.Header().Set("Content-Type", "text/plain; charset=UTF-8")
+               w.Write(data)
+
+       case strings.HasPrefix(r.URL.Path, "/tile/"):
+               t, err := tlog.ParseTilePath(r.URL.Path[1:])
+               if err != nil {
+                       http.Error(w, "invalid tile syntax", http.StatusBadRequest)
+                       return
+               }
+               if t.L == -1 {
+                       // Record data.
+                       start := t.N << uint(t.H)
+                       records, err := s.ops.ReadRecords(ctx, start, int64(t.W))
+                       if err != nil {
+                               reportError(w, err)
+                               return
+                       }
+                       if len(records) != t.W {
+                               http.Error(w, "invalid record count returned by ReadRecords", http.StatusInternalServerError)
+                               return
+                       }
+                       var data []byte
+                       for i, text := range records {
+                               msg, err := tlog.FormatRecord(start+int64(i), text)
+                               if err != nil {
+                                       http.Error(w, err.Error(), http.StatusInternalServerError)
+                               }
+                               data = append(data, msg...)
+                       }
+                       w.Header().Set("Content-Type", "text/plain; charset=UTF-8")
+                       w.Write(data)
+                       return
+               }
+
+               data, err := s.ops.ReadTileData(ctx, t)
+               if err != nil {
+                       reportError(w, err)
+                       return
+               }
+               w.Header().Set("Content-Type", "application/octet-stream")
+               w.Write(data)
+       }
+}
+
+// reportError reports err to w.
+// If it's a not-found, the reported error is 404.
+// Otherwise it is an internal server error.
+// The caller must only call reportError in contexts where
+// a not-found err should be reported as 404.
+func reportError(w http.ResponseWriter, err error) {
+       if os.IsNotExist(err) {
+               http.Error(w, err.Error(), http.StatusNotFound)
+               return
+       }
+       http.Error(w, err.Error(), http.StatusInternalServerError)
+}