diff --git a/CHANGELOG.md b/CHANGELOG.md index 4547b95..9a607f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Opening local files with `file://` URIs (#103, #117) + ### Changed -- Updated [go-gemini](https://github.com/makeworld-the-better-one/go-gemini) to v0.9.1 to support CN-only wildcard certs -- Preformatted text is now grey by default +- Updated [go-gemini](https://github.com/makeworld-the-better-one/go-gemini) to v0.9.3 + - Supports CN-only wildcard certs + - Time out when header takes too long +- Preformatted text is now light yellow by default + +### Fixed +- Single quotes are used in the default config for commands and paths so that Windows paths with backslashes will be parsed correctly +- Downloading now uses proxies when appropriate ## [1.6.0] - 2020-11-04 diff --git a/NOTES.md b/NOTES.md index bd6951a..0ed9778 100644 --- a/NOTES.md +++ b/NOTES.md @@ -1,8 +1,6 @@ # Notes ## Feeds (temp) -- Support multiple links in Atom feeds - - Display gemini one if it exist, then HTTP(S), then whatever is first - TODO: remove all logger lines ## Issues diff --git a/README.md b/README.md index faeac87..667e750 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ Features in *italics* are in the master branch, but not in the latest release. - [x] Bookmarks - [x] Download pages and arbitrary data - [x] Theming + - Check out the [user contributed themes](https://github.com/makeworld-the-better-one/amfora/tree/master/contrib/themes)! - [x] Emoji favicons - See `gemini://mozz.us/files/rfc_gemini_favicon.gmi` for details - Disabled by default, enable in config diff --git a/THANKS.md b/THANKS.md index 0e093f4..e5ba5b9 100644 --- a/THANKS.md +++ b/THANKS.md @@ -10,4 +10,5 @@ Thank you to the following contributors, who have helped make Amfora great. FOSS - Timur Ismagilov (@bouncepaw) - Matt Caroll (@ohiolab) - Patryk Niedźwiedziński (@pniedzwiedzinski) -- Trevor Slocum (@tsclocum) \ No newline at end of file +- Trevor Slocum (@tsclocum) +- Mattias Jadelius (@jedthehumanoid) diff --git a/amfora.go b/amfora.go index d99a94a..25d9365 100644 --- a/amfora.go +++ b/amfora.go @@ -4,6 +4,7 @@ import ( "fmt" "os" + "github.com/makeworld-the-better-one/amfora/client" "github.com/makeworld-the-better-one/amfora/config" "github.com/makeworld-the-better-one/amfora/display" "github.com/makeworld-the-better-one/amfora/feeds" @@ -50,6 +51,8 @@ func main() { os.Exit(1) } + client.Init() + display.Init() display.NewTab() display.NewTab() // Open extra tab and close it to fully initialize the app and wrapping diff --git a/client/client.go b/client/client.go index 5f45f90..42e9777 100644 --- a/client/client.go +++ b/client/client.go @@ -6,14 +6,31 @@ import ( "net" "net/url" "sync" + "time" "github.com/makeworld-the-better-one/go-gemini" "github.com/mitchellh/go-homedir" "github.com/spf13/viper" ) -var certCache = make(map[string][][]byte) -var certCacheMu = &sync.RWMutex{} +var ( + certCache = make(map[string][][]byte) + certCacheMu = &sync.RWMutex{} + + fetchClient *gemini.Client + dlClient *gemini.Client // For downloading +) + +func Init() { + fetchClient = &gemini.Client{ + ConnectTimeout: 10 * time.Second, // Default is 15 + ReadTimeout: time.Duration(viper.GetInt("a-general.page_max_time")) * time.Second, + } + dlClient = &gemini.Client{ + ConnectTimeout: 10 * time.Second, // Default is 15 + // No read timeout, download can take as long as it needs + } +} func clientCert(host string) ([]byte, []byte) { certCacheMu.RLock() @@ -66,18 +83,16 @@ func HasClientCert(host string) bool { return cert != nil } -// Fetch returns response data and an error. -// The error text is human friendly and should be displayed. -func Fetch(u string) (*gemini.Response, error) { +func fetch(u string, c *gemini.Client) (*gemini.Response, error) { parsed, _ := url.Parse(u) cert, key := clientCert(parsed.Host) var res *gemini.Response var err error if cert != nil { - res, err = gemini.FetchWithCert(u, cert, key) + res, err = c.FetchWithCert(u, cert, key) } else { - res, err = gemini.Fetch(u) + res, err = c.Fetch(u) } if err != nil { return nil, err @@ -91,17 +106,27 @@ func Fetch(u string) (*gemini.Response, error) { return res, err } -// FetchWithProxy is the same as Fetch, but uses a proxy. -func FetchWithProxy(proxyHostname, proxyPort, u string) (*gemini.Response, error) { +// Fetch returns response data and an error. +// The error text is human friendly and should be displayed. +func Fetch(u string) (*gemini.Response, error) { + return fetch(u, fetchClient) +} + +// Download is the same as Fetch but with no read timeout. +func Download(u string) (*gemini.Response, error) { + return fetch(u, dlClient) +} + +func fetchWithProxy(proxyHostname, proxyPort, u string, c *gemini.Client) (*gemini.Response, error) { parsed, _ := url.Parse(u) cert, key := clientCert(parsed.Host) var res *gemini.Response var err error if cert != nil { - res, err = gemini.FetchWithHostAndCert(net.JoinHostPort(proxyHostname, proxyPort), u, cert, key) + res, err = c.FetchWithHostAndCert(net.JoinHostPort(proxyHostname, proxyPort), u, cert, key) } else { - res, err = gemini.FetchWithHost(net.JoinHostPort(proxyHostname, proxyPort), u) + res, err = c.FetchWithHost(net.JoinHostPort(proxyHostname, proxyPort), u) } if err != nil { return nil, err @@ -115,3 +140,13 @@ func FetchWithProxy(proxyHostname, proxyPort, u string) (*gemini.Response, error return res, nil } + +// FetchWithProxy is the same as Fetch, but uses a proxy. +func FetchWithProxy(proxyHostname, proxyPort, u string) (*gemini.Response, error) { + return fetchWithProxy(proxyHostname, proxyPort, u, fetchClient) +} + +// DownloadWithProxy is the same as FetchWithProxy but with no read timeout. +func DownloadWithProxy(proxyHostname, proxyPort, u string) (*gemini.Response, error) { + return fetchWithProxy(proxyHostname, proxyPort, u, dlClient) +} diff --git a/config/default.go b/config/default.go index ea8e65f..b3dca36 100644 --- a/config/default.go +++ b/config/default.go @@ -28,14 +28,15 @@ auto_redirect = false # # The best to define a command is using a string array. # Examples: -# http = ["firefox"] -# http = ["custom-browser", "--flag", "--option=2"] -# http = ["/path/with spaces/in it/firefox"] +# http = ['firefox'] +# http = ['custom-browser', '--flag', '--option=2'] +# http = ['/path/with spaces/in it/firefox'] # -# Using just a string will also work, but it is deprecated, -# and will degrade if you use paths with spaces. +# Note the use of single quotes, so that backslashes will not be escaped. +# Using just a string will also work, but it is deprecated, and will degrade if +# you use paths with spaces. -http = "default" +http = 'default' # Any URL that will accept a query string can be put here search = "gemini://gus.guru/search" @@ -58,7 +59,8 @@ max_width = 100 # 'downloads' is the path to a downloads folder. # An empty value means the code will find the default downloads folder for your system. # If the path does not exist it will be created. -downloads = "" +# Note the use of single quotes, so that backslashes will not be escaped. +downloads = '' # Max size for displayable content in bytes - after that size a download window pops up page_max_size = 2097152 # 2 MiB @@ -71,16 +73,17 @@ emoji_favicons = false [auth] # Authentication settings +# Note the use of single quotes for values, so that backslashes will not be escaped. [auth.certs] # Client certificates # Set domain name equal to path to client cert -# "example.com" = "mycert.crt" +# "example.com" = 'mycert.crt' [auth.keys] # Client certificate keys # Set domain name equal to path to key for the client cert above -# "example.com" = "mycert.key" +# "example.com" = 'mycert.key' [keybindings] @@ -94,18 +97,19 @@ shift_numbers = "!@#$%^&*()" [url-handlers] # Allows setting the commands to run for various URL schemes. # E.g. to open FTP URLs with FileZilla set the following key: -# ftp = "filezilla" +# ftp = 'filezilla' # You can set any scheme to "off" or "" to disable handling it, or # just leave the key unset. # # DO NOT use this for setting the HTTP command. # Use the http setting in the "a-general" section above. # -# NOTE: These settings are override by the ones in the proxies section. +# NOTE: These settings are overrided by the ones in the proxies section. +# Note the use of single quotes, so that backslashes will not be escaped. # This is a special key that defines the handler for all URL schemes for which # no handler is defined. -other = "off" +other = 'off' [cache] diff --git a/config/theme.go b/config/theme.go index 8a34655..71f42dc 100644 --- a/config/theme.go +++ b/config/theme.go @@ -60,7 +60,7 @@ var theme = map[string]tcell.Color{ "link_number": tcell.ColorSilver, "regular_text": tcell.ColorWhite, "quote_text": tcell.ColorWhite, - "preformatted_text": tcell.ColorGrey, + "preformatted_text": tcell.Color229, // xterm:Wheat1, #ffffaf "list_text": tcell.ColorWhite, } diff --git a/contrib/themes/README.md b/contrib/themes/README.md new file mode 100644 index 0000000..ad0d10d --- /dev/null +++ b/contrib/themes/README.md @@ -0,0 +1,26 @@ +# User Contributed Themes + +You can use these themes by replacing the `[theme]` section of your config with their contents. Some themes won't display properly on terminals that do not have truecolor support. + +## Nord + +Contributed by **[@lokesh-krishna](https://github.com/lokesh-krishna)**. + +![screenshot of the nord theme](https://user-images.githubusercontent.com/20235646/99020443-a93a1980-2584-11eb-8028-0b95cfcf0fc6.png) + +## Dracula + +Contributed by **[@crdpa](https://github.com/crdpa)**. + +![screenshot of dracula theme](https://user-images.githubusercontent.com/61637474/99983229-5b928d80-2d8a-11eb-8e5c-e5681bb274c5.png) + +
+More screenshots + +![screenshot of dracula theme](https://user-images.githubusercontent.com/61637474/99983237-5e8d7e00-2d8a-11eb-8e22-3a3459ae560a.png) +![screenshot of dracula theme](https://user-images.githubusercontent.com/61637474/99983210-53d2e900-2d8a-11eb-9ab7-12dc10c2933a.png) +
+ +## Yours? + +Contribute your own theme by opening a PR. diff --git a/contrib/themes/dracula.toml b/contrib/themes/dracula.toml new file mode 100644 index 0000000..3be9b62 --- /dev/null +++ b/contrib/themes/dracula.toml @@ -0,0 +1,103 @@ +[theme] +# This section is for changing the COLORS used in Amfora. +# These colors only apply if 'color' is enabled above. +# Colors can be set using a W3C color name, or a hex value such as "#ffffff". + +# Note that not all colors will work on terminals that do not have truecolor support. +# If you want to stick to the standard 16 or 256 colors, you can get +# a list of those here: https://jonasjacek.github.io/colors/ +# DO NOT use the names from that site, just the hex codes. + +# Definitions: +# bg = background +# fg = foreground +# dl = download +# btn = button +# hdg = heading +# bkmk = bookmark +# modal = a popup window/box in the middle of the screen + +# EXAMPLES: +# hdg_1 = "green" +# hdg_2 = "#5f0000" + +# Available keys to set: + +# bg: background for pages, tab row, app in general +# tab_num: The number/highlight of the tabs at the top +# tab_divider: The color of the divider character between tab numbers: | +# bottombar_label: The color of the prompt that appears when you press space +# bottombar_text: The color of the text you type +# bottombar_bg + +bg = "#282a36" +fg = "#f8f8f2" +tab_num = "#50fa7b" +tab_divider = "#f8f8f2" +bottombar_bg = "#282a36" +bottombar_text = "#f8f8f2" +bottombar_label = "#9aedfe" + +# hdg_1 +# hdg_2 +# hdg_3 +# amfora_link: A link that Amfora supports viewing. For now this is only gemini:// +# foreign_link: HTTP(S), Gopher, etc +# link_number: The silver number that appears to the left of a link +# regular_text: Normal gemini text, and plaintext documents +# quote_text +# preformatted_text +# list_text + +hdg_1 = "#5af78e" +hdg_2 = "#9aedfe" +hdg_3 = "#caa9fa" +amfora_link = "#f4f99d" +foreign_link = "#d4d989" +link_number = "#ff5555" +regular_text = "#f8f8f2" +quote_text = "#E6E6E6" +preformatted_text = "#f8f8f2" +list_text = "#f8f8f2" + +# btn_bg: The bg color for all modal buttons +# btn_text: The text color for all modal buttons + +btn_bg = "#bfbfbf" +btn_text = "#4d4d4d" + +dl_choice_modal_bg = "#282a36" +dl_choice_modal_text = "#f8f8f2" +dl_modal_bg = "#282a36" +dl_modal_text = "#f8f8f2" +info_modal_bg = "#282a36" +info_modal_text = "#f8f8f2" +error_modal_bg = "#282a36" +error_modal_text = "#ff5555" +yesno_modal_bg = "#282a36" +yesno_modal_text = "#f1fa8c" +tofu_modal_bg = "#282a36" +tofu_modal_text = "#f8f8f2" + +# input_modal_bg +# input_modal_text +# input_modal_field_bg: The bg of the input field, where you type the text +# input_modal_field_text: The color of the text you type + +input_modal_bg = "#282a36" +input_modal_text = "#f8f8f2" +input_modal_field_bg = "#4d4d4d" +input_modal_field_text ="#f8f8f2" + +# bkmk_modal_bg +# bkmk_modal_text +# bkmk_modal_label +# bkmk_modal_field_bg +# bkmk_modal_field_text + +bkmk_modal_bg = "#282a36" +bkmk_modal_text = "#f8f8f2" +bkmk_modal_label = "#f8f8f2" +bkmk_modal_field_bg = "#000000" +bkmk_modal_field_text = "#f8f8f2" + diff --git a/default-config.toml b/default-config.toml index 0365613..09a4c61 100644 --- a/default-config.toml +++ b/default-config.toml @@ -25,14 +25,15 @@ auto_redirect = false # # The best to define a command is using a string array. # Examples: -# http = ["firefox"] -# http = ["custom-browser", "--flag", "--option=2"] -# http = ["/path/with spaces/in it/firefox"] +# http = ['firefox'] +# http = ['custom-browser', '--flag', '--option=2'] +# http = ['/path/with spaces/in it/firefox'] # -# Using just a string will also work, but it is deprecated, -# and will degrade if you use paths with spaces. +# Note the use of single quotes, so that backslashes will not be escaped. +# Using just a string will also work, but it is deprecated, and will degrade if +# you use paths with spaces. -http = "default" +http = 'default' # Any URL that will accept a query string can be put here search = "gemini://gus.guru/search" @@ -55,7 +56,8 @@ max_width = 100 # 'downloads' is the path to a downloads folder. # An empty value means the code will find the default downloads folder for your system. # If the path does not exist it will be created. -downloads = "" +# Note the use of single quotes, so that backslashes will not be escaped. +downloads = '' # Max size for displayable content in bytes - after that size a download window pops up page_max_size = 2097152 # 2 MiB @@ -68,16 +70,17 @@ emoji_favicons = false [auth] # Authentication settings +# Note the use of single quotes for values, so that backslashes will not be escaped. [auth.certs] # Client certificates # Set domain name equal to path to client cert -# "example.com" = "mycert.crt" +# "example.com" = 'mycert.crt' [auth.keys] # Client certificate keys # Set domain name equal to path to key for the client cert above -# "example.com" = "mycert.key" +# "example.com" = 'mycert.key' [keybindings] @@ -91,18 +94,19 @@ shift_numbers = "!@#$%^&*()" [url-handlers] # Allows setting the commands to run for various URL schemes. # E.g. to open FTP URLs with FileZilla set the following key: -# ftp = "filezilla" +# ftp = 'filezilla' # You can set any scheme to "off" or "" to disable handling it, or # just leave the key unset. # # DO NOT use this for setting the HTTP command. # Use the http setting in the "a-general" section above. # -# NOTE: These settings are override by the ones in the proxies section. +# NOTE: These settings are overrided by the ones in the proxies section. +# Note the use of single quotes, so that backslashes will not be escaped. # This is a special key that defines the handler for all URL schemes for which # no handler is defined. -other = "off" +other = 'off' [cache] diff --git a/display/file.go b/display/file.go new file mode 100644 index 0000000..51a660c --- /dev/null +++ b/display/file.go @@ -0,0 +1,116 @@ +package display + +import ( + "fmt" + "io/ioutil" + "mime" + "net/url" + "os" + "path/filepath" + "strings" + + "github.com/makeworld-the-better-one/amfora/renderer" + "github.com/makeworld-the-better-one/amfora/structs" + "github.com/spf13/viper" +) + +// handleFile handles urls using file:// protocol +func handleFile(u string) (*structs.Page, bool) { + page := &structs.Page{} + + uri, err := url.ParseRequestURI(u) + if err != nil { + Error("File Error", "Cannot parse URI: "+err.Error()) + return page, false + } + fi, err := os.Stat(uri.Path) + if err != nil { + Error("File Error", "Cannot open local file: "+err.Error()) + return page, false + } + + switch mode := fi.Mode(); { + case mode.IsDir(): + return createDirectoryListing(u) + case mode.IsRegular(): + if fi.Size() > viper.GetInt64("a-general.page_max_size") { + Error("File Error", "Cannot open local file, exceeds page max size") + return page, false + } + + mimetype := mime.TypeByExtension(filepath.Ext(uri.Path)) + if strings.HasSuffix(u, ".gmi") || strings.HasSuffix(u, ".gemini") { + mimetype = "text/gemini" + } + + if !strings.HasPrefix(mimetype, "text/") { + Error("File Error", "Cannot open file, not recognized as text.") + return page, false + } + + content, err := ioutil.ReadFile(uri.Path) + if err != nil { + Error("File Error", "Cannot open local file: "+err.Error()) + return page, false + } + + if mimetype == "text/gemini" { + rendered, links := renderer.RenderGemini(string(content), textWidth(), leftMargin(), false) + page = &structs.Page{ + Mediatype: structs.TextGemini, + URL: u, + Raw: string(content), + Content: rendered, + Links: links, + Width: termW, + } + } else { + page = &structs.Page{ + Mediatype: structs.TextPlain, + URL: u, + Raw: string(content), + Content: renderer.RenderPlainText(string(content), leftMargin()), + Links: []string{}, + Width: termW, + } + } + } + return page, true +} + +// createDirectoryListing creates a text/gemini page for a directory +// that lists all the files as links. +func createDirectoryListing(u string) (*structs.Page, bool) { + page := &structs.Page{} + + uri, err := url.ParseRequestURI(u) + if err != nil { + Error("Directory Error", "Cannot parse URI: "+err.Error()) + } + + files, err := ioutil.ReadDir(uri.Path) + if err != nil { + Error("Directory error", "Cannot open local directory: "+err.Error()) + return page, false + } + content := "Index of " + uri.Path + "\n" + content += "=> ../ ../\n" + for _, f := range files { + separator := "" + if f.IsDir() { + separator = "/" + } + content += fmt.Sprintf("=> %s%s %s%s\n", f.Name(), separator, f.Name(), separator) + } + + rendered, links := renderer.RenderGemini(content, textWidth(), leftMargin(), false) + page = &structs.Page{ + Mediatype: structs.TextGemini, + URL: u, + Raw: content, + Content: rendered, + Links: links, + Width: termW, + } + return page, true +} diff --git a/display/private.go b/display/private.go index 3ebe5f8..ba7d976 100644 --- a/display/private.go +++ b/display/private.go @@ -86,7 +86,9 @@ func reformatPage(p *structs.Page) { case structs.TextGemini: // Links are not recorded because they won't change proxied := true - if strings.HasPrefix(p.URL, "gemini") || strings.HasPrefix(p.URL, "about") { + if strings.HasPrefix(p.URL, "gemini") || + strings.HasPrefix(p.URL, "about") || + strings.HasPrefix(p.URL, "file") { proxied = false } rendered, _ = renderer.RenderGemini(p.Raw, textWidth(), leftMargin(), proxied) @@ -396,7 +398,16 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) { usingProxy = true } - if !strings.HasPrefix(u, "http") && !strings.HasPrefix(u, "gemini") { + if strings.HasPrefix(u, "file") { + page, ok := handleFile(u) + if !ok { + return ret("", false) + } + setPage(t, page) + return ret(u, true) + } + + if !strings.HasPrefix(u, "http") && !strings.HasPrefix(u, "gemini") && !strings.HasPrefix(u, "file") { // Not a Gemini URL if proxy == "" || proxy == "off" { // No proxy available @@ -467,24 +478,35 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) { return ret("", false) } + var res2 *gemini.Response + var dlErr error + if errors.Is(err, renderer.ErrTooLarge) { // Make new request for downloading purposes - res, clientErr := client.Fetch(u) - if clientErr != nil && !errors.Is(clientErr, client.ErrTofu) { + if usingProxy { + res2, dlErr = client.DownloadWithProxy(proxyHostname, proxyPort, u) + } else { + res2, dlErr = client.Download(u) + } + if dlErr != nil && !errors.Is(dlErr, client.ErrTofu) { Error("URL Fetch Error", err.Error()) return ret("", false) } - go dlChoice("That page is too large. What would you like to do?", u, res) + go dlChoice("That page is too large. What would you like to do?", u, res2) return ret("", false) } if errors.Is(err, renderer.ErrTimedOut) { // Make new request for downloading purposes - res, clientErr := client.Fetch(u) - if clientErr != nil && !errors.Is(clientErr, client.ErrTofu) { + if usingProxy { + res2, dlErr = client.DownloadWithProxy(proxyHostname, proxyPort, u) + } else { + res2, dlErr = client.Download(u) + } + if dlErr != nil && !errors.Is(dlErr, client.ErrTofu) { Error("URL Fetch Error", err.Error()) return ret("", false) } - go dlChoice("Loading that page timed out. What would you like to do?", u, res) + go dlChoice("Loading that page timed out. What would you like to do?", u, res2) return ret("", false) } if err != nil { diff --git a/go.mod b/go.mod index 796274e..70b1468 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/gdamore/tcell v1.3.1-0.20200608133353-cb1e5d6fa606 github.com/google/go-cmp v0.5.0 // indirect - github.com/makeworld-the-better-one/go-gemini v0.9.1 + github.com/makeworld-the-better-one/go-gemini v0.9.3 github.com/makeworld-the-better-one/go-isemoji v1.1.0 github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f github.com/mitchellh/go-homedir v1.1.0 diff --git a/go.sum b/go.sum index f26e776..8c7bee8 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tW github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/makeworld-the-better-one/go-gemini v0.9.1 h1:/Vc6Y4Y1aOi4lZIBA1wDe+4N2xAI8EQ0CIjip2NUQkk= -github.com/makeworld-the-better-one/go-gemini v0.9.1/go.mod h1:P7/FbZ+IEIbA/d+A0Y3w2GNgD8SA2AcNv7aDGJbaWG4= +github.com/makeworld-the-better-one/go-gemini v0.9.3 h1:vpJc1u4LYpEI5h7GcOE2zSfOmpE9gQzt0vEayp/ilWc= +github.com/makeworld-the-better-one/go-gemini v0.9.3/go.mod h1:P7/FbZ+IEIbA/d+A0Y3w2GNgD8SA2AcNv7aDGJbaWG4= github.com/makeworld-the-better-one/go-isemoji v1.1.0 h1:wZBHOKB5zAIgaU2vaWnXFDDhatebB8TySrNVxjVV84g= github.com/makeworld-the-better-one/go-isemoji v1.1.0/go.mod h1:FBjkPl9rr0G4vlZCc+Mr+QcnOfGCTbGWYW8/1sp06I0= github.com/makeworld-the-better-one/gofeed v1.1.1-0.20201123002655-c0c6354134fe h1:i3b9Qy5z23DcXRnrsMYcM5s9Ng5VIidM1xZd+szuTsY= diff --git a/renderer/page.go b/renderer/page.go index 1319d16..e0b728e 100644 --- a/renderer/page.go +++ b/renderer/page.go @@ -5,8 +5,8 @@ import ( "errors" "io" "mime" + "os" "strings" - "time" "github.com/makeworld-the-better-one/amfora/structs" "github.com/makeworld-the-better-one/go-gemini" @@ -63,18 +63,13 @@ func MakePage(url string, res *gemini.Response, width, leftMargin int, proxied b } buf := new(bytes.Buffer) - go func() { - time.Sleep(time.Duration(viper.GetInt("a-general.page_max_time")) * time.Second) - res.Body.Close() - }() - _, err := io.CopyN(buf, res.Body, viper.GetInt64("a-general.page_max_size")+1) res.Body.Close() if err == nil { // Content was larger than max size return nil, ErrTooLarge } else if err != io.EOF { - if strings.HasSuffix(err.Error(), "use of closed network connection") { + if errors.Is(err, os.ErrDeadlineExceeded) { // Timed out return nil, ErrTimedOut }