@@ -2,7 +2,6 @@ import * as http from 'http';
22import Log , { hasBeenLoggedSymbol } from '@secret-agent/commons/Logger' ;
33import * as http2 from 'http2' ;
44import { ClientHttp2Stream , Http2ServerRequest , Http2ServerResponse } from 'http2' ;
5- import { URL } from 'url' ;
65import { CanceledPromiseError } from '@secret-agent/commons/interfaces/IPendingWaitEvent' ;
76import IMitmRequestContext from '../interfaces/IMitmRequestContext' ;
87import HeadersHandler from './HeadersHandler' ;
@@ -14,7 +13,6 @@ import HttpResponseCache from '../lib/HttpResponseCache';
1413import ResourceState from '../interfaces/ResourceState' ;
1514
1615const { log } = Log ( module ) ;
17- const redirectCodes = new Set ( [ 300 , 301 , 302 , 303 , 305 , 307 , 308 ] ) ;
1816
1917export default class HttpRequestHandler extends BaseHttpHandler {
2018 protected static responseCache = new HttpResponseCache ( ) ;
@@ -29,32 +27,7 @@ export default class HttpRequestHandler extends BaseHttpHandler {
2927 this . context . setState ( ResourceState . ClientToProxyRequest ) ;
3028
3129 // register error listeners first
32- const { clientToProxyRequest, proxyToClientResponse } = request ;
33- clientToProxyRequest . on ( 'error' , this . onError . bind ( this , 'ClientToProxy.RequestError' ) ) ;
34- if ( clientToProxyRequest instanceof Http2ServerRequest ) {
35- clientToProxyRequest . stream . on (
36- 'error' ,
37- this . onError . bind ( this , 'ClientToProxy.Http2StreamError' ) ,
38- ) ;
39- clientToProxyRequest . stream . on ( 'streamClosed' , code =>
40- this . onError ( 'ClientToProxy.Http2StreamError' , new Error ( `Stream Closed ${ code } ` ) ) ,
41- ) ;
42- const http2Session = clientToProxyRequest . stream . session ;
43- if ( ! http2Session . listenerCount ( 'error' ) ) {
44- http2Session . on ( 'error' , this . onError . bind ( this , 'ClientToProxy.Http2SessionError' ) ) ;
45- }
46- }
47- if ( proxyToClientResponse instanceof Http2ServerResponse ) {
48- proxyToClientResponse . stream . on (
49- 'error' ,
50- this . onError . bind ( this , 'ProxyToClient.Http2StreamError' ) ,
51- ) ;
52- const http2Session = proxyToClientResponse . stream . session ;
53- if ( ! http2Session . listenerCount ( 'error' ) ) {
54- http2Session . on ( 'error' , this . onError . bind ( this , 'ProxyToClient.Http2SessionError' ) ) ;
55- }
56- }
57- proxyToClientResponse . on ( 'error' , this . onError . bind ( this , 'ProxyToClient.ResponseError' ) ) ;
30+ this . bindErrorListeners ( ) ;
5831 }
5932
6033 public async onRequest ( ) : Promise < void > {
@@ -83,6 +56,7 @@ export default class HttpRequestHandler extends BaseHttpHandler {
8356 rawHeaders ?: string [ ] ,
8457 ) : Promise < void > {
8558 const context = this . context ;
59+
8660 context . setState ( ResourceState . ServerToProxyOnResponse ) ;
8761
8862 if ( response instanceof http . IncomingMessage ) {
@@ -95,25 +69,36 @@ export default class HttpRequestHandler extends BaseHttpHandler {
9569 rawHeaders ,
9670 ) ;
9771 }
98- const { serverToProxyResponse } = context ;
99- serverToProxyResponse . on ( 'error' , this . onError . bind ( this , 'ServerToProxy.ResponseError' ) ) ;
72+ // wait for MitmRequestContext to read this
73+ context . serverToProxyResponse . on (
74+ 'error' ,
75+ this . onError . bind ( this , 'ServerToProxy.ResponseError' ) ,
76+ ) ;
10077
10178 try {
10279 context . cacheHandler . onResponseHeaders ( ) ;
10380 } catch ( err ) {
10481 return this . onError ( 'ServerToProxy.ResponseHeadersHandlerError' , err ) ;
10582 }
10683
107- if ( redirectCodes . has ( context . status ) ) {
108- const redirectLocation = context . responseHeaders . location || context . responseHeaders . Location ;
109- if ( redirectLocation ) {
110- const redirectUrl = new URL ( redirectLocation as string , context . url ) ;
111- context . redirectedToUrl = redirectUrl . href ;
112- context . responseUrl = context . redirectedToUrl ;
113- }
114- }
11584 await CookieHandler . readServerResponseCookies ( context ) ;
11685
86+ /////// WRITE CLIENT RESPONSE //////////////////
87+
88+ if ( ! context . proxyToClientResponse ) {
89+ log . warn ( 'Error.NoProxyToClientResponse' , {
90+ sessionId : context . requestSession . sessionId ,
91+ } ) ;
92+ context . setState ( ResourceState . PrematurelyClosed ) ;
93+ return ;
94+ }
95+
96+ try {
97+ this . writeResponseHead ( ) ;
98+ } catch ( err ) {
99+ return this . onError ( 'ServerToProxyToClient.WriteResponseHeadError' , err ) ;
100+ }
101+
117102 try {
118103 await this . writeResponse ( ) ;
119104 } catch ( err ) {
@@ -164,6 +149,22 @@ export default class HttpRequestHandler extends BaseHttpHandler {
164149 }
165150 }
166151
152+ private bindErrorListeners ( ) : void {
153+ const { clientToProxyRequest, proxyToClientResponse } = this . context ;
154+ clientToProxyRequest . on ( 'error' , this . onError . bind ( this , 'ClientToProxy.RequestError' ) ) ;
155+ proxyToClientResponse . on ( 'error' , this . onError . bind ( this , 'ProxyToClient.ResponseError' ) ) ;
156+
157+ if ( clientToProxyRequest instanceof Http2ServerRequest ) {
158+ const stream = clientToProxyRequest . stream ;
159+ this . bindHttp2ErrorListeners ( 'ClientToProxy' , stream , stream . session ) ;
160+ }
161+
162+ if ( proxyToClientResponse instanceof Http2ServerResponse ) {
163+ const stream = proxyToClientResponse . stream ;
164+ this . bindHttp2ErrorListeners ( 'ProxyToClient' , stream , stream . session ) ;
165+ }
166+ }
167+
167168 private async writeRequest ( ) : Promise < void > {
168169 this . context . setState ( ResourceState . WriteProxyToServerRequestBody ) ;
169170 const { proxyToServerRequest, clientToProxyRequest } = this . context ;
@@ -185,17 +186,9 @@ export default class HttpRequestHandler extends BaseHttpHandler {
185186 this . context . requestPostData = Buffer . concat ( data ) ;
186187 }
187188
188- private async writeResponse ( ) : Promise < void > {
189+ private writeResponseHead ( ) : void {
189190 const context = this . context ;
190- if ( ! context . proxyToClientResponse ) {
191- log . warn ( 'Error.NoProxyToClientResponse' , {
192- sessionId : context . requestSession . sessionId ,
193- } ) ;
194- context . setState ( ResourceState . PrematurelyClosed ) ;
195- return ;
196- }
197-
198- const { serverToProxyResponse, proxyToClientResponse } = this . context ;
191+ const { serverToProxyResponse, proxyToClientResponse } = context ;
199192
200193 proxyToClientResponse . statusCode = context . status ;
201194 // write individually so we properly write header-lists
@@ -207,32 +200,24 @@ export default class HttpRequestHandler extends BaseHttpHandler {
207200 context . responseTrailers = headers ;
208201 } ) ;
209202
210- try {
211- proxyToClientResponse . writeHead ( proxyToClientResponse . statusCode ) ;
212- } catch ( err ) {
213- return this . onError ( 'ServerToProxy.WriteResponseHeadError' , err ) ;
214- }
203+ proxyToClientResponse . writeHead ( proxyToClientResponse . statusCode ) ;
204+ }
205+
206+ private async writeResponse ( ) : Promise < void > {
207+ const context = this . context ;
208+ const { serverToProxyResponse, proxyToClientResponse } = context ;
215209
216210 context . setState ( ResourceState . WriteProxyToClientResponseBody ) ;
217211
218212 await context . requestSession . willSendResponse ( context ) ;
219213
220214 for await ( const chunk of serverToProxyResponse ) {
221215 const data = context . cacheHandler . onResponseData ( chunk as Buffer ) ;
222- if ( data && ! this . isClientConnectionDestroyed ( ) ) {
223- proxyToClientResponse . write ( data , error => {
224- if ( error && ! this . isClientConnectionDestroyed ( ) )
225- this . onError ( 'ServerToProxy.WriteResponseError' , error ) ;
226- } ) ;
227- }
216+ this . safeWriteToClient ( data ) ;
228217 }
229218
230219 if ( context . cacheHandler . shouldServeCachedData ) {
231- if ( ! this . isClientConnectionDestroyed ( ) )
232- proxyToClientResponse . write ( context . cacheHandler . cacheData , error => {
233- if ( error && ! this . isClientConnectionDestroyed ( ) )
234- this . onError ( 'ServerToProxy.WriteCachedResponseError' , error ) ;
235- } ) ;
220+ this . safeWriteToClient ( context . cacheHandler . cacheData ) ;
236221 }
237222
238223 if ( serverToProxyResponse instanceof http . IncomingMessage ) {
@@ -250,6 +235,15 @@ export default class HttpRequestHandler extends BaseHttpHandler {
250235 context . requestSession . emit ( 'response' , MitmRequestContext . toEmittedResource ( context ) ) ;
251236 }
252237
238+ private safeWriteToClient ( data : Buffer ) : void {
239+ if ( ! data || this . isClientConnectionDestroyed ( ) ) return ;
240+
241+ this . context . proxyToClientResponse . write ( data , error => {
242+ if ( error && ! this . isClientConnectionDestroyed ( ) )
243+ this . onError ( 'ServerToProxy.WriteResponseError' , error ) ;
244+ } ) ;
245+ }
246+
253247 private isClientConnectionDestroyed ( ) : boolean {
254248 const proxyToClientResponse = this . context . proxyToClientResponse ;
255249 return (
@@ -269,5 +263,3 @@ export default class HttpRequestHandler extends BaseHttpHandler {
269263 await handler . onRequest ( ) ;
270264 }
271265}
272-
273- export { redirectCodes } ;
0 commit comments