transport.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Package transport provides a custom HTTP transport that supports multiple protocols
  2. // such as S3, GCS, ABS, Swift, and local file system.
  3. package transport
  4. import (
  5. "context"
  6. "log/slog"
  7. "net/http"
  8. "github.com/imgproxy/imgproxy/v3/fetcher/transport/generichttp"
  9. absStorage "github.com/imgproxy/imgproxy/v3/storage/abs"
  10. fsStorage "github.com/imgproxy/imgproxy/v3/storage/fs"
  11. gcsStorage "github.com/imgproxy/imgproxy/v3/storage/gcs"
  12. s3Storage "github.com/imgproxy/imgproxy/v3/storage/s3"
  13. swiftStorage "github.com/imgproxy/imgproxy/v3/storage/swift"
  14. )
  15. // Transport is a wrapper around http.Transport which allows to track registered protocols
  16. type Transport struct {
  17. config *Config
  18. transport *http.Transport
  19. schemes map[string]struct{}
  20. }
  21. // New creates a new HTTP transport with no protocols registered
  22. func New(config *Config) (*Transport, error) {
  23. if err := config.Validate(); err != nil {
  24. return nil, err
  25. }
  26. transport, err := generichttp.New(true, &config.HTTP)
  27. if err != nil {
  28. return nil, err
  29. }
  30. // http and https are always registered
  31. schemes := map[string]struct{}{
  32. "http": {},
  33. "https": {},
  34. }
  35. t := &Transport{
  36. config: config,
  37. transport: transport,
  38. schemes: schemes,
  39. }
  40. err = t.registerAllProtocols()
  41. if err != nil {
  42. return nil, err
  43. }
  44. return t, nil
  45. }
  46. // Transport returns the underlying http.Transport
  47. func (t *Transport) Transport() *http.Transport {
  48. return t.transport
  49. }
  50. // RegisterProtocol registers a new transport protocol with the transport
  51. func (t *Transport) RegisterProtocol(scheme string, rt http.RoundTripper) {
  52. t.transport.RegisterProtocol(scheme, rt)
  53. t.schemes[scheme] = struct{}{}
  54. slog.Info("Scheme registered", "scheme", scheme)
  55. }
  56. // IsProtocolRegistered checks if a protocol is registered in the transport
  57. func (t *Transport) IsProtocolRegistered(scheme string) bool {
  58. _, ok := t.schemes[scheme]
  59. return ok
  60. }
  61. // RegisterAllProtocols registers all enabled protocols in the given transport
  62. func (t *Transport) registerAllProtocols() error {
  63. sep := t.config.SourceURLQuerySeparator // shortcut
  64. transp, err := generichttp.New(false, &t.config.HTTP)
  65. if err != nil {
  66. return err
  67. }
  68. if t.config.Local.Root != "" {
  69. tr, err := fsStorage.New(&t.config.Local)
  70. if err != nil {
  71. return err
  72. }
  73. t.RegisterProtocol("local", NewRoundTripper(tr, sep))
  74. }
  75. if t.config.S3Enabled {
  76. tr, err := s3Storage.New(&t.config.S3, transp)
  77. if err != nil {
  78. return err
  79. }
  80. t.RegisterProtocol("s3", NewRoundTripper(tr, sep))
  81. }
  82. if t.config.GCSEnabled {
  83. tr, err := gcsStorage.New(&t.config.GCS, transp)
  84. if err != nil {
  85. return err
  86. }
  87. t.RegisterProtocol("gs", NewRoundTripper(tr, sep))
  88. }
  89. if t.config.ABSEnabled {
  90. tr, err := absStorage.New(&t.config.ABS, transp)
  91. if err != nil {
  92. return err
  93. }
  94. t.RegisterProtocol("abs", NewRoundTripper(tr, sep))
  95. }
  96. if t.config.SwiftEnabled {
  97. tr, err := swiftStorage.New(
  98. context.Background(),
  99. &t.config.Swift,
  100. transp,
  101. )
  102. if err != nil {
  103. return err
  104. }
  105. t.RegisterProtocol("swift", NewRoundTripper(tr, sep))
  106. }
  107. return nil
  108. }