summaryrefslogtreecommitdiff
path: root/app/router.go
diff options
context:
space:
mode:
Diffstat (limited to 'app/router.go')
-rwxr-xr-xapp/router.go45
1 files changed, 34 insertions, 11 deletions
diff --git a/app/router.go b/app/router.go
index 13e8415..e29005d 100755
--- a/app/router.go
+++ b/app/router.go
@@ -7,10 +7,15 @@ import (
"skunkyart/static"
"strconv"
"strings"
+ "time"
)
+// Host is the scheme and host that generated links are built from. It is set per
+// request from the Host header and X-Forwarded-Proto.
var Host string
+// Router registers the single catch-all handler that dispatches every path, then
+// serves until the process exits. It does not return on success.
func Router() {
parsepath := func(path string) map[int]string {
if l := len(CFG.URI); len(path) > l {
@@ -33,22 +38,30 @@ func Router() {
return parsedpath
}
- next := func(path map[int]string, from int) (out string) {
+ next := func(path map[int]string, from int) string {
+ var out strings.Builder
for x, l := from, len(path)-1; x <= l; x++ {
- out += path[x]
+ out.WriteString(path[x])
if x != l {
- out += "/"
+ out.WriteString("/")
}
}
- return
+ return out.String()
}
open := func(name string) []byte {
file, err := static.Templates.Open(name)
- try(err)
- fileReaded, err := io.ReadAll(file)
- try(err)
+ if err != nil {
+ try(err)
+ return nil
+ }
+ defer func() { try(file.Close()) }()
+ fileReaded, err := io.ReadAll(file)
+ if err != nil {
+ try(err)
+ return nil
+ }
return fileReaded
}
@@ -119,10 +132,10 @@ func Router() {
skunky.Emojitar(path[3])
}
case "stylesheet":
- w.Header().Add("content-type", "text/css")
- w.Write(open("css/skunky.css"))
+ w.Header().Add("Content-Type", "text/css")
+ _, _ = w.Write(open("css/skunky.css"))
case "favicon.ico":
- w.Write(open("images/logo.png"))
+ _, _ = w.Write(open("images/logo.png"))
// API
case "api":
@@ -145,5 +158,15 @@ func Router() {
http.HandleFunc("/", handle)
println("SkunkyArt is listening on", CFG.Listen)
- tryWithExitStatus(http.ListenAndServe(CFG.Listen, nil), 1)
+ // Explicit timeouts: the bare http.ListenAndServe has none, so a slow client
+ // can hold a connection (and its handler) open indefinitely. WriteTimeout is
+ // generous because media proxying streams large files through a handler.
+ srv := &http.Server{
+ Addr: CFG.Listen,
+ ReadHeaderTimeout: 10 * time.Second,
+ ReadTimeout: 30 * time.Second,
+ WriteTimeout: 120 * time.Second,
+ IdleTimeout: 120 * time.Second,
+ }
+ tryWithExitStatus(srv.ListenAndServe(), 1)
}