Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 74 additions & 7 deletions lib/web/fetch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ const {
simpleRangeHeaderValue,
buildContentRange,
createInflate,
extractMimeType
extractMimeType,
hasAuthenticationEntry,
includesCredentials,
isTraversableNavigable
} = require('./util')
const assert = require('node:assert')
const { safelyExtractBody, extractBody } = require('./body')
Expand Down Expand Up @@ -1524,13 +1527,39 @@ async function httpNetworkOrCacheFetch (

httpRequest.headersList.delete('host', true)

// 20. If includeCredentials is true, then:
// 21. If includeCredentials is true, then:
if (includeCredentials) {
// 1. If the user agent is not configured to block cookies for httpRequest
// (see section 7 of [COOKIES]), then:
// TODO: credentials

// 2. If httpRequest’s header list does not contain `Authorization`, then:
// TODO: credentials
if (!httpRequest.headersList.contains('authorization', true)) {
// 1. Let authorizationValue be null.
let authorizationValue = null

// 2. If there’s an authentication entry for httpRequest and either
// httpRequest’s use-URL-credentials flag is unset or httpRequest’s
// current URL does not include credentials, then set
// authorizationValue to authentication entry.
if (hasAuthenticationEntry(httpRequest) && (
httpRequest.useURLCredentials === undefined || !includesCredentials(requestCurrentURL(httpRequest))
)) {
// TODO
} else if (includesCredentials(requestCurrentURL(httpRequest)) && isAuthenticationFetch) {
// 3. Otherwise, if httpRequest’s current URL does include credentials
// and isAuthenticationFetch is true, set authorizationValue to
// httpRequest’s current URL, converted to an `Authorization` value
const { username, password } = requestCurrentURL(httpRequest)
authorizationValue = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`
}

// 4. If authorizationValue is non-null, then append (`Authorization`,
// authorizationValue) to httpRequest’s header list.
if (authorizationValue !== null) {
httpRequest.headersList.append('Authorization', authorizationValue, false)
}
}
}

// 21. If there’s a proxy-authentication entry, use it as appropriate.
Expand Down Expand Up @@ -1612,10 +1641,48 @@ async function httpNetworkOrCacheFetch (
// 13. Set response’s request-includes-credentials to includeCredentials.
response.requestIncludesCredentials = includeCredentials

// 14. If response’s status is 401, httpRequest’s response tainting is not
// "cors", includeCredentials is true, and request’s window is an environment
// settings object, then:
// TODO
// 14. If response’s status is 401, httpRequest’s response tainting is not "cors",
// includeCredentials is true, and request’s traversable for user prompts is
// a traversable navigable:
if (response.status === 401 && httpRequest.responseTainting !== 'cors' && includeCredentials && isTraversableNavigable(request.traversableForUserPrompts)) {
// 2. If request’s body is non-null, then:
if (request.body != null) {
// 1. If request’s body’s source is null, then return a network error.
if (request.body.source == null) {
return makeNetworkError('expected non-null body source')
}

// 2. Set request’s body to the body of the result of safely extracting
// request’s body’s source.
request.body = safelyExtractBody(request.body.source)[0]
}

// 3. If request’s use-URL-credentials flag is unset or isAuthenticationFetch is
// true, then:
if (request.useURLCredentials === undefined || isAuthenticationFetch) {
// 1. If fetchParams is canceled, then return the appropriate network error
// for fetchParams.
if (isCancelled(fetchParams)) {
return makeAppropriateNetworkError(fetchParams)
}

// 2. Let username and password be the result of prompting the end user for a
// username and password, respectively, in request’s traversable for user prompts.
// TODO

// 3. Set the username given request’s current URL and username.
// requestCurrentURL(request).username = TODO

// 4. Set the password given request’s current URL and password.
// requestCurrentURL(request).password = TODO
}

// 4. Set response to the result of running HTTP-network-or-cache fetch given
// fetchParams and true.
fetchParams.controller.connection.destroy()

response = await httpNetworkOrCacheFetch(fetchParams, true)
}

// 15. If response’s status is 407, then:
if (response.status === 407) {
Expand Down
2 changes: 2 additions & 0 deletions lib/web/fetch/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,8 @@ function makeRequest (init) {
preventNoCacheCacheControlHeaderModification: init.preventNoCacheCacheControlHeaderModification ?? false,
done: init.done ?? false,
timingAllowFailed: init.timingAllowFailed ?? false,
useURLCredentials: init.useURLCredentials ?? undefined,
traversableForUserPrompts: init.traversableForUserPrompts ?? 'client',
urlList: init.urlList,
url: init.urlList[0],
headersList: init.headersList
Expand Down
27 changes: 26 additions & 1 deletion lib/web/fetch/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -1429,6 +1429,28 @@ function getDecodeSplit (name, list) {
return gettingDecodingSplitting(value)
}

function hasAuthenticationEntry (request) {
return false
}

/**
* @see https://url.spec.whatwg.org/#include-credentials
* @param {URL} url
*/
function includesCredentials (url) {
// A URL includes credentials if its username or password is not the empty string.
return !!(url.username && url.password)
}

/**
* @see https://html.spec.whatwg.org/multipage/document-sequences.html#traversable-navigable
* @param {object|string} navigable
*/
function isTraversableNavigable (navigable) {
// TODO
return true
}

class EnvironmentSettingsObjectBase {
get baseUrl () {
return getGlobalOrigin()
Expand Down Expand Up @@ -1491,5 +1513,8 @@ module.exports = {
extractMimeType,
getDecodeSplit,
environmentSettingsObject,
isOriginIPPotentiallyTrustworthy
isOriginIPPotentiallyTrustworthy,
hasAuthenticationEntry,
includesCredentials,
isTraversableNavigable
}
5 changes: 3 additions & 2 deletions lib/web/websocket/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
// 2. Let request be a new request, whose URL is requestURL, client is client,
// service-workers mode is "none", referrer is "no-referrer", mode is
// "websocket", credentials mode is "include", cache mode is "no-store" ,
// and redirect mode is "error".
// redirect mode is "error", and use-URL-credentials flag is set.
const request = makeRequest({
urlList: [requestURL],
client,
Expand All @@ -42,7 +42,8 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
mode: 'websocket',
credentials: 'include',
cache: 'no-store',
redirect: 'error'
redirect: 'error',
useURLCredentials: true
})

// Note: undici extension, allow setting custom headers.
Expand Down
Loading
Loading