fix(blob): infer callback URL from node headers#1044
fix(blob): infer callback URL from node headers#1044matingathani wants to merge 1 commit intovercel:mainfrom
Conversation
|
@matingathani is attempting to deploy a commit to the Curated Tests - Permanent E2E Team on Vercel. A member of the Team first needs to authorize it. |
🦋 Changeset detectedLatest commit: ae65cd2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Pull request overview
Adds a Node-specific fallback to infer onUploadCompleted callback URLs from request headers when onBeforeGenerateToken() doesn’t return an explicit callbackUrl, addressing cases where callbacks weren’t firing off-Vercel.
Changes:
- Infer callback URL from Node request headers (
x-forwarded-host,x-forwarded-proto,host) when needed. - Default inferred protocol to
httpfor localhost hosts. - Add regression tests for forwarded-host/proto and localhost Node request flows, plus a patch changeset.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
packages/blob/src/client.ts |
Adds header-based callback URL inference helpers and integrates them into getCallbackUrl(). |
packages/blob/src/client.node.test.ts |
Adds tests validating forwarded header precedence and localhost protocol inference. |
.changeset/fix-blob-handle-upload-callback-url.md |
Publishes a patch changeset describing the fix. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function hasHeadersGet( | ||
| headers: IncomingMessage['headers'] | Headers | undefined, | ||
| ): headers is Headers { | ||
| return typeof headers === 'object' && headers !== null && 'get' in headers; |
There was a problem hiding this comment.
hasHeadersGet() can return a false positive when the Node IncomingMessage.headers object contains a header named get (header names are lowercased), because 'get' in headers will then be true but headers.get will be a string/string[]. This would cause a runtime TypeError when calling request.headers.get(...). Consider tightening the guard to check that get is actually a function (e.g., typeof (headers as any).get === 'function') before treating it as a Headers instance.
| return typeof headers === 'object' && headers !== null && 'get' in headers; | |
| return ( | |
| typeof headers === 'object' && | |
| headers !== null && | |
| typeof (headers as { get?: unknown }).get === 'function' | |
| ); |
| } | ||
|
|
||
| function inferProtocol(host: string): 'http' | 'https' { | ||
| return host.startsWith('localhost') || host.startsWith('127.0.0.1') |
There was a problem hiding this comment.
inferProtocol() uses startsWith('localhost') / startsWith('127.0.0.1'), which will misclassify non-local hosts like localhost.example.com as http, and it doesn’t cover common local hosts like [::1] (IPv6 loopback). Consider parsing out the hostname (strip port / brackets) and doing exact matches against known loopback names/addresses (e.g., localhost, 127.0.0.1, ::1, maybe 0.0.0.0) before defaulting to https.
| return host.startsWith('localhost') || host.startsWith('127.0.0.1') | |
| const normalizedHost = host.trim().toLowerCase(); | |
| let hostname: string; | |
| if (normalizedHost.startsWith('[')) { | |
| const closingBracketIndex = normalizedHost.indexOf(']'); | |
| hostname = | |
| closingBracketIndex === -1 | |
| ? normalizedHost.slice(1) | |
| : normalizedHost.slice(1, closingBracketIndex); | |
| } else { | |
| hostname = normalizedHost.split(':', 1)[0] ?? normalizedHost; | |
| } | |
| return hostname === 'localhost' || | |
| hostname === '127.0.0.1' || | |
| hostname === '::1' || | |
| hostname === '0.0.0.0' |
|
A note on the fallback order here: |
Summary
Fixes #874
When
handleUpload()is used withonUploadCompleted()and no explicitcallbackUrlis returned fromonBeforeGenerateToken(), the SDK should stillbe able to infer a callback URL for Node handlers from public request headers.
This change adds a fallback that uses
x-forwarded-host,x-forwarded-proto, andhostto infer the callback URL before falling back toVercel environment variables only.
Changes
onUploadCompletedis sethttp@vercel/blobTest Plan
pnpm -C packages/blob run test:nodehttp