mirror of
https://code.rocketnine.space/tslocum/twins.git
synced 2024-11-27 13:28:15 +01:00
Support redirecting to path or URL
This commit is contained in:
parent
58a4ecd958
commit
c64a59c44e
4 changed files with 62 additions and 34 deletions
|
@ -87,12 +87,6 @@ One resource must be defined for each path.
|
||||||
|
|
||||||
Serve static files from specified root directory.
|
Serve static files from specified root directory.
|
||||||
|
|
||||||
##### Proxy
|
|
||||||
|
|
||||||
Forward requests to Gemini server at specified URL.
|
|
||||||
|
|
||||||
Use the pseudo-scheme `gemini-insecure://` to disable certificate verification.
|
|
||||||
|
|
||||||
##### Command
|
##### Command
|
||||||
|
|
||||||
Serve output of system command.
|
Serve output of system command.
|
||||||
|
@ -101,6 +95,16 @@ When input is requested from the user, it is available as a pseudo-variable
|
||||||
`$USERINPUT` which does not require surrounding quotes. It may be used as an
|
`$USERINPUT` which does not require surrounding quotes. It may be used as an
|
||||||
argument to the command, otherwise user input is passed via standard input.
|
argument to the command, otherwise user input is passed via standard input.
|
||||||
|
|
||||||
|
##### Proxy
|
||||||
|
|
||||||
|
Forward requests to Gemini server at specified URL.
|
||||||
|
|
||||||
|
Use the pseudo-scheme `gemini-insecure://` to disable certificate verification.
|
||||||
|
|
||||||
|
##### Redirect
|
||||||
|
|
||||||
|
Redirect requests to specified path or URL.
|
||||||
|
|
||||||
#### Attributes
|
#### Attributes
|
||||||
|
|
||||||
Any number of attributes may be defined for a path.
|
Any number of attributes may be defined for a path.
|
||||||
|
@ -220,6 +224,12 @@ hosts:
|
||||||
path: ^/cmd-example$
|
path: ^/cmd-example$
|
||||||
command: uname -a
|
command: uname -a
|
||||||
cache: 0 # Do not cache
|
cache: 0 # Do not cache
|
||||||
|
-
|
||||||
|
path: /redir-path-example
|
||||||
|
redirect: /other-resource
|
||||||
|
-
|
||||||
|
path: /redir-url-example
|
||||||
|
redirect: gemini://gemini.circumlunar.space/
|
||||||
-
|
-
|
||||||
path: /
|
path: /
|
||||||
root: /home/geminirocks/data/home
|
root: /home/geminirocks/data/home
|
||||||
|
|
|
@ -19,6 +19,7 @@ This page is also available at [gemini://twins.rocketnine.space](gemini://twins.
|
||||||
- TCP
|
- TCP
|
||||||
- [FastCGI](https://en.wikipedia.org/wiki/FastCGI)
|
- [FastCGI](https://en.wikipedia.org/wiki/FastCGI)
|
||||||
- Serve system command output
|
- Serve system command output
|
||||||
|
- Redirect to path or URL
|
||||||
- Reload configuration on `SIGHUP`
|
- Reload configuration on `SIGHUP`
|
||||||
|
|
||||||
## Proposals
|
## Proposals
|
||||||
|
|
47
config.go
47
config.go
|
@ -22,8 +22,9 @@ type pathConfig struct {
|
||||||
|
|
||||||
// Resource to serve
|
// Resource to serve
|
||||||
Root string
|
Root string
|
||||||
Proxy string
|
|
||||||
Command string
|
Command string
|
||||||
|
Proxy string
|
||||||
|
Redirect string
|
||||||
|
|
||||||
// Request input
|
// Request input
|
||||||
Input string
|
Input string
|
||||||
|
@ -164,12 +165,12 @@ func readconfig(configPath string) error {
|
||||||
if defaultPath.Root != "" && serve.Root == "" {
|
if defaultPath.Root != "" && serve.Root == "" {
|
||||||
serve.Root = defaultPath.Root
|
serve.Root = defaultPath.Root
|
||||||
}
|
}
|
||||||
if defaultPath.Proxy != "" && serve.Proxy == "" {
|
|
||||||
serve.Proxy = defaultPath.Proxy
|
|
||||||
}
|
|
||||||
if defaultPath.Command != "" && serve.Command == "" {
|
if defaultPath.Command != "" && serve.Command == "" {
|
||||||
serve.Command = defaultPath.Command
|
serve.Command = defaultPath.Command
|
||||||
}
|
}
|
||||||
|
if defaultPath.Proxy != "" && serve.Proxy == "" {
|
||||||
|
serve.Proxy = defaultPath.Proxy
|
||||||
|
}
|
||||||
if defaultPath.SymLinks {
|
if defaultPath.SymLinks {
|
||||||
serve.SymLinks = defaultPath.SymLinks
|
serve.SymLinks = defaultPath.SymLinks
|
||||||
}
|
}
|
||||||
|
@ -206,17 +207,31 @@ func readconfig(configPath string) error {
|
||||||
|
|
||||||
for _, serve := range host.Paths {
|
for _, serve := range host.Paths {
|
||||||
if serve.Path == "" {
|
if serve.Path == "" {
|
||||||
log.Fatal("path must be specified in serve entry")
|
log.Fatal("a path must be specified in each serve entry")
|
||||||
} else if (serve.Root != "" && (serve.Proxy != "" || serve.Command != "")) ||
|
|
||||||
(serve.Proxy != "" && (serve.Root != "" || serve.Command != "")) ||
|
|
||||||
(serve.Command != "" && (serve.Root != "" || serve.Proxy != "")) {
|
|
||||||
log.Fatal("only one root, proxy or command resource may specified for a path")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if serve.Path[0] == '^' {
|
if serve.Path[0] == '^' {
|
||||||
serve.r = regexp.MustCompile(serve.Path)
|
serve.r = regexp.MustCompile(serve.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var resources int
|
||||||
|
if serve.Root != "" {
|
||||||
|
resources++
|
||||||
|
}
|
||||||
|
if serve.Command != "" {
|
||||||
|
resources++
|
||||||
|
}
|
||||||
|
if serve.Proxy != "" {
|
||||||
|
resources++
|
||||||
|
}
|
||||||
|
if serve.Redirect != "" {
|
||||||
|
resources++
|
||||||
|
}
|
||||||
|
if resources == 0 {
|
||||||
|
log.Fatalf("a resource must specified for path %s%s", hostname, serve.Path)
|
||||||
|
} else if resources > 1 {
|
||||||
|
log.Fatalf("only one resource (root, command, proxy or redirect) may specified for path %s%s", hostname, serve.Path)
|
||||||
|
}
|
||||||
|
|
||||||
serve.cache = cacheUnset
|
serve.cache = cacheUnset
|
||||||
if serve.Cache != "" {
|
if serve.Cache != "" {
|
||||||
serve.cache, err = strconv.ParseInt(serve.Cache, 10, 64)
|
serve.cache, err = strconv.ParseInt(serve.Cache, 10, 64)
|
||||||
|
@ -225,7 +240,12 @@ func readconfig(configPath string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if serve.FastCGI != "" {
|
if serve.Command != "" {
|
||||||
|
serve.cmd, err = shellquote.Split(serve.Command)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to parse command %s: %s", serve.cmd, err)
|
||||||
|
}
|
||||||
|
} else if serve.FastCGI != "" {
|
||||||
if serve.Root == "" {
|
if serve.Root == "" {
|
||||||
log.Fatalf("root must be specified to use fastcgi resource %s of path %s%s", serve.FastCGI, hostname, serve.Path)
|
log.Fatalf("root must be specified to use fastcgi resource %s of path %s%s", serve.FastCGI, hostname, serve.Path)
|
||||||
}
|
}
|
||||||
|
@ -238,11 +258,6 @@ func readconfig(configPath string) error {
|
||||||
|
|
||||||
config.fcgiPools[serve.FastCGI] = gofast.SimpleConnFactory(f.Scheme, f.Host+f.Path)
|
config.fcgiPools[serve.FastCGI] = gofast.SimpleConnFactory(f.Scheme, f.Host+f.Path)
|
||||||
}
|
}
|
||||||
} else if serve.Command != "" {
|
|
||||||
serve.cmd, err = shellquote.Split(serve.Command)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to parse command %s: %s", serve.cmd, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
22
server.go
22
server.go
|
@ -174,7 +174,16 @@ func servePath(c *tls.Conn, request *url.URL, serve *pathConfig) (int, int64) {
|
||||||
filePath = path.Join(root, resolvedPath)
|
filePath = path.Join(root, resolvedPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if serve.Proxy != "" {
|
if serve.cmd != nil {
|
||||||
|
requireInput := serve.Input != "" || serve.SensitiveInput != ""
|
||||||
|
if requireInput {
|
||||||
|
newCommand := replaceWithUserInput(serve.cmd, request)
|
||||||
|
if newCommand != nil {
|
||||||
|
return serveCommand(c, serve, request, newCommand)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return serveCommand(c, serve, request, serve.cmd)
|
||||||
|
} else if serve.Proxy != "" {
|
||||||
return serveProxy(c, request, serve.Proxy), -1
|
return serveProxy(c, request, serve.Proxy), -1
|
||||||
} else if serve.FastCGI != "" {
|
} else if serve.FastCGI != "" {
|
||||||
if filePath == "" {
|
if filePath == "" {
|
||||||
|
@ -189,15 +198,8 @@ func servePath(c *tls.Conn, request *url.URL, serve *pathConfig) (int, int64) {
|
||||||
|
|
||||||
serveFastCGI(c, config.fcgiPools[serve.FastCGI], request, filePath)
|
serveFastCGI(c, config.fcgiPools[serve.FastCGI], request, filePath)
|
||||||
return statusSuccess, -1
|
return statusSuccess, -1
|
||||||
} else if serve.cmd != nil {
|
} else if serve.Redirect != "" {
|
||||||
requireInput := serve.Input != "" || serve.SensitiveInput != ""
|
return writeHeader(c, statusRedirectTemporary, serve.Redirect), -1
|
||||||
if requireInput {
|
|
||||||
newCommand := replaceWithUserInput(serve.cmd, request)
|
|
||||||
if newCommand != nil {
|
|
||||||
return serveCommand(c, serve, request, newCommand)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return serveCommand(c, serve, request, serve.cmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if filePath == "" {
|
if filePath == "" {
|
||||||
|
|
Loading…
Reference in a new issue