Support input requests

This commit is contained in:
Trevor Slocum 2020-11-22 18:32:29 -08:00
parent 44aa04981e
commit 72c8172ab8
4 changed files with 76 additions and 25 deletions

View file

@ -19,21 +19,18 @@ The resulting binary is available as `~/go/bin/gmitohtml`.
## Usage ## Usage
Run daemon at [http://localhost:1967](http://localhost:1967):
```bash
gmitohtml --daemon=localhost:1967
```
Convert a single document: Convert a single document:
```bash ```bash
gmitohtml < document.gmi gmitohtml < document.gmi
``` ```
Run as daemon at `http://localhost:8080`:
```bash
# Start the daemon:
gmitohtml --daemon=localhost:8080
# Access via browser:
xdg-open http://localhost:8080/gemini/twins.rocketnine.space/
```
## Support ## Support
Please share issues and suggestions [here](https://gitlab.com/tslocum/gmitohtml/issues). Please share issues and suggestions [here](https://gitlab.com/tslocum/gmitohtml/issues).

View file

@ -2,27 +2,38 @@ package gmitohtml
var fs = make(inMemoryFS) var fs = make(inMemoryFS)
const indexPage = ` const pageHeader = `
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Xenia</title> <meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="/assets/style.css"></link> <link rel="stylesheet" href="/assets/style.css">
</head> </head>
<body> <body>`
<h1>Welcome to Xenia</h1><br>
<form method="post" action="/"> const pageFooter = `
<input type="text" name="address" placeholder="Address" size="50" autofocus> <input type="submit" value="Go"> </body>
</html>
`
const indexPage = pageHeader + `
<form method="post" action="/" novalidate>
<input type="url" name="address" placeholder="Address" size="50" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus> <input type="submit" value="Go">
</form> </form>
<br> <br>
<ul> <ul>
<li><a href="/gemini/gus.guru/">GUS - Gemini Universal Search</a></li> <li><a href="/gemini/gus.guru/">GUS - Gemini Universal Search</a></li>
<li><a href="/gemini/gemini.circumlunar.space/">Gemini protocol</a></li> <li><a href="/gemini/gemini.circumlunar.space/">Gemini protocol</a></li>
<li><a href="https://gitlab.com/tslocum/xenia">Xenia</a></li>
</ul> </ul>
</body> ` + pageFooter
</html>
` const inputPage = pageHeader + `
<form method="post" action="GEMINICURRENTURL">
<b>GEMINICURRENTURL</b> requests input.<br><br><br>
<b>GEMINIINPUTPROMPT</b><br><br>
<input type="GEMINIINPUTTYPE" name="input" placeholder="Input" size="50" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus> <input type="submit" value="Go">
</form>
` + pageFooter
func loadAssets() { func loadAssets() {
fs["/assets/style.css"] = loadFile("style.css", ` fs["/assets/style.css"] = loadFile("style.css", `

View file

@ -105,7 +105,7 @@ func Convert(page []byte, u string) []byte {
result = append(result, []byte("</pre>\n")...) result = append(result, []byte("</pre>\n")...)
} }
result = append([]byte("<!DOCTYPE html>\n<html>\n<head>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<link rel=\"stylesheet\" href=\"/assets/style.css\"></link>\n</head>\n<body>\n"), result...) result = append([]byte(pageHeader), result...)
result = append(result, []byte("\n</body>\n</html>")...) result = append(result, []byte(pageFooter)...)
return result return result
} }

View file

@ -65,7 +65,40 @@ func fetch(u string, clientCertFile string, clientCertKey string) ([]byte, []byt
data = data[firstNewLine+1:] data = data[firstNewLine+1:]
} }
if bytes.HasPrefix(header, []byte("text/html")) { requestInput := bytes.HasPrefix(header, []byte("1"))
if requestInput {
requestSensitiveInput := bytes.HasPrefix(header, []byte("11"))
data = []byte(inputPage)
data = bytes.Replace(data, []byte("GEMINICURRENTURL"), []byte(rewriteURL(u, requestURL)), 1)
currentURL := u
if strings.HasPrefix(currentURL, "gemini://") {
currentURL = currentURL[9:]
}
data = bytes.Replace(data, []byte("GEMINICURRENTURL"), []byte(currentURL), 1)
prompt := "(No input prompt)"
if len(header) > 3 {
prompt = string(header[3:])
}
data = bytes.Replace(data, []byte("GEMINIINPUTPROMPT"), []byte(prompt), 1)
inputType := "text"
if requestSensitiveInput {
inputType = "password"
}
data = bytes.Replace(data, []byte("GEMINIINPUTTYPE"), []byte(inputType), 1)
return header, data, nil
}
if !bytes.HasPrefix(header, []byte("2")) {
return header, []byte(fmt.Sprintf("Unexpected header: %s", header)), nil
}
if bytes.HasPrefix(header, []byte("20 text/html")) {
return header, data, nil return header, data, nil
} }
return header, Convert(data, requestURL.String()), nil return header, Convert(data, requestURL.String()), nil
@ -74,7 +107,7 @@ func fetch(u string, clientCertFile string, clientCertKey string) ([]byte, []byt
func handleIndex(writer http.ResponseWriter, request *http.Request) { func handleIndex(writer http.ResponseWriter, request *http.Request) {
address := request.FormValue("address") address := request.FormValue("address")
if address != "" { if address != "" {
http.Redirect(writer, request, rewriteURL(address, request.URL), http.StatusTemporaryRedirect) http.Redirect(writer, request, rewriteURL(address, request.URL), http.StatusSeeOther)
return return
} }
@ -92,6 +125,13 @@ func handleRequest(writer http.ResponseWriter, request *http.Request) {
return return
} }
inputText := request.PostFormValue("input")
if inputText != "" {
request.URL.RawQuery = inputText
http.Redirect(writer, request, request.URL.String(), http.StatusSeeOther)
return
}
pathSplit := strings.Split(request.URL.Path, "/") pathSplit := strings.Split(request.URL.Path, "/")
if len(pathSplit) < 2 || pathSplit[1] != "gemini" { if len(pathSplit) < 2 || pathSplit[1] != "gemini" {
writer.Write([]byte("Error: invalid protocol, only Gemini is supported")) writer.Write([]byte("Error: invalid protocol, only Gemini is supported"))
@ -103,6 +143,9 @@ func handleRequest(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("Error: invalid URL")) writer.Write([]byte("Error: invalid URL"))
return return
} }
if request.URL.RawQuery != "" {
u.RawQuery = request.URL.RawQuery
}
header, data, err := fetch(u.String(), "", "") header, data, err := fetch(u.String(), "", "")
if err != nil { if err != nil {
@ -113,7 +156,7 @@ func handleRequest(writer http.ResponseWriter, request *http.Request) {
if len(header) > 0 && header[0] == '3' { if len(header) > 0 && header[0] == '3' {
split := bytes.SplitN(header, []byte(" "), 2) split := bytes.SplitN(header, []byte(" "), 2)
if len(split) == 2 { if len(split) == 2 {
http.Redirect(writer, request, rewriteURL(string(split[1]), request.URL), http.StatusTemporaryRedirect) http.Redirect(writer, request, rewriteURL(string(split[1]), request.URL), http.StatusSeeOther)
return return
} }
} }