Handle CGI requests with URI components after the script.
This commit is contained in:
parent
68398ef0be
commit
b30fc0923b
57
dynamic.go
57
dynamic.go
|
@ -9,29 +9,63 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleCGI(config Config, path string, URL *url.URL, log *LogEntry, errorLog chan string, conn net.Conn) {
|
func handleCGI(config Config, path string, cgiPath string, URL *url.URL, log *LogEntry, errorLog chan string, conn net.Conn) {
|
||||||
// Make sure file is executable
|
// Attempt to find the shortest leading part of path which maps to an executable file while still matching cgiPath
|
||||||
info, err := os.Stat(path)
|
// If we find such, call it script_path, and everything after it path_info
|
||||||
if info.Mode().Perm()&0111 != 0111 {
|
components := strings.Split(path, "/")
|
||||||
|
script_path := ""
|
||||||
|
path_info := ""
|
||||||
|
matched := false
|
||||||
|
for i := 0; i <= len(components); i++ {
|
||||||
|
script_path = strings.Join(components[0:i], "/")
|
||||||
|
path_info = strings.Join(components[i:], "/")
|
||||||
|
if !strings.HasPrefix(script_path, config.DocBase) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
inCGIPath, err := regexp.Match(cgiPath, []byte(path))
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if !inCGIPath {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
info, err := os.Stat(script_path)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info.Mode().Perm()&0111 == 0111 {
|
||||||
|
matched = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we didn't find a match, give up and let this request be handled as
|
||||||
|
// if it were a static file
|
||||||
|
if !matched {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare environment variables
|
||||||
|
vars := prepareCGIVariables(config, URL, conn, script_path, path_info)
|
||||||
|
|
||||||
|
// Spawn process
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
cmd := exec.CommandContext(ctx, path)
|
cmd := exec.CommandContext(ctx, script_path)
|
||||||
|
|
||||||
// Set environment variables
|
|
||||||
vars := prepareCGIVariables(config, URL, conn, path)
|
|
||||||
cmd.Env = []string{}
|
cmd.Env = []string{}
|
||||||
for key, value := range vars {
|
for key, value := range vars {
|
||||||
cmd.Env = append(cmd.Env, key+"="+value)
|
cmd.Env = append(cmd.Env, key+"="+value)
|
||||||
}
|
}
|
||||||
response, err := cmd.Output()
|
response, err := cmd.Output()
|
||||||
|
|
||||||
if ctx.Err() == context.DeadlineExceeded {
|
if ctx.Err() == context.DeadlineExceeded {
|
||||||
errorLog <- "Terminating CGI process " + path + " due to exceeding 10 second runtime limit."
|
errorLog <- "Terminating CGI process " + path + " due to exceeding 10 second runtime limit."
|
||||||
conn.Write([]byte("42 CGI process timed out!\r\n"))
|
conn.Write([]byte("42 CGI process timed out!\r\n"))
|
||||||
|
@ -118,10 +152,11 @@ func handleSCGI(socket_path string, config Config, URL *url.URL, log *LogEntry,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareCGIVariables(config Config, URL *url.URL, conn net.Conn, path string) map[string]string {
|
func prepareCGIVariables(config Config, URL *url.URL, conn net.Conn, script_path string, path_info string) map[string]string {
|
||||||
vars := prepareGatewayVariables(config, URL, conn)
|
vars := prepareGatewayVariables(config, URL, conn)
|
||||||
vars["GATEWAY_INTERFACE"] = "CGI/1.1"
|
vars["GATEWAY_INTERFACE"] = "CGI/1.1"
|
||||||
vars["SCRIPT_PATH"] = path
|
vars["SCRIPT_PATH"] = script_path
|
||||||
|
vars["PATH_INFO"] = path_info
|
||||||
return vars
|
return vars
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,12 +164,12 @@ func prepareSCGIVariables(config Config, URL *url.URL, conn net.Conn) map[string
|
||||||
vars := prepareGatewayVariables(config, URL, conn)
|
vars := prepareGatewayVariables(config, URL, conn)
|
||||||
vars["SCGI"] = "1"
|
vars["SCGI"] = "1"
|
||||||
vars["CONTENT_LENGTH"] = "0"
|
vars["CONTENT_LENGTH"] = "0"
|
||||||
|
vars["PATH_INFO"] = "/"
|
||||||
return vars
|
return vars
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareGatewayVariables(config Config, URL *url.URL, conn net.Conn) map[string]string {
|
func prepareGatewayVariables(config Config, URL *url.URL, conn net.Conn) map[string]string {
|
||||||
vars := make(map[string]string)
|
vars := make(map[string]string)
|
||||||
vars["PATH_INFO"] = "/"
|
|
||||||
vars["QUERY_STRING"] = URL.RawQuery
|
vars["QUERY_STRING"] = URL.RawQuery
|
||||||
vars["REMOTE_ADDR"] = conn.RemoteAddr().String()
|
vars["REMOTE_ADDR"] = conn.RemoteAddr().String()
|
||||||
vars["REQUEST_METHOD"] = ""
|
vars["REQUEST_METHOD"] = ""
|
||||||
|
|
|
@ -94,7 +94,7 @@ func handleGeminiRequest(conn net.Conn, config Config, accessLogEntries chan Log
|
||||||
for _, cgiPath := range config.CGIPaths {
|
for _, cgiPath := range config.CGIPaths {
|
||||||
inCGIPath, err := regexp.Match(cgiPath, []byte(path))
|
inCGIPath, err := regexp.Match(cgiPath, []byte(path))
|
||||||
if err == nil && inCGIPath {
|
if err == nil && inCGIPath {
|
||||||
handleCGI(config, path, URL, &log, errorLogEntries, conn)
|
handleCGI(config, path, cgiPath, URL, &log, errorLogEntries, conn)
|
||||||
if log.Status != 0 {
|
if log.Status != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue