diff --git a/asyncbuffer/cond_test.go b/asyncbuffer/cond_test.go index ee25bd86..d3a8d96a 100644 --- a/asyncbuffer/cond_test.go +++ b/asyncbuffer/cond_test.go @@ -18,7 +18,7 @@ func (s *TestCondSuite) SetupTest() { s.cond = NewCond() } -func (s *TestCondSuite) TeardownTest() { +func (s *TestCondSuite) TearDownTest() { if s.cond != nil { s.cond.Close() } diff --git a/auximageprovider/static_provider_test.go b/auximageprovider/static_provider_test.go index ba9a8b67..08cb273e 100644 --- a/auximageprovider/static_provider_test.go +++ b/auximageprovider/static_provider_test.go @@ -16,7 +16,6 @@ import ( "github.com/imgproxy/imgproxy/v3/httpheaders" "github.com/imgproxy/imgproxy/v3/imagedata" "github.com/imgproxy/imgproxy/v3/options" - "github.com/imgproxy/imgproxy/v3/transport" ) type ImageProviderTestSuite struct { @@ -168,12 +167,8 @@ func (s *ImageProviderTestSuite) TestNewProvider() { }, } - trc := transport.NewDefaultConfig() - tr, err := transport.New(&trc) - s.Require().NoError(err) - fc := fetcher.NewDefaultConfig() - f, err := fetcher.New(tr, &fc) + f, err := fetcher.New(&fc) s.Require().NoError(err) idf := imagedata.NewFactory(f) diff --git a/cli/main.go b/cli/main.go index 57bf68b6..a1b3d508 100644 --- a/cli/main.go +++ b/cli/main.go @@ -42,7 +42,7 @@ func run(ctx context.Context, cmd *cli.Command) error { return err } - if err := instance.StartServer(ctx); err != nil { + if err := instance.StartServer(ctx, nil); err != nil { return err } diff --git a/config.go b/config.go index 96b2160e..2b4f097b 100644 --- a/config.go +++ b/config.go @@ -9,7 +9,6 @@ import ( "github.com/imgproxy/imgproxy/v3/headerwriter" "github.com/imgproxy/imgproxy/v3/semaphores" "github.com/imgproxy/imgproxy/v3/server" - "github.com/imgproxy/imgproxy/v3/transport" ) // Config represents an instance configuration @@ -18,7 +17,6 @@ type Config struct { Semaphores semaphores.Config FallbackImage auximageprovider.StaticConfig WatermarkImage auximageprovider.StaticConfig - Transport transport.Config Fetcher fetcher.Config ProcessingHandler processinghandler.Config StreamHandler stream.Config @@ -32,7 +30,6 @@ func NewDefaultConfig() Config { Semaphores: semaphores.NewDefaultConfig(), FallbackImage: auximageprovider.NewDefaultStaticConfig(), WatermarkImage: auximageprovider.NewDefaultStaticConfig(), - Transport: transport.NewDefaultConfig(), Fetcher: fetcher.NewDefaultConfig(), ProcessingHandler: processinghandler.NewDefaultConfig(), StreamHandler: stream.NewDefaultConfig(), @@ -66,10 +63,6 @@ func LoadConfigFromEnv(c *Config) (*Config, error) { return nil, err } - if _, err = transport.LoadConfigFromEnv(&c.Transport); err != nil { - return nil, err - } - if _, err = fetcher.LoadConfigFromEnv(&c.Fetcher); err != nil { return nil, err } diff --git a/fetcher/config.go b/fetcher/config.go index f39acd71..d125a388 100644 --- a/fetcher/config.go +++ b/fetcher/config.go @@ -6,6 +6,7 @@ import ( "github.com/imgproxy/imgproxy/v3/config" "github.com/imgproxy/imgproxy/v3/ensure" + "github.com/imgproxy/imgproxy/v3/fetcher/transport" "github.com/imgproxy/imgproxy/v3/version" ) @@ -19,6 +20,9 @@ type Config struct { // MaxRedirects is the maximum number of redirects to follow when fetching an image. MaxRedirects int + + // Transport holds the configuration for the transport layer. + Transport transport.Config } // NewDefaultConfig returns a new Config instance with default values. @@ -27,6 +31,7 @@ func NewDefaultConfig() Config { UserAgent: "imgproxy/" + version.Version, DownloadTimeout: 5 * time.Second, MaxRedirects: 10, + Transport: transport.NewDefaultConfig(), } } @@ -38,6 +43,11 @@ func LoadConfigFromEnv(c *Config) (*Config, error) { c.DownloadTimeout = time.Duration(config.DownloadTimeout) * time.Second c.MaxRedirects = config.MaxRedirects + _, err := transport.LoadConfigFromEnv(&c.Transport) + if err != nil { + return nil, err + } + return c, nil } diff --git a/fetcher/fetcher.go b/fetcher/fetcher.go index 5796be84..584d540e 100644 --- a/fetcher/fetcher.go +++ b/fetcher/fetcher.go @@ -7,9 +7,9 @@ import ( "net/http" "time" + "github.com/imgproxy/imgproxy/v3/fetcher/transport" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/common" "github.com/imgproxy/imgproxy/v3/httpheaders" - "github.com/imgproxy/imgproxy/v3/transport" - "github.com/imgproxy/imgproxy/v3/transport/common" ) const ( @@ -24,11 +24,16 @@ type Fetcher struct { } // New creates a new ImageFetcher with the provided transport -func New(transport *transport.Transport, config *Config) (*Fetcher, error) { +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 } diff --git a/transport/azure/azure.go b/fetcher/transport/azure/azure.go similarity index 97% rename from transport/azure/azure.go rename to fetcher/transport/azure/azure.go index b389354f..f0ace42f 100644 --- a/transport/azure/azure.go +++ b/fetcher/transport/azure/azure.go @@ -15,10 +15,10 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/common" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/notmodified" "github.com/imgproxy/imgproxy/v3/httpheaders" "github.com/imgproxy/imgproxy/v3/httprange" - "github.com/imgproxy/imgproxy/v3/transport/common" - "github.com/imgproxy/imgproxy/v3/transport/notmodified" ) type transport struct { diff --git a/transport/azure/azure_test.go b/fetcher/transport/azure/azure_test.go similarity index 98% rename from transport/azure/azure_test.go rename to fetcher/transport/azure/azure_test.go index 940d1b30..6370e312 100644 --- a/transport/azure/azure_test.go +++ b/fetcher/transport/azure/azure_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/suite" "github.com/imgproxy/imgproxy/v3/config" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/generichttp" "github.com/imgproxy/imgproxy/v3/httpheaders" - "github.com/imgproxy/imgproxy/v3/transport/generichttp" ) type AzureTestSuite struct { diff --git a/transport/azure/config.go b/fetcher/transport/azure/config.go similarity index 100% rename from transport/azure/config.go rename to fetcher/transport/azure/config.go diff --git a/transport/common/common.go b/fetcher/transport/common/common.go similarity index 100% rename from transport/common/common.go rename to fetcher/transport/common/common.go diff --git a/transport/config.go b/fetcher/transport/config.go similarity index 84% rename from transport/config.go rename to fetcher/transport/config.go index c58aebb6..6981bc98 100644 --- a/transport/config.go +++ b/fetcher/transport/config.go @@ -5,12 +5,12 @@ package transport import ( "github.com/imgproxy/imgproxy/v3/config" "github.com/imgproxy/imgproxy/v3/ensure" - "github.com/imgproxy/imgproxy/v3/transport/azure" - "github.com/imgproxy/imgproxy/v3/transport/fs" - "github.com/imgproxy/imgproxy/v3/transport/gcs" - "github.com/imgproxy/imgproxy/v3/transport/generichttp" - "github.com/imgproxy/imgproxy/v3/transport/s3" - "github.com/imgproxy/imgproxy/v3/transport/swift" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/azure" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/fs" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/gcs" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/generichttp" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/s3" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/swift" ) // Config represents configuration of the transport package diff --git a/transport/fs/config.go b/fetcher/transport/fs/config.go similarity index 100% rename from transport/fs/config.go rename to fetcher/transport/fs/config.go diff --git a/transport/fs/file_limiter.go b/fetcher/transport/fs/file_limiter.go similarity index 100% rename from transport/fs/file_limiter.go rename to fetcher/transport/fs/file_limiter.go diff --git a/transport/fs/fs.go b/fetcher/transport/fs/fs.go similarity index 96% rename from transport/fs/fs.go rename to fetcher/transport/fs/fs.go index 3e07c397..e9314863 100644 --- a/transport/fs/fs.go +++ b/fetcher/transport/fs/fs.go @@ -13,10 +13,10 @@ import ( "strconv" "strings" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/common" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/notmodified" "github.com/imgproxy/imgproxy/v3/httpheaders" "github.com/imgproxy/imgproxy/v3/httprange" - "github.com/imgproxy/imgproxy/v3/transport/common" - "github.com/imgproxy/imgproxy/v3/transport/notmodified" ) type transport struct { diff --git a/transport/fs/fs_test.go b/fetcher/transport/fs/fs_test.go similarity index 97% rename from transport/fs/fs_test.go rename to fetcher/transport/fs/fs_test.go index 3adaab96..bdc1edc7 100644 --- a/transport/fs/fs_test.go +++ b/fetcher/transport/fs/fs_test.go @@ -24,7 +24,7 @@ func (s *FsTestSuite) SetupSuite() { wd, err := os.Getwd() s.Require().NoError(err) - fsRoot := filepath.Join(wd, "..", "..", "testdata") + fsRoot := filepath.Join(wd, "..", "..", "..", "testdata") fi, err := os.Stat(filepath.Join(fsRoot, "test1.png")) s.Require().NoError(err) diff --git a/transport/gcs/config.go b/fetcher/transport/gcs/config.go similarity index 100% rename from transport/gcs/config.go rename to fetcher/transport/gcs/config.go diff --git a/transport/gcs/gcs.go b/fetcher/transport/gcs/gcs.go similarity index 97% rename from transport/gcs/gcs.go rename to fetcher/transport/gcs/gcs.go index e768bec8..4fba025e 100644 --- a/transport/gcs/gcs.go +++ b/fetcher/transport/gcs/gcs.go @@ -14,11 +14,11 @@ import ( raw "google.golang.org/api/storage/v1" htransport "google.golang.org/api/transport/http" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/common" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/notmodified" "github.com/imgproxy/imgproxy/v3/httpheaders" "github.com/imgproxy/imgproxy/v3/httprange" "github.com/imgproxy/imgproxy/v3/ierrors" - "github.com/imgproxy/imgproxy/v3/transport/common" - "github.com/imgproxy/imgproxy/v3/transport/notmodified" ) // For tests diff --git a/transport/gcs/gcs_test.go b/fetcher/transport/gcs/gcs_test.go similarity index 98% rename from transport/gcs/gcs_test.go rename to fetcher/transport/gcs/gcs_test.go index c8417958..55fbb6d8 100644 --- a/transport/gcs/gcs_test.go +++ b/fetcher/transport/gcs/gcs_test.go @@ -10,8 +10,8 @@ import ( "github.com/fsouza/fake-gcs-server/fakestorage" "github.com/stretchr/testify/suite" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/generichttp" "github.com/imgproxy/imgproxy/v3/httpheaders" - "github.com/imgproxy/imgproxy/v3/transport/generichttp" ) func getFreePort() (int, error) { diff --git a/transport/generichttp/config.go b/fetcher/transport/generichttp/config.go similarity index 100% rename from transport/generichttp/config.go rename to fetcher/transport/generichttp/config.go diff --git a/transport/generichttp/generic_http.go b/fetcher/transport/generichttp/generic_http.go similarity index 100% rename from transport/generichttp/generic_http.go rename to fetcher/transport/generichttp/generic_http.go diff --git a/transport/notmodified/notmodified.go b/fetcher/transport/notmodified/notmodified.go similarity index 100% rename from transport/notmodified/notmodified.go rename to fetcher/transport/notmodified/notmodified.go diff --git a/transport/s3/config.go b/fetcher/transport/s3/config.go similarity index 100% rename from transport/s3/config.go rename to fetcher/transport/s3/config.go diff --git a/transport/s3/s3.go b/fetcher/transport/s3/s3.go similarity index 99% rename from transport/s3/s3.go rename to fetcher/transport/s3/s3.go index 76b79458..334e17a0 100644 --- a/transport/s3/s3.go +++ b/fetcher/transport/s3/s3.go @@ -20,9 +20,9 @@ import ( "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/common" "github.com/imgproxy/imgproxy/v3/httpheaders" "github.com/imgproxy/imgproxy/v3/ierrors" - "github.com/imgproxy/imgproxy/v3/transport/common" ) type s3Client interface { diff --git a/transport/s3/s3_test.go b/fetcher/transport/s3/s3_test.go similarity index 98% rename from transport/s3/s3_test.go rename to fetcher/transport/s3/s3_test.go index e289e89f..dfffad80 100644 --- a/transport/s3/s3_test.go +++ b/fetcher/transport/s3/s3_test.go @@ -15,7 +15,7 @@ import ( "github.com/johannesboyne/gofakes3/backend/s3mem" "github.com/stretchr/testify/suite" - "github.com/imgproxy/imgproxy/v3/transport/generichttp" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/generichttp" ) type S3TestSuite struct { diff --git a/transport/swift/config.go b/fetcher/transport/swift/config.go similarity index 100% rename from transport/swift/config.go rename to fetcher/transport/swift/config.go diff --git a/transport/swift/swift.go b/fetcher/transport/swift/swift.go similarity index 96% rename from transport/swift/swift.go rename to fetcher/transport/swift/swift.go index 4e70199c..be81dd43 100644 --- a/transport/swift/swift.go +++ b/fetcher/transport/swift/swift.go @@ -10,9 +10,9 @@ import ( "github.com/ncw/swift/v2" "github.com/imgproxy/imgproxy/v3/config" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/common" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/notmodified" "github.com/imgproxy/imgproxy/v3/ierrors" - "github.com/imgproxy/imgproxy/v3/transport/common" - "github.com/imgproxy/imgproxy/v3/transport/notmodified" ) type transport struct { diff --git a/transport/swift/swift_test.go b/fetcher/transport/swift/swift_test.go similarity index 98% rename from transport/swift/swift_test.go rename to fetcher/transport/swift/swift_test.go index bb1efcbc..92838bfc 100644 --- a/transport/swift/swift_test.go +++ b/fetcher/transport/swift/swift_test.go @@ -10,7 +10,7 @@ import ( "github.com/ncw/swift/v2/swifttest" "github.com/stretchr/testify/suite" - "github.com/imgproxy/imgproxy/v3/transport/generichttp" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/generichttp" ) const ( diff --git a/transport/transport.go b/fetcher/transport/transport.go similarity index 85% rename from transport/transport.go rename to fetcher/transport/transport.go index c4db9fd7..7a8aab22 100644 --- a/transport/transport.go +++ b/fetcher/transport/transport.go @@ -5,13 +5,13 @@ package transport import ( "net/http" - "github.com/imgproxy/imgproxy/v3/transport/generichttp" + "github.com/imgproxy/imgproxy/v3/fetcher/transport/generichttp" - azureTransport "github.com/imgproxy/imgproxy/v3/transport/azure" - fsTransport "github.com/imgproxy/imgproxy/v3/transport/fs" - gcsTransport "github.com/imgproxy/imgproxy/v3/transport/gcs" - s3Transport "github.com/imgproxy/imgproxy/v3/transport/s3" - swiftTransport "github.com/imgproxy/imgproxy/v3/transport/swift" + azureTransport "github.com/imgproxy/imgproxy/v3/fetcher/transport/azure" + fsTransport "github.com/imgproxy/imgproxy/v3/fetcher/transport/fs" + gcsTransport "github.com/imgproxy/imgproxy/v3/fetcher/transport/gcs" + s3Transport "github.com/imgproxy/imgproxy/v3/fetcher/transport/s3" + swiftTransport "github.com/imgproxy/imgproxy/v3/fetcher/transport/swift" ) // Transport is a wrapper around http.Transport which allows to track registered protocols diff --git a/handlers/processing/request_methods.go b/handlers/processing/request_methods.go index b692e981..c2791105 100644 --- a/handlers/processing/request_methods.go +++ b/handlers/processing/request_methods.go @@ -154,7 +154,7 @@ func (r *request) getFallbackImage( // processImage calls actual image processing func (r *request) processImage(ctx context.Context, originData imagedata.ImageData) (*processing.Result, error) { defer monitoring.StartProcessingSegment(ctx, r.monitoringMeta.Filter(monitoring.MetaProcessingOptions))() - return processing.ProcessImage(ctx, originData, r.po, r.handler.watermarkImage, r.handler.idf) + return processing.ProcessImage(ctx, originData, r.po, r.handler.watermarkImage) } // writeDebugHeaders writes debug headers (X-Origin-*, X-Result-*) to the response diff --git a/handlers/stream/handler_test.go b/handlers/stream/handler_test.go index 2555727f..1a9418f5 100644 --- a/handlers/stream/handler_test.go +++ b/handlers/stream/handler_test.go @@ -20,7 +20,6 @@ import ( "github.com/imgproxy/imgproxy/v3/headerwriter" "github.com/imgproxy/imgproxy/v3/httpheaders" "github.com/imgproxy/imgproxy/v3/options" - "github.com/imgproxy/imgproxy/v3/transport" ) const ( @@ -49,15 +48,9 @@ func (s *HandlerTestSuite) SetupTest() { config.Reset() config.AllowLoopbackSourceAddresses = true - trc, err := transport.LoadConfigFromEnv(nil) - s.Require().NoError(err) - - tr, err := transport.New(trc) - s.Require().NoError(err) - fc := fetcher.NewDefaultConfig() - fetcher, err := fetcher.New(tr, &fc) + fetcher, err := fetcher.New(&fc) s.Require().NoError(err) cfg := NewDefaultConfig() @@ -349,16 +342,10 @@ func (s *HandlerTestSuite) TestHandlerCacheControl() { })) defer ts.Close() - trc, err := transport.LoadConfigFromEnv(nil) + fc, err := fetcher.LoadConfigFromEnv(nil) s.Require().NoError(err) - // Create new handler with updated config for each test - tr, err := transport.New(trc) - s.Require().NoError(err) - - fc := fetcher.NewDefaultConfig() - - fetcher, err := fetcher.New(tr, &fc) + fetcher, err := fetcher.New(fc) s.Require().NoError(err) cfg := NewDefaultConfig() @@ -446,15 +433,10 @@ func (s *HandlerTestSuite) TestHandlerErrorResponse() { // TestHandlerCookiePassthrough tests the cookie passthrough behavior of the streaming service. func (s *HandlerTestSuite) TestHandlerCookiePassthrough() { - trc, err := transport.LoadConfigFromEnv(nil) + fc, err := fetcher.LoadConfigFromEnv(nil) s.Require().NoError(err) - // Create new handler with updated config - tr, err := transport.New(trc) - s.Require().NoError(err) - - fc := fetcher.NewDefaultConfig() - fetcher, err := fetcher.New(tr, &fc) + fetcher, err := fetcher.New(fc) s.Require().NoError(err) cfg := NewDefaultConfig() @@ -506,15 +488,10 @@ func (s *HandlerTestSuite) TestHandlerCanonicalHeader() { defer ts.Close() for _, sc := range []bool{true, false} { - trc, err := transport.LoadConfigFromEnv(nil) + fc, err := fetcher.LoadConfigFromEnv(nil) s.Require().NoError(err) - // Create new handler with updated config - tr, err := transport.New(trc) - s.Require().NoError(err) - - fc := fetcher.NewDefaultConfig() - fetcher, err := fetcher.New(tr, &fc) + fetcher, err := fetcher.New(fc) s.Require().NoError(err) cfg := NewDefaultConfig() diff --git a/imagedata/image_data_test.go b/imagedata/image_data_test.go index 05c83842..9534aae3 100644 --- a/imagedata/image_data_test.go +++ b/imagedata/image_data_test.go @@ -22,7 +22,6 @@ import ( "github.com/imgproxy/imgproxy/v3/ierrors" "github.com/imgproxy/imgproxy/v3/imagetype" "github.com/imgproxy/imgproxy/v3/testutil" - "github.com/imgproxy/imgproxy/v3/transport" ) type ImageDataTestSuite struct { @@ -70,16 +69,10 @@ func (s *ImageDataTestSuite) SetupSuite() { rw.Write(data) })) - ctr, err := transport.LoadConfigFromEnv(nil) - s.Require().NoError(err) - - ts, err := transport.New(ctr) - s.Require().NoError(err) - c, err := fetcher.LoadConfigFromEnv(nil) s.Require().NoError(err) - fetcher, err := fetcher.New(ts, c) + fetcher, err := fetcher.New(c) s.Require().NoError(err) s.factory = NewFactory(fetcher) diff --git a/imgproxy.go b/imgproxy.go index bdb71d47..4abc69c2 100644 --- a/imgproxy.go +++ b/imgproxy.go @@ -2,6 +2,7 @@ package imgproxy import ( "context" + "net" "time" "github.com/imgproxy/imgproxy/v3/auximageprovider" @@ -15,7 +16,6 @@ import ( "github.com/imgproxy/imgproxy/v3/monitoring/prometheus" "github.com/imgproxy/imgproxy/v3/semaphores" "github.com/imgproxy/imgproxy/v3/server" - "github.com/imgproxy/imgproxy/v3/transport" ) const ( @@ -43,12 +43,7 @@ func New(ctx context.Context, config *Config) (*Imgproxy, error) { return nil, err } - ts, err := transport.New(&config.Transport) - if err != nil { - return nil, err - } - - fetcher, err := fetcher.New(ts, &config.Fetcher) + fetcher, err := fetcher.New(&config.Fetcher) if err != nil { return nil, err } @@ -123,7 +118,9 @@ func (i *Imgproxy) BuildRouter() (*server.Router, error) { } // Start runs the imgproxy server. This function blocks until the context is cancelled. -func (i *Imgproxy) StartServer(ctx context.Context) error { +// If hasStarted is not nil, it will be notified with the server address once +// the server is ready or about to be ready to accept requests. +func (i *Imgproxy) StartServer(ctx context.Context, hasStarted chan net.Addr) error { go i.startMemoryTicker(ctx) ctx, cancel := context.WithCancel(ctx) @@ -143,6 +140,11 @@ func (i *Imgproxy) StartServer(ctx context.Context) error { } defer s.Shutdown(context.Background()) + if hasStarted != nil { + hasStarted <- s.Addr + close(hasStarted) + } + <-ctx.Done() return nil diff --git a/integration/load_test.go b/integration/load_test.go index 71f40389..a8273f3c 100644 --- a/integration/load_test.go +++ b/integration/load_test.go @@ -6,6 +6,7 @@ import ( "fmt" "image/png" "io" + "net" "net/http" "os" "path" @@ -27,25 +28,33 @@ const ( ) type LoadTestSuite struct { - suite.Suite - ctx context.Context - cancel context.CancelFunc + Suite testData *testutil.TestDataProvider testImagesPath string + + addr net.Addr + stopImgproxy context.CancelFunc } // SetupSuite starts imgproxy instance server func (s *LoadTestSuite) SetupSuite() { s.testData = testutil.NewTestDataProvider(s.T()) s.testImagesPath = s.testData.Path("test-images") - s.ctx, s.cancel = context.WithCancel(s.T().Context()) - s.startImgproxy(s.ctx) + c, err := imgproxy.LoadConfigFromEnv(nil) + s.Require().NoError(err) + + c.Fetcher.Transport.Local.Root = s.testImagesPath + config.MaxAnimationFrames = 999 + config.DevelopmentErrorsMode = true + + // In this test we start the single imgproxy server for all test cases + s.addr, s.stopImgproxy = s.StartImgproxy(c) } // TearDownSuite stops imgproxy instance server func (s *LoadTestSuite) TearDownSuite() { - s.cancel() + s.stopImgproxy() } // testLoadFolder fetches images iterates over images in the specified folder, @@ -108,7 +117,7 @@ func (s *LoadTestSuite) testLoadFolder(folder string) { // fetchImage fetches an image from the imgproxy server func (s *LoadTestSuite) fetchImage(path string) []byte { - url := fmt.Sprintf("http://%s:%d/%s", bindHost, bindPort, path) + url := fmt.Sprintf("http://%s/%s", s.addr.String(), path) resp, err := http.Get(url) s.Require().NoError(err, "Failed to fetch image from %s", url) @@ -122,30 +131,6 @@ func (s *LoadTestSuite) fetchImage(path string) []byte { return bytes } -func (s *LoadTestSuite) startImgproxy(ctx context.Context) *imgproxy.Imgproxy { - c, err := imgproxy.LoadConfigFromEnv(nil) - s.Require().NoError(err) - - c.Server.Bind = ":" + fmt.Sprintf("%d", bindPort) - c.Transport.Local.Root = s.testImagesPath - c.Server.LogMemStats = true - - config.MaxAnimationFrames = 999 - config.DevelopmentErrorsMode = true - - i, err := imgproxy.New(ctx, c) - s.Require().NoError(err) - - go func() { - err = i.StartServer(ctx) - if err != nil { - s.T().Errorf("Imgproxy server exited with error: %v", err) - } - }() - - return i -} - // TestLoadSaveToPng ensures that our load pipeline works, // including standard and custom loaders. For each source image // in the folder, it does the passthrough request through imgproxy: diff --git a/integration/main_test.go b/integration/main_test.go index c8b3da6f..7ee0cc6d 100644 --- a/integration/main_test.go +++ b/integration/main_test.go @@ -7,11 +7,6 @@ import ( "github.com/imgproxy/imgproxy/v3" ) -const ( - bindPort = 9090 // Port to bind imgproxy to - bindHost = "localhost" -) - // TestMain performs global setup/teardown for the integration tests. func TestMain(m *testing.M) { imgproxy.Init() diff --git a/integration/processing_handler_test.go b/integration/processing_handler_test.go index a191bae3..0b5c940f 100644 --- a/integration/processing_handler_test.go +++ b/integration/processing_handler_test.go @@ -1,6 +1,7 @@ package integration import ( + "bytes" "fmt" "io" "net/http" @@ -13,10 +14,10 @@ import ( "github.com/imgproxy/imgproxy/v3" "github.com/imgproxy/imgproxy/v3/config" "github.com/imgproxy/imgproxy/v3/config/configurators" + "github.com/imgproxy/imgproxy/v3/fetcher" "github.com/imgproxy/imgproxy/v3/httpheaders" "github.com/imgproxy/imgproxy/v3/imagedata" "github.com/imgproxy/imgproxy/v3/imagetype" - "github.com/imgproxy/imgproxy/v3/server" "github.com/imgproxy/imgproxy/v3/svg" "github.com/imgproxy/imgproxy/v3/testutil" "github.com/imgproxy/imgproxy/v3/vips" @@ -26,12 +27,15 @@ import ( // ProcessingHandlerTestSuite is a test suite for testing image processing handler type ProcessingHandlerTestSuite struct { - suite.Suite + Suite testData *testutil.TestDataProvider - config testutil.LazyObj[*imgproxy.Config] - router testutil.LazyObj[*server.Router] - imgproxy testutil.LazyObj[*imgproxy.Imgproxy] + + // NOTE: lazy obj is required here because in the specific tests we sometimes + // change the config values in config.go. Config instantiation should + // happen afterwards. It is done via lazy obj. When all config values will be moved + // to imgproxy.Config struct, this can be removed. + config testutil.LazyObj[*imgproxy.Config] } func (s *ProcessingHandlerTestSuite) SetupSuite() { @@ -42,7 +46,7 @@ func (s *ProcessingHandlerTestSuite) SetupSuite() { s.testData = testutil.NewTestDataProvider(s.T()) } -func (s *ProcessingHandlerTestSuite) TeardownSuite() { +func (s *ProcessingHandlerTestSuite) TearDownSuite() { logrus.SetOutput(os.Stdout) } @@ -52,19 +56,11 @@ func (s *ProcessingHandlerTestSuite) setupObjs() { c, err := imgproxy.LoadConfigFromEnv(nil) s.Require().NoError(err) - c.Transport.Local.Root = s.testData.Root() - c.Transport.HTTP.ClientKeepAliveTimeout = 0 + c.Fetcher.Transport.Local.Root = s.testData.Root() + c.Fetcher.Transport.HTTP.ClientKeepAliveTimeout = 0 return c, nil }) - - s.imgproxy = testutil.NewLazyObj(s.T(), func() (*imgproxy.Imgproxy, error) { - return imgproxy.New(s.T().Context(), s.config()) - }) - - s.router = testutil.NewLazyObj(s.T(), func() (*server.Router, error) { - return s.imgproxy().BuildRouter() - }) } func (s *ProcessingHandlerTestSuite) SetupTest() { @@ -82,18 +78,35 @@ func (s *ProcessingHandlerTestSuite) SetupSubTest() { s.setupObjs() } -// GET performs a GET request to the given path and returns the response recorder +// GET performs a GET request to the imageproxy real server +// NOTE: Do not forget to move this to Suite in case of need in other future test suites func (s *ProcessingHandlerTestSuite) GET(path string, header ...http.Header) *http.Response { - req := httptest.NewRequest(http.MethodGet, path, nil) - rw := httptest.NewRecorder() + // In this test we start the imgproxy server instance per request + addr, stopServer := s.StartImgproxy(s.config()) + defer stopServer() - if len(header) > 0 { - req.Header = header[0] + url := fmt.Sprintf("http://%s%s", addr.String(), path) + + // Perform GET request to an url + req, _ := http.NewRequest("GET", url, nil) + for h := range header { + for k, v := range header[h] { + req.Header.Set(k, v[0]) // only first value will go to the request + } } - s.router().ServeHTTP(rw, req) + // Do the request + resp, err := http.DefaultClient.Do(req) + s.Require().NoError(err) - return rw.Result() + // Read the entire body into memory and replace the original body with memory reader + // to avoid the defer + bodyBytes, err := io.ReadAll(resp.Body) + s.Require().NoError(err) + resp.Body.Close() + resp.Body = io.NopCloser(bytes.NewReader(bodyBytes)) + + return resp } func (s *ProcessingHandlerTestSuite) TestSignatureValidationFailure() { @@ -267,7 +280,13 @@ func (s *ProcessingHandlerTestSuite) TestSkipProcessingSVG() { s.Require().Equal(http.StatusOK, res.StatusCode) - data, err := s.imgproxy().ImageDataFactory.NewFromBytes(s.testData.Read("test1.svg")) + c := fetcher.NewDefaultConfig() + f, err := fetcher.New(&c) + s.Require().NoError(err) + + idf := imagedata.NewFactory(f) + + data, err := idf.NewFromBytes(s.testData.Read("test1.svg")) s.Require().NoError(err) expected, err := svg.Sanitize(data) diff --git a/integration/suite.go b/integration/suite.go new file mode 100644 index 00000000..6b8cdac0 --- /dev/null +++ b/integration/suite.go @@ -0,0 +1,36 @@ +package integration + +import ( + "context" + "net" + + "github.com/imgproxy/imgproxy/v3" + "github.com/stretchr/testify/suite" +) + +type Suite struct { + suite.Suite +} + +// StartImgproxy starts imgproxy instance for the tests +// Returns instance, instance address and stop function +func (s *Suite) StartImgproxy(c *imgproxy.Config) (net.Addr, context.CancelFunc) { + ctx, cancel := context.WithCancel(s.T().Context()) + + c.Server.Bind = ":0" + c.Server.LogMemStats = true + + i, err := imgproxy.New(ctx, c) + s.Require().NoError(err) + + addrCh := make(chan net.Addr) + + go func() { + err = i.StartServer(s.T().Context(), addrCh) + if err != nil { + s.T().Errorf("Imgproxy stopped with error: %v", err) + } + }() + + return <-addrCh, cancel +} diff --git a/processing/processing.go b/processing/processing.go index 4fc5f611..53bf8592 100644 --- a/processing/processing.go +++ b/processing/processing.go @@ -85,7 +85,6 @@ func ProcessImage( imgdata imagedata.ImageData, po *options.ProcessingOptions, watermarkProvider auximageprovider.Provider, - idf *imagedata.Factory, ) (*Result, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() diff --git a/processing/processing_test.go b/processing/processing_test.go index beeb762a..3e017350 100644 --- a/processing/processing_test.go +++ b/processing/processing_test.go @@ -16,7 +16,6 @@ import ( "github.com/imgproxy/imgproxy/v3/ierrors" "github.com/imgproxy/imgproxy/v3/imagedata" "github.com/imgproxy/imgproxy/v3/options" - "github.com/imgproxy/imgproxy/v3/transport" "github.com/imgproxy/imgproxy/v3/vips" ) @@ -37,12 +36,8 @@ func (s *ProcessingTestSuite) SetupSuite() { logrus.SetOutput(io.Discard) - trc := transport.NewDefaultConfig() - tr, err := transport.New(&trc) - s.Require().NoError(err) - fc := fetcher.NewDefaultConfig() - f, err := fetcher.New(tr, &fc) + f, err := fetcher.New(&fc) s.Require().NoError(err) s.idf = imagedata.NewFactory(f) @@ -94,7 +89,7 @@ func (s *ProcessingTestSuite) TestResizeToFit() { po.Width = tc.width po.Height = tc.height - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -133,7 +128,7 @@ func (s *ProcessingTestSuite) TestResizeToFitEnlarge() { po.Width = tc.width po.Height = tc.height - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -177,7 +172,7 @@ func (s *ProcessingTestSuite) TestResizeToFitExtend() { po.Width = tc.width po.Height = tc.height - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -221,7 +216,7 @@ func (s *ProcessingTestSuite) TestResizeToFitExtendAR() { po.Width = tc.width po.Height = tc.height - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -259,7 +254,7 @@ func (s *ProcessingTestSuite) TestResizeToFill() { po.Width = tc.width po.Height = tc.height - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -298,7 +293,7 @@ func (s *ProcessingTestSuite) TestResizeToFillEnlarge() { po.Width = tc.width po.Height = tc.height - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -344,7 +339,7 @@ func (s *ProcessingTestSuite) TestResizeToFillExtend() { po.Width = tc.width po.Height = tc.height - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -390,7 +385,7 @@ func (s *ProcessingTestSuite) TestResizeToFillExtendAR() { po.Width = tc.width po.Height = tc.height - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -428,7 +423,7 @@ func (s *ProcessingTestSuite) TestResizeToFillDown() { po.Width = tc.width po.Height = tc.height - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -467,7 +462,7 @@ func (s *ProcessingTestSuite) TestResizeToFillDownEnlarge() { po.Width = tc.width po.Height = tc.height - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -513,7 +508,7 @@ func (s *ProcessingTestSuite) TestResizeToFillDownExtend() { po.Width = tc.width po.Height = tc.height - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -557,7 +552,7 @@ func (s *ProcessingTestSuite) TestResizeToFillDownExtendAR() { po.Width = tc.width po.Height = tc.height - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -986,7 +981,7 @@ func (s *ProcessingTestSuite) TestResultSizeLimit() { po.Rotate = tc.rotate po.Padding = tc.padding - result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + result, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().NoError(err) s.Require().NotNil(result) @@ -1001,7 +996,7 @@ func (s *ProcessingTestSuite) TestImageResolutionTooLarge() { po.SecurityOptions.MaxSrcResolution = 1 imgdata := s.openFile("test2.jpg") - _, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf) + _, err := ProcessImage(context.Background(), imgdata, po, nil) s.Require().Error(err) s.Require().Equal(422, ierrors.Wrap(err, 0).StatusCode()) diff --git a/server/server.go b/server/server.go index a1d6d1d6..a6c45cef 100644 --- a/server/server.go +++ b/server/server.go @@ -4,6 +4,7 @@ import ( "context" "fmt" golog "log" + "net" "net/http" log "github.com/sirupsen/logrus" @@ -22,6 +23,7 @@ const ( type Server struct { router *Router server *http.Server + Addr net.Addr } // Start starts the http server. cancel is called in case server failed to start, but it happened @@ -42,6 +44,8 @@ func Start(cancel context.CancelFunc, router *Router) (*Server, error) { "", 0, ) + addr := l.Addr() + srv := &http.Server{ Handler: router, ReadTimeout: router.config.ReadRequestTimeout, @@ -68,6 +72,7 @@ func Start(cancel context.CancelFunc, router *Router) (*Server, error) { return &Server{ router: router, server: srv, + Addr: addr, }, nil } diff --git a/svg/svg_test.go b/svg/svg_test.go index 960010b1..fdde4d2a 100644 --- a/svg/svg_test.go +++ b/svg/svg_test.go @@ -11,7 +11,6 @@ import ( "github.com/imgproxy/imgproxy/v3/fetcher" "github.com/imgproxy/imgproxy/v3/imagedata" "github.com/imgproxy/imgproxy/v3/testutil" - "github.com/imgproxy/imgproxy/v3/transport" ) type SvgTestSuite struct { @@ -22,12 +21,8 @@ type SvgTestSuite struct { func (s *SvgTestSuite) SetupSuite() { config.Reset() - trc := transport.NewDefaultConfig() - tr, err := transport.New(&trc) - s.Require().NoError(err) - - fc := fetcher.NewDefaultConfig() - f, err := fetcher.New(tr, &fc) + c := fetcher.NewDefaultConfig() + f, err := fetcher.New(&c) s.Require().NoError(err) s.idf = imagedata.NewFactory(f)