~sircmpwn/godocs.io

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH gddo] gddo-server: Consolidate request path parsing

Details
Message ID
<20210619193001.19642-1-me@adnano.co>
DKIM signature
pass
Download raw message
Patch: +36 -28
Consolidate the parsing of request paths into a single function.
Also take the opportunity to reject invalid versions like "master" or
"main" which cause issues.

---
 gddo-server/crawl.go  |  2 +-
 gddo-server/gemini.go | 18 +++++-------------
 gddo-server/http.go   | 20 ++++++--------------
 gddo-server/server.go | 24 ++++++++++++++++++++++++
 4 files changed, 36 insertions(+), 28 deletions(-)

diff --git a/gddo-server/crawl.go b/gddo-server/crawl.go
index 4e527e8..766ce65 100644
--- a/gddo-server/crawl.go
+++ b/gddo-server/crawl.go
@@ -27,7 +27,7 @@ var (
	ErrBlocked    = errors.New("blocked import path")
	ErrMismatch   = errors.New("import paths don't match")
	ErrNoPackages = errors.New("no packages found")
	ErrPseudo     = errors.New("pseudo version not allowed")
	ErrBadVersion = errors.New("invalid version")
)

// byVersion sorts versions from latest to oldest.
diff --git a/gddo-server/gemini.go b/gddo-server/gemini.go
index 4988b98..8c1b236 100644
--- a/gddo-server/gemini.go
+++ b/gddo-server/gemini.go
@@ -14,7 +14,6 @@ import (
	"git.sr.ht/~sircmpwn/gddo/internal/proxy"
	"git.sr.ht/~sircmpwn/gddo/internal/source"
	"git.sr.ht/~sircmpwn/gddo/internal/stdlib"
	versionpkg "git.sr.ht/~sircmpwn/gddo/internal/version"
)

func (s *Server) GeminiHandler() (gemini.Handler, error) {
@@ -87,16 +86,9 @@ func (s *Server) serveGeminiPackage(ctx context.Context, w gemini.ResponseWriter
		return s.serveGeminiRefresh(ctx, w, r)
	}

	importPath := strings.TrimPrefix(r.URL.Path, "/")
	version := "latest"
	at := strings.Index(importPath, "@")
	if at != -1 {
		version = importPath[at+1:]
		importPath = importPath[:at]
	}

	if versionpkg.IsPseudo(version) {
		return ErrPseudo
	importPath, version, err := s.parseRequestPath(ctx, r.URL.Path)
	if err != nil {
		return err
	}

	mod, pkg, pdoc, err := s.GetDoc(ctx, importPath, version)
@@ -251,8 +243,8 @@ func geminiErrorHandler(fn func(ctx context.Context, w gemini.ResponseWriter, r
			w.WriteHeader(gemini.StatusNotFound, "The provided import path doesn't match the module path present in the go.mod file.")
		case errors.Is(err, ErrNoPackages):
			w.WriteHeader(gemini.StatusNotFound, "The requested module doesn't contain any packages.")
		case errors.Is(err, ErrPseudo):
			w.WriteHeader(gemini.StatusNotFound, "Pseudo-versions are not allowed.")
		case errors.Is(err, ErrBadVersion):
			w.WriteHeader(gemini.StatusNotFound, "Invalid version.")
		default:
			w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
		}
diff --git a/gddo-server/http.go b/gddo-server/http.go
index 0387a42..def19e2 100644
--- a/gddo-server/http.go
+++ b/gddo-server/http.go
@@ -21,7 +21,6 @@ import (
	"git.sr.ht/~sircmpwn/gddo/internal/proxy"
	"git.sr.ht/~sircmpwn/gddo/internal/source"
	"git.sr.ht/~sircmpwn/gddo/internal/stdlib"
	versionpkg "git.sr.ht/~sircmpwn/gddo/internal/version"
)

const (
@@ -109,16 +108,9 @@ func (s *Server) servePackage(resp http.ResponseWriter, req *http.Request) error
		return nil
	}

	importPath := strings.TrimPrefix(req.URL.Path, "/")
	version := "latest"
	at := strings.Index(importPath, "@")
	if at != -1 {
		version = importPath[at+1:]
		importPath = importPath[:at]
	}

	if versionpkg.IsPseudo(version) {
		return ErrPseudo
	importPath, version, err := s.parseRequestPath(req.Context(), req.URL.Path)
	if err != nil {
		return err
	}

	mod, pkg, pdoc, err := s.GetDoc(req.Context(), importPath, version)
@@ -389,10 +381,10 @@ func errorMessages(err error) []flashMessage {
			ID:   "error",
			Args: []string{"Error fetching module: The requested module doesn't contain any packages."},
		}}
	case errors.Is(err, ErrPseudo):
	case errors.Is(err, ErrBadVersion):
		return []flashMessage{{
			ID:   "error",
			Args: []string{"Error fetching module: Pseudo-versions are not allowed."},
			Args: []string{"Error fetching module: Invalid version."},
		}}
	}
	return nil
@@ -423,7 +415,7 @@ func (s *Server) errorHandler(fn func(http.ResponseWriter, *http.Request) error)
			errors.Is(err, ErrBlocked) ||
			errors.Is(err, ErrMismatch) ||
			errors.Is(err, ErrNoPackages) ||
			errors.Is(err, ErrPseudo) {
			errors.Is(err, ErrBadVersion) {

			msgs := errorMessages(err)
			s.templates.Execute(resp, "notfound.html",
diff --git a/gddo-server/server.go b/gddo-server/server.go
index f2f81ad..17532a5 100644
--- a/gddo-server/server.go
+++ b/gddo-server/server.go
@@ -13,6 +13,8 @@ import (
	"git.sr.ht/~sircmpwn/gddo/internal/database"
	"git.sr.ht/~sircmpwn/gddo/internal/doc"
	"git.sr.ht/~sircmpwn/gddo/internal/proxy"
	"git.sr.ht/~sircmpwn/gddo/internal/version"
	"golang.org/x/mod/semver"
)

// The Go documentation server.
@@ -124,6 +126,28 @@ func (s *Server) GetDoc(ctx context.Context, importPath, version string) (*datab
	}
}

// Parses the provided request path, returning the package import path and version.
func (s *Server) parseRequestPath(ctx context.Context, path string) (string, string, error) {
	// Trim leading forward slash
	path = strings.TrimPrefix(path, "/")

	// Use version if present
	at := strings.Index(path, "@")
	if at != -1 {
		v := path[at+1:]
		importPath := path[:at]

		if !semver.IsValid(v) || version.IsPseudo(v) {
			return "", "", ErrBadVersion
		}

		return importPath, v, nil
	}

	// Use latest version
	return path, proxy.LatestVersion, nil
}

func isView(u *url.URL, key string) bool {
	rq := u.RawQuery
	return strings.HasPrefix(rq, key) &&
-- 
2.32.0
Details
Message ID
<CC8J48AV9GME.39W7KVFW5RJ5E@taiga>
In-Reply-To
<20210619193001.19642-1-me@adnano.co> (view parent)
DKIM signature
fail
Download raw message
DKIM signature: fail
Thanks!

To git@git.sr.ht:~sircmpwn/gddo
   92a10f1..df74f2d  master -> master
Reply to thread Export thread (mbox)