Skip to content

Commit 3cc4c02

Browse files
committed
feat: enhance image processing to support custom S3 object retrieval and improve error handling
1 parent 976cf6a commit 3cc4c02

1 file changed

Lines changed: 52 additions & 32 deletions

File tree

routes/image.go

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/dgraph-io/ristretto/v2"
2020
"github.com/kolesa-team/go-webp/encoder"
2121
"github.com/kolesa-team/go-webp/webp"
22+
"github.com/minio/minio-go/v7"
2223
)
2324

2425
const (
@@ -120,47 +121,66 @@ func processImageResponse(c *fiber.Ctx, logger *zap.Logger, cache *ristretto.Cac
120121
}
121122
}
122123

123-
// If no URL is provided at this point, we can't fetch from remote
124-
if params.Url == "" {
124+
var processingBody []byte
125+
var parsedContentType string
126+
127+
if params.CustomObjectKey != "" {
128+
object, err := s3cache.Client.GetObject(context.Background(), s3cache.Bucket, params.CustomObjectKey, minio.GetObjectOptions{})
129+
if err != nil {
130+
logger.Error("failed to get object from S3", zap.String("custom_object_key", params.CustomObjectKey), zap.Error(err))
131+
return c.Status(fiber.StatusInternalServerError).SendString("failed to get object from S3")
132+
}
133+
134+
stat, err := object.Stat()
135+
if err != nil {
136+
logger.Error("failed to stat object from S3", zap.String("custom_object_key", params.CustomObjectKey), zap.Error(err))
137+
return c.Status(fiber.StatusInternalServerError).SendString("failed to stat object from S3")
138+
}
139+
140+
processingBody, err = io.ReadAll(object)
141+
parsedContentType = stat.ContentType
142+
} else if params.Url == "" {
143+
// If no URL is provided at this point, we can't fetch from remote
144+
125145
logger.Error("no URL provided and no valid S3 location", zap.String("custom_object_key", params.CustomObjectKey))
126146
return c.Status(fiber.StatusBadRequest).SendString("no URL or valid location provided")
127-
}
128-
129-
response, err := client.GetHTTPClient().Get(params.Url)
130-
if err != nil {
131-
logger.Error("failed to fetch image", zap.Error(err), zap.String("url", params.Url), zap.String("hostname", params.Hostname))
132-
return c.Status(fiber.StatusInternalServerError).SendString("failed to fetch image")
133-
}
134-
defer func() {
135-
if closeErr := response.Body.Close(); closeErr != nil {
136-
logger.Error("failed to close response body", zap.Error(closeErr), zap.String("url", params.Url))
147+
} else {
148+
response, err := client.GetHTTPClient().Get(params.Url)
149+
if err != nil {
150+
logger.Error("failed to fetch image", zap.Error(err), zap.String("url", params.Url), zap.String("hostname", params.Hostname))
151+
return c.Status(fiber.StatusInternalServerError).SendString("failed to fetch image")
137152
}
138-
}()
153+
defer func() {
154+
if closeErr := response.Body.Close(); closeErr != nil {
155+
logger.Error("failed to close response body", zap.Error(closeErr), zap.String("url", params.Url))
156+
}
157+
}()
139158

140-
responseContentType := response.Header.Get("Content-Type")
141-
if responseContentType == "" {
142-
logger.Error("no content type received from remote", zap.String("url", params.Url), zap.String("hostname", params.Hostname))
143-
return c.Status(fiber.StatusForbidden).SendString("no content type received")
144-
}
159+
responseContentType := response.Header.Get("Content-Type")
160+
if responseContentType == "" {
161+
logger.Error("no content type received from remote", zap.String("url", params.Url), zap.String("hostname", params.Hostname))
162+
return c.Status(fiber.StatusForbidden).SendString("no content type received")
163+
}
145164

146-
parsedContentType, _, err := mime.ParseMediaType(responseContentType)
147-
if err != nil {
148-
logger.Error("failed to parse content type", zap.String("content_type", responseContentType), zap.Error(err), zap.String("url", params.Url))
149-
return c.Status(fiber.StatusInternalServerError).SendString("failed to parse content type")
150-
}
165+
parsedContentType, _, err := mime.ParseMediaType(responseContentType)
166+
if err != nil {
167+
logger.Error("failed to parse content type", zap.String("content_type", responseContentType), zap.Error(err), zap.String("url", params.Url))
168+
return c.Status(fiber.StatusInternalServerError).SendString("failed to parse content type")
169+
}
151170

152-
if !validation.IsImageMime(parsedContentType) {
153-
logger.Error("invalid image mime type", zap.String("mime_type", parsedContentType), zap.String("url", params.Url), zap.String("hostname", params.Hostname))
154-
return c.Status(fiber.StatusForbidden).SendString(fmt.Sprintf("content type '%s' is not allowed", parsedContentType))
155-
}
171+
if !validation.IsImageMime(parsedContentType) {
172+
logger.Error("invalid image mime type", zap.String("mime_type", parsedContentType), zap.String("url", params.Url), zap.String("hostname", params.Hostname))
173+
return c.Status(fiber.StatusForbidden).SendString(fmt.Sprintf("content type '%s' is not allowed", parsedContentType))
174+
}
156175

157-
responseBody, err := io.ReadAll(response.Body)
158-
if err != nil {
159-
logger.Error("failed to read response body", zap.Error(err), zap.String("url", params.Url), zap.String("hostname", params.Hostname))
160-
return c.Status(fiber.StatusInternalServerError).SendString("failed to read response body")
176+
processingBody, err = io.ReadAll(response.Body)
177+
if err != nil {
178+
logger.Error("failed to read response body", zap.Error(err), zap.String("url", params.Url), zap.String("hostname", params.Hostname))
179+
return c.Status(fiber.StatusInternalServerError).SendString("failed to read response body")
180+
}
161181
}
162182

163-
return processImageData(c, logger, cache, config, counters, params, responseBody, parsedContentType, s3cache)
183+
return processImageData(c, logger, cache, config, counters, params, processingBody, parsedContentType, s3cache)
164184
}
165185

166186
//#endregion

0 commit comments

Comments
 (0)