diff options
| author | Xe Iaso <me@xeiaso.net> | 2023-06-19 12:56:31 -0400 |
|---|---|---|
| committer | Xe Iaso <me@xeiaso.net> | 2023-06-19 12:56:31 -0400 |
| commit | c592b6d195aedcd6ec86e8c60d3ba91d524e293b (patch) | |
| tree | fbdb9fe9331ce491d606402d4b62ba5999ce6122 /web | |
| parent | 84e8f57b98fd1038e6f2fc401277d936ef45522a (diff) | |
| download | x-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/LICENSE | 41 | ||||
| -rw-r--r-- | web/vanity/legal.go | 47 | ||||
| -rw-r--r-- | web/vanity/vanity.go | 188 |
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"), + ) +} |
