2020-11-18 22:24:10 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2024-03-19 05:42:02 +00:00
|
|
|
"embed"
|
2020-11-18 22:24:10 +00:00
|
|
|
"encoding/base64"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2024-03-19 05:42:02 +00:00
|
|
|
//go:embed static/*
|
|
|
|
var StaticFiles embed.FS
|
|
|
|
|
|
|
|
func (this *Application) ServeStatic(w http.ResponseWriter, r *http.Request) {
|
|
|
|
http.FileServer(http.FS(StaticFiles)).ServeHTTP(w, r)
|
|
|
|
// http.StripPrefix(`/static/`, http.FileServer(http.FS(StaticFiles))).ServeHTTP(w, r)
|
|
|
|
}
|
|
|
|
|
2020-11-18 22:24:10 +00:00
|
|
|
func (this *Application) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if r.Method == `GET` {
|
|
|
|
if r.URL.Path == `/` {
|
|
|
|
this.Homepage(w, r)
|
|
|
|
|
|
|
|
} else if r.URL.Path == `/favicon.ico` {
|
|
|
|
w.Header().Set(`Location`, `/static/logo.png`)
|
|
|
|
w.WriteHeader(301)
|
|
|
|
|
|
|
|
} else if r.URL.Path == `/robots.txt` {
|
|
|
|
http.Error(w, "not found", 404)
|
|
|
|
|
|
|
|
} else if parts := this.rxRepoImage.FindStringSubmatch(r.URL.Path); parts != nil {
|
|
|
|
this.Bannerpage(w, r, parts[1])
|
|
|
|
|
|
|
|
} else if parts := this.rxRepoPage.FindStringSubmatch(r.URL.Path); parts != nil {
|
|
|
|
|
|
|
|
// Support /repo.html URIs for backward compatibility
|
|
|
|
if strings.HasSuffix(parts[1], `.html`) {
|
|
|
|
w.Header().Set(`Location`, r.URL.Path[0:len(r.URL.Path)-5])
|
|
|
|
w.WriteHeader(301)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// The regexp supports an optional trailing slash
|
|
|
|
// Redirect to canonical no-trailing-slash
|
|
|
|
if strings.HasSuffix(r.URL.Path, `/`) {
|
|
|
|
w.Header().Set(`Location`, `/`+parts[1]) // n.b. parts[1] isn't urldecoded yet
|
|
|
|
w.WriteHeader(301)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Proper decoding of special characters in repo path component
|
|
|
|
repoName, err := url.PathUnescape(parts[1])
|
|
|
|
if err != nil {
|
|
|
|
http.Error(w, "malformed url encoding in repository name", 400)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Maybe it's a redirected project (alternative name)
|
|
|
|
if rename, ok := this.cfg.Redirect[repoName]; ok {
|
|
|
|
w.Header().Set(`Location`, `/`+url.PathEscape(rename))
|
|
|
|
w.WriteHeader(301)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
this.Repopage(w, r, repoName)
|
|
|
|
|
2024-03-19 05:42:02 +00:00
|
|
|
} else if strings.HasPrefix(r.URL.Path, `/static/`) {
|
|
|
|
|
|
|
|
if r.URL.Path == `/static/logo.png` && this.cfg.Template.CustomLogoPngBase64 != "" {
|
2020-11-18 22:24:10 +00:00
|
|
|
|
|
|
|
logoPng, err := base64.StdEncoding.DecodeString(this.cfg.Template.CustomLogoPngBase64)
|
|
|
|
if err != nil {
|
|
|
|
this.internalError(w, r, fmt.Errorf("parsing base64 logo: %w", err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
w.Header().Set(`Content-Length`, fmt.Sprintf("%d", len(logoPng)))
|
|
|
|
w.Header().Set(`Content-Type`, `image/png`)
|
|
|
|
w.WriteHeader(200)
|
|
|
|
w.Write(logoPng)
|
2024-03-19 05:42:02 +00:00
|
|
|
return
|
2020-11-18 22:24:10 +00:00
|
|
|
}
|
|
|
|
|
2024-03-19 05:42:02 +00:00
|
|
|
// Embedded resource
|
|
|
|
// r.URL.Path = r.URL.Path[8:]
|
|
|
|
this.ServeStatic(w, r)
|
2020-11-18 22:24:10 +00:00
|
|
|
|
|
|
|
} else if r.URL.Query().Get("go-get") == "1" {
|
|
|
|
// This wasn't one of our standard `/repo` paths, but there is the ?go-get=1 parameter
|
|
|
|
// It must be a subpackage request
|
|
|
|
// We can't serve the proper go-import meta tag immediately because
|
|
|
|
// we haven't looked up the go.mod yet. Just redirect to the root
|
|
|
|
// package - `go get` will follow redirects and the resulting meta tag is correct
|
|
|
|
|
|
|
|
slashParts := strings.SplitN(r.URL.Path, `/`, 3) // len === 3 is guaranteed from earlier if cases
|
|
|
|
|
|
|
|
w.Header().Set(`Location`, `/`+slashParts[1])
|
|
|
|
w.WriteHeader(301)
|
|
|
|
return
|
|
|
|
|
|
|
|
} else {
|
|
|
|
http.Error(w, "not found", 404)
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
http.Error(w, "invalid method", 400)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|