Skip to content

fix: correct multipart file MIME types and remove duplicate file part - #366

Open
u7k4rs6 wants to merge 1 commit into
razorpay:masterfrom
u7k4rs6:fix/365-multipart-mime
Open

u7k4rs6 wants to merge 1 commit into
razorpay:masterfrom
u7k4rs6:fix/365-multipart-mime

Conversation

@u7k4rs6

@u7k4rs6 u7k4rs6 commented Sep 17, 2026 •

Copy link
Copy Markdown

Problem

The multipart serializer had two issues when uploading files:

  1. getMediaType compared file extensions using ==, causing supported extensions to fall through to the image/pdf fallback. PNGs, JPEGs, and PDFs were therefore sent with incorrect MIME types.

  2. fileRequestBody added the file as a binary multipart part and then added it again as a regular form field, causing the local filesystem path to be sent as a second file value.

Fix

  • Correct MIME type detection for jpg, jpeg, jfif, png, and pdf.
  • Use case-insensitive extension handling with Locale.ROOT.
  • Prevent the file field from being added twice to multipart requests.
  • Preserve the existing fallback behavior for unsupported or extension-less filenames.

Tests

Added regression tests covering:

  • PNG MIME type
  • JPG MIME type
  • JPEG MIME type
  • PDF MIME type
  • Uppercase .PNG
  • Exactly one file multipart part
  • Filename preservation
  • Preservation of other form fields
  • Existing fallback behavior for unsupported extensions

Verification

  • Full test suite: 188 tests, 0 failures, 0 errors
  • Verified on JDK 8
  • No changes to public APIs, dependencies, or pom.xml

Fixes #365


@u7k4rs6

u7k4rs6 commented Sep 19, 2026

Copy link
Copy Markdown
Author

Flagging an overlap I should have noted when opening this: #348 (@sahilleth, Feb 2026) already fixes the == comparison in getMediaType, and predates this PR. Maintainers should feel free to prefer it — I'm not trying to jump the queue.

Where the two differ, in case it's useful for deciding:

This PR additionally fixes the second defect in #365 — fileRequestBody adds file as a binary part and then re-adds it as a text field while iterating the request keys, so every upload sends two file parts and puts the caller's local filesystem path on the wire. #348 does not touch that. Measured on current master:

proof.png  ->  Content-Type: image/pdf,  3 parts / 2 named "file"

Unknown extensions. #348 returns application/octet-stream; this PR keeps the pre-existing image/pdf fallback. That was deliberate: getMediaType is shared with AccountClient.uploadAccountDoc and StakeholderClient.uploadStakeholderDoc, and I couldn't establish from this repository which formats those onboarding endpoints accept, so I avoided changing behaviour for files that upload successfully today. If you can confirm the accepted set, application/octet-stream (or a hard rejection) is easy to switch to.

One small thing worth taking from here into whichever PR you merge: toLowerCase() without a locale is locale-sensitive. Under tr-TR the dotted I lowercases to ı, so photo.JFIF becomes jfıf and fails to match:

PNG->png ok   JPG->jpg ok   JPEG->jpeg ok   PDF->pdf ok
JFIF->jfıf  <-- diverges

toLowerCase(Locale.ROOT) avoids it. Only JFIF is affected, since it's the one supported extension containing an I.

Happy to close this in favour of #348 and re-submit the duplicate-part fix separately if that's cleaner for review.

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.

Document multipart serializer mislabels MIME and emits duplicate file parts

1 participant