aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornytpu <alex@nytpu.com>2021-05-31 12:19:31 -0600
committernytpu <alex@nytpu.com>2021-05-31 12:19:31 -0600
commit3189bdaa6d4abeca41e66456f83178e9fe79aad8 (patch)
tree68221b8dd41c4744b27c9529b86133215b5d58f2
parentUpdate go-gemini dependency (diff)
downloadkineto-3189bdaa6d4abeca41e66456f83178e9fe79aad8.tar.bz2
kineto-3189bdaa6d4abeca41e66456f83178e9fe79aad8.zip
Add -e flag to place a stylesheet externally rather than loading it inline
By default, kineto loads a stylesheet given to -s from disk and places it inline with the HTML in a <style>...</style> block. This patch adds a -e flag to load a stylesheet externally. When the -e flag is passed with a URI (relative or absolute), the given link is placed in the href of a <link rel="stylesheet"...> tag. This helps facilitate caching which can *significantly* reduce request overhead, particularly when the stylesheet is large (>= the size of the page content). The given URI is not validated, and if it is invalid the browser will 404 when requesting it and the page will have no style.
-rw-r--r--README.md14
-rw-r--r--main.go77
2 files changed, 58 insertions, 33 deletions
diff --git a/README.md b/README.md
index 01197a8..f0851f3 100644
--- a/README.md
+++ b/README.md
@@ -12,15 +12,23 @@ Geminispace, but it defaults to a specific domain.
```
$ go build
-$ ./kineto [-b 127.0.0.1:8080] [-s style.css] gemini://example.org
+$ ./kineto [-b 127.0.0.1:8080] [-s style.css] [-e style.css] gemini://example.org
```
The -b argument is optional and allows you to bind to an arbitrary address; by
default kineto will bind to `:8080`. You should set up some external reverse
proxy like nginx to forward traffic to this port and add TLS.
-The -s argument is optional and allows you to specify a custom CSS file. By
-default kineto will serve its built-in style.
+The -s argument is optional and allows you to specify a custom CSS filename.
+The given file will be loaded from the local disk and placed in a `<style>`
+block. By default kineto will serve its built-in style.
+
+The -e argument is optional and allows you to specify a custom CSS URL. If
+provided, the style.css given will be treated as a link to be put in the href
+of a `<link rel="stylesheet"...>` instead of being placed inline with the body
+in a `<style>` block like with the -s flag. The given stylesheet can be a
+relative link, for instance `-e /main.css` will serve `main.css` from the root
+of the proxied Gemini capsule.
## "kineto"?
diff --git a/main.go b/main.go
index e03574f..c600985 100644
--- a/main.go
+++ b/main.go
@@ -127,10 +127,14 @@ var gemtextPage = template.Must(template.
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
{{- if .CSS }}
+{{- if .ExternalCSS }}
+<link rel="stylesheet" type="text/css" href="{{.CSS | safeCSS}}">
+{{- else }}
<style>
{{.CSS | safeCSS}}
</style>
{{- end }}
+{{- end }}
<title>{{.Title}}</title>
<article{{if .Lang}} lang="{{.Lang}}"{{end}}>
{{ $ctx := . -}}
@@ -229,10 +233,14 @@ var inputPage = template.Must(template.
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
{{- if .CSS }}
+{{- if .ExternalCSS }}
+<link rel="stylesheet" type="text/css" href="{{.CSS | safeCSS}}">
+{{- else }}
<style>
{{.CSS | safeCSS}}
</style>
{{- end }}
+{{- end }}
<title>{{.Prompt}}</title>
<form method="POST">
<label for="input">{{.Prompt}}</label>
@@ -359,22 +367,24 @@ input:focus {
`
type GemtextContext struct {
- CSS string
- External bool
- Lines []gemini.Line
- Pre int
- Resp *gemini.Response
- Title string
- Lang string
- URL *url.URL
- Root *url.URL
+ CSS string
+ ExternalCSS bool
+ External bool
+ Lines []gemini.Line
+ Pre int
+ Resp *gemini.Response
+ Title string
+ Lang string
+ URL *url.URL
+ Root *url.URL
}
type InputContext struct {
- CSS string
- Prompt string
- Secret bool
- URL *url.URL
+ CSS string
+ ExternalCSS bool
+ Prompt string
+ Secret bool
+ URL *url.URL
}
type GemtextHeading struct {
@@ -383,7 +393,7 @@ type GemtextHeading struct {
}
func proxyGemini(req gemini.Request, external bool, root *url.URL,
- w http.ResponseWriter, r *http.Request, css string) {
+ w http.ResponseWriter, r *http.Request, css string, externalCSS bool) {
ctx, cancel := context.WithTimeout(r.Context(), 20*time.Second)
defer cancel()
@@ -401,10 +411,11 @@ func proxyGemini(req gemini.Request, external bool, root *url.URL,
case 10, 11:
w.Header().Add("Content-Type", "text/html")
err = inputPage.Execute(w, &InputContext{
- CSS: css,
- Prompt: resp.Meta,
- Secret: resp.Status == 11,
- URL: req.URL,
+ CSS: css,
+ ExternalCSS: externalCSS,
+ Prompt: resp.Meta,
+ Secret: resp.Status == 11,
+ URL: req.URL,
})
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
@@ -478,13 +489,14 @@ func proxyGemini(req gemini.Request, external bool, root *url.URL,
w.Header().Add("Content-Type", "text/html")
gemctx := &GemtextContext{
- CSS: css,
- External: external,
- Resp: resp,
- Title: req.URL.Host + " " + req.URL.Path,
- Lang: lang,
- URL: req.URL,
- Root: root,
+ CSS: css,
+ ExternalCSS: externalCSS,
+ External: external,
+ Resp: resp,
+ Title: req.URL.Host + " " + req.URL.Path,
+ Lang: lang,
+ URL: req.URL,
+ Root: root,
}
var title bool
@@ -508,11 +520,12 @@ func proxyGemini(req gemini.Request, external bool, root *url.URL,
func main() {
var (
- bind string = ":8080"
- css string = defaultCSS
+ bind string = ":8080"
+ css string = defaultCSS
+ external bool = false
)
- opts, optind, err := getopt.Getopts(os.Args, "b:c:s:")
+ opts, optind, err := getopt.Getopts(os.Args, "b:c:s:e:")
if err != nil {
log.Fatal(err)
}
@@ -521,12 +534,16 @@ func main() {
case 'b':
bind = opt.Value
case 's':
+ external = false
cssContent, err := ioutil.ReadFile(opt.Value)
if err == nil {
css = string(cssContent)
} else {
log.Fatalf("Error opening custom CSS from '%s': %v", opt.Value, err)
}
+ case 'e':
+ external = true
+ css = opt.Value
}
}
@@ -572,7 +589,7 @@ func main() {
req.URL.Host = root.Host
req.URL.Path = r.URL.Path
req.URL.RawQuery = r.URL.RawQuery
- proxyGemini(req, false, root, w, r, css)
+ proxyGemini(req, false, root, w, r, css, external)
}))
http.Handle("/x/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -606,7 +623,7 @@ func main() {
req.URL.Path = "/" + path[3]
req.URL.RawQuery = r.URL.RawQuery
log.Printf("%s (external) %s%s", r.Method, r.URL.Host, r.URL.Path)
- proxyGemini(req, true, root, w, r, css)
+ proxyGemini(req, true, root, w, r, css, external)
}))
log.Printf("HTTP server listening on %s", bind)