mirror of
https://code.rocketnine.space/tslocum/twins.git
synced 2024-11-27 13:38:14 +01:00
Add SaneEOL configuration option
This commit is contained in:
parent
0b744eba7e
commit
e3aeb18053
6 changed files with 41 additions and 14 deletions
|
@ -119,16 +119,31 @@ specified address or path.
|
||||||
|
|
||||||
A `Root` attribute must also be specified to use `FastCGI`.
|
A `Root` attribute must also be specified to use `FastCGI`.
|
||||||
|
|
||||||
|
## End-of-line indicator
|
||||||
|
|
||||||
|
The Gemini protocol requires `\r\n` (CRLF) as the end-of-line indicator. This
|
||||||
|
convention is carried over from protocol specifications **first written in the
|
||||||
|
1970s**. This requirement is antithetic to the spirit of Gemini (to improve
|
||||||
|
upon the Finger and Gopher protocols) because it unnecessarily tacks on ancient
|
||||||
|
baggage. This baggage has caused (and continues to cause) increased complexity in
|
||||||
|
client and server implementations, which naturally gives rise to more bugs.
|
||||||
|
|
||||||
|
In anticipation of an improvement to the Gemini specification, administrators
|
||||||
|
may configure twins to send standard `\n` (LF) line endings by setting
|
||||||
|
`SaneEOL` to `true`.
|
||||||
|
|
||||||
|
References:
|
||||||
|
[1](https://lists.orbitalfox.eu/archives/gemini/2019/000131.html)
|
||||||
|
[2](https://lists.orbitalfox.eu/archives/gemini/2020/000756.html)
|
||||||
|
[3](https://lists.orbitalfox.eu/archives/gemini/2020/001339.html)
|
||||||
|
[4](https://lists.orbitalfox.eu/archives/gemini/2020/003065.html)
|
||||||
|
|
||||||
# Example config.yaml
|
# Example config.yaml
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# Address to listen on
|
# Address to listen on
|
||||||
listen: :1965
|
listen: :1965
|
||||||
|
|
||||||
# TLS certificates
|
|
||||||
certificates:
|
|
||||||
-
|
|
||||||
|
|
||||||
# Hosts and paths to serve
|
# Hosts and paths to serve
|
||||||
hosts:
|
hosts:
|
||||||
gemini.rocks:
|
gemini.rocks:
|
||||||
|
|
|
@ -12,7 +12,7 @@ This page is also available at [gemini://twins.rocketnine.space](gemini://twins.
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Serve static files
|
- Serve static files
|
||||||
- Directory listing (when enabled)
|
- List files and directories (when enabled)
|
||||||
- Reverse proxy requests
|
- Reverse proxy requests
|
||||||
- TCP
|
- TCP
|
||||||
- [FastCGI](https://en.wikipedia.org/wiki/FastCGI)
|
- [FastCGI](https://en.wikipedia.org/wiki/FastCGI)
|
||||||
|
|
|
@ -59,6 +59,8 @@ type serverConfig struct {
|
||||||
|
|
||||||
DisableSize bool
|
DisableSize bool
|
||||||
|
|
||||||
|
SaneEOL bool
|
||||||
|
|
||||||
hostname string
|
hostname string
|
||||||
port int
|
port int
|
||||||
fcgiPools map[string]gofast.ConnFactory
|
fcgiPools map[string]gofast.ConnFactory
|
||||||
|
@ -91,6 +93,12 @@ func readconfig(configPath string) error {
|
||||||
log.Fatal("listen address must be specified")
|
log.Fatal("listen address must be specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.SaneEOL {
|
||||||
|
newLine = "\n"
|
||||||
|
} else {
|
||||||
|
newLine = "\r\n"
|
||||||
|
}
|
||||||
|
|
||||||
split := strings.Split(config.Listen, ":")
|
split := strings.Split(config.Listen, ":")
|
||||||
if len(split) != 2 {
|
if len(split) != 2 {
|
||||||
config.hostname = config.Listen
|
config.hostname = config.Listen
|
||||||
|
|
|
@ -52,7 +52,7 @@ func serveDirList(c net.Conn, request *url.URL, dirPath string) {
|
||||||
|
|
||||||
writeHeader(c, statusSuccess, "text/gemini; charset=utf-8")
|
writeHeader(c, statusSuccess, "text/gemini; charset=utf-8")
|
||||||
|
|
||||||
fmt.Fprintf(c, "# %s\r\n", request.Path)
|
fmt.Fprintf(c, "# %s%s", request.Path, newLine)
|
||||||
if numDirs == 1 {
|
if numDirs == 1 {
|
||||||
c.Write([]byte("1 directory"))
|
c.Write([]byte("1 directory"))
|
||||||
} else {
|
} else {
|
||||||
|
@ -64,10 +64,10 @@ func serveDirList(c net.Conn, request *url.URL, dirPath string) {
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(c, "%d files", numFiles)
|
fmt.Fprintf(c, "%d files", numFiles)
|
||||||
}
|
}
|
||||||
c.Write([]byte("\r\n\n"))
|
c.Write([]byte(newLine + newLine))
|
||||||
|
|
||||||
if request.Path != "/" {
|
if request.Path != "/" {
|
||||||
c.Write([]byte("=> ../ ../\r\n\r\n"))
|
c.Write([]byte("=> ../ ../" + newLine + newLine))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, info := range files {
|
for _, info := range files {
|
||||||
|
@ -78,10 +78,10 @@ func serveDirList(c net.Conn, request *url.URL, dirPath string) {
|
||||||
filePath += "/"
|
filePath += "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Write([]byte("=> " + fileName + " " + filePath + "\r\n"))
|
c.Write([]byte("=> " + fileName + " " + filePath + newLine))
|
||||||
|
|
||||||
if info.IsDir() || info.Mode()&os.ModeSymlink != 0 {
|
if info.IsDir() || info.Mode()&os.ModeSymlink != 0 {
|
||||||
c.Write([]byte("\r\n"))
|
c.Write([]byte(newLine))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ func serveDirList(c net.Conn, request *url.URL, dirPath string) {
|
||||||
if !info.ModTime().IsZero() {
|
if !info.ModTime().IsZero() {
|
||||||
modified = info.ModTime().Format("2006-01-02 3:04 PM")
|
modified = info.ModTime().Format("2006-01-02 3:04 PM")
|
||||||
}
|
}
|
||||||
c.Write([]byte(modified + " - " + formatFileSize(info.Size()) + "\r\n\r\n"))
|
c.Write([]byte(modified + " - " + formatFileSize(info.Size()) + newLine + newLine))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ func serveProxy(c net.Conn, request *url.URL, proxyURL string) {
|
||||||
|
|
||||||
// Forward request
|
// Forward request
|
||||||
proxy.Write([]byte(request.String()))
|
proxy.Write([]byte(request.String()))
|
||||||
proxy.Write([]byte("\r\n"))
|
proxy.Write([]byte(newLine))
|
||||||
|
|
||||||
// Forward response
|
// Forward response
|
||||||
io.Copy(c, proxy)
|
io.Copy(c, proxy)
|
||||||
|
|
|
@ -47,8 +47,10 @@ const (
|
||||||
|
|
||||||
var slashesRegexp = regexp.MustCompile(`[^\\]\/`)
|
var slashesRegexp = regexp.MustCompile(`[^\\]\/`)
|
||||||
|
|
||||||
|
var newLine = "\r\n"
|
||||||
|
|
||||||
func writeHeader(c net.Conn, code int, meta string) {
|
func writeHeader(c net.Conn, code int, meta string) {
|
||||||
fmt.Fprintf(c, "%d %s\r\n", code, meta)
|
fmt.Fprintf(c, "%d %s%s", code, meta, newLine)
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
log.Printf("< %d %s\n", code, meta)
|
log.Printf("< %d %s\n", code, meta)
|
||||||
|
@ -203,7 +205,9 @@ func servePath(c *tls.Conn, request *url.URL, serve *pathConfig) {
|
||||||
func serveConn(c *tls.Conn) {
|
func serveConn(c *tls.Conn) {
|
||||||
var requestData string
|
var requestData string
|
||||||
scanner := bufio.NewScanner(c)
|
scanner := bufio.NewScanner(c)
|
||||||
scanner.Split(scanCRLF)
|
if !config.SaneEOL {
|
||||||
|
scanner.Split(scanCRLF)
|
||||||
|
}
|
||||||
if scanner.Scan() {
|
if scanner.Scan() {
|
||||||
requestData = scanner.Text()
|
requestData = scanner.Text()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue