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 | 28x 28x 7x 7x | /**
* @class
*
* The one header that carries a request id from one Worker to the next.
*
* @remarks
* Cloudflare gives every request that arrives from the internet a `CF-Ray`, and
* [`CloudflareRequestMetadata`](../services/CloudflareRequestMetadata.ts) reads
* it as the request id — the id the dashboard's own logs are keyed by, so a
* line here and a line there can be joined without inventing anything.
*
* A **subrequest** gets no new one. When a Worker calls another over a Service
* Binding, or reaches an external API, the far end sees whatever headers the
* caller built and nothing the edge added. Without a header of its own the
* trail stops at each hop, and a failure three Workers deep cannot be walked
* back to the request that caused it.
*
* This is that header. The caller stamps its request id on the way out, the
* callee prefers an inbound value over minting a fresh one, and one id spans
* the whole fan-out.
*
* ## It is correlation, and only correlation
*
* The value is attacker-controlled: anyone may send `X-Request-Id`. That is
* acceptable for joining log lines and unacceptable for anything else. It must
* never gate access, identify a caller, or stand in for a credential — the API
* key check in [`SecurityMiddleware`](../../middlewares/SecurityMiddleware.ts)
* is what decides who may call, and it reads none of this. The worst a forged
* value can do is put two unrelated requests under one id in a log query.
*
* @example
* ```ts
* const requestId = ctx.get('requestId')
*
* await env.NLP_WORKER.fetch('https://nlp/analyse', {
* method: 'POST',
* headers: { 'content-type': 'application/json', ...RequestCorrelation.of(requestId) },
* body
* })
* ```
*
* @author Bayu Dwiyan Satria
* @version 1.2.0
* @since 1.2.0
*/
export class RequestCorrelation {
/**
* Name of the header carrying the request id between Workers.
*
* @remarks
* Lowercase because that is how the Workers runtime normalises header names,
* so a lookup and a comparison agree without either side calling
* `toLowerCase` first.
*/
public static readonly HEADER = 'x-request-id'
/**
* Builds the correlation header for an outbound call.
*
* @remarks
* Returns a plain object rather than a `Headers`, so it spreads into the
* headers a caller was already building instead of replacing them:
*
* ```ts
* headers: { 'content-type': 'application/json', ...RequestCorrelation.of(requestId) }
* ```
*
* An absent id yields an empty object. A hop with nothing to propagate should
* send no header at all rather than an empty one, which the far end would
* read as an id and correlate against.
*
* @param requestId The id to propagate. Omit or pass a blank value to send
* nothing.
* @returns The header as a spreadable object, empty when there is no id.
*/
public static of(requestId?: string | null): Record<string, string> {
const id = (requestId || '').trim()
return id ? { [RequestCorrelation.HEADER]: id } : {}
}
}
|