pages-server/handler/handler.go
hazycora fac988d9ac
All checks were successful
Deploy to VPS / build_site (push) Successful in 6s
only redirect to preferred domain if it points to pages.gay
2024-04-09 15:51:34 -05:00

145 lines
3.8 KiB
Go

package handler
import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
"git.gay/gitgay/pages/cache"
"git.gay/gitgay/pages/errors"
"git.gay/gitgay/pages/forgejo"
"git.gay/gitgay/pages/pagerouter"
"git.gay/gitgay/pages/render"
"git.gay/gitgay/pages/utils"
"github.com/rs/zerolog/log"
)
func serveFile(w http.ResponseWriter, r *http.Request, file *forgejo.TreeFile) {
reader, err := file.Reader()
if err != nil {
ErrorResponse(w, r, err)
return
}
defer reader.Close()
w.Header().Set("ETag", fmt.Sprintf("W/\"%s\"", file.SHA))
if file.Mime == "text/markdown; charset=utf-8" {
reader, err = render.Markdown(reader)
if err != nil {
ErrorResponse(w, r, err)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
} else {
w.Header().Set("Content-Type", file.Mime)
}
w.Header().Set("Cache-Control", "public, max-age=600")
if r.Header.Get("If-None-Match") == fmt.Sprintf("W/\"%s\"", file.SHA) {
w.WriteHeader(304)
return
}
_, err = io.Copy(w, reader)
if err != nil {
ErrorResponse(w, r, err)
return
}
}
func handleRedirect(w http.ResponseWriter, r *http.Request, page *pagerouter.PageRouter, pathname string) (ok bool) {
if r.URL.RawQuery != "" {
pathname += "?" + r.URL.RawQuery
}
redirect, ok := page.Redirects.Apply(fmt.Sprintf("/%s", pathname))
if !ok {
return
}
if (redirect.StatusCode != 200 && redirect.StatusCode != 400) || strings.HasPrefix(redirect.To, "https://") || strings.HasPrefix(redirect.To, "http://") {
w.Header().Add("Location", redirect.To)
w.WriteHeader(301)
return
}
file, _, err := page.GetFile(redirect.To)
if err != nil {
ErrorResponse(w, r, err)
return
}
serveFile(w, r, file)
ok = true
return
}
func Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Server", "https://git.gay/gitgay/pages-server")
begin := time.Now()
hardRefresh := r.Header.Get("Cache-Control") == "no-cache"
path := utils.CleanPath(r.URL.Path)
host := r.Host
options := []cache.CachedCallOptions{
{
HardRefresh: hardRefresh,
},
}
info, err := pagerouter.GetTarget(host, path, options...)
if err != nil {
return
}
path = strings.TrimSuffix(strings.TrimPrefix(path+"/", info.BasePath), "/")
page, err := pagerouter.GetPage(info)
if err != nil {
ErrorResponse(w, r, err)
return
}
if !page.Settings.AllowInsecure {
if r.TLS == nil {
newURL := &url.URL{Scheme: "https", Host: host, Path: path, RawQuery: r.URL.RawQuery}
w.Header().Add("Location", newURL.String())
w.WriteHeader(http.StatusMovedPermanently)
return
}
}
log.Debug().Str("host", host).Str("path", path).Dur("duration", time.Since(begin)).Msg("Got page")
matchedDomain := false
if len(page.Domains) > 0 {
for _, domains := range page.Domains {
if domains == host {
matchedDomain = true
break
}
}
preferredDomain := page.Domains[0]
// TODO: check that preferredDomain not just points at pages.gay
// but this specific repository on this specific user (not branch-specific though)
if !matchedDomain && utils.PointingAtUs(preferredDomain) {
newURL := &url.URL{Scheme: r.URL.Scheme, Host: preferredDomain, Path: path}
w.Header().Add("Location", newURL.String())
w.WriteHeader(301)
return
}
}
file, isIndex, err := page.GetFile(path)
if err != nil {
switch err.(type) {
case *errors.ErrorNotFound:
if page.Redirects != nil {
ok := handleRedirect(w, r, page, path)
if ok {
return
}
}
}
ErrorResponse(w, r, err)
return
}
if isIndex && !strings.HasSuffix(r.URL.Path, "/") {
w.Header().Add("Location", fmt.Sprintf("%s/", r.URL.Path))
w.WriteHeader(301)
return
}
serveFile(w, r, file)
})
}