Commit: a4d6c2d1ceb019f93d3c6fabf34c81e61cfbba9d Author: Vi Grey Date: 2023-07-09 01:47 UTC Summary: Add index file support CHANGELOG.md | 6 ++++++ src/bergelmir.go | 2 +- src/gemini.go | 36 ++++++++++++++++-------------------- src/gopher.go | 11 +++++------ src/http.go | 26 +++++++++++++------------- src/rss.go | 8 +++++--- 6 files changed, 46 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cf788c..d9558c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +## [0.0.21] - 2023-07-08 + +### Added + +- index file support + ## [0.0.20] - 2023-07-03 ### Fixed diff --git a/src/bergelmir.go b/src/bergelmir.go index 161c497..468a8c4 100644 --- a/src/bergelmir.go +++ b/src/bergelmir.go @@ -13,7 +13,7 @@ var ( ) const ( - VERSION = "0.0.20" + VERSION = "0.0.21" ) func init() { diff --git a/src/gemini.go b/src/gemini.go index 3909520..f74a8c5 100644 --- a/src/gemini.go +++ b/src/gemini.go @@ -141,20 +141,9 @@ func handleGeminiRequest(conn net.Conn, addr string, clientCertFingerprint []byt // Handle Gemini request func handleGeminiResponseBody(conn net.Conn, urlPath, host string) { - if len(urlPath) > 0 { - if urlPath[len(urlPath)-1] == '/' { - urlPath = urlPath[:len(urlPath)-1] - } - } urlExtension := filepath.Ext(urlPath) - if urlExtension == ".gmi" || urlExtension == ".gemini" { - urlPath = urlPath[:len(urlPath)-len(urlExtension)] - urlExtension = "" - } - if urlPath == "" { - urlPath = "/index" - } - geminiDataPath := safeJoinPath(configData.Gemini.DataPath, urlPath) + gmiFilePath, _ := gemtextFileExists(urlPath) + geminiDataPath := safeJoinPath(configData.Gemini.DataPath, gmiFilePath) if !isRSSFeed(urlPath) { mimeType := "text/gemini" content, exists := getGemtextContent(geminiDataPath) @@ -194,11 +183,19 @@ func handleGeminiServeFile(conn net.Conn, path string) { sendGeminiResponseBody(conn, f) } -func gemtextFileExists(resourcePath string) (exists bool) { +func gemtextFileExists(resourcePath string) (resourceExtensionPath string, exists bool) { geminiExtensions := []string{".gmi", ".gemini", ".GMI", ".GEMINI"} + // Check for resourcePath.(gmi/gemini/GMI/GEMINI) for _, extension := range geminiExtensions { if _, err := os.Stat(safeJoinPath(configData.Gemini.DataPath, resourcePath+extension)); err == nil { - return true + return resourcePath + extension, true + } + } + // Check for resourcePath/index.(gmi/gemini/GMI/GEMINI) + resourcePathIndex := safeJoinPath(resourcePath, "index") + for _, extension := range geminiExtensions { + if _, err := os.Stat(safeJoinPath(configData.Gemini.DataPath, resourcePathIndex+extension)); err == nil { + return resourcePathIndex + extension, true } } return @@ -206,11 +203,10 @@ func gemtextFileExists(resourcePath string) (exists bool) { // Get Gemtext content from .gmi or .gemini func getGemtextContent(path string) (content []byte, exists bool) { - geminiExtensions := []string{".gmi", ".gemini", ".GMI", ".GEMINI"} - for _, extension := range geminiExtensions { - if content, err := os.ReadFile(path + extension); err == nil { - return content, true - } + var err error + content, err = os.ReadFile(path) + if err == nil { + exists = true } return } diff --git a/src/gopher.go b/src/gopher.go index c4746f0..a767c3e 100644 --- a/src/gopher.go +++ b/src/gopher.go @@ -48,10 +48,8 @@ func handleGopherConnection(conn net.Conn, tor bool) { reqPath = strings.ReplaceAll(reqPath, "\r", "") reqPath = strings.ReplaceAll(reqPath, "\n", "") reqPath = path.Clean(reqPath) - if reqPath == "/" || reqPath == "" || reqPath == "." { - reqPath = "/index" - } - geminiDataPath := safeJoinPath(configData.Gemini.DataPath, reqPath) + gmiFilePath, gmiFileExists := gemtextFileExists(reqPath) + geminiDataPath := safeJoinPath(configData.Gemini.DataPath, gmiFilePath) gopherHostname := "localhost" gopherPort := strconv.Itoa(configData.Gopher.Port) if tor { @@ -67,7 +65,8 @@ func handleGopherConnection(conn net.Conn, tor bool) { } gopherContentError := []byte("3The selected resource does not exist\t" + "\t" + gopherHostname + "\t" + gopherPort + "\r\n.\r\n") - if (!gemtextFileExists(reqPath) && filepath.Ext(reqPath) != "") || isRSSFeed(reqPath) { + + if (!gmiFileExists && filepath.Ext(reqPath) != "") || isRSSFeed(reqPath) { // file is not a gemtext file if isRSSFeed(reqPath) { // RSS feed @@ -235,7 +234,7 @@ func translateGemtextToGopher(gmi, gopherHostname, gopherPort, gmiDirPath string } } // Determine if file exists in gemini data path first - gmiFileExists := gemtextFileExists(g.path) + _, gmiFileExists := gemtextFileExists(g.path) if !gmiFileExists { switch { case strings.Contains(mimeType, "text/plain"): diff --git a/src/http.go b/src/http.go index 025741f..1a766a0 100644 --- a/src/http.go +++ b/src/http.go @@ -29,40 +29,40 @@ var ( // returns false func textSubdomain(host string) bool { host = strings.ToLower(strings.TrimSpace(host)) - return (len(strings.Split(host, ".")) > 2 && - (strings.Index(host, "text.") == 0 || strings.Index(host, "www.text.") == 0)) + return (strings.Index(host, "text.") == 0 || strings.Index(host, "www.text.") == 0) } func htmlFileExists(resourcePath string) (resourceExtensionPath string, exists bool) { htmlExtensions := []string{".html", ".htm", ".HTML", ".HTM"} + // Check for resourcePath.(html/htm/HTML/HTM) for _, extension := range htmlExtensions { if _, err := os.Stat(safeJoinPath(configData.HTTP.DataPath, resourcePath+extension)); err == nil { return resourcePath + extension, true } } + // Check for resourcePath/index.(html/htm/HTML/HTM) + resourcePathIndex := safeJoinPath(resourcePath, "index") + for _, extension := range htmlExtensions { + if _, err := os.Stat(safeJoinPath(configData.HTTP.DataPath, resourcePathIndex+extension)); err == nil { + return resourcePathIndex + extension, true + } + } return } func catchAll(w http.ResponseWriter, r *http.Request) { u := r.URL.Path - if len(u) > 0 { - if u[len(u)-1] == '/' { - u = u[:len(u)-1] - } - } urlExtension := filepath.Ext(u) - if u == "" { - u = "/index" - } urlIsRSSFeed := isRSSFeed(u) if !urlIsRSSFeed { - htmlFilePath, htmlFileExists := htmlFileExists(u) - if htmlFileExists { + htmlFilePath, htmlFExists := htmlFileExists(u) + if htmlFExists { handleHTTPFile(w, r, htmlFilePath) return } // HTML file doesn't exist - gemtextFilePath := safeJoinPath(configData.Gemini.DataPath, u) + gmiFilePath, _ := gemtextFileExists(u) + gemtextFilePath := safeJoinPath(configData.Gemini.DataPath, gmiFilePath) textOnly := configData.HTTP.TextOnly && textSubdomain(r.Host) content, pageTitle, exists := geminiToHTMLFileContent(gemtextFilePath, textOnly) if exists { diff --git a/src/rss.go b/src/rss.go index f3b7071..d3af769 100644 --- a/src/rss.go +++ b/src/rss.go @@ -28,8 +28,8 @@ func isRSSFeed(u string) bool { } func createRSSFeed(host string) *bytes.Buffer { - rssGeminiDataPath := safeJoinPath(configData.Gemini.DataPath, - configData.RSS.FeedSourceGeminiPath) + gmiFilePath, _ := gemtextFileExists(configData.RSS.FeedSourceGeminiPath) + rssGeminiDataPath := safeJoinPath(configData.Gemini.DataPath, gmiFilePath) gmiContent, exists := getGemtextContent(rssGeminiDataPath) if exists { return translateGemtextToRSS(string(gmiContent), host) @@ -99,7 +99,9 @@ func translateGemtextToRSS(gmi, host string) *bytes.Buffer { if i >= maxEntries && maxEntries > 0 { break } - gmiContent, exists := getGemtextContent(safeJoinPath(configData.Gemini.DataPath, entry.path)) + gmiFilePath, _ := gemtextFileExists(entry.path) + rssGeminiDataPath := safeJoinPath(configData.Gemini.DataPath, gmiFilePath) + gmiContent, exists := getGemtextContent(rssGeminiDataPath) if exists { feedPubDate, _ := time.Parse(time.RFC3339, entry.pubDate) pubDate := feedPubDate.Format(time.RFC1123Z) gemini://vigrey.com/git/bergelmir/commit/a4d6c2d1ceb019f93d3c6fabf34c81e61cfbba9d.txt

-- Leo's gemini proxy

-- Connecting to vigrey.com:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/plain; charset=UTF-8

-- Response ended

-- Page fetched on Sat Jun 1 22:57:54 2024