1
0
mirror of https://github.com/makew0rld/amfora.git synced 2024-06-19 19:25:24 +00:00

Response size and time limit - fixes #30

This commit is contained in:
makeworld 2020-07-10 15:33:39 -04:00
parent eae118faac
commit 7fe78f4d6b
8 changed files with 59 additions and 11 deletions

View File

@ -3,7 +3,6 @@
## Issues
- URL for each tab should not be stored as a string - in the current code there's lots of reparsing the URL
- Can't go back or do other things while page is loading - need a way to stop `handleURL`
- dlChoiceModal doesn't go away when portal is selected, and freezes on Cancel
## Upstream Bugs
- Wrapping messes up on brackets

View File

@ -149,6 +149,8 @@ func Init() error {
viper.SetDefault("a-general.left_margin", 0.15)
viper.SetDefault("a-general.max_width", 100)
viper.SetDefault("a-general.downloads", "")
viper.SetDefault("a-general.page_max_size", 2097152)
viper.SetDefault("a-general.page_max_time", 10)
viper.SetDefault("cache.max_size", 0)
viper.SetDefault("cache.max_pages", 20)

View File

@ -1,6 +1,5 @@
package config
//go:generate ./default.sh
var defaultConf = []byte(`# This is the default config file.
# It also shows all the default values, if you don't create the file.
@ -29,6 +28,11 @@ max_width = 100 # The max number of columns to wrap a page's text to. Preformat
# 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 = ""
# Max size for displayable content in bytes - after that size a download window pops up
page_max_size = 2097152 # 2 MiB
# Max time it takes to load a page in seconds - after that a download window pops up
page_max_time = 10
# Options for page cache - which is only for text/gemini pages
# Increase the cache size to speed up browsing at the expense of memory
[cache]

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
head -n 3 default.go | tee default.go > /dev/null
head -n 1 default.go | tee default.go > /dev/null
echo -n 'var defaultConf = []byte(`' >> default.go
cat ../default-config.toml >> default.go
echo '`)' >> default.go

View File

@ -26,6 +26,11 @@ max_width = 100 # The max number of columns to wrap a page's text to. Preformat
# 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 = ""
# Max size for displayable content in bytes - after that size a download window pops up
page_max_size = 2097152 # 2 MiB
# Max time it takes to load a page in seconds - after that a download window pops up
page_max_time = 10
# Options for page cache - which is only for text/gemini pages
# Increase the cache size to speed up browsing at the expense of memory
[cache]

View File

@ -24,7 +24,6 @@ import (
// For choosing between download and the portal - copy of YesNo basically
var dlChoiceModal = cview.NewModal().
SetTextColor(tcell.ColorWhite).
SetText("That file could not be displayed. What would you like to do?").
AddButtons([]string{"Download", "Open in portal", "Cancel"})
// Channel to indicate what choice they made using the button text
@ -72,7 +71,7 @@ func dlInit() {
// dlChoice displays the download choice modal and acts on the user's choice.
// It should run in a goroutine.
func dlChoice(u string, resp *gemini.Response) {
func dlChoice(text, u string, resp *gemini.Response) {
defer resp.Body.Close()
parsed, err := url.Parse(u)
@ -81,6 +80,7 @@ func dlChoice(u string, resp *gemini.Response) {
return
}
dlChoiceModal.SetText(text)
tabPages.ShowPage("dlChoice")
tabPages.SendToFront("dlChoice")
App.SetFocus(dlChoiceModal)

View File

@ -309,11 +309,27 @@ func handleURL(t *tab, u string) (string, bool) {
return ret("", false)
}
page.Width = termW
// Make new request for downloading purposes
res, clientErr := client.Fetch(u)
if clientErr != nil && clientErr != client.ErrTofu {
Error("URL Fetch Error", err.Error())
return ret("", false)
}
if err == renderer.ErrTooLarge {
go dlChoice("That page is too large. What would you like to do?", u, res)
return ret("", false)
}
if err == renderer.ErrTimedOut {
go dlChoice("Loading that page timed out. What would you like to do?", u, res)
return ret("", false)
}
if err != nil {
Error("Page Error", "Issuing creating page: "+err.Error())
return ret("", false)
}
page.Width = termW
go cache.Add(page)
setPage(t, page)
return ret(u, true)
@ -359,7 +375,7 @@ func handleURL(t *tab, u string) (string, bool) {
return ret("", false)
}
// Status code 20, but not a document that can be displayed
go dlChoice(u, res)
go dlChoice("That file could not be displayed. What would you like to do?", u, res)
return ret("", false)
}

View File

@ -1,16 +1,22 @@
package renderer
import (
"bytes"
"errors"
"io/ioutil"
"io"
"mime"
"strings"
"time"
"github.com/makeworld-the-better-one/amfora/structs"
"github.com/makeworld-the-better-one/go-gemini"
"github.com/spf13/viper"
"golang.org/x/text/encoding/ianaindex"
)
var ErrTooLarge = errors.New("page content would be too large")
var ErrTimedOut = errors.New("page download timed out")
// isUTF8 returns true for charsets that are compatible with UTF-8 and don't need to be decoded.
func isUTF8(charset string) bool {
utfCharsets := []string{"", "utf-8", "us-ascii"}
@ -53,11 +59,27 @@ func MakePage(url string, res *gemini.Response, width, leftMargin int) (*structs
return nil, errors.New("not valid content for a Page")
}
rawText, err := ioutil.ReadAll(res.Body) // TODO: Don't use all memory on large pages
if err != nil {
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")) // 2 MiB max
res.Body.Close()
rawText := buf.Bytes()
if err == nil {
// Content was larger than 2 MiB
return nil, ErrTooLarge
} else if err != io.EOF {
if strings.HasSuffix(err.Error(), "use of closed network connection") {
// Timed out
return nil, ErrTimedOut
}
// Some other error
return nil, err
}
res.Body.Close()
// Otherwise, the error is EOF, which is what we want.
mediatype, params, _ := mime.ParseMediaType(res.Meta)