1
0
Fork 0

Big rearrange: resolve URL to filesystem earlier, so we can check for .molly files ASAP, so that they can handle redirects, certificate zones, etc.

This commit is contained in:
Solderpunk 2020-06-30 19:31:27 +02:00
parent 990b7071d0
commit e43fc7877c

View file

@ -74,6 +74,14 @@ func handleGeminiRequest(conn net.Conn, config Config, accessLogEntries chan Log
return return
} }
// Resolve URI path to actual filesystem path
path := resolvePath(URL.Path, config)
// Read Molly files
if config.ReadMollyFiles {
parseMollyFiles(path, &config, errorLogEntries)
}
// Check for redirects // Check for redirects
for src, dst := range config.TempRedirects { for src, dst := range config.TempRedirects {
if URL.Path == src { if URL.Path == src {
@ -120,6 +128,22 @@ func handleGeminiRequest(conn net.Conn, config Config, accessLogEntries chan Log
return return
} }
// Check whether this URL is in a configured CGI path
for _, cgiPath := range config.CGIPaths {
inCGIPath, err := regexp.Match(cgiPath, []byte(path))
if err != nil || !inCGIPath {
continue
}
info, err := os.Stat(path)
if err != nil {
continue
}
if info.Mode().Perm()&0111 == 0111 {
handleCGI(config, path, URL, &log, errorLogEntries, conn)
return
}
}
// Check whether this URL is mapped to an SCGI app // Check whether this URL is mapped to an SCGI app
for scgi_url, scgi_socket := range config.SCGIPaths { for scgi_url, scgi_socket := range config.SCGIPaths {
matched, err := regexp.Match(scgi_url, []byte(URL.Path)) matched, err := regexp.Match(scgi_url, []byte(URL.Path))
@ -129,10 +153,8 @@ func handleGeminiRequest(conn net.Conn, config Config, accessLogEntries chan Log
} }
} }
// Resolve URI path to actual filesystem path
path, info, err := resolvePath(URL.Path, config)
// Fail if file does not exist or perms aren't right // Fail if file does not exist or perms aren't right
info, err := os.Stat(path)
if os.IsNotExist(err) || os.IsPermission(err) { if os.IsNotExist(err) || os.IsPermission(err) {
conn.Write([]byte("51 Not found!\r\n")) conn.Write([]byte("51 Not found!\r\n"))
log.Status = 51 log.Status = 51
@ -162,11 +184,6 @@ func handleGeminiRequest(conn net.Conn, config Config, accessLogEntries chan Log
return return
} }
// Read Molly files
if config.ReadMollyFiles {
parseMollyFiles(path, info, &config, errorLogEntries)
}
// Handle directories // Handle directories
if info.IsDir() { if info.IsDir() {
// Redirect to add trailing slash if missing // Redirect to add trailing slash if missing
@ -190,17 +207,6 @@ func handleGeminiRequest(conn net.Conn, config Config, accessLogEntries chan Log
return return
} }
// If this file is executable, get dynamic content
if info.Mode().Perm()&0111 == 0111 {
for _, cgiPath := range config.CGIPaths {
inCGIPath, err := regexp.Match(cgiPath, []byte(path))
if err == nil && inCGIPath {
handleCGI(config, path, URL, &log, errorLogEntries, conn)
return
}
}
}
// Otherwise, serve the file contents // Otherwise, serve the file contents
serveFile(path, &log, conn, config, errorLogEntries) serveFile(path, &log, conn, config, errorLogEntries)
return return
@ -239,7 +245,7 @@ func readRequest(conn net.Conn, log *LogEntry, errorLog chan string) (*url.URL,
return URL, nil return URL, nil
} }
func resolvePath(path string, config Config) (string, os.FileInfo, error) { func resolvePath(path string, config Config) string {
// Handle tildes // Handle tildes
if strings.HasPrefix(path, "/~") { if strings.HasPrefix(path, "/~") {
bits := strings.Split(path, "/") bits := strings.Split(path, "/")
@ -250,20 +256,12 @@ func resolvePath(path string, config Config) (string, os.FileInfo, error) {
} else { } else {
path = filepath.Join(config.DocBase, path) path = filepath.Join(config.DocBase, path)
} }
// Make sure this file exists and is readable return path
info, err := os.Stat(path)
if err != nil {
return "", nil, err
}
return path, info, nil
} }
func parseMollyFiles(path string, info os.FileInfo, config *Config, errorLogEntries chan string) { func parseMollyFiles(path string, config *Config, errorLogEntries chan string) {
// Build list of directories to check // Build list of directories to check
dirs := make([]string, 16) var dirs []string
if !info.IsDir() {
path = filepath.Dir(path)
}
dirs = append(dirs, path) dirs = append(dirs, path)
for { for {
if path == filepath.Clean(config.DocBase) { if path == filepath.Clean(config.DocBase) {
@ -280,14 +278,22 @@ func parseMollyFiles(path string, info os.FileInfo, config *Config, errorLogEntr
mollyFile.DirectorySort = config.DirectorySort mollyFile.DirectorySort = config.DirectorySort
mollyFile.DirectoryReverse = config.DirectoryReverse mollyFile.DirectoryReverse = config.DirectoryReverse
mollyFile.DirectoryTitles = config.DirectoryTitles mollyFile.DirectoryTitles = config.DirectoryTitles
// Parse files // Parse files in reverse order
for i := len(dirs) - 1; i >= 0; i-- { for i := len(dirs) - 1; i >= 0; i-- {
dir := dirs[i] dir := dirs[i]
fmt.Println("Considering " + dir)
// Break out of the loop if a directory doesn't exist
_, err := os.Stat(dir)
if os.IsNotExist(err) {
break
}
// Construct path for a .molly file in this dir
mollyPath := filepath.Join(dir, ".molly") mollyPath := filepath.Join(dir, ".molly")
_, err := os.Stat(mollyPath) _, err = os.Stat(mollyPath)
if err != nil { if err != nil {
continue continue
} }
// If the file exists and we can read it, try to parse it
_, err = toml.DecodeFile(mollyPath, &mollyFile) _, err = toml.DecodeFile(mollyPath, &mollyFile)
if err != nil { if err != nil {
errorLogEntries <- "Error parsing .molly file " + mollyPath + ": " + err.Error() errorLogEntries <- "Error parsing .molly file " + mollyPath + ": " + err.Error()