HTTPResponse.ts (3986B)
1 /** 2 * @license 3 * Copyright 2020 Google Inc. 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; 7 import type {Protocol} from 'devtools-protocol'; 8 9 import type {Frame} from '../api/Frame.js'; 10 import {HTTPResponse, type RemoteAddress} from '../api/HTTPResponse.js'; 11 import {PageEvent} from '../api/Page.js'; 12 import {UnsupportedOperation} from '../common/Errors.js'; 13 import {SecurityDetails} from '../common/SecurityDetails.js'; 14 import {invokeAtMostOnceForArguments} from '../util/decorators.js'; 15 16 import type {BidiHTTPRequest} from './HTTPRequest.js'; 17 18 /** 19 * @internal 20 */ 21 export class BidiHTTPResponse extends HTTPResponse { 22 static from( 23 data: Bidi.Network.ResponseData, 24 request: BidiHTTPRequest, 25 cdpSupported: boolean, 26 ): BidiHTTPResponse { 27 const response = new BidiHTTPResponse(data, request, cdpSupported); 28 response.#initialize(); 29 return response; 30 } 31 32 #data: Bidi.Network.ResponseData; 33 #request: BidiHTTPRequest; 34 #securityDetails?: SecurityDetails; 35 #cdpSupported = false; 36 37 private constructor( 38 data: Bidi.Network.ResponseData, 39 request: BidiHTTPRequest, 40 cdpSupported: boolean, 41 ) { 42 super(); 43 this.#data = data; 44 this.#request = request; 45 this.#cdpSupported = cdpSupported; 46 47 // @ts-expect-error non-standard property. 48 const securityDetails = data['goog:securityDetails']; 49 if (cdpSupported && securityDetails) { 50 this.#securityDetails = new SecurityDetails( 51 securityDetails as Protocol.Network.SecurityDetails, 52 ); 53 } 54 } 55 56 #initialize() { 57 if (this.#data.fromCache) { 58 this.#request._fromMemoryCache = true; 59 this.#request 60 .frame() 61 ?.page() 62 .trustedEmitter.emit(PageEvent.RequestServedFromCache, this.#request); 63 } 64 this.#request.frame()?.page().trustedEmitter.emit(PageEvent.Response, this); 65 } 66 67 @invokeAtMostOnceForArguments 68 override remoteAddress(): RemoteAddress { 69 return { 70 ip: '', 71 port: -1, 72 }; 73 } 74 75 override url(): string { 76 return this.#data.url; 77 } 78 79 override status(): number { 80 return this.#data.status; 81 } 82 83 override statusText(): string { 84 return this.#data.statusText; 85 } 86 87 override headers(): Record<string, string> { 88 const headers: Record<string, string> = {}; 89 for (const header of this.#data.headers) { 90 // TODO: How to handle Binary Headers 91 // https://w3c.github.io/webdriver-bidi/#type-network-Header 92 if (header.value.type === 'string') { 93 headers[header.name.toLowerCase()] = header.value.value; 94 } 95 } 96 return headers; 97 } 98 99 override request(): BidiHTTPRequest { 100 return this.#request; 101 } 102 103 override fromCache(): boolean { 104 return this.#data.fromCache; 105 } 106 107 override timing(): Protocol.Network.ResourceTiming | null { 108 const bidiTiming = this.#request.timing(); 109 return { 110 requestTime: bidiTiming.requestTime, 111 proxyStart: -1, 112 proxyEnd: -1, 113 dnsStart: bidiTiming.dnsStart, 114 dnsEnd: bidiTiming.dnsEnd, 115 connectStart: bidiTiming.connectStart, 116 connectEnd: bidiTiming.connectEnd, 117 sslStart: bidiTiming.tlsStart, 118 sslEnd: -1, 119 workerStart: -1, 120 workerReady: -1, 121 workerFetchStart: -1, 122 workerRespondWithSettled: -1, 123 workerRouterEvaluationStart: -1, 124 workerCacheLookupStart: -1, 125 sendStart: bidiTiming.requestStart, 126 sendEnd: -1, 127 pushStart: -1, 128 pushEnd: -1, 129 receiveHeadersStart: bidiTiming.responseStart, 130 receiveHeadersEnd: bidiTiming.responseEnd, 131 }; 132 } 133 134 override frame(): Frame | null { 135 return this.#request.frame(); 136 } 137 138 override fromServiceWorker(): boolean { 139 return false; 140 } 141 142 override securityDetails(): SecurityDetails | null { 143 if (!this.#cdpSupported) { 144 throw new UnsupportedOperation(); 145 } 146 return this.#securityDetails ?? null; 147 } 148 149 override content(): never { 150 throw new UnsupportedOperation(); 151 } 152 }