Add new flags for robots.txt and URL rewrites
This commit is contained in:
parent
c36b3b6cb0
commit
32c87fbc39
2 changed files with 124 additions and 66 deletions
20
README.md
20
README.md
|
@ -6,15 +6,24 @@ can proxy to any domain in order to facilitate linking to the rest of
|
|||
Geminispace, but it defaults to a specific domain.
|
||||
|
||||
[http]: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
|
||||
[gemini]: https://gemini.circumlunar.space/
|
||||
[gemini]: https://geminiprotocol.net/
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
$ go build
|
||||
$ ./kineto [-b 127.0.0.1:8080] [-s style.css] [-e style.css] [-p https://portal.mozz.us] gemini://example.org
|
||||
$ ./kineto [-P] [-R] [-b 127.0.0.1:8080] [-r /learn-more-about-gemini] [-s style.css] [-e style.css] [-p https://portal.mozz.us] gemini://example.org
|
||||
```
|
||||
|
||||
The -P argument is optional and allows you to completely disable proxying
|
||||
and URL rewriting external gemini URLs. The user visiting your site will need
|
||||
to have a browser or browser extension that understands how to handle
|
||||
gemini:// links.
|
||||
|
||||
The -R argument is optional and allows you to completely disables serving a
|
||||
custom robots.txt response. When enabled the request will be proxied to your
|
||||
gemini site.
|
||||
|
||||
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.
|
||||
|
@ -30,8 +39,13 @@ 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.
|
||||
|
||||
The -r argument is optional and allows you rewrite external gemini links to a
|
||||
custom URL. Use this if you have external gemini links but instead of proxying
|
||||
them you prefer to invite your visitors to learn more about the Gemini protocol
|
||||
and download a Gemini browser. This can be a relative or absolute URL.
|
||||
|
||||
The -p argument is optional and allows you to specify a custom Portal to proxy
|
||||
external gemini requests. This option will effectively disable the use of `/x/`
|
||||
external Gemini requests. This option will effectively disable the use of `/x/`
|
||||
for all external URLs, that is al URLs whose host does not match the proxied site.
|
||||
|
||||
## "kineto"?
|
||||
|
|
90
main.go
90
main.go
|
@ -108,27 +108,44 @@ var gemtextPage = template.Must(template.
|
|||
|
||||
u = ctx.URL.ResolveReference(u)
|
||||
|
||||
if u.Scheme == "" || u.Scheme == "gemini" {
|
||||
if u.Host != ctx.Root.Host {
|
||||
if u.Scheme != "" && u.Scheme != "gemini" {
|
||||
return template.URL(u.String())
|
||||
}
|
||||
|
||||
if u.Host == ctx.Root.Host {
|
||||
u.Scheme = ""
|
||||
u.Host = ""
|
||||
return template.URL(u.String())
|
||||
}
|
||||
|
||||
if ctx.DisableExternalProxy {
|
||||
return template.URL(u.String())
|
||||
}
|
||||
|
||||
if ctx.UseRewrite {
|
||||
r, err := url.Parse(ctx.Rewrite)
|
||||
if err != nil {
|
||||
return template.URL("error")
|
||||
}
|
||||
return template.URL(r.String())
|
||||
}
|
||||
|
||||
if ctx.UsePortal {
|
||||
p, err := url.Parse(ctx.Portal)
|
||||
if err != nil {
|
||||
return template.URL("error")
|
||||
}
|
||||
p = ctx.URL.ResolveReference(p)
|
||||
u.Path = fmt.Sprintf("%s/gemini/%s%s", p.Path, u.Host, u.Path)
|
||||
u.Path = fmt.Sprintf("%s/%s/%s%s", p.Path, u.Scheme, u.Host, u.Path)
|
||||
u.Scheme = p.Scheme
|
||||
u.Host = p.Host
|
||||
} else {
|
||||
|
||||
return template.URL(u.String())
|
||||
}
|
||||
|
||||
u.Path = fmt.Sprintf("/x/%s%s", u.Host, u.Path)
|
||||
u.Scheme = ""
|
||||
u.Host = ""
|
||||
}
|
||||
} else {
|
||||
u.Scheme = ""
|
||||
u.Host = ""
|
||||
}
|
||||
}
|
||||
|
||||
return template.URL(u.String())
|
||||
},
|
||||
|
@ -383,6 +400,11 @@ input:focus {
|
|||
}
|
||||
`
|
||||
|
||||
const defaultRobots = `
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
`
|
||||
|
||||
type GemtextContext struct {
|
||||
CSS string
|
||||
ExternalCSS bool
|
||||
|
@ -396,6 +418,9 @@ type GemtextContext struct {
|
|||
Root *url.URL
|
||||
UsePortal bool
|
||||
Portal string
|
||||
DisableExternalProxy bool
|
||||
UseRewrite bool
|
||||
Rewrite string
|
||||
}
|
||||
|
||||
type InputContext struct {
|
||||
|
@ -427,8 +452,9 @@ func createAnchor(heading string) string {
|
|||
return strings.ToLower(anchor.String())
|
||||
}
|
||||
|
||||
func proxyGemini(req gemini.Request, external bool, root *url.URL,
|
||||
w http.ResponseWriter, r *http.Request, css string, externalCSS bool, usePortal bool, portal string) {
|
||||
func proxyGemini(req gemini.Request, external bool, root *url.URL, w http.ResponseWriter,
|
||||
r *http.Request, css string, externalCSS bool, usePortal bool, portal string, disableExternalProxy bool,
|
||||
useRewrite bool, rewrite string) {
|
||||
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 20*time.Second)
|
||||
defer cancel()
|
||||
|
@ -534,6 +560,9 @@ func proxyGemini(req gemini.Request, external bool, root *url.URL,
|
|||
Root: root,
|
||||
UsePortal: usePortal,
|
||||
Portal: portal,
|
||||
DisableExternalProxy: disableExternalProxy,
|
||||
UseRewrite: useRewrite,
|
||||
Rewrite: rewrite,
|
||||
}
|
||||
|
||||
var title bool
|
||||
|
@ -562,16 +591,35 @@ func main() {
|
|||
external bool = false
|
||||
usePortal bool = false
|
||||
portal string = ""
|
||||
useRewrite bool = false
|
||||
rewrite string = ""
|
||||
disableExternalProxy bool = false
|
||||
disableRobots bool = false
|
||||
)
|
||||
|
||||
opts, optind, err := getopt.Getopts(os.Args, "b:c:s:e:p:")
|
||||
opts, optind, err := getopt.Getopts(os.Args, "PRb:c:e:p:r:s:")
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
switch opt.Option {
|
||||
case 'P':
|
||||
disableExternalProxy = true
|
||||
case 'R':
|
||||
disableRobots = true
|
||||
case 'b':
|
||||
bind = opt.Value
|
||||
case 'e':
|
||||
external = true
|
||||
css = opt.Value
|
||||
case 'p':
|
||||
usePortal = true
|
||||
portal = opt.Value
|
||||
case 'r':
|
||||
useRewrite = true
|
||||
rewrite = opt.Value
|
||||
case 's':
|
||||
external = false
|
||||
cssContent, err := os.ReadFile(opt.Value)
|
||||
|
@ -580,12 +628,6 @@ func main() {
|
|||
} else {
|
||||
log.Fatalf("Error opening custom CSS from '%s': %v", opt.Value, err)
|
||||
}
|
||||
case 'e':
|
||||
external = true
|
||||
css = opt.Value
|
||||
case 'p':
|
||||
usePortal = true
|
||||
portal = opt.Value
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -625,11 +667,13 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
if !disableRobots {
|
||||
if r.URL.Path == "/robots.txt" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("User-agent: *\nDisallow: /\n"))
|
||||
w.Write([]byte(defaultRobots))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
req := gemini.Request{}
|
||||
req.URL = &url.URL{}
|
||||
|
@ -637,7 +681,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, external, usePortal, portal)
|
||||
proxyGemini(req, false, root, w, r, css, external, usePortal, portal, disableExternalProxy, useRewrite, rewrite)
|
||||
}))
|
||||
|
||||
http.Handle("/x/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -646,7 +690,7 @@ func main() {
|
|||
path = append(path, "")
|
||||
}
|
||||
|
||||
if usePortal && path[2] != root.Host {
|
||||
if path[2] != root.Host && (usePortal || disableExternalProxy) {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
w.Write([]byte("404 Not found"))
|
||||
return
|
||||
|
@ -678,7 +722,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, external, usePortal, portal)
|
||||
proxyGemini(req, true, root, w, r, css, external, usePortal, portal, disableExternalProxy, useRewrite, rewrite)
|
||||
}))
|
||||
|
||||
log.Printf("HTTP server listening on %s", bind)
|
||||
|
|
Loading…
Reference in a new issue