Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | 73x 73x 73x 7x 66x 1x 65x 65x 2x 2x 63x 33x 30x 1x 29x 41x 41x 26x 15x 8x 8x 5x 3x 12x 12x 10x 4x 2x | import { AGENT_DATA_HEADER, SIGNALS_KEY } from '../../shared/const'
import { appendHeaderValue } from './headers'
interface CopyRequestParams {
// The original request to be copied
request: Request
// Object containing custom settings to apply to the new Request
init: RequestInit
// Optional parameter to specify a new URL for the copied Request. If empty, the original request URL is used.
url?: string | URL
}
/**
* Creates a new Request object by copying an existing one and optionally modifying its URL.
* Using `Request.clone()` in Cloudflare runtime is not recommended: https://developers.cloudflare.com/workers/examples/modify-request-property/
*
* @return {Request} A new Request object based on the original, with any modifications applied.
*
* @example Modifing headers in a request.
* ```typescript
* const request = new Request('https://example.com/', { headers: { 'Original-Header': 'value' }, method: 'GET' })
*
* // In case if you'd like to completly overwrite headers, use 'new Headers()' instead.
* const updatedHeaders = new Headers(request.headers)
* updatedHeaders.set('X-New-Header', 'new-value')
*
* const modifiedRequest = copyRequest({
* request,
* init: {
* // Updates request headers with new values
* headers: updatedHeaders,
* // Modify request method
* method: 'POST',
* },
* })
*
* console.log(modifiedRequest.headers.get('X-New-Header')) // 'new-value'
* console.log(modifiedRequest.headers.get('Original-Header')) // 'value'
* ```
*/
export function copyRequest({ request, init, url }: CopyRequestParams): Request<unknown, IncomingRequestCfProperties> {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return new Request(url ?? request.url, new Request(request, init)) as unknown as Request<
unknown,
IncomingRequestCfProperties
>
}
/**
* @param request the `Request` to examine
*
* @return if the request is a cross-origin request, the normalized origin value from the `Origin` header, as a URL
* if the request is a same-origin request or the origin value is invalid, null is returned
*/
export function getCrossOriginUrl(request: Request): URL | null {
const originHeader = request.headers.get('Origin')
if (!originHeader) {
return null
}
if (originHeader === 'null') {
// Special handling for the special "null" origin
return null
}
let originUrl: URL
try {
originUrl = new URL(originHeader)
} catch (e) {
console.debug('Origin value is not a valid URL')
return null
}
// Validate that the originHeader is only an origin (protocol://host[:port])
if (originHeader.endsWith('/') || originUrl.toString() !== `${originUrl.origin}/`) {
return null
}
// If the Origin header matches the request's origin, it's same-origin
if (originUrl.origin === new URL(request.url).origin) {
return null
}
return originUrl
}
/**
* Sets the CORS headers needed to allow the browser to expose the response to an instrumented, cross-origin
* request to the instrumentation script and JS app.
*
* The `Access-Control-Allow-Origin` header field from the response is used to determine if updates are
* required.
*
* @param request the `Request` being handled
* @param originResponseHeaders the headers from the origin `Response`, to be updated by this function
*/
export function setCorsHeadersForInstrumentation(request: Request, originResponseHeaders: Headers) {
const allowedOrigin = originResponseHeaders.get('Access-Control-Allow-Origin')
if (!allowedOrigin || allowedOrigin === 'null') {
return
}
// A cross-origin request is being allowed by the origin server or by a
// response generated by this worker. Add the additional CORS headers
// needed by the instrumentation script and agent
if (allowedOrigin === '*') {
// Access-Control-Allow-Credentials is not valid for the wildcard origin
// but the origin is allowed by the origin server so the Origin can be
// reflected to the response without security concerns.
const crossOriginUrl = getCrossOriginUrl(request)
if (crossOriginUrl) {
originResponseHeaders.set('Access-Control-Allow-Origin', crossOriginUrl.origin)
} else {
// Because a wildcard origin may be set universally by some APIs that allow
// cross-origin access from any origin, only set additional header fields when
// the request is a cross-origin request
return
}
}
originResponseHeaders.set('Access-Control-Allow-Credentials', 'true')
if (request.method !== 'OPTIONS') {
if (originResponseHeaders.get(AGENT_DATA_HEADER) !== null) {
appendHeaderValue(originResponseHeaders, 'Access-Control-Expose-Headers', AGENT_DATA_HEADER)
}
} else {
appendHeaderValue(originResponseHeaders, 'Access-Control-Allow-Headers', SIGNALS_KEY)
}
}
|