Skip to content

guess() is case-sensitive on file extensions, so uppercase suffixes (.PDF, .JPG) resolve to application/octet-stream #3857

Description

Summary

composio/utils/mimetypes.py has two functions that together form the file/MIME utility, and they disagree on case handling.

get_extension_from_mime_type() is deliberately case-insensitive: it lowercases its input and has a test_is_case_insensitive covering it.

guess() looks up Path(file).suffix against the lowercase _types table without normalizing case:

def guess(file: t.Union[str, Path]) -> str:
    return _types.get(Path(file).suffix, _default)

so an uppercase suffix misses the table:

guess("photo.PNG")   # -> "application/octet-stream", not "image/png"
guess("report.PDF")  # -> "application/octet-stream", not "application/pdf"

There's a test_extension_lookup_is_case_sensitive documenting this today, so I wanted to raise it rather than just change it. But it looks unintentional:

  • it's inconsistent with the sibling get_extension_from_mime_type, which is case-insensitive;
  • the stdlib mimetypes.guess_type is also case-insensitive on the extension.

Impact

guess() feeds the mimetype field when uploading files (core/models/_files.py):

mimetype = mimetypes.guess(file=file)

Uppercase extensions are common in practice (phone cameras, scanners, Windows), so those uploads currently get application/octet-stream instead of the correct content type.

Suggested fix

Normalize the suffix before the lookup:

return _types.get(Path(file).suffix.lower(), _default)

and update test_extension_lookup_is_case_sensitive to assert the case-insensitive result. Happy to open the PR if you agree guess() should be case-insensitive like its sibling.

Metadata

Metadata

Labels

bugSomething isn't workingpy

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions