Skip to content

Commit

Permalink
✨ Support mutiple proxies per-scheme - fixes #80
Browse files Browse the repository at this point in the history
  • Loading branch information
makew0rld committed Sep 1, 2020
1 parent 30873e1 commit 1d3e309
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 30 deletions.
29 changes: 20 additions & 9 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,43 @@
package client

import (
"net"
"net/url"

"github.com/makeworld-the-better-one/amfora/config"
"github.com/makeworld-the-better-one/go-gemini"
"github.com/spf13/viper"
)

// Fetch returns response data and an error.
// The error text is human friendly and should be displayed.
func Fetch(u string) (*gemini.Response, error) {
var res *gemini.Response
var err error

if config.GemProxy == nil {
res, err = gemini.Fetch(u)
} else {
res, err = gemini.FetchWithHost(viper.GetString("proxies.gemini"), u)
}
res, err := gemini.Fetch(u)
if err != nil {
return nil, err
}

parsed, _ := url.Parse(u)

ok := handleTofu(parsed.Hostname(), parsed.Port(), res.Cert)
if !ok {
return res, ErrTofu
}

return res, err
}

// FetchWithProxy is the same as Fetch, but uses a proxy.
func FetchWithProxy(proxyHostname, proxyPort, u string) (*gemini.Response, error) {
res, err := gemini.FetchWithHost(net.JoinHostPort(proxyHostname, proxyPort), u)
if err != nil {
return nil, err
}

// Only associate the returned cert with the proxy
ok := handleTofu(proxyHostname, proxyPort, res.Cert)
if !ok {
return res, ErrTofu
}

return res, nil
}
7 changes: 0 additions & 7 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package config

import (
"fmt"
"net/url"
"os"
"path/filepath"
"runtime"
Expand Down Expand Up @@ -34,8 +33,6 @@ var bkmkPath string

var DownloadsDir string

var GemProxy *url.URL

//nolint:golint,goerr113
func Init() error {
home, err := homedir.Dir()
Expand Down Expand Up @@ -181,10 +178,6 @@ func Init() error {
return err
}

if viper.GetString("proxies.gemini") != "" {
GemProxy, _ = url.Parse(viper.GetString("proxies.gemini"))
}

// Setup downloads dir
if viper.GetString("a-general.downloads") == "" {
// Find default Downloads dir
Expand Down
57 changes: 43 additions & 14 deletions display/private.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"io"
"net"
"net/url"
"os/exec"
"strconv"
Expand Down Expand Up @@ -163,7 +164,7 @@ func handleHTTP(u string, showInfo bool) {
}

// handleOther is used by handleURL.
// It opens or proxies links other than Gemini and HTTP and displays Error modals.
// It opens links other than Gemini and HTTP and displays Error modals.
func handleOther(u string) {
// The URL should have a scheme due to a previous call to normalizeURL
parsed, _ := url.Parse(u)
Expand Down Expand Up @@ -331,15 +332,38 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) {
return ret("", false)
}

proxy := strings.TrimSpace(viper.GetString("proxies." + parsed.Scheme))
usingProxy := false

proxyHostname, proxyPort, err := net.SplitHostPort(proxy)
if err != nil {
// Error likely means there's no port in the host
proxyHostname = proxy
proxyPort = "1965"
}

if strings.HasPrefix(u, "http") {
handleHTTP(u, true)
return ret("", false)
if proxy == "" || proxy == "off" {
// No proxy available
handleHTTP(u, true)
return ret("", false)
} else {
usingProxy = true
}
}
if !strings.HasPrefix(u, "gemini") {
handleOther(u)
return ret("", false)

if !strings.HasPrefix(u, "http") && !strings.HasPrefix(u, "gemini") {
// Not a Gemini URL
if proxy == "" || proxy == "off" {
// No proxy available
handleOther(u)
return ret("", false)
} else {
usingProxy = true
}
}
// Gemini URL

// Gemini URL, or one with a Gemini proxy available

// Load page from cache if possible
page, ok := cache.GetPage(u)
Expand All @@ -353,28 +377,33 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) {
t.mode = tabModeLoading
App.Draw()

res, err := client.Fetch(u)
var res *gemini.Response
if usingProxy {
res, err = client.FetchWithProxy(proxyHostname, proxyPort, u)
} else {
res, err = client.Fetch(u)
}

// Loading may have taken a while, make sure tab is still valid
if !isValidTab(t) {
return ret("", false)
}

if errors.Is(err, client.ErrTofu) {
if config.GemProxy == nil {
if Tofu(parsed.Host, client.GetExpiry(parsed.Hostname(), parsed.Port())) {
if usingProxy {
// They are using a proxy
if Tofu(proxy, client.GetExpiry(proxyHostname, proxyPort)) {
// They want to continue anyway
client.ResetTofuEntry(parsed.Hostname(), parsed.Port(), res.Cert)
client.ResetTofuEntry(proxyHostname, proxyPort, res.Cert)
// Response can be used further down, no need to reload
} else {
// They don't want to continue
return ret("", false)
}
} else {
// They are using a proxy
if Tofu(config.GemProxy.Host, client.GetExpiry(config.GemProxy.Hostname(), config.GemProxy.Port())) {
if Tofu(parsed.Host, client.GetExpiry(parsed.Hostname(), parsed.Port())) {
// They want to continue anyway
client.ResetTofuEntry(config.GemProxy.Hostname(), config.GemProxy.Port(), res.Cert)
client.ResetTofuEntry(parsed.Hostname(), parsed.Port(), res.Cert)
// Response can be used further down, no need to reload
} else {
// They don't want to continue
Expand Down

0 comments on commit 1d3e309

Please sign in to comment.