Skip to content

fix: use registered MIME type for uploaded files instead of image/<ext> - #1618

Open
rstrzelecki-inne-projekty wants to merge 1 commit into
apache:mainfrom
rstrzelecki-inne-projekty:fix/upload-content-type
Open

rstrzelecki-inne-projekty wants to merge 1 commit into
apache:mainfrom
rstrzelecki-inne-projekty:fix/upload-content-type

Conversation

@rstrzelecki-inne-projekty

Copy link
Copy Markdown

Proposed Changes

  • The AvatarThumb middleware sets content-type: image/<extension> for every request under /uploads. For SVG files this produces image/svg, which browsers refuse to render inside <img> (they require image/svg+xml), so SVG branding files or custom badge icons served from /uploads/branding/... show up as broken images. Other extensions get made-up types as well (e.g. image/txt).
  • Use mime.TypeByExtension (Go's built-in table already knows .svgimage/svg+xml, .webp, .jpg, …) and keep the previous image/<ext> guess only as a fallback for unknown extensions.
  • Adds unit tests for the helper and for the middleware behaviour on /uploads/branding/*.svg and *.png.

How to reproduce: put x.svg into /data/uploads/branding/ and request it — response has Content-Type: image/svg, and <img src="/uploads/branding/x.svg"> does not render. With this change: image/svg+xml.

The AvatarThumb middleware sets `content-type: image/<extension>` for every
request under /uploads. For SVG files this yields `image/svg`, which browsers
refuse to render inside <img> (they require `image/svg+xml`), so custom badge
icons or branding files in SVG show up as broken images. Other extensions get
nonsense types too (e.g. `image/txt`).

Use mime.TypeByExtension and keep the previous guess only as a fallback for
unknown extensions. Adds unit tests.
rstrzelecki-inne-projekty pushed a commit to rstrzelecki-inne-projekty/answer that referenced this pull request Sep 15, 2026
@fenbox
fenbox requested a lite review from Copilot September 16, 2026 14:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Updates the upload-serving middleware to set Content-Type using Go’s registered MIME types (fixing SVG rendering by using image/svg+xml), while preserving the legacy image/<ext> fallback for unknown extensions, and adds unit tests to cover the helper and middleware behavior.

Changes:

  • Replace hardcoded image/<ext> content type guessing with mime.TypeByExtension + fallback.
  • Introduce contentTypeByExt helper to centralize MIME resolution.
  • Add unit tests for MIME resolution and /uploads/branding/* middleware behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
internal/base/middleware/avatar.go Uses mime.TypeByExtension via a new helper to set correct Content-Type for uploaded files (notably SVG).
internal/base/middleware/avatar_test.go Adds tests verifying MIME mapping and middleware headers for SVG/PNG under /uploads/branding.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +99 to +104
func contentTypeByExt(ext string) string {
if ct := mime.TypeByExtension(strings.ToLower(ext)); ct != "" {
return ct
}
return fmt.Sprintf("image/%s", strings.TrimPrefix(ext, "."))
}
Comment on lines +31 to +38
func TestContentTypeByExt(t *testing.T) {
assert.Equal(t, "image/svg+xml", contentTypeByExt(".svg"))
assert.Equal(t, "image/png", contentTypeByExt(".png"))
assert.Equal(t, "image/jpeg", contentTypeByExt(".JPG"))
assert.Equal(t, "image/webp", contentTypeByExt(".webp"))
// unknown extension keeps the legacy behaviour
assert.Equal(t, "image/unknownext", contentTypeByExt(".unknownext"))
}
return
}
ctx.Header("content-type", fmt.Sprintf("image/%s", strings.TrimLeft(path.Ext(filePath), ".")))
ctx.Header("content-type", contentTypeByExt(path.Ext(filePath)))
}
ext := strings.TrimPrefix(filepath.Ext(urlInfo.Path), ".")
ctx.Header("content-type", fmt.Sprintf("image/%s", ext))
ctx.Header("content-type", contentTypeByExt(filepath.Ext(urlInfo.Path)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants