fix(api,imports): force parameter-free Content-Type on multipart file part#24
Conversation
… part
Caught during the live smoke test of \`imports preflight --file\` against a
real Sure instance: the upload was rejected with
\`{"error":"invalid_file_type","message":"Invalid file type. Please upload a CSV file."}\`
even though Sure's allow-list (\`Import::ALLOWED_CSV_MIME_TYPES\`) accepts
\`text/csv\`, \`text/plain\`, \`application/vnd.ms-excel\`, \`application/csv\`.
Root cause: resty's default \`SetFile\` uses Go's \`http.DetectContentType\`
on the first 512 bytes. For an ASCII CSV that returns
\`text/plain; charset=utf-8\`. Sure does an exact-match \`include?\` on the
allow-list, so the charset suffix breaks the check. Empirically verified
with an httptest probe before patching.
\`--raw-file-content\` was a workaround (different code path, server picks
the type from the controller's hardcoded "import.csv" filename).
Fix:
- \`PostMultipart\` gains a \`fileContentType string\` parameter. When
non-empty it switches from \`SetFile\` to \`SetMultipartField\` so the
Content-Type on the file part can be set explicitly. Empty preserves the
current detection behavior.
- New \`mimeForImportFile(path)\` helper in imports_cmd.go maps file
extensions to parameter-free MIME types:
- \`.csv\` → \`text/csv\`
- \`.ndjson\` → \`application/x-ndjson\`
- \`.json\` → \`application/json\` (also in SureImport allow-list)
- other → "" (let resty detect, matching prior behavior)
- Both call sites (\`imports create\`, \`imports preflight\`) thread the
computed type through.
Tests:
- \`TestClient_PostMultipart_ExplicitContentType\` captures the file part's
Content-Type header via httptest and asserts it equals \`text/csv\` when
passed explicitly. Locks in the fix.
- \`TestClient_PostMultipart_DefaultContentType\` confirms \`""\` preserves
resty's auto-detection (non-empty, current behavior).
- Existing \`TestClient_PostMultipart\` updated to the new signature.
- \`TestMimeForImportFile\` unit-tests the extension→MIME map across
case-insensitive matches, absolute paths, unknown extensions.
Verified live against sure.h.dgilperez.com: \`imports preflight --file
test.csv\` now returns the parsed preflight payload with
\`content_type: "text/csv"\` instead of the 422 it produced before.
\`go test ./... -race\` green across the suite.
Refs the post-merge smoke test.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughCLI import commands now send multipart uploads with explicit MIME types derived from file extensions. A new ChangesExplicit MIME type handling for multipart imports
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Suggested labels
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@jjmata hey, I think this PR is the last of the bunch - I tested the cli a bit against my local sure and all seems to work as expected. I think it's time to release 0.2.0, but you probably want to do that yourself? |
Sure, but would love @JSONbored to give this a go as well before we cut a new CLI release. Can you do that? 🙏 |
Caught during a live smoke test of
imports preflight --fileagainst a real Sure instance: the upload was rejected with{"error":"invalid_file_type","message":"Invalid file type. Please upload a CSV file."}…even though Sure's
Import::ALLOWED_CSV_MIME_TYPESacceptstext/csv,text/plain,application/vnd.ms-excel,application/csv.Root cause
resty's default
SetFileuses Go'shttp.DetectContentTypeon the first 512 bytes. For an ASCII CSV that returns **text/plain; charset=utf-8\**. Sure does an exact-matchinclude?` on the allow-list, so the charset suffix breaks the check.Confirmed with an httptest probe:
--raw-file-contentwas a workaround (different code path; server picks the type from the controller's hardcoded"import.csv"filename).Fix
internal/api/client.goPostMultipartgains afileContentType stringparam. When non-empty it switches fromSetFiletoSetMultipartField, setting the Content-Type on the file part explicitly. Empty preserves prior detection behavior.cmd/sure-cli/root/imports_cmd.gomimeForImportFile(path)helper maps extensions to parameter-free MIME types:.csv→text/csv,.ndjson→application/x-ndjson,.json→application/json, other →"".imports create+imports preflightTests
TestClient_PostMultipart_ExplicitContentTypecaptures the file part'sContent-Typeheader via httptest and asserts it equalstext/csvwhen passed explicitly. Locks the fix in.TestClient_PostMultipart_DefaultContentTypeconfirms""preserves resty's auto-detection (non-empty value, prior behavior).TestClient_PostMultipartupdated to the new signature.TestMimeForImportFileunit-tests the extension→MIME map across case-insensitive matches, absolute paths, unknown extensions.go test ./... -racegreen across the suite.Live verification
Before (against live Sure): 422
invalid_file_type.After:
{ "data": { "data": { "content": { "byte_size": 41, "content_type": "text/csv", "filename": "test-import.csv" }, "errors": [], "headers": ["Date", "Name", "Amount"], "valid": true, ...Scope
5 files, +154/-7. Caller signature change is contained — only
imports_cmd.goandimports_preflight_cmd.gousePostMultipart.Refs the post-merge smoke test against sure.h.dgilperez.com.
Summary by CodeRabbit
Improvements
Tests