All files / src/handlers handleApiRequest.ts

95.23% Statements 20/21
83.33% Branches 5/6
100% Functions 5/5
94.73% Lines 18/19

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                    162x 162x   162x 79x 79x   79x   83x   83x 83x   83x           162x     162x   17x 8x     9x         162x           83x                       83x                
import { WorkerEnv } from '../env'
import {
  addProxyIntegrationHeaders,
  createErrorResponseForIngress,
  createFallbackErrorResponse,
  filterCookies,
} from '../utils'
import { addTrafficMonitoringSearchParamsForIngressRequest } from '../utils/addTrafficMonitoring'
 
export async function handleApiRequest(receivedRequest: Request, env: WorkerEnv, targetURL: URL): Promise<Response> {
  const methodAuthorized = isMethodAuthorized(receivedRequest.method)
  try {
    let fingerprintRequest: Request<unknown, CfProperties<unknown>>
    if (!methodAuthorized) {
      const headers = new Headers(receivedRequest.headers)
      headers.delete('Cookie')
 
      fingerprintRequest = new Request(targetURL, new Request(receivedRequest, { headers }))
    } else {
      addTrafficMonitoringSearchParamsForIngressRequest(targetURL)
 
      const headers = filterCookies(new Headers(receivedRequest.headers), (key) => key === '_iidt')
      addProxyIntegrationHeaders(headers, receivedRequest.url, env)
 
      fingerprintRequest = new Request(
        targetURL,
        new Request(receivedRequest, updateRequestInitForIngress({ headers, body: receivedRequest.body }))
      )
    }
 
    console.log(`Sending ${fingerprintRequest.method} to ${fingerprintRequest.url}...`)
    // The response is copied so that its headers stay mutable, because headers on a `fetch`
    // response are immutable and `returnHttpResponse` strips `Strict-Transport-Security`.
    return await fetch(fingerprintRequest).then((originResponse) => new Response(originResponse.body, originResponse))
  } catch (e) {
    if (!methodAuthorized) {
      return createFallbackErrorResponse(e)
    }
 
    return createErrorResponseForIngress(receivedRequest, e)
  }
}
 
export function isMethodAuthorized(method: string) {
  return method === 'POST'
}
 
function updateRequestInitForIngress(
  requestInit: RequestInit<CfProperties<unknown>>
): RequestInit<CfProperties<unknown>> {
  Eif (import.meta.env.MODE !== 'production') {
    // The local worker runtime requires duplex half when making a fetch
    // that is streaming the request body and receiving a response body.
    //
    // This requirement comes from the undici client used by the workers
    // runtime to implement fetch.
    //
    // This is not required by the deployed workers runtime. By wrapping this
    // modification in the meta.env.MODE check, the production build will
    // omit this if branch.
    //
    // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
    return {
      ...requestInit,
      duplex: 'half',
    } as unknown as RequestInit<CfProperties<unknown>>
  }
 
  return requestInit
}