~sircmpwn/gmni-devel

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH kineto] Add -e flag to place a stylesheet externally rather than loading it inline

Details
Message ID
<20210531182659.11956-1-alex@nytpu.com>
DKIM signature
pass
Download raw message
Patch: +58 -33
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.
---
 README.md | 14 +++++++---
 main.go   | 77 +++++++++++++++++++++++++++++++++----------------------
 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)
-- 
2.31.1
Details
Message ID
<CBRT2TD1DPLK.XETDX7OJQ5B6@sayaka>
In-Reply-To
<20210531182659.11956-1-alex@nytpu.com> (view parent)
DKIM signature
pass
Download raw message
Thanks!

To git@git.sr.ht:~sircmpwn/kineto
   988a00f..  master -> master
Reply to thread Export thread (mbox)