close
Skip to content

[Website] Use content-type: application/octet-stream for CORS proxy requests#3364

Merged
adamziel merged 8 commits intotrunkfrom
fix/cors-proxy-multipart-body
Mar 10, 2026
Merged

[Website] Use content-type: application/octet-stream for CORS proxy requests#3364
adamziel merged 8 commits intotrunkfrom
fix/cors-proxy-multipart-body

Conversation

@adamziel
Copy link
Collaborator

@adamziel adamziel commented Mar 10, 2026

Summary

When sending requests through the CORS proxy, PHP runtime automatically parses the multipart/form-data body into $_POST/$_FILES, emptying php://input and removing our ability to pass through the unchanged request body.

This PR:

  • Replaces the Content-type with application/octet-stream
  • Sends the original Content-type via X-Cors-Proxy-Content-Type
  • Adjusts the cors-proxy.php implementation to support is
  • Simplifies the request body streaming and fetching. No more duplexSafeFetch function. We only buffer when sending to the local dev server's CORS proxy. It turns out that change was misguided and we can actually send streamed request bodies to the production CORS proxy.

Deployment note

The Playground changes and the CORS proxy changes must be deployed at the same time.

Test plan

  • Run npx nx test php-wasm-web-service-worker — all tests pass including Content-Type wrapping and body buffering tests
  • Run npx nx test playground-php-cors-proxy — CORS proxy tests pass
  • Test site import through CORS proxy with a multipart/form-data POST body
  • Verify GET requests through CORS proxy are unaffected
  • Verify non-multipart POST requests through CORS proxy are unaffected

When PHP receives a multipart/form-data POST request, it automatically
parses the body into $_POST and $_FILES, emptying php://input. If file
uploads are disabled or fail on the production server, both $_POST and
$_FILES end up empty, and the proxy falls back to reading from the
already-empty php://input. This causes curl to fail with "client read
function EOF fail, only 0/N of needed bytes read".

The fix wraps the Content-Type header before sending through the CORS
proxy: multipart/form-data is replaced with application/octet-stream
(which PHP doesn't auto-parse), and the original Content-Type is stored
in X-Cors-Proxy-Content-Type. The proxy restores the original
Content-Type for the outgoing curl request to the target server.
Copilot AI review requested due to automatic review settings March 10, 2026 11:35
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes multipart/form-data POST bodies being lost when retrying requests via the PHP CORS proxy by preventing PHP from auto-parsing multipart requests and ensuring the proxy forwards the raw body correctly.

Changes:

  • Wrap multipart/form-data Content-Type as application/octet-stream (and preserve original in x-cors-proxy-content-type) before proxying.
  • Restore the original Content-Type in the PHP proxy while blocking the internal wrapper header from being forwarded.
  • Add a unit test covering Content-Type wrapping and body preservation on the proxy retry path.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
packages/playground/php-cors-proxy/cors-proxy.php Accepts the new wrapper header, prevents it from being forwarded, and restores the original Content-Type for outgoing curl requests.
packages/php-wasm/web-service-worker/src/fetch-with-cors-proxy.ts Wraps multipart Content-Type and buffers request bodies before proxying to avoid streaming/body-consumption issues.
packages/php-wasm/web-service-worker/src/fetch-with-cors-proxy.spec.ts Adds coverage ensuring Content-Type wrapping and request body integrity during proxy retry.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

… omission

Reject X-Cors-Proxy-Content-Type values containing CR/LF characters to
prevent header injection toward the upstream server. Use explicit null
check instead of truthiness. Add comment explaining why init is not
forwarded to duplexSafeFetch in the retry path.
The mock CORS proxy in the test needs to restore X-Cors-Proxy-Content-Type
back to Content-Type when forwarding to the target, matching the behavior
of the real PHP CORS proxy.
@adamziel adamziel marked this pull request as draft March 10, 2026 14:30
adamziel and others added 4 commits March 10, 2026 15:53
Move body buffering from the CORS proxy catch block into duplexSafeFetch
so it applies universally. This avoids duplex streaming issues for all
protocols and ensures the CORS proxy always receives a fully buffered
body.
Direct requests (localhost, no-proxy HTTPS) now pass through to
fetch() without buffering. Only CORS proxy retries buffer the body.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@adamziel adamziel marked this pull request as ready for review March 10, 2026 22:09
@adamziel adamziel changed the title Fix CORS proxy losing POST body for multipart/form-data requests [Website] Buffer POST body for all CORS proxy requests Mar 10, 2026
@adamziel adamziel changed the title [Website] Buffer POST body for all CORS proxy requests [Website] Buffer the request body stream for all CORS proxy requests Mar 10, 2026
@adamziel adamziel changed the title [Website] Buffer the request body stream for all CORS proxy requests [Website] Use Content-Type: application/octet-stream instead of multipart/form-data in the cors Proxy Mar 10, 2026
Streaming bodies over HTTP/1.1 fail in Chrome due to ALPN negotiation.
Buffer only when the CORS proxy URL uses http:// (dev server), not always.
Also fix cloneRequest to properly pass through body overrides.
@adamziel adamziel changed the title [Website] Use Content-Type: application/octet-stream instead of multipart/form-data in the cors Proxy Fix CORS proxy losing POST body for multipart/form-data requests Mar 10, 2026
@adamziel adamziel changed the title Fix CORS proxy losing POST body for multipart/form-data requests [Website] Use content-type: application/octet-stream for CORS proxy requests Mar 10, 2026
@adamziel adamziel merged commit e0b3232 into trunk Mar 10, 2026
43 checks passed
@adamziel adamziel deleted the fix/cors-proxy-multipart-body branch March 10, 2026 23:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants