diff --git a/handlers/media.go b/handlers/media.go index 136040584..f1a51bd53 100644 --- a/handlers/media.go +++ b/handlers/media.go @@ -20,8 +20,10 @@ const ( ) type MediaTypeSupport struct { - Types []string - MaxBytes int + Types []string + MaxBytes int + MaxWidth int + MaxHeight int } // Attachment is a resolved attachment @@ -84,7 +86,10 @@ func resolveAttachment(ctx context.Context, b courier.Backend, contentType, medi } mediaType, _ := parseContentType(media.ContentType()) - mediaSupport := support[mediaType] + mediaSupport, ok := support[MediaType(media.ContentType())] + if !ok { + mediaSupport = support[mediaType] + } // our candidates are the uploaded media and any alternates of the same media type candidates := append([]courier.Media{media}, filterMediaByType(media.Alternates(), mediaType)...) @@ -99,6 +104,11 @@ func resolveAttachment(ctx context.Context, b courier.Backend, contentType, medi candidates = filterMediaBySize(candidates, mediaSupport.MaxBytes) } + // narrow down the candidates to the ones that don't exceed our max dimensions + if mediaSupport.MaxWidth > 0 && mediaSupport.MaxHeight > 0 { + candidates = filterMediaByDimensions(candidates, mediaSupport.MaxWidth, mediaSupport.MaxHeight) + } + // if we have no candidates, we can't use this media if len(candidates) == 0 { return nil, nil @@ -144,6 +154,10 @@ func filterMediaBySize(in []courier.Media, maxBytes int) []courier.Media { return filterMedia(in, func(m courier.Media) bool { return m.Size() <= maxBytes }) } +func filterMediaByDimensions(in []courier.Media, maxWidth int, MaxHeight int) []courier.Media { + return filterMedia(in, func(m courier.Media) bool { return m.Width() <= maxWidth && m.Height() <= MaxHeight }) +} + func filterMedia(in []courier.Media, f func(courier.Media) bool) []courier.Media { filtered := make([]courier.Media, 0, len(in)) for _, m := range in { diff --git a/handlers/media_test.go b/handlers/media_test.go index 5fd132db6..15ac0df5c 100644 --- a/handlers/media_test.go +++ b/handlers/media_test.go @@ -139,6 +139,28 @@ func TestResolveAttachments(t *testing.T) { mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{}, err: "invalid attachment format: http://mock.com/1234/test.jpg", }, + { // 14: resolveable uploaded image URL with matching dimensions + attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}, MaxWidth: 1000, MaxHeight: 1000}}, + allowURLOnly: true, + resolved: []*handlers.Attachment{ + {Type: handlers.MediaTypeImage, Name: "test.jpg", ContentType: "image/jpeg", URL: "http://mock.com/1234/test.jpg", Media: imageJPG, Thumbnail: nil}, + }, + }, + { // 15: resolveable uploaded image URL without matching dimensions + attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}, MaxWidth: 100, MaxHeight: 100}}, + allowURLOnly: true, + resolved: []*handlers.Attachment{}, + }, + { // 16: resolveable uploaded image URL without matching dimensions by specific content type precendence + attachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"}, + mediaSupport: map[handlers.MediaType]handlers.MediaTypeSupport{handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}, MaxWidth: 100, MaxHeight: 100}, handlers.MediaType("image/jpeg"): {Types: []string{"image/jpeg", "image/png"}, MaxWidth: 1000, MaxHeight: 1000}}, + allowURLOnly: true, + resolved: []*handlers.Attachment{ + {Type: handlers.MediaTypeImage, Name: "test.jpg", ContentType: "image/jpeg", URL: "http://mock.com/1234/test.jpg", Media: imageJPG, Thumbnail: nil}, + }, + }, } for i, tc := range tcs {