123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- // fetcher is responsible for downloading images using HTTP requests through various protocols
- // defined in transport package
- package fetcher
- import (
- "context"
- "net/http"
- "time"
- "github.com/imgproxy/imgproxy/v3/fetcher/transport"
- "github.com/imgproxy/imgproxy/v3/fetcher/transport/common"
- "github.com/imgproxy/imgproxy/v3/httpheaders"
- )
- const (
- connectionLostError = "client connection lost" // Error message indicating a lost connection
- bounceDelay = 100 * time.Microsecond // Delay before retrying a request
- )
- // Fetcher is a struct that holds the HTTP client and transport for fetching images
- type Fetcher struct {
- transport *transport.Transport // Transport used for making HTTP requests
- config *Config // Configuration for the image fetcher
- }
- // New creates a new ImageFetcher with the provided transport
- func New(config *Config) (*Fetcher, error) {
- if err := config.Validate(); err != nil {
- return nil, err
- }
- transport, err := transport.New(&config.Transport)
- if err != nil {
- return nil, err
- }
- return &Fetcher{transport, config}, nil
- }
- // checkRedirect is a method that checks if the number of redirects exceeds the maximum allowed
- func (f *Fetcher) checkRedirect(req *http.Request, via []*http.Request) error {
- redirects := len(via)
- if redirects >= f.config.MaxRedirects {
- return newImageTooManyRedirectsError(redirects)
- }
- return nil
- }
- // newHttpClient returns new HTTP client
- func (f *Fetcher) newHttpClient() *http.Client {
- return &http.Client{
- Transport: f.transport.Transport(), // Connection pool is there
- CheckRedirect: f.checkRedirect,
- }
- }
- // NewImageFetcherRequest creates a new ImageFetcherRequest with the provided context, URL, headers, and cookie jar
- func (f *Fetcher) BuildRequest(ctx context.Context, url string, header http.Header, jar http.CookieJar) (*Request, error) {
- url = common.EscapeURL(url)
- // Set request timeout and get cancel function
- ctx, cancel := context.WithTimeout(ctx, f.config.DownloadTimeout)
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
- if err != nil {
- cancel()
- return nil, newImageRequestError(err)
- }
- // Check if the URL scheme is supported
- if !f.transport.IsProtocolRegistered(req.URL.Scheme) {
- cancel()
- return nil, newImageRequstSchemeError(req.URL.Scheme)
- }
- // Add cookies from the jar to the request (if any)
- if jar != nil {
- for _, cookie := range jar.Cookies(req.URL) {
- req.AddCookie(cookie)
- }
- }
- // Set user agent header
- req.Header.Set(httpheaders.UserAgent, f.config.UserAgent)
- // Set headers
- httpheaders.CopyToRequest(header, req)
- return &Request{f, req, cancel}, nil
- }
|