1
- const npmPackage = require ( './package.json' ) ;
2
- const crypto = require ( 'crypto' ) ;
3
- const express = require ( 'express' ) ;
4
- const proxy = require ( 'express-http-proxy' ) ;
5
- const cors = require ( 'cors' ) ;
6
- const bodyParser = require ( 'body-parser' ) ;
7
- const urlUtil = require ( 'url' ) ;
8
- const chalk = require ( 'chalk' ) ;
9
-
10
- /** The caching proxy server. */
11
- class JsonCachingProxy {
1
+ import bodyParser from 'body-parser' ;
2
+ import chalk from 'chalk' ;
3
+ import cors from 'cors' ;
4
+ import crypto from 'crypto' ;
5
+ import express from 'express' ;
6
+ import fs from 'fs' ;
7
+ import proxy from 'express-http-proxy' ;
8
+ import urlUtil from 'url' ;
9
+ import { promisify } from 'util' ;
10
+ import zlib from 'zlib' ;
11
+
12
+ const brotliDecompress = promisify ( zlib . brotliDecompress ) ;
13
+ const npmPackage = JSON . parse ( fs . readFileSync ( 'package.json' ) ) ;
14
+
15
+ export default class JsonCachingProxy {
12
16
/**
13
17
* @param {Object } options - Options passed into the ctor will override defaults if defined
14
18
*/
@@ -130,10 +134,10 @@ class JsonCachingProxy {
130
134
* @param {string } startedDateTime - An ISO Datetime String
131
135
* @param {Object } req - An express IncomingMessage request
132
136
* @param {Object } res - An express ServerResponse response
133
- * @param {Object } data - An express response body (the content)
137
+ * @param {Buffer } data - An express response body (the content buffer )
134
138
* @returns {Object } A HAR entry object
135
139
*/
136
- createHarEntry ( startedDateTime , req , res , data ) {
140
+ async createHarEntry ( startedDateTime , req , res , data ) {
137
141
let reqMimeType = req . get ( 'Content-Type' ) ;
138
142
let resMimeType = res . get ( 'Content-Type' ) || 'text/plain' ;
139
143
let encoding = ( / ^ t e x t \/ | ^ a p p l i c a t i o n \/ ( j a v a s c r i p t | j s o n ) / ) . test ( resMimeType ) ? 'utf8' : 'base64' ;
@@ -153,11 +157,16 @@ class JsonCachingProxy {
153
157
status : res . statusCode ,
154
158
statusText : res . statusMessage ,
155
159
cookies : this . convertToNameValueList ( res . cookies ) ,
156
- headers : this . convertToNameValueList ( res . _headers ) . filter ( header => header . name . toLowerCase ( ) !== 'content-encoding' ) , // Not compressed
160
+ headers : this . convertToNameValueList ( res . getHeaders ( ) ) . filter ( header => header . name . toLowerCase ( ) !== 'content-encoding' ) , // Not compressed
157
161
content : {
158
162
size : - 1 ,
159
163
mimeType : resMimeType ,
160
- text : data . toString ( encoding ) ,
164
+
165
+ // Workaround for http-express-proxy not handling brotli encoding. TODO: remove this code when HEP fixes this
166
+ text : ( res . getHeaders ( ) [ 'content-encoding' ] || '' ) . toLowerCase ( ) == 'br' ?
167
+ ( await brotliDecompress ( data ) ) . toString ( encoding ) :
168
+ data . toString ( encoding ) ,
169
+
161
170
encoding : encoding
162
171
} ,
163
172
headersSize : - 1 ,
@@ -301,7 +310,7 @@ class JsonCachingProxy {
301
310
}
302
311
303
312
/**
304
- * Add Request body parsing into RAW if there is actual body content
313
+ * Add Request body parsing into bodyParser if there is actual body content
305
314
* @returns {JsonCachingProxy }
306
315
*/
307
316
addBodyParser ( ) {
@@ -376,9 +385,11 @@ class JsonCachingProxy {
376
385
* Modifies locations on redirects.
377
386
* @returns {JsonCachingProxy }
378
387
*/
379
- addProxyRoute ( ) {
388
+ async addProxyRoute ( ) {
380
389
this . app . use ( '/' , proxy ( this . options . remoteServerUrl , {
381
- userResDecorator : ( rsp , rspData , req , res ) => {
390
+ userResDecorator : async ( rsp , rspData , req , res ) => {
391
+ let headers = res . getHeaders ( ) ;
392
+
382
393
// Handle Redirects by modifying the location property of the response header
383
394
let location = res . get ( 'location' ) ;
384
395
if ( location ) {
@@ -389,20 +400,21 @@ class JsonCachingProxy {
389
400
res . header ( 'access-control-allow-origin' , this . options . overrideCors ) ;
390
401
}
391
402
392
- if ( this . options . deleteCookieDomain && res . _headers [ 'set-cookie' ] ) {
393
- res . header ( 'set-cookie' , this . removeCookiesDomain ( res . _headers [ 'set-cookie' ] || [ ] ) ) ;
403
+ if ( this . options . deleteCookieDomain && headers [ 'set-cookie' ] ) {
404
+ res . header ( 'set-cookie' , this . removeCookiesDomain ( headers [ 'set-cookie' ] || [ ] ) ) ;
394
405
}
395
406
396
407
if ( this . isRouteExcluded ( req . method , req . url ) ) {
397
408
this . log ( chalk . red ( 'Exclude Proxied Resource' , chalk . bold ( req . method , req . url ) ) ) ;
398
409
} else if ( this . isStatusExcluded ( res . statusCode ) ) {
399
410
this . log ( chalk . red ( 'Exclude Proxied Resource' , chalk . bold ( req . method , req . url , `\tStatus: ${ res . statusCode } ` ) ) ) ;
400
411
} else {
401
- let mimeType = res . _headers [ 'content-type' ] ;
412
+ let mimeType = headers [ 'content-type' ] ;
402
413
403
414
if ( this . options . dataRecord && ( this . options . cacheEverything || ! this . options . cacheEverything && mimeType && mimeType . indexOf ( 'application/json' ) >= 0 ) ) {
404
415
let { key, hash } = this . genKeyFromExpressReq ( req ) ;
405
- let entry = this . createHarEntry ( new Date ( ) . toISOString ( ) , req , res , rspData ) ;
416
+ let entry = await this . createHarEntry ( new Date ( ) . toISOString ( ) , req , res , rspData ) ;
417
+
406
418
this . routeCache [ key ] = entry ;
407
419
this . log ( chalk . yellow ( 'Saved to Cache' , hash , chalk . bold ( entry . request . method , entry . request . url ) ) ) ;
408
420
} else {
@@ -532,5 +544,3 @@ class JsonCachingProxy {
532
544
*/
533
545
isRecording ( ) { return this . options . dataRecord ; }
534
546
}
535
-
536
- module . exports = JsonCachingProxy ;
0 commit comments