internal/website/mux.go (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | package website
import (
"encoding/json"
"net/http"
"regexp"
"slices"
"strings"
ihttp "go.alanpearce.eu/homestead/internal/http"
"go.alanpearce.eu/homestead/internal/server"
"github.com/kevinpollet/nego"
)
func (website *Website) webfinger(w http.ResponseWriter, r *http.Request) *ihttp.Error {
if r.URL.Query().Get("resource") == website.acctResource {
w.Header().Add("Content-Type", "application/jrd+json")
w.Header().Add("Access-Control-Allow-Origin", "*")
if err := json.NewEncoder(w).Encode(website.me); err != nil {
return &ihttp.Error{
Code: http.StatusInternalServerError,
Cause: err,
}
}
}
return nil
}
func (website *Website) ServeHTTP(w http.ResponseWriter, r *http.Request) *ihttp.Error {
urlPath, shouldRedirect := website.reader.CanonicalisePath(r.URL.Path)
if shouldRedirect {
http.Redirect(w, r, urlPath, 302)
return nil
}
file, err := website.reader.GetFile(urlPath)
if err != nil {
website.log.Warn("Error reading file", "error", err)
return &ihttp.Error{
Message: "Error reading file",
Code: http.StatusInternalServerError,
}
}
if file == nil {
return &ihttp.Error{
Message: "File not found",
Code: http.StatusNotFound,
}
}
w.Header().Add("ETag", file.Etag)
w.Header().Add("Vary", "Accept-Encoding")
csp := *website.config.CSP
if file.StyleHash != "" {
csp.StyleSrc = []string{"'" + file.StyleHash + "'"}
}
w.Header().Add("Content-Security-Policy", csp.String())
for k, v := range website.config.Extra.Headers {
w.Header().Add(k, v)
}
enc := nego.NegotiateContentEncoding(r, file.AvailableEncodings()...)
if enc != "" {
w.Header().Add("Content-Encoding", enc)
}
w.Header().Add("Content-Type", file.ContentType)
http.ServeContent(w, r, file.Path, file.LastModified, file.Encodings[enc])
return nil
}
func (website *Website) MakeRedirectorApp() *server.App {
mux := http.NewServeMux()
re := regexp.MustCompile(
"^(.*)\\." + strings.ReplaceAll(website.config.WildcardDomain, ".", `\.`) + "$",
)
replace := "${1}." + website.config.Domains[0]
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
switch {
case slices.Contains(website.config.Domains, r.Host):
path, _ := website.reader.CanonicalisePath(r.URL.Path)
ihttp.Redirect(
w,
r,
website.config.BaseURL.JoinPath(path),
http.StatusMovedPermanently,
)
case re.MatchString(r.Host):
url := website.config.BaseURL.JoinPath()
url.Host = re.ReplaceAllString(r.Host, replace)
ihttp.Redirect(w, r, url, http.StatusTemporaryRedirect)
case true:
http.NotFound(w, r)
}
})
return &server.App{
WildcardDomain: website.config.WildcardDomain,
Domains: website.config.Domains,
Handler: mux,
}
}
|