internal/fetch: implement parse url for fetch service

The fetch service accepts HTTP requests at
http(s)://<fetchURL>/<module>@<version>.

ParseNameAndVersion is implemented, which validates the module name and
version for requests to this endpoint.

Change-Id: Iacf7f4ae8dfef54a024172807d8bc9ff01749c84
Reviewed-on: https://team-review.git.corp.google.com/c/422997
Reviewed-by: Channing Kimble-Brown <ckimblebrown@google.com>
Reviewed-by: Andrew Bonventre <andybons@google.com>
This commit is contained in:
Julie Qiu 2019-02-26 12:20:07 -05:00
Родитель 518ce0a7d6
Коммит ae504474f3
2 изменённых файлов: 82 добавлений и 0 удалений

Просмотреть файл

@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"io/ioutil"
"net/url"
"os"
"path/filepath"
"strconv"
@ -20,6 +21,25 @@ import (
var errReadmeNotFound = errors.New("fetch: zip file does not contain a README")
// ParseNameAndVersion returns the module and version specified by u. u is
// assumed to be a valid url following the structure http(s)://<fetchURL>/<module>@<version>.
func ParseNameAndVersion(u *url.URL) (string, string, error) {
parts := strings.Split(strings.TrimPrefix(u.Path, "/"), "/@v/")
if len(parts) != 2 {
return "", "", fmt.Errorf("invalid path: %q", u)
}
// TODO(julieqiu): Check module name is valid using
// https://github.com/golang/go/blob/c97e576/src/cmd/go/internal/module/module.go#L123
// Check version is valid using
// https://github.com/golang/go/blob/c97e576/src/cmd/go/internal/modload/query.go#L183
if parts[0] == "" || parts[1] == "" {
return "", "", fmt.Errorf("invalid path: %q", u)
}
return parts[0], parts[1], nil
}
// isReadme checks if file is the README. It is case insensitive.
func isReadme(file string) bool {
base := filepath.Base(file)

Просмотреть файл

@ -9,10 +9,72 @@ import (
"bytes"
"errors"
"io/ioutil"
"net/url"
"strings"
"testing"
)
func TestParseNameAndVersion(t *testing.T) {
testCases := []struct {
name string
url string
module string
version string
err error
}{
{
name: "ValidFetchURL",
url: "https://proxy.com/module/@v/v1.0.0",
module: "module",
version: "v1.0.0",
err: nil,
},
{
name: "InvalidFetchURL",
url: "https://proxy.com/",
err: errors.New(`invalid path: "https://proxy.com/"`),
},
{
name: "InvalidFetchURLNoModule",
url: "https://proxy.com/@v/version",
err: errors.New(`invalid path: "https://proxy.com/@v/version"`),
},
{
name: "InvalidFetchURLNoVersion",
url: "https://proxy.com/module/@v/",
err: errors.New(`invalid path: "https://proxy.com/module/@v/"`),
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
u, err := url.Parse(tc.url)
if err != nil {
t.Errorf("url.Parse(%q): %v", tc.url, err)
}
m, v, err := ParseNameAndVersion(u)
if tc.err != nil {
if err == nil {
t.Fatalf("ParseNameAndVersion(%v) error = (%v); want = (%v)", u, err, tc.err)
}
if tc.err.Error() != err.Error() {
t.Fatalf("ParseNameAndVersion(%v) error = (%v); want = (%v)", u, err, tc.err)
} else {
return
}
} else if err != nil {
t.Fatalf("ParseNameAndVersion(%v) error = (%v); want = (%v)", u, err, tc.err)
}
if tc.module != m || tc.version != v {
t.Fatalf("ParseNameAndVersion(%v): %q, %q, %v; want = %q, %q, %v",
u, m, v, err, tc.module, tc.version, tc.err)
}
})
}
}
func TestIsReadme(t *testing.T) {
for input, want := range map[string]bool{
"rEaDme": true,