@@ -8,6 +8,8 @@ import HTTP, { IncomingMessage } from 'http';
8
8
import HTTPS from 'https' ;
9
9
import Zlib from 'zlib' ;
10
10
import URL from '../url/URL.js' ;
11
+ import FS from 'fs' ;
12
+ import Path from 'path' ;
11
13
import { Socket } from 'net' ;
12
14
import Stream from 'stream' ;
13
15
import DataURIParser from './data-uri/DataURIParser.js' ;
@@ -27,6 +29,7 @@ import FetchHTTPSCertificate from './certificate/FetchHTTPSCertificate.js';
27
29
import { Buffer } from 'buffer' ;
28
30
import FetchBodyUtility from './utilities/FetchBodyUtility.js' ;
29
31
import IFetchInterceptor from './types/IFetchInterceptor.js' ;
32
+ import VirtualServerUtility from './utilities/VirtualServerUtility.js' ;
30
33
31
34
const LAST_CHUNK = Buffer . from ( '0\r\n\r\n' ) ;
32
35
@@ -51,7 +54,7 @@ export default class Fetch {
51
54
private nodeResponse : IncomingMessage | null = null ;
52
55
private response : Response | null = null ;
53
56
private responseHeaders : Headers | null = null ;
54
- private interceptor ? : IFetchInterceptor ;
57
+ private interceptor : IFetchInterceptor | null ;
55
58
private request : Request ;
56
59
private redirectCount = 0 ;
57
60
private disableCache : boolean ;
@@ -111,17 +114,27 @@ export default class Fetch {
111
114
*/
112
115
public async send ( ) : Promise < Response > {
113
116
FetchRequestReferrerUtility . prepareRequest ( new URL ( this . #window. location . href ) , this . request ) ;
114
- const beforeRequestResponse = this . interceptor ?. beforeAsyncRequest
115
- ? await this . interceptor . beforeAsyncRequest ( {
116
- request : this . request ,
117
- window : this . #window
118
- } )
119
- : undefined ;
120
- if ( beforeRequestResponse instanceof Response ) {
121
- return beforeRequestResponse ;
117
+
118
+ if ( this . interceptor ?. beforeAsyncRequest ) {
119
+ const taskID = this . #browserFrame[ PropertySymbol . asyncTaskManager ] . startTask ( ) ;
120
+ const response = await this . interceptor . beforeAsyncRequest ( {
121
+ request : this . request ,
122
+ window : this . #window
123
+ } ) ;
124
+ this . #browserFrame[ PropertySymbol . asyncTaskManager ] . endTask ( taskID ) ;
125
+ if ( response instanceof Response ) {
126
+ return response ;
127
+ }
122
128
}
129
+
123
130
FetchRequestValidationUtility . validateSchema ( this . request ) ;
124
131
132
+ const virtualServerResponse = await this . getVirtualServerResponse ( ) ;
133
+
134
+ if ( virtualServerResponse ) {
135
+ return virtualServerResponse ;
136
+ }
137
+
125
138
if ( this . request . signal . aborted ) {
126
139
throw new this . #window. DOMException (
127
140
'The operation was aborted.' ,
@@ -171,7 +184,7 @@ export default class Fetch {
171
184
const compliesWithCrossOriginPolicy = await this . compliesWithCrossOriginPolicy ( ) ;
172
185
173
186
if ( ! compliesWithCrossOriginPolicy ) {
174
- this . #window . console . warn (
187
+ this . #browserFrame ?. page ? .console . warn (
175
188
`Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at "${ this . request . url } ".`
176
189
) ;
177
190
throw new this . #window. DOMException (
@@ -270,6 +283,62 @@ export default class Fetch {
270
283
return response ;
271
284
}
272
285
286
+ /**
287
+ * Returns virtual server response.
288
+ *
289
+ * @returns Response.
290
+ */
291
+ private async getVirtualServerResponse ( ) : Promise < Response | null > {
292
+ const filePath = VirtualServerUtility . getFilepath ( this . #window, this . request . url ) ;
293
+
294
+ if ( ! filePath ) {
295
+ return null ;
296
+ }
297
+
298
+ if ( this . request . method !== 'GET' ) {
299
+ this . #browserFrame?. page ?. console . error (
300
+ `${ this . request . method } ${ this . request . url } 404 (Not Found)`
301
+ ) ;
302
+ return VirtualServerUtility . getNotFoundResponse ( this . #window) ;
303
+ }
304
+
305
+ const taskID = this . #browserFrame[ PropertySymbol . asyncTaskManager ] . startTask ( ) ;
306
+ let buffer : Buffer ;
307
+
308
+ try {
309
+ const stat = await FS . promises . stat ( filePath ) ;
310
+ buffer = await FS . promises . readFile (
311
+ stat . isDirectory ( ) ? Path . join ( filePath , 'index.html' ) : filePath
312
+ ) ;
313
+ } catch ( error ) {
314
+ this . #browserFrame?. page ?. console . error (
315
+ `${ this . request . method } ${ this . request . url } 404 (Not Found)`
316
+ ) ;
317
+
318
+ this . #browserFrame[ PropertySymbol . asyncTaskManager ] . endTask ( taskID ) ;
319
+
320
+ return VirtualServerUtility . getNotFoundResponse ( this . #window) ;
321
+ }
322
+
323
+ this . #browserFrame[ PropertySymbol . asyncTaskManager ] . endTask ( taskID ) ;
324
+
325
+ const body = new this . #window. ReadableStream ( {
326
+ start ( controller ) {
327
+ setTimeout ( ( ) => {
328
+ controller . enqueue ( buffer ) ;
329
+ controller . close ( ) ;
330
+ } ) ;
331
+ }
332
+ } ) ;
333
+
334
+ const response = new this . #window. Response ( body ) ;
335
+
336
+ response [ PropertySymbol . buffer ] = buffer ;
337
+ ( < string > response . url ) = this . request . url ;
338
+
339
+ return response ;
340
+ }
341
+
273
342
/**
274
343
* Checks if the request complies with the Cross-Origin policy.
275
344
*
@@ -410,7 +479,17 @@ export default class Fetch {
410
479
} )
411
480
: undefined ;
412
481
this . #browserFrame[ PropertySymbol . asyncTaskManager ] . endTask ( taskID ) ;
413
- resolve ( interceptedResponse instanceof Response ? interceptedResponse : response ) ;
482
+ const returnResponse =
483
+ interceptedResponse instanceof Response ? interceptedResponse : response ;
484
+
485
+ // The browser outputs errors to the console when the response is not ok.
486
+ if ( returnResponse instanceof Response && ! returnResponse . ok ) {
487
+ this . #browserFrame?. page ?. console . error (
488
+ `${ this . request . method } ${ this . request . url } ${ returnResponse . status } (${ returnResponse . statusText } )`
489
+ ) ;
490
+ }
491
+
492
+ resolve ( returnResponse ) ;
414
493
} ;
415
494
this . reject = ( error : Error ) : void => {
416
495
this . #browserFrame[ PropertySymbol . asyncTaskManager ] . endTask ( taskID ) ;
@@ -517,7 +596,7 @@ export default class Fetch {
517
596
*/
518
597
private onError ( error : Error ) : void {
519
598
this . finalizeRequest ( ) ;
520
- this . #window . console . error ( error ) ;
599
+ this . #browserFrame ?. page ? .console . error ( error ) ;
521
600
this . reject (
522
601
new this . #window. DOMException (
523
602
`Failed to execute "fetch()" on "Window" with URL "${ this . request . url } ": ${ error . message } ` ,
0 commit comments