mirror of
https://github.com/makew0rld/amfora.git
synced 2024-12-04 14:46:29 -05:00
⬆️ go-gemini v0.9.3
Timeout when header takes too long, downloading uses proxies if appropriate
This commit is contained in:
parent
8cc240bb4e
commit
c53c36a4d0
@ -9,11 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Opening local files with `file://` URIs (#103, #117)
|
- Opening local files with `file://` URIs (#103, #117)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Updated [go-gemini](https://github.com/makeworld-the-better-one/go-gemini) to v0.9.1 to support CN-only wildcard certs
|
- 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
|
- Preformatted text is now light yellow by default
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Single quotes are used in the default config for commands and paths so that Windows paths with backslashes will be parsed correctly
|
- 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
|
## [1.6.0] - 2020-11-04
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/makeworld-the-better-one/amfora/client"
|
||||||
"github.com/makeworld-the-better-one/amfora/config"
|
"github.com/makeworld-the-better-one/amfora/config"
|
||||||
"github.com/makeworld-the-better-one/amfora/display"
|
"github.com/makeworld-the-better-one/amfora/display"
|
||||||
)
|
)
|
||||||
@ -43,6 +44,8 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client.Init()
|
||||||
|
|
||||||
display.Init()
|
display.Init()
|
||||||
display.NewTab()
|
display.NewTab()
|
||||||
display.NewTab() // Open extra tab and close it to fully initialize the app and wrapping
|
display.NewTab() // Open extra tab and close it to fully initialize the app and wrapping
|
||||||
|
@ -5,13 +5,29 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/makeworld-the-better-one/go-gemini"
|
"github.com/makeworld-the-better-one/go-gemini"
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
var certCache = make(map[string][][]byte)
|
var (
|
||||||
|
certCache = make(map[string][][]byte)
|
||||||
|
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) {
|
func clientCert(host string) ([]byte, []byte) {
|
||||||
if cert := certCache[host]; cert != nil {
|
if cert := certCache[host]; cert != nil {
|
||||||
@ -53,18 +69,16 @@ func HasClientCert(host string) bool {
|
|||||||
return cert != nil
|
return cert != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch returns response data and an error.
|
func fetch(u string, c *gemini.Client) (*gemini.Response, error) {
|
||||||
// The error text is human friendly and should be displayed.
|
|
||||||
func Fetch(u string) (*gemini.Response, error) {
|
|
||||||
parsed, _ := url.Parse(u)
|
parsed, _ := url.Parse(u)
|
||||||
cert, key := clientCert(parsed.Host)
|
cert, key := clientCert(parsed.Host)
|
||||||
|
|
||||||
var res *gemini.Response
|
var res *gemini.Response
|
||||||
var err error
|
var err error
|
||||||
if cert != nil {
|
if cert != nil {
|
||||||
res, err = gemini.FetchWithCert(u, cert, key)
|
res, err = c.FetchWithCert(u, cert, key)
|
||||||
} else {
|
} else {
|
||||||
res, err = gemini.Fetch(u)
|
res, err = c.Fetch(u)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -78,17 +92,27 @@ func Fetch(u string) (*gemini.Response, error) {
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchWithProxy is the same as Fetch, but uses a proxy.
|
// Fetch returns response data and an error.
|
||||||
func FetchWithProxy(proxyHostname, proxyPort, u string) (*gemini.Response, 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)
|
parsed, _ := url.Parse(u)
|
||||||
cert, key := clientCert(parsed.Host)
|
cert, key := clientCert(parsed.Host)
|
||||||
|
|
||||||
var res *gemini.Response
|
var res *gemini.Response
|
||||||
var err error
|
var err error
|
||||||
if cert != nil {
|
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 {
|
} else {
|
||||||
res, err = gemini.FetchWithHost(net.JoinHostPort(proxyHostname, proxyPort), u)
|
res, err = c.FetchWithHost(net.JoinHostPort(proxyHostname, proxyPort), u)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -102,3 +126,13 @@ func FetchWithProxy(proxyHostname, proxyPort, u string) (*gemini.Response, error
|
|||||||
|
|
||||||
return res, nil
|
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)
|
||||||
|
}
|
||||||
|
@ -452,24 +452,35 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) {
|
|||||||
return ret("", false)
|
return ret("", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var res2 *gemini.Response
|
||||||
|
var dlErr error
|
||||||
|
|
||||||
if errors.Is(err, renderer.ErrTooLarge) {
|
if errors.Is(err, renderer.ErrTooLarge) {
|
||||||
// Make new request for downloading purposes
|
// Make new request for downloading purposes
|
||||||
res, clientErr := client.Fetch(u)
|
if usingProxy {
|
||||||
if clientErr != nil && !errors.Is(clientErr, client.ErrTofu) {
|
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())
|
Error("URL Fetch Error", err.Error())
|
||||||
return ret("", false)
|
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)
|
return ret("", false)
|
||||||
}
|
}
|
||||||
if errors.Is(err, renderer.ErrTimedOut) {
|
if errors.Is(err, renderer.ErrTimedOut) {
|
||||||
// Make new request for downloading purposes
|
// Make new request for downloading purposes
|
||||||
res, clientErr := client.Fetch(u)
|
if usingProxy {
|
||||||
if clientErr != nil && !errors.Is(clientErr, client.ErrTofu) {
|
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())
|
Error("URL Fetch Error", err.Error())
|
||||||
return ret("", false)
|
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)
|
return ret("", false)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ require (
|
|||||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
github.com/gdamore/tcell v1.3.1-0.20200608133353-cb1e5d6fa606
|
github.com/gdamore/tcell v1.3.1-0.20200608133353-cb1e5d6fa606
|
||||||
github.com/google/go-cmp v0.5.0 // indirect
|
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/go-isemoji v1.1.0
|
||||||
github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f
|
github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
|
4
go.sum
4
go.sum
@ -125,8 +125,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/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 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
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.3 h1:vpJc1u4LYpEI5h7GcOE2zSfOmpE9gQzt0vEayp/ilWc=
|
||||||
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/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 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/go-isemoji v1.1.0/go.mod h1:FBjkPl9rr0G4vlZCc+Mr+QcnOfGCTbGWYW8/1sp06I0=
|
||||||
github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f h1:YEUlTs5gb35UlBLTgqrub9axWTYB3d7/8TxrkJDZpRI=
|
github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f h1:YEUlTs5gb35UlBLTgqrub9axWTYB3d7/8TxrkJDZpRI=
|
||||||
|
@ -5,8 +5,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/makeworld-the-better-one/amfora/structs"
|
"github.com/makeworld-the-better-one/amfora/structs"
|
||||||
"github.com/makeworld-the-better-one/go-gemini"
|
"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)
|
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)
|
_, err := io.CopyN(buf, res.Body, viper.GetInt64("a-general.page_max_size")+1)
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Content was larger than max size
|
// Content was larger than max size
|
||||||
return nil, ErrTooLarge
|
return nil, ErrTooLarge
|
||||||
} else if err != io.EOF {
|
} else if err != io.EOF {
|
||||||
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
if errors.Is(err, os.ErrDeadlineExceeded) {
|
||||||
// Timed out
|
// Timed out
|
||||||
return nil, ErrTimedOut
|
return nil, ErrTimedOut
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user