Comparing version 4.12.1 to 4.12.2
@@ -574,3 +574,3 @@ # Dispatcher | ||
As demonstrated in [Example 1 - Basic GET stream request](#example-1---basic-get-stream-request), it is recommended to use the `option.opaque` property to avoid creating a closure for the `factory` method. This pattern works well with Node.js Web Frameworks such as [Fastify](https://fastify.io). See [Example 2 - Stream to Fastify Response](#example-2---stream-to-fastify-response) for more details. | ||
As demonstrated in [Example 1 - Basic GET stream request](#example-1-basic-get-stream-request), it is recommended to use the `option.opaque` property to avoid creating a closure for the `factory` method. This pattern works well with Node.js Web Frameworks such as [Fastify](https://fastify.io). See [Example 2 - Stream to Fastify Response](#example-2-stream-to-fastify-response) for more details. | ||
@@ -577,0 +577,0 @@ Arguments: |
# Mocking Request | ||
Undici have its own mocking [utility](docs/api/MockAgent.md). It allow us to intercept undici HTTP request and return mocked value instead. It can be useful for testing purposes. | ||
Undici have its own mocking [utility](../api/MockAgent.md). It allow us to intercept undici HTTP request and return mocked value instead. It can be useful for testing purposes. | ||
@@ -73,3 +73,3 @@ Example: | ||
Explore other MockAgent functionality [here](docs/api/MockAgent.md) | ||
Explore other MockAgent functionality [here](../api/MockAgent.md) | ||
@@ -76,0 +76,0 @@ ## Debug Mock Value |
@@ -5,3 +5,3 @@ # Connecting through a proxy | ||
- Using [AgentProxy](docs/api/ProxyAgent.md). | ||
- Using [AgentProxy](../api/ProxyAgent.md). | ||
- Configuring `Client` or `Pool` constructor. | ||
@@ -8,0 +8,0 @@ |
@@ -61,2 +61,3 @@ 'use strict' | ||
// https://fetch.spec.whatwg.org/#forbidden-response-header-name | ||
const forbiddenResponseHeaderNames = ['set-cookie', 'set-cookie2'] | ||
@@ -63,0 +64,0 @@ |
@@ -32,3 +32,5 @@ // https://github.com/Ethan-Arrowood/undici-fetch | ||
determineRequestsReferrer, | ||
coarsenedSharedCurrentTime | ||
coarsenedSharedCurrentTime, | ||
createDeferredPromise, | ||
sameOrigin | ||
} = require('./util') | ||
@@ -209,4 +211,10 @@ const { kState, kHeaders, kGuard, kRealm } = require('./symbols') | ||
// https://fetch.spec.whatwg.org/#finalize-and-report-timing | ||
function finalizeAndReportTiming (response, initiatorType = 'other') { | ||
// 1. If response’s URL list is null or empty, then return. | ||
// 1. If response is an aborted network error, then return. | ||
if (response.type === 'error' && response.aborted) { | ||
return | ||
} | ||
// 2. If response’s URL list is null or empty, then return. | ||
if (!response.urlList?.length) { | ||
@@ -216,12 +224,17 @@ return | ||
// 2. Let originalURL be response’s URL list[0]. | ||
// 3. Let originalURL be response’s URL list[0]. | ||
const originalURL = response.urlList[0] | ||
// 3. Let timingInfo be response’s timing info. | ||
// 4. Let timingInfo be response’s timing info. | ||
let timingInfo = response.timingInfo | ||
// 4. Let cacheState be response’s cache state. | ||
// 5. Let cacheState be response’s cache state. | ||
let cacheState = response.cacheState | ||
// 5. If timingInfo is null, then return. | ||
// 6. If originalURL’s scheme is not an HTTP(S) scheme, then return. | ||
if (!/^https?:/.test(originalURL.protocol)) { | ||
return | ||
} | ||
// 7. If timingInfo is null, then return. | ||
if (timingInfo === null) { | ||
@@ -231,3 +244,3 @@ return | ||
// 6. If response’s timing allow passed flag is not set, then: | ||
// 8. If response’s timing allow passed flag is not set, then: | ||
if (!timingInfo.timingAllowPassed) { | ||
@@ -243,3 +256,3 @@ // 1. Set timingInfo to a the result of creating an opaque timing info for timingInfo. | ||
// 7. Set timingInfo’s end time to the coarsened shared current time | ||
// 9. Set timingInfo’s end time to the coarsened shared current time | ||
// given global’s relevant settings object’s cross-origin isolated | ||
@@ -251,6 +264,6 @@ // capability. | ||
// 8. Set response’s timing info to timingInfo. | ||
// 10. Set response’s timing info to timingInfo. | ||
response.timingInfo = timingInfo | ||
// 9. Mark resource timing for timingInfo, originalURL, initiatorType, | ||
// 11. Mark resource timing for timingInfo, originalURL, initiatorType, | ||
// global, and cacheState. | ||
@@ -261,3 +274,3 @@ markResourceTiming( | ||
initiatorType, | ||
global, | ||
globalThis, | ||
cacheState | ||
@@ -432,9 +445,9 @@ ) | ||
request.headersList.append('accept', value) | ||
} | ||
// 12. If request’s header list does not contain `Accept-Language`, then | ||
// user agents should append `Accept-Language`/an appropriate value to | ||
// request’s header list. | ||
if (!request.headersList.has('accept-language')) { | ||
request.headersList.append('accept-language', '*') | ||
} | ||
// 12. If request’s header list does not contain `Accept-Language`, then | ||
// user agents should append `Accept-Language`/an appropriate value to | ||
// request’s header list. | ||
if (!request.headersList.has('accept-language')) { | ||
request.headersList.append('accept-language', '*') | ||
} | ||
@@ -479,3 +492,3 @@ | ||
) { | ||
return makeNetworkError('local URLs only') | ||
response = makeNetworkError('local URLs only') | ||
} | ||
@@ -493,3 +506,3 @@ | ||
if (requestBadPort(request) === 'blocked') { | ||
return makeNetworkError('bad port') | ||
response = makeNetworkError('bad port') | ||
} | ||
@@ -688,3 +701,3 @@ // TODO: should fetching request be blocked as mixed content? | ||
const processBodyError = (reason) => | ||
fetchFinale(fetchParams, makeNetworkError(reason)) | ||
fetchFinale.call(context, fetchParams, makeNetworkError(reason)) | ||
@@ -712,3 +725,3 @@ // 2. If request’s response tainting is "opaque", or response’s body is null, | ||
// 3. Run fetch finale given fetchParams and response. | ||
fetchFinale(fetchParams, response) | ||
fetchFinale.call(context, fetchParams, response) | ||
} | ||
@@ -724,3 +737,3 @@ | ||
// 21. Otherwise, run fetch finale given fetchParams and response. | ||
fetchFinale(fetchParams, response) | ||
fetchFinale.call(context, fetchParams, response) | ||
} | ||
@@ -746,5 +759,20 @@ } | ||
// 1. If fetchParams’s process response is non-null, | ||
// then queue a fetch task to run fetchParams’s process response | ||
// given response, with fetchParams’s task destination. | ||
// 1. If response is a network error, then: | ||
if (response.type === 'error') { | ||
// 1. Set response’s URL list to « fetchParams’s request’s URL list[0] ». | ||
response.urlList = [fetchParams.request.urlList[0]] | ||
// 2. Set response’s timing info to the result of creating an opaque timing | ||
// info for fetchParams’s timing info. | ||
response.timingInfo = createOpaqueTimingInfo({ | ||
startTime: fetchParams.timingInfo.startTime | ||
}) | ||
} | ||
// 2. Let processResponseEndOfBody be the following steps: | ||
// TODO | ||
// 3. If fetchParams’s process response is non-null, then queue a fetch task | ||
// to run fetchParams’s process response given response, with fetchParams’s | ||
// task destination. | ||
if (fetchParams.processResponse != null) { | ||
@@ -754,19 +782,18 @@ fetchParams.processResponse(response) | ||
// 2. If fetchParams’s process response consume is non-null, then:. | ||
// TODO | ||
// 1. Let processBody given nullOrBytes be this step: run fetchParams’s | ||
// process response consume given response and nullOrBytes.on. | ||
// TODO | ||
// 2. Let processBodyError be this step: run fetchParams’s process | ||
// response consume given response and failure.on. | ||
// TODO | ||
// 3. If response’s body is null, then queue a fetch task to run | ||
// processBody given null, with fetchParams’s task destination.on. | ||
// TODO | ||
// 4. Otherwise, fully read response’s body given processBody, | ||
// processBodyError, and fetchParams’s task destination.on. | ||
// TODO | ||
// 4. If fetchParams’s process response is non-null, then queue a fetch task | ||
// to run fetchParams’s process response given response, with fetchParams’s | ||
// task destination. | ||
// TODO | ||
// TODO (spec): The spec doesn't specify this but we need to | ||
// terminate fetch if we have an error response. | ||
// 5. If response’s body is null, then run processResponseEndOfBody. | ||
// TODO | ||
// 6. Otherwise: | ||
// TODO | ||
// 7. If fetchParams’s process response consume body is non-null, then: | ||
// TODO | ||
// TODO: This is a workaround. Until the above has been implemented, i.e. | ||
// we need to either fully consume the body or terminate the fetch. | ||
if (response.type === 'error') { | ||
@@ -930,3 +957,3 @@ context.terminate({ reason: response.error }) | ||
(locationURL.username || locationURL.password) && | ||
request.origin !== locationURL.origin | ||
!sameOrigin(request, locationURL) | ||
) { | ||
@@ -957,13 +984,3 @@ return makeNetworkError('cross origin not allowed for request mode "cors"') | ||
// 12. If locationURL’s origin is not same origin with request’s current URL’s | ||
// origin and request’s origin is not same origin with request’s current | ||
// URL’s origin, then set request’s tainted origin flag. | ||
if ( | ||
locationURL.origin !== requestCurrentURL(request).origin && | ||
request.origin !== locationURL.origin | ||
) { | ||
request.taintedOrigin = true | ||
} | ||
// 13. If one of the following is true | ||
// 12. If one of the following is true | ||
// - actualResponse’s status is 301 or 302 and request’s method is `POST` | ||
@@ -988,3 +1005,3 @@ // - actualResponse’s status is 303 and request’s method is not `GET` or `HEAD` | ||
// 14. If request’s body is non-null, then set request’s body to the first return | ||
// 13. If request’s body is non-null, then set request’s body to the first return | ||
// value of safely extracting request’s body’s source. | ||
@@ -996,6 +1013,6 @@ if (request.body != null) { | ||
// 15. Let timingInfo be fetchParams’s timing info. | ||
// 14. Let timingInfo be fetchParams’s timing info. | ||
const timingInfo = fetchParams.timingInfo | ||
// 16. Set timingInfo’s redirect end time and post-redirect start time to the | ||
// 15. Set timingInfo’s redirect end time and post-redirect start time to the | ||
// coarsened shared current time given fetchParams’s cross-origin isolated | ||
@@ -1006,3 +1023,3 @@ // capability. | ||
// 17. If timingInfo’s redirect start time is 0, then set timingInfo’s | ||
// 16. If timingInfo’s redirect start time is 0, then set timingInfo’s | ||
// redirect start time to timingInfo’s start time. | ||
@@ -1013,10 +1030,10 @@ if (timingInfo.redirectStartTime === 0) { | ||
// 18. Append locationURL to request’s URL list. | ||
// 17. Append locationURL to request’s URL list. | ||
request.urlList.push(locationURL) | ||
// 19. Invoke set request’s referrer policy on redirect on request and | ||
// 18. Invoke set request’s referrer policy on redirect on request and | ||
// actualResponse. | ||
setRequestReferrerPolicyOnRedirect(request, actualResponse) | ||
// 20. Return the result of running main fetch given fetchParams and true. | ||
// 19. Return the result of running main fetch given fetchParams and true. | ||
return mainFetch.call(this, fetchParams, true) | ||
@@ -1609,9 +1626,6 @@ } | ||
function onResponseAborted () { | ||
// 1. Finalize response for fetchParams and response. | ||
finalizeResponse(fetchParams, response) | ||
// 2. Let aborted be the termination’s aborted flag. | ||
// 1. Let aborted be the termination’s aborted flag. | ||
const aborted = this.terminated.aborted | ||
// 3. If aborted is set, then: | ||
// 2. If aborted is set, then: | ||
if (aborted) { | ||
@@ -1626,3 +1640,3 @@ // 1. Set response’s aborted flag. | ||
} else { | ||
// 4. Otherwise, if stream is readable, error stream with a TypeError. | ||
// 3. Otherwise, if stream is readable, error stream with a TypeError. | ||
if (isReadable(stream)) { | ||
@@ -1633,4 +1647,4 @@ this.controller.error(new TypeError('terminated')) | ||
// 5. If connection uses HTTP/2, then transmit an RST_STREAM frame. | ||
// 6. Otherwise, the user agent should close connection unless it would be bad for performance to do so. | ||
// 4. If connection uses HTTP/2, then transmit an RST_STREAM frame. | ||
// 5. Otherwise, the user agent should close connection unless it would be bad for performance to do so. | ||
this.connection.destroy() | ||
@@ -1828,13 +1842,2 @@ } | ||
function createDeferredPromise () { | ||
let res | ||
let rej | ||
const promise = new Promise((resolve, reject) => { | ||
res = resolve | ||
rej = reject | ||
}) | ||
return { promise, resolve: res, reject: rej } | ||
} | ||
module.exports = fetch |
@@ -124,3 +124,3 @@ /* globals AbortController */ | ||
request.window instanceof EnvironmentSettingsObject && | ||
request.window.origin === origin | ||
sameOrigin(request.window, origin) | ||
) { | ||
@@ -127,0 +127,0 @@ window = request.window |
@@ -11,3 +11,3 @@ 'use strict' | ||
nullBodyStatus, | ||
forbiddenHeaderNames | ||
forbiddenResponseHeaderNames | ||
} = require('./constants') | ||
@@ -370,2 +370,3 @@ const { kState, kHeaders, kGuard, kRealm } = require('./symbols') | ||
// https://fetch.spec.whatwg.org/#concept-filtered-response | ||
function filterResponse (response, type) { | ||
@@ -381,3 +382,3 @@ // Set response to the following filtered response with response as its | ||
for (let n = 0; n < response.headersList.length; n += 2) { | ||
if (!forbiddenHeaderNames.includes(response.headersList[n])) { | ||
if (!forbiddenResponseHeaderNames.includes(response.headersList[n])) { | ||
headers.push(response.headersList[n + 0], response.headersList[n + 1]) | ||
@@ -384,0 +385,0 @@ } |
@@ -236,3 +236,3 @@ 'use strict' | ||
// If request’s origin is not same origin with request’s current URL’s origin, then set serializedOrigin to `null`. | ||
if (request.origin !== requestCurrentURL(request).origin) { | ||
if (!sameOrigin(request, requestCurrentURL(request))) { | ||
serializedOrigin = null | ||
@@ -301,2 +301,32 @@ } | ||
/** | ||
* @link {https://html.spec.whatwg.org/multipage/origin.html#same-origin} | ||
* @param {URL} A | ||
* @param {URL} B | ||
*/ | ||
function sameOrigin (A, B) { | ||
// 1. If A and B are the same opaque origin, then return true. | ||
// "opaque origin" is an internal value we cannot access, ignore. | ||
// 2. If A and B are both tuple origins and their schemes, | ||
// hosts, and port are identical, then return true. | ||
if (A.protocol === B.protocol && A.hostname === B.hostname && A.port === B.port) { | ||
return true | ||
} | ||
// 3. Return false. | ||
return false | ||
} | ||
function createDeferredPromise () { | ||
let res | ||
let rej | ||
const promise = new Promise((resolve, reject) => { | ||
res = resolve | ||
rej = reject | ||
}) | ||
return { promise, resolve: res, reject: rej } | ||
} | ||
class ServiceWorkerGlobalScope {} // dummy | ||
@@ -310,2 +340,3 @@ class Window {} // dummy | ||
EnvironmentSettingsObject, | ||
createDeferredPromise, | ||
ReadableStreamFrom, | ||
@@ -333,3 +364,4 @@ toUSVString, | ||
isFileLike, | ||
isValidReasonPhrase | ||
isValidReasonPhrase, | ||
sameOrigin | ||
} |
{ | ||
"name": "undici", | ||
"version": "4.12.1", | ||
"version": "4.12.2", | ||
"description": "An HTTP/1.1 client, written from scratch for Node.js", | ||
@@ -5,0 +5,0 @@ "homepage": "https://undici.nodejs.org", |
643534
10240