aboutsummaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
authorXe Iaso <me@xeiaso.net>2023-06-19 12:56:31 -0400
committerXe Iaso <me@xeiaso.net>2023-06-19 12:56:31 -0400
commitc592b6d195aedcd6ec86e8c60d3ba91d524e293b (patch)
treefbdb9fe9331ce491d606402d4b62ba5999ce6122 /web
parent84e8f57b98fd1038e6f2fc401277d936ef45522a (diff)
downloadx-c592b6d195aedcd6ec86e8c60d3ba91d524e293b.tar.xz
x-c592b6d195aedcd6ec86e8c60d3ba91d524e293b.zip
second reshuffling
Signed-off-by: Xe Iaso <me@xeiaso.net>
Diffstat (limited to 'web')
-rw-r--r--web/vanity/LICENSE41
-rw-r--r--web/vanity/legal.go47
-rw-r--r--web/vanity/vanity.go188
3 files changed, 276 insertions, 0 deletions
diff --git a/web/vanity/LICENSE b/web/vanity/LICENSE
new file mode 100644
index 0000000..79353b0
--- /dev/null
+++ b/web/vanity/LICENSE
@@ -0,0 +1,41 @@
+Copyright (c) 2018, Jon Betti
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+Copyright (c) 2016, Kare Nuorteva
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/web/vanity/legal.go b/web/vanity/legal.go
new file mode 100644
index 0000000..5638820
--- /dev/null
+++ b/web/vanity/legal.go
@@ -0,0 +1,47 @@
+package vanity
+
+import "go4.org/legal"
+
+func init() {
+ legal.RegisterLicense(`Copyright (c) 2018, Jon Betti
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+Copyright (c) 2016, Kare Nuorteva
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.`)
+}
diff --git a/web/vanity/vanity.go b/web/vanity/vanity.go
new file mode 100644
index 0000000..b637817
--- /dev/null
+++ b/web/vanity/vanity.go
@@ -0,0 +1,188 @@
+/*
+Package vanity implements custom import paths (Go vanity URLs) as an HTTP
+handler that can be installed at the vanity URL.
+*/
+package vanity
+
+import (
+ "fmt"
+ "html/template"
+ "net/http"
+ "strings"
+)
+
+type config struct {
+ importTag []string
+ sourceTag *string
+ redir Redirector
+}
+
+// Configures the Handler. The only required option is WithImport.
+type Option func(*config)
+
+// Instructs the go tool where to fetch the repo at vcsRoot and the importPath
+// that tree should be rooted at.
+func WithImport(importPath, vcs, vcsRoot string) Option {
+ importTag := "<meta name=\"go-import\" content=\"" + importPath + " " +
+ vcs + " " + vcsRoot + "\">"
+ return func(cfg *config) {
+ cfg.importTag = append(cfg.importTag, importTag)
+ }
+}
+
+// WithGoModProxy adds a go module proxy to the option chain.
+func WithGoModProxy(importPath, proxyServer string) Option {
+ return WithImport(importPath, "mod", proxyServer)
+}
+
+// Instructs gddo (godoc.org) how to direct browsers to browsable source code
+// for packages and their contents rooted at prefix.
+//
+// home specifies the home page of prefix, directory gives a format for how to
+// browse a directory, and file gives a format for how to view a file and go to
+// specific lines within it.
+//
+// More information can be found at https://github.com/golang/gddo/wiki/Source-Code-Links.
+//
+func WithSource(prefix, home, directory, file string) Option {
+ sourceTag := "<meta name=\"go-source\" content=\"" + prefix + " " +
+ home + " " + directory + " " + file + "\">"
+ return func(cfg *config) {
+ if cfg.sourceTag != nil {
+ panic(fmt.Sprintf("vanity: existing source tag: %s", *cfg.sourceTag))
+ }
+ cfg.sourceTag = &sourceTag
+ }
+}
+
+// When a browser navigates to the vanity URL of pkg, this function rewrites
+// pkg to a browsable URL.
+type Redirector func(pkg string) (url string)
+
+// WithRedirector loads a redirector instance into the config.
+func WithRedirector(redir Redirector) Option {
+ return func(cfg *config) {
+ if cfg.redir != nil {
+ panic("vanity: existing Redirector")
+ }
+ cfg.redir = redir
+ }
+}
+
+// MakeHandler creates a handler with custom options.
+func MakeHandler(opts ...Option) http.Handler {
+ return handlerFrom(compile(opts))
+}
+
+func compile(opts []Option) (*template.Template, Redirector) {
+ // Process options.
+ var cfg config
+ for _, opt := range opts {
+ opt(&cfg)
+ }
+
+ // A WithImport is required.
+ if cfg.importTag == nil {
+ panic("vanity: WithImport is required")
+ }
+
+ tags := make([]string, len(cfg.importTag))
+ copy(tags, cfg.importTag)
+ if cfg.sourceTag != nil {
+ tags = append(tags, *cfg.sourceTag)
+ }
+ tagBlk := strings.Join(tags, "\n")
+
+ h := fmt.Sprintf(`<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+%s
+<meta http-equiv="refresh" content="0; url={{ . }}">
+</head>
+<body>
+Please see <a href="{{ . }}">here</a> for documentation on this package.
+</body>
+</html>
+`, tagBlk)
+
+ // Use default GDDO Redirector.
+ if cfg.redir == nil {
+ cfg.redir = func(pkg string) string {
+ return "https://godoc.org/" + pkg
+ }
+ }
+
+ return template.Must(template.New("").Parse(h)), cfg.redir
+}
+
+func handlerFrom(tpl *template.Template, redir Redirector) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // Only method supported is GET.
+ if r.Method != http.MethodGet {
+ status := http.StatusMethodNotAllowed
+ http.Error(w, http.StatusText(status), status)
+ return
+ }
+
+ pkg := r.Host + r.URL.Path
+ redirURL := redir(pkg)
+
+ // Issue an HTTP redirect if this is definitely a browser.
+ if r.FormValue("go-get") != "1" {
+ http.Redirect(w, r, redirURL, http.StatusTemporaryRedirect)
+ return
+ }
+
+ w.Header().Set("Cache-Control", "public, max-age=300")
+ if err := tpl.ExecuteTemplate(w, "", redirURL); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ })
+}
+
+// Handler returns an http.Handler that serves the vanity URL information for a single
+// repository. Each Option gives additional information to agents about the
+// repository or provides help to browsers that may have navigated to the vanity
+// URL. The WithImport Option is mandatory since the go tool requires it to
+// fetch the repository.
+func Handler(opts ...Option) http.Handler {
+ return handlerFrom(compile(opts))
+}
+
+// Helpers for common VCSs.
+
+// Redirects gddo to browsable source files for GitHub hosted repositories.
+func WithGitHubStyleSource(importPath, repoPath, ref string) Option {
+ directory := repoPath + "/tree/" + ref + "{/dir}"
+ file := repoPath + "/blob/" + ref + "{/dir}/{file}#L{line}"
+
+ return WithSource(importPath, repoPath, directory, file)
+}
+
+// Redirects gddo to browsable source files for Gogs hosted repositories.
+func WithGogsStyleSource(importPath, repoPath, ref string) Option {
+ directory := repoPath + "/src/" + ref + "{/dir}"
+ file := repoPath + "/src/" + ref + "{/dir}/{file}#L{line}"
+
+ return WithSource(importPath, repoPath, directory, file)
+}
+
+// Creates a Handler that serves a GitHub repository at a specific importPath.
+func GitHubHandler(importPath, user, repo, gitScheme string) http.Handler {
+ ghImportPath := "github.com/" + user + "/" + repo
+ return Handler(
+ WithImport(importPath, "git", gitScheme+"://"+ghImportPath),
+ WithGitHubStyleSource(importPath, "https://"+ghImportPath, "master"),
+ )
+}
+
+// Creates a Handler that serves a repository hosted with Gogs at host at a
+// specific importPath.
+func GogsHandler(importPath, host, user, repo, gitScheme string) http.Handler {
+ gogsImportPath := host + "/" + user + "/" + repo
+ return Handler(
+ WithImport(importPath, "git", gitScheme+"://"+gogsImportPath),
+ WithGogsStyleSource(importPath, "https://"+gogsImportPath, "master"),
+ )
+}