summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--roseh.moe.go92
1 files changed, 61 insertions, 31 deletions
diff --git a/roseh.moe.go b/roseh.moe.go
index 637c22b..4f0b86d 100644
--- a/roseh.moe.go
+++ b/roseh.moe.go
@@ -5,6 +5,7 @@ import (
"bytes"
"cmp"
"compress/gzip"
+ "context"
"crypto/hkdf"
"crypto/hmac"
"crypto/rand"
@@ -1019,6 +1020,10 @@ type gzipResponseWriter struct {
code int
}
+func (w *gzipResponseWriter) Unwrap() http.ResponseWriter {
+ return w.ResponseWriter
+}
+
func shouldGzip(w http.ResponseWriter) bool {
disposition, _, _ := strings.Cut(w.Header().Get("Content-Disposition"), ";")
length, lengthErr := strconv.Atoi(w.Header().Get("Content-Length"))
@@ -1138,6 +1143,26 @@ func (h *authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.h.ServeHTTP(w, r)
}
+type timeoutHandler struct {
+ h http.Handler
+ timeout time.Duration
+}
+
+func (h *timeoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+ rc := http.NewResponseController(w)
+ deadline := time.Now().Add(h.timeout)
+ if err := rc.SetReadDeadline(deadline); err != nil {
+ log.Printf("Error: set read deadline: %s", err)
+ }
+ if err := rc.SetWriteDeadline(deadline); err != nil {
+ log.Printf("Error: set write deadline: %s", err)
+ }
+ ctx, cancel := context.WithDeadline(ctx, deadline)
+ defer cancel()
+ h.h.ServeHTTP(w, r.WithContext(ctx))
+}
+
type loggingHandler struct {
h http.Handler
}
@@ -1179,7 +1204,7 @@ func main() {
if err != nil {
log.Fatal(err)
}
- mux.Handle("GET /{$}", indexHandler)
+ mux.Handle("GET /{$}", &timeoutHandler{h: indexHandler, timeout: 5 * time.Minute})
gamesIndexTemplate, err := outlinedTemplate(gamesIndexString)
if err != nil {
log.Fatal(err)
@@ -1188,7 +1213,7 @@ func main() {
if err != nil {
log.Fatal(err)
}
- mux.Handle("GET /games/{$}", gamesIndexHandler)
+ mux.Handle("GET /games/{$}", &timeoutHandler{h: gamesIndexHandler, timeout: 5 * time.Minute})
pongTemplate, err := template.New("pong").Parse(pongString)
if err != nil {
log.Fatal(err)
@@ -1197,7 +1222,7 @@ func main() {
if err != nil {
log.Fatal(err)
}
- mux.Handle("GET /games/pong", pongHandler)
+ mux.Handle("GET /games/pong", &timeoutHandler{h: pongHandler, timeout: 5 * time.Minute})
stallmanShooterTemplate, err := outlinedTemplate(stallmanShooterString)
if err != nil {
log.Fatal(err)
@@ -1206,29 +1231,29 @@ func main() {
if err != nil {
log.Fatal(err)
}
- mux.Handle("GET /games/rms", stallmanShooterHandler)
- mux.HandleFunc("GET /qr.png", qrHandler)
- mux.HandleFunc("GET /wormhole", wormhole)
+ mux.Handle("GET /games/rms", &timeoutHandler{h: stallmanShooterHandler, timeout: 5 * time.Minute})
+ mux.Handle("GET /qr.png", &timeoutHandler{h: http.HandlerFunc(qrHandler), timeout: 5 * time.Minute})
+ mux.Handle("GET /wormhole", &timeoutHandler{h: http.HandlerFunc(wormhole), timeout: 5 * time.Minute})
mux.HandleFunc("POST /wormhole", wormholeUpload)
mux.HandleFunc("GET /wormhole/{hole}", wormholeDownload)
- mux.HandleFunc("GET /login", serveLogin)
- mux.HandleFunc("POST /login", login)
- mux.Handle("GET /otp", &authHandler{h: http.HandlerFunc(otp)})
- mux.HandleFunc("GET /otp/{code}", otpCode)
- mux.Handle("GET /logout", &authHandler{h: http.HandlerFunc(logout), noRedirect: true})
- mux.Handle("GET /notepad", &authHandler{h: http.HandlerFunc(notepad)})
- mux.Handle("POST /notepad", &authHandler{h: http.HandlerFunc(autosave), noRedirect: true})
- mux.HandleFunc("GET /cmd/{$}", cmdIndex)
- mux.HandleFunc("GET /cmd/{cmd}", cmd)
- mux.HandleFunc("GET /pkg/{$}", pkgIndex)
- mux.HandleFunc("GET /pkg/{pkg}", pkg)
- mux.Handle("GET /nezuko/", &authHandler{h: http.StripPrefix("/nezuko/", http.FileServer(http.Dir(*nezuko)))})
- mux.HandleFunc("GET /static/", static)
- mux.HandleFunc("GET /favicon.ico", favicon)
+ mux.Handle("GET /login", &timeoutHandler{h: http.HandlerFunc(serveLogin), timeout: 5 * time.Minute})
+ mux.Handle("POST /login", &timeoutHandler{h: http.HandlerFunc(login), timeout: 5 * time.Minute})
+ mux.Handle("GET /otp", &timeoutHandler{h: &authHandler{h: http.HandlerFunc(otp)}, timeout: 5 * time.Minute})
+ mux.Handle("GET /otp/{code}", &timeoutHandler{h: http.HandlerFunc(otpCode), timeout: 5 * time.Minute})
+ mux.Handle("GET /logout", &timeoutHandler{h: &authHandler{h: http.HandlerFunc(logout), noRedirect: true}, timeout: 5 * time.Minute})
+ mux.Handle("GET /notepad", &timeoutHandler{h: &authHandler{h: http.HandlerFunc(notepad)}, timeout: 5 * time.Minute})
+ mux.Handle("POST /notepad", &timeoutHandler{h: &authHandler{h: http.HandlerFunc(autosave), noRedirect: true}, timeout: 5 * time.Minute})
+ mux.Handle("GET /cmd/{$}", &timeoutHandler{h: http.HandlerFunc(cmdIndex), timeout: 5 * time.Minute})
+ mux.Handle("GET /cmd/{cmd}", &timeoutHandler{h: http.HandlerFunc(cmd), timeout: 5 * time.Minute})
+ mux.Handle("GET /pkg/{$}", &timeoutHandler{h: http.HandlerFunc(pkgIndex), timeout: 5 * time.Minute})
+ mux.Handle("GET /pkg/{pkg}", &timeoutHandler{h: http.HandlerFunc(pkg), timeout: 5 * time.Minute})
+ mux.Handle("GET /nezuko/", &timeoutHandler{h: &authHandler{h: http.StripPrefix("/nezuko/", http.FileServer(http.Dir(*nezuko)))}, timeout: 10 * time.Minute})
+ mux.Handle("GET /static/", &timeoutHandler{h: http.HandlerFunc(static), timeout: 5 * time.Minute})
+ mux.Handle("GET /favicon.ico", &timeoutHandler{h: http.HandlerFunc(favicon), timeout: 5 * time.Minute})
apiMux := http.NewServeMux()
apiMux.HandleFunc("PUT /api/wormhole/{name}", wormholeAPIUpload)
mux.Handle("/api/", apiMux)
- mux.HandleFunc("/", notFound)
+ mux.Handle("/", &timeoutHandler{h: http.HandlerFunc(notFound), timeout: 5 * time.Minute})
serverMux := http.NewServeMux()
serverMux.Handle(selfURL.Hostname()+"/", http.NewCrossOriginProtection().Handler(&gzipHandler{mux}))
jellyfinURL, err := url.Parse("http://127.0.0.1:8096")
@@ -1243,10 +1268,10 @@ func main() {
}})
codeMux := http.NewServeMux()
cgitStaticFiles := http.FileServer(http.Dir(*cgit))
- codeMux.Handle("/cgit.css", cgitStaticFiles)
- codeMux.Handle("/cgit.js", cgitStaticFiles)
- codeMux.Handle("/robots.txt", cgitStaticFiles)
- codeMux.HandleFunc("/favicon.ico", favicon)
+ codeMux.Handle("/cgit.css", &timeoutHandler{h: cgitStaticFiles, timeout: 5 * time.Minute})
+ codeMux.Handle("/cgit.js", &timeoutHandler{h: cgitStaticFiles, timeout: 5 * time.Minute})
+ codeMux.Handle("/robots.txt", &timeoutHandler{h: cgitStaticFiles, timeout: 5 * time.Minute})
+ codeMux.Handle("/favicon.ico", &timeoutHandler{h: http.HandlerFunc(favicon), timeout: 5 * time.Minute})
cgitConfigAbsPath, err := filepath.Abs(*cgitConfig)
if err != nil {
log.Fatal(err)
@@ -1256,9 +1281,14 @@ func main() {
Env: []string{"CGIT_CONFIG=" + cgitConfigAbsPath},
}
cgitCGI.PathLocationHandler = cgitCGI
- codeMux.Handle("/", cgitCGI)
+ codeMux.Handle("/", &timeoutHandler{h: cgitCGI, timeout: 5 * time.Minute})
serverMux.Handle("code."+selfURL.Hostname()+"/", &gzipHandler{codeMux})
- handler := &loggingHandler{serverMux}
+ server := &http.Server{
+ Handler: &loggingHandler{serverMux},
+
+ ReadHeaderTimeout: 5 * time.Minute,
+ IdleTimeout: 10 * time.Minute,
+ }
port := selfURL.Port()
if port == "" {
@@ -1267,11 +1297,11 @@ func main() {
port = "443"
}
}
- addr := ":" + port
- log.Printf("Listening on %q", addr)
+ server.Addr = ":" + port
+ log.Printf("Listening on %q", server.Addr)
if *https != "" {
- log.Fatal(http.ListenAndServeTLS(addr, *https+"/cert.pem", *https+"/key.pem", handler))
+ log.Fatal(server.ListenAndServeTLS(*https+"/cert.pem", *https+"/key.pem"))
} else {
- log.Fatal(http.ListenAndServe(addr, handler))
+ log.Fatal(server.ListenAndServe())
}
}