multipart/mixed ordered parts
Parse ordered multipart payloads where part order matters.
Full source
File: pwsh/tutorial/examples/22.4-Multipart-Mixed.ps1
<#!
22.4 multipart/mixed (ordered parts)
Client example (PowerShell):
$boundary = 'mixed-boundary'
$body = @(
"--$boundary",
"Content-Type: text/plain",
"",
"first",
"--$boundary",
"Content-Type: application/json",
"",
'{"value":42}',
"--$boundary--",
""
) -join "`r`n"
Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:$Port/mixed" -ContentType "multipart/mixed; boundary=$boundary" -Body $body
Cleanup:
Remove-Item -Recurse -Force (Join-Path ([System.IO.Path]::GetTempPath()) 'kestrun-uploads-22.4-multipart-mixed')
#>
param(
[int]$Port = 5000,
[IPAddress]$IPAddress = [IPAddress]::Loopback
)
New-KrLogger |
Set-KrLoggerLevel -Value Debug |
Add-KrSinkConsole |
Register-KrLogger -Name 'console' -SetAsDefault
New-KrServer -Name 'Forms 22.4'
Add-KrEndpoint -Port $Port -IPAddress $IPAddress | Out-Null
# Upload directory
$scriptName = [System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath)
$uploadRoot = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "kestrun-uploads-$scriptName"
# Add Rules
# Note: multipart/mixed is parsed as ordered parts. Rules apply when a part includes a Content-Disposition name.
# Opt-in: only multipart/form-data is enabled by default
New-KrFormPartRule -Name 'text' -MaxBytes 1024 |
New-KrFormPartRule -Name 'json' -MaxBytes 1024 |
Add-KrFormOption -DefaultUploadPath $uploadRoot -AllowedRequestContentTypes 'multipart/mixed' |
Add-KrFormRoute -Pattern '/mixed' -ScriptBlock {
$contentTypes = $FormPayload.Parts | ForEach-Object { $_.ContentType }
Write-KrJsonResponse -InputObject @{ count = $FormPayload.Parts.Count; contentTypes = $contentTypes } -StatusCode 200
}
Enable-KrConfiguration
# Start the server asynchronously
Start-KrServer
Step-by-step
- Logger: Enable console logging.
- Server: Create the host and bind a listener.
- Storage: Configure a temporary upload directory.
- Options: Opt in to
multipart/mixedviaAllowedRequestContentTypes. - Route: Add
/mixedwithAdd-KrFormRouteand return ordered content types and count.
Try it
$boundary = 'mixed-boundary'
$body = @(
"--$boundary",
"Content-Disposition: form-data; name=\"text\"",
"Content-Type: text/plain",
"",
"first",
"--$boundary",
"Content-Disposition: form-data; name=\"json\"",
"Content-Type: application/json",
"",
'{"value":42}',
"--$boundary--",
""
) -join "`r`n"
Invoke-RestMethod -Method Post -Uri 'http://127.0.0.1:5000/mixed' -ContentType "multipart/mixed; boundary=$boundary" -Body $body
cat > payload.txt <<'EOF'
--mixed-boundary
Content-Disposition: form-data; name="text"
Content-Type: text/plain
first
--mixed-boundary
Content-Disposition: form-data; name="json"
Content-Type: application/json
{"value":42}
--mixed-boundary--
EOF
curl -X POST -H "Content-Type: multipart/mixed; boundary=mixed-boundary" --data-binary @payload.txt http://127.0.0.1:5000/mixed
Expected output
{
"count": 2,
"contentTypes": ["text/plain", "application/json"]
}
Notes
- Content types:
Add-KrFormRoutedefaults tomultipart/form-dataonly; this script opts in tomultipart/mixed. - Limits:
MaxPartsconstrains how many sections are processed. - Security: Parts are stored to disk without loading whole bodies into memory.
- Logging: Per-part metadata is logged via
host.Logger. - Rules: If you configure
KrPartRule, includeContent-Disposition: ...; name="..."so rules can match ordered parts.
Troubleshooting
- 415 / Unsupported Content-Type: Ensure the request
Content-Typeismultipart/mixed; boundary=...and the route options allow it. - Unexpected part order: For ordered payloads, keep the body exactly in the intended sequence.
References
Previous / Next
Previous: application/x-www-form-urlencoded forms Next: Nested multipart/mixed