mirror of
https://tildegit.org/solderpunk/molly-brown.git
synced 2025-04-13 09:29:46 +00:00
Factor out header parsing code for CGI and SCGI into one function, so the checks from last commit can be applied to both.
This commit is contained in:
parent
0f833ba57b
commit
565f54bff8
1 changed files with 49 additions and 38 deletions
87
dynamic.go
87
dynamic.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
@ -15,6 +16,35 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func extractStatusFromDynamicResponse(reader *bufio.Reader, source string) (int, error) {
|
||||||
|
rawHeader, _, err := reader.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Unable to read header in dynamic output from " + source + ".")
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
header := string(rawHeader)
|
||||||
|
logErrorMsg := "Unable to parse first line of dynamic output from " +
|
||||||
|
source +
|
||||||
|
" as valid Gemini response header. Line was: " +
|
||||||
|
header
|
||||||
|
header_fields := strings.Fields(header)
|
||||||
|
if len(header_fields) == 0 {
|
||||||
|
log.Println(logErrorMsg)
|
||||||
|
return 0, errors.New("")
|
||||||
|
}
|
||||||
|
status, err := strconv.Atoi(header_fields[0])
|
||||||
|
if err != nil {
|
||||||
|
log.Println(logErrorMsg)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if status < 10 || status > 70 {
|
||||||
|
log.Println(logErrorMsg)
|
||||||
|
return 0, errors.New("")
|
||||||
|
}
|
||||||
|
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
func handleCGI(config SysConfig, path string, cgiPath string, URL *url.URL, logEntry *LogEntry, conn net.Conn) {
|
func handleCGI(config SysConfig, path string, cgiPath string, URL *url.URL, logEntry *LogEntry, conn net.Conn) {
|
||||||
// Find the shortest leading part of path which maps to an executable file.
|
// Find the shortest leading part of path which maps to an executable file.
|
||||||
// Call this part scriptPath, and everything after it pathInfo.
|
// Call this part scriptPath, and everything after it pathInfo.
|
||||||
|
@ -72,6 +102,7 @@ func handleCGI(config SysConfig, path string, cgiPath string, URL *url.URL, logE
|
||||||
logEntry.Status = 42
|
logEntry.Status = 42
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract response header
|
// Extract response header
|
||||||
responseString := string(response)
|
responseString := string(response)
|
||||||
if len(responseString) == 0 {
|
if len(responseString) == 0 {
|
||||||
|
@ -80,28 +111,16 @@ func handleCGI(config SysConfig, path string, cgiPath string, URL *url.URL, logE
|
||||||
logEntry.Status = 42
|
logEntry.Status = 42
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
header, _, err := bufio.NewReader(strings.NewReader(string(response))).ReadLine()
|
|
||||||
if err != nil || len(header) == 0 {
|
responseReader := bufio.NewReader(strings.NewReader(string(response)))
|
||||||
log.Println("Unable to parse first line of output from CGI process " + path + " as valid Gemini response header. Line was: " + string(header))
|
status, err := extractStatusFromDynamicResponse(responseReader, path)
|
||||||
|
if err != nil {
|
||||||
conn.Write([]byte("42 CGI error!\r\n"))
|
conn.Write([]byte("42 CGI error!\r\n"))
|
||||||
logEntry.Status = 42
|
logEntry.Status = 42
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
logEntry.Status = status
|
||||||
}
|
}
|
||||||
header_fields := strings.Fields(string(header))
|
|
||||||
if len(header_fields) == 0 {
|
|
||||||
log.Println("Unable to parse first line of output from CGI process " + path + " as valid Gemini response header. Line was: " + string(header))
|
|
||||||
conn.Write([]byte("42 CGI error!\r\n"))
|
|
||||||
logEntry.Status = 42
|
|
||||||
return
|
|
||||||
}
|
|
||||||
status, err := strconv.Atoi(header_fields[0])
|
|
||||||
if err != nil || status < 10 || status > 70 {
|
|
||||||
log.Println("Unable to parse first line of output from CGI process " + path + " as valid Gemini response header. Line was: " + string(header))
|
|
||||||
conn.Write([]byte("42 CGI error!\r\n"))
|
|
||||||
logEntry.Status = 42
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logEntry.Status = status
|
|
||||||
|
|
||||||
// Write response
|
// Write response
|
||||||
conn.Write(response)
|
conn.Write(response)
|
||||||
|
@ -135,36 +154,28 @@ func handleSCGI(URL *url.URL, scgiPath string, scgiSocket string, config SysConf
|
||||||
socket.Write([]byte(","))
|
socket.Write([]byte(","))
|
||||||
|
|
||||||
// Read and relay response
|
// Read and relay response
|
||||||
|
responseReader := bufio.NewReader(socket)
|
||||||
|
status, err := extractStatusFromDynamicResponse(responseReader, scgiSocket)
|
||||||
|
if err != nil {
|
||||||
|
conn.Write([]byte("42 SCGI error!\r\n"))
|
||||||
|
logEntry.Status = 42
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
logEntry.Status = status
|
||||||
|
}
|
||||||
|
|
||||||
buffer := make([]byte, 1027)
|
buffer := make([]byte, 1027)
|
||||||
first := true
|
|
||||||
for {
|
for {
|
||||||
n, err := socket.Read(buffer)
|
n, err := responseReader.Read(buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
} else if !first {
|
} else {
|
||||||
// Err
|
// Err
|
||||||
log.Println("Error reading from SCGI socket " + scgiSocket + ": " + err.Error())
|
log.Println("Error reading from SCGI socket " + scgiSocket + ": " + err.Error())
|
||||||
conn.Write([]byte("42 Error reading from SCGI service!\r\n"))
|
|
||||||
logEntry.Status = 42
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Extract status code from first line
|
|
||||||
if first {
|
|
||||||
first = false
|
|
||||||
lines := strings.SplitN(string(buffer), "\r\n", 2)
|
|
||||||
status, err := strconv.Atoi(strings.Fields(lines[0])[0])
|
|
||||||
if err != nil || status < 10 || status > 70 {
|
|
||||||
conn.Write([]byte("42 CGI error!\r\n"))
|
|
||||||
log.Println("Unable to parse first line of output from SCGI socket " + scgiSocket + " as valid Gemini response header. Line was: " + lines[0])
|
|
||||||
logEntry.Status = 42
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logEntry.Status = status
|
|
||||||
}
|
|
||||||
// Send to client
|
// Send to client
|
||||||
conn.Write(buffer[:n])
|
conn.Write(buffer[:n])
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue