diff options
Diffstat (limited to 'gemini/client.go')
-rw-r--r-- | gemini/client.go | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/gemini/client.go b/gemini/client.go index 7c78b71..338271c 100644 --- a/gemini/client.go +++ b/gemini/client.go @@ -6,6 +6,7 @@ import ( "errors" "io" "net" + neturl "net/url" sr "tildegit.org/tjp/sliderule" ) @@ -18,14 +19,22 @@ import ( // // The zero value is a usable Client with no client TLS certificate. type Client struct { + MaxRedirects int + tlsConf *tls.Config } // Create a gemini Client with the given TLS configuration. func NewClient(tlsConf *tls.Config) Client { - return Client{tlsConf: tlsConf} + return Client{tlsConf: tlsConf, MaxRedirects: DefaultMaxRedirects} } +// DefaultMaxRedirects is the number of chained redirects a Client will perform for a +// single request by default. This can be changed by altering the MaxRedirects field. +const DefaultMaxRedirects int = 2 + +var ExceededMaxRedirects = errors.New("gemini.Client: exceeded MaxRedirects") + // RoundTrip sends a single gemini request to the correct server and returns its response. // // It also populates the TLSState and RemoteAddr fields on the request - the only field @@ -77,3 +86,32 @@ func (client Client) RoundTrip(request *sr.Request) (*sr.Response, error) { return response, nil } + +// Fetch parses a URL string and fetches the gemini resource. +// +// It will resolve any redirects along the way, up to client.MaxRedirects. +func (c Client) Fetch(url string) (*sr.Response, error) { + u, err := neturl.Parse(url) + if err != nil { + return nil, err + } + + for i := 0; i <= c.MaxRedirects; i += 1 { + response, err := c.RoundTrip(&sr.Request{URL: u}) + if err != nil { + return nil, err + } + if ResponseCategoryForStatus(response.Status) != ResponseCategoryRedirect { + return response, nil + } + + prev := u + u, err = neturl.Parse(url) + if err != nil { + return nil, err + } + u = prev.ResolveReference(u) + } + + return nil, ExceededMaxRedirects +} |