mirror of
https://code.rocketnine.space/tslocum/gmitohtml.git
synced 2024-11-27 16:28:13 +01:00
Support input requests
This commit is contained in:
parent
44aa04981e
commit
72c8172ab8
4 changed files with 76 additions and 25 deletions
15
README.md
15
README.md
|
@ -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).
|
||||||
|
|
|
@ -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", `
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue