Skip to content

feat: curl -F multipart form data support #288

@chaliy

Description

@chaliy

Description

The curl builtin does not support -F (multipart form data uploads). The flag is silently ignored by the unknown-option fallback at curl.rs:158. This means file upload commands like curl -F "file=@archive.tgz" execute but send no data body, producing incorrect HTTP requests.

Reproduction

# Upload a file via multipart form
echo "test content" > /tmp/upload.txt
curl -s -X POST "https://httpbin.org/post" -F "file=@/tmp/upload.txt"
# BUG: -F flag silently ignored, sends empty POST instead of multipart form

# Upload with multiple form fields
curl -s -X POST "https://example.com/api" -F "file=@/tmp/project.tgz" -F "framework=nextjs"
# BUG: both -F flags ignored, framework field not sent

# The -F flag should:
# 1. Set Content-Type to multipart/form-data with boundary
# 2. For "key=value": send as text field
# 3. For "key=@filepath": read file and send as file upload
# 4. Imply POST method (like -d does)

Source: skills.sh leaderboard

Skill: vercel-deploy-claimable from vercel-labs/agent-skills (~58K installs)

Script: skills/claude.ai/vercel-deploy-claimable/scripts/deploy.sh line 222:

RESPONSE=$(curl -s -X POST "$DEPLOY_ENDPOINT" -F "file=@$TARBALL" -F "framework=$FRAMEWORK")

This is a 250-line deployment script that packages a web project into a tarball and uploads it via multipart POST. The entire bash portion of the script (nested functions, trap, mktemp, tar, grep -o, cut, [[ ]] globs, >&2 redirection) works perfectly in bashkit — the only gap is curl -F.

Cross-ref: specs/015-skills-analysis.md — External binaries table lists curl -F as PARTIAL.

Current implementation

curl.rs:79-162 parses flags in a sequential match. Unknown flags (including -F) hit the fallback at line 158:

_ => {
    // Ignore unknown options for compatibility
}

This silently drops -F and its argument, so the upload never happens.

Suggested scope

Multipart form data support for -F/--form:

  • -F "key=value" — text form field
  • -F "key=@filepath" — file upload (read from VFS, detect MIME from extension)
  • -F "key=@filepath;type=mime" — explicit MIME type
  • Multiple -F flags in one command
  • Auto-set Content-Type: multipart/form-data; boundary=...
  • Imply POST if no -X specified (same as -d behavior at line 107)

Implementation notes

The multipart/form-data format is straightforward (RFC 2046 boundary-delimited parts). File contents read from ctx.fs (VFS). No new crate dependency needed — can build MIME body from string concatenation with a random boundary. The existing execute_curl_request function at line 236 would need a new body variant alongside the current data: Option<String>.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions