@@ -18,48 +18,89 @@ import fs from 'fs';
18
18
import type { HAREntry , HARFile , HARResponse } from '../../types/types' ;
19
19
import { debugLogger } from '../common/debugLogger' ;
20
20
import { rewriteErrorMessage } from '../utils/stackTrace' ;
21
+ import { ZipFile } from '../utils/zipFile' ;
21
22
import type { BrowserContext } from './browserContext' ;
23
+ import { Events } from './events' ;
22
24
import type { Route } from './network' ;
23
25
import type { BrowserContextOptions } from './types' ;
24
26
25
27
type HarOptions = NonNullable < BrowserContextOptions [ 'har' ] > ;
26
28
27
29
export class HarRouter {
28
30
private _pattern : string | RegExp ;
29
- private _handler : ( route : Route ) => Promise < void > ;
31
+ private _harFile : HARFile ;
32
+ private _zipFile : ZipFile | null ;
33
+ private _options : HarOptions | undefined ;
30
34
31
35
static async create ( options : HarOptions ) : Promise < HarRouter > {
36
+ if ( options . path . endsWith ( '.zip' ) ) {
37
+ const zipFile = new ZipFile ( options . path ) ;
38
+ const har = await zipFile . read ( 'har.har' ) ;
39
+ const harFile = JSON . parse ( har . toString ( ) ) as HARFile ;
40
+ return new HarRouter ( harFile , zipFile , options ) ;
41
+ }
32
42
const harFile = JSON . parse ( await fs . promises . readFile ( options . path , 'utf-8' ) ) as HARFile ;
33
- return new HarRouter ( harFile , options ) ;
43
+ return new HarRouter ( harFile , null , options ) ;
34
44
}
35
45
36
- constructor ( harFile : HARFile , options ?: HarOptions ) {
46
+ constructor ( harFile : HARFile , zipFile : ZipFile | null , options ?: HarOptions ) {
47
+ this . _harFile = harFile ;
48
+ this . _zipFile = zipFile ;
37
49
this . _pattern = options ?. urlFilter ?? / .* / ;
38
- this . _handler = async ( route : Route ) => {
39
- let response ;
40
- try {
41
- response = harFindResponse ( harFile , {
42
- url : route . request ( ) . url ( ) ,
43
- method : route . request ( ) . method ( )
50
+ this . _options = options ;
51
+ }
52
+
53
+ private async _handle ( route : Route ) {
54
+ let response ;
55
+ try {
56
+ response = harFindResponse ( this . _harFile , {
57
+ url : route . request ( ) . url ( ) ,
58
+ method : route . request ( ) . method ( )
59
+ } ) ;
60
+ } catch ( e ) {
61
+ rewriteErrorMessage ( e , `Error while finding entry for ${ route . request ( ) . method ( ) } ${ route . request ( ) . url ( ) } in HAR file:\n${ e . message } ` ) ;
62
+ debugLogger . log ( 'api' , e ) ;
63
+ }
64
+
65
+ if ( response ) {
66
+ debugLogger . log ( 'api' , `serving from HAR: ${ route . request ( ) . method ( ) } ${ route . request ( ) . url ( ) } ` ) ;
67
+ const sha1 = ( response . content as any ) . _sha1 ;
68
+
69
+ if ( this . _zipFile && sha1 ) {
70
+ const body = await this . _zipFile . read ( sha1 ) . catch ( ( ) => {
71
+ debugLogger . log ( 'api' , `payload ${ sha1 } for request ${ route . request ( ) . url ( ) } is not found in archive` ) ;
72
+ return null ;
44
73
} ) ;
45
- } catch ( e ) {
46
- rewriteErrorMessage ( e , `Error while finding entry for ${ route . request ( ) . method ( ) } ${ route . request ( ) . url ( ) } in HAR file:\n${ e . message } ` ) ;
47
- debugLogger . log ( 'api' , e ) ;
74
+ if ( body ) {
75
+ await route . fulfill ( {
76
+ status : response . status ,
77
+ headers : Object . fromEntries ( response . headers . map ( h => [ h . name , h . value ] ) ) ,
78
+ body
79
+ } ) ;
80
+ return ;
81
+ }
48
82
}
49
- if ( response ) {
50
- debugLogger . log ( 'api' , `serving from HAR: ${ route . request ( ) . method ( ) } ${ route . request ( ) . url ( ) } ` ) ;
51
- await route . fulfill ( { response } ) ;
52
- } else if ( options ?. fallback === 'continue' ) {
53
- await route . fallback ( ) ;
54
- } else {
55
- debugLogger . log ( 'api' , `request not in HAR, aborting: ${ route . request ( ) . method ( ) } ${ route . request ( ) . url ( ) } ` ) ;
56
- await route . abort ( ) ;
57
- }
58
- } ;
83
+
84
+ await route . fulfill ( { response } ) ;
85
+ return ;
86
+ }
87
+
88
+ if ( this . _options ?. fallback === 'continue' ) {
89
+ await route . fallback ( ) ;
90
+ return ;
91
+ }
92
+
93
+ debugLogger . log ( 'api' , `request not in HAR, aborting: ${ route . request ( ) . method ( ) } ${ route . request ( ) . url ( ) } ` ) ;
94
+ await route . abort ( ) ;
59
95
}
60
96
61
97
async addRoute ( context : BrowserContext ) {
62
- await context . route ( this . _pattern , this . _handler ) ;
98
+ await context . route ( this . _pattern , route => this . _handle ( route ) ) ;
99
+ context . once ( Events . BrowserContext . Close , ( ) => this . dispose ( ) ) ;
100
+ }
101
+
102
+ dispose ( ) {
103
+ this . _zipFile ?. close ( ) ;
63
104
}
64
105
}
65
106
0 commit comments