diff options
Diffstat (limited to 'gemini')
| -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 +} | 
