@@ -7,18 +7,26 @@ import { HttpStatusCodes } from "./constants";
7
7
import * as request from "request" ;
8
8
9
9
export class HttpClient implements Server . IHttpClient {
10
- private defaultUserAgent : string ;
11
10
private static STATUS_CODE_REGEX = / s t a t u s c o d e = ( \d + ) / i;
12
11
private static STUCK_REQUEST_ERROR_MESSAGE = "The request can't receive any response." ;
13
12
private static STUCK_RESPONSE_ERROR_MESSAGE = "Can't receive all parts of the response." ;
14
13
private static STUCK_REQUEST_TIMEOUT = 60000 ;
15
14
// We receive multiple response packets every ms but we don't need to be very aggressive here.
16
15
private static STUCK_RESPONSE_CHECK_INTERVAL = 10000 ;
17
16
17
+ private defaultUserAgent : string ;
18
+ private cleanupData : ICleanupRequestData [ ] ;
19
+
18
20
constructor ( private $config : Config . IConfig ,
19
21
private $logger : ILogger ,
22
+ private $processService : IProcessService ,
20
23
private $proxyService : IProxyService ,
21
- private $staticConfig : Config . IStaticConfig ) { }
24
+ private $staticConfig : Config . IStaticConfig ) {
25
+ this . cleanupData = [ ] ;
26
+ this . $processService . attachToProcessExitSignals ( this , ( ) => {
27
+ this . cleanupData . forEach ( d => this . cleanupAfterRequest ( d ) ) ;
28
+ } ) ;
29
+ }
22
30
23
31
public async httpRequest ( options : any , proxySettings ?: IProxySettings ) : Promise < Server . IResponse > {
24
32
try {
@@ -97,9 +105,9 @@ export class HttpClient implements Server.IHttpClient {
97
105
const result = new Promise < Server . IResponse > ( ( resolve , reject ) => {
98
106
let timerId : number ;
99
107
let stuckRequestTimerId : number ;
100
- let stuckResponseIntervalId : NodeJS . Timer ;
101
108
let hasResponse = false ;
102
- const timers : number [ ] = [ ] ;
109
+ const cleanupRequestData : ICleanupRequestData = { timers : [ ] , stuckResponseIntervalId : null } ;
110
+ this . cleanupData . push ( cleanupRequestData ) ;
103
111
104
112
const promiseActions : IPromiseActions < Server . IResponse > = {
105
113
resolve,
@@ -109,9 +117,9 @@ export class HttpClient implements Server.IHttpClient {
109
117
110
118
if ( options . timeout ) {
111
119
timerId = setTimeout ( ( ) => {
112
- this . setResponseResult ( promiseActions , timers , stuckResponseIntervalId , { err : new Error ( `Request to ${ unmodifiedOptions . url } timed out.` ) } ) ;
120
+ this . setResponseResult ( promiseActions , cleanupRequestData , { err : new Error ( `Request to ${ unmodifiedOptions . url } timed out.` ) } ) ;
113
121
} , options . timeout ) ;
114
- timers . push ( timerId ) ;
122
+ cleanupRequestData . timers . push ( timerId ) ;
115
123
116
124
delete options . timeout ;
117
125
}
@@ -128,10 +136,10 @@ export class HttpClient implements Server.IHttpClient {
128
136
stuckRequestTimerId = null ;
129
137
if ( ! hasResponse ) {
130
138
requestObj . abort ( ) ;
131
- this . setResponseResult ( promiseActions , timers , stuckResponseIntervalId , { err : new Error ( HttpClient . STUCK_REQUEST_ERROR_MESSAGE ) } ) ;
139
+ this . setResponseResult ( promiseActions , cleanupRequestData , { err : new Error ( HttpClient . STUCK_REQUEST_ERROR_MESSAGE ) } ) ;
132
140
}
133
141
} , options . timeout || HttpClient . STUCK_REQUEST_TIMEOUT ) ;
134
- timers . push ( stuckRequestTimerId ) ;
142
+ cleanupRequestData . timers . push ( stuckRequestTimerId ) ;
135
143
136
144
requestObj
137
145
. on ( "error" , ( err : IHttpRequestError ) => {
@@ -145,18 +153,18 @@ export class HttpClient implements Server.IHttpClient {
145
153
const errorMessage = this . getErrorMessage ( errorMessageStatusCode , null ) ;
146
154
err . proxyAuthenticationRequired = errorMessageStatusCode === HttpStatusCodes . PROXY_AUTHENTICATION_REQUIRED ;
147
155
err . message = errorMessage || err . message ;
148
- this . setResponseResult ( promiseActions , timers , stuckResponseIntervalId , { err } ) ;
156
+ this . setResponseResult ( promiseActions , cleanupRequestData , { err } ) ;
149
157
} )
150
158
. on ( "response" , ( response : Server . IRequestResponseData ) => {
151
159
hasResponse = true ;
152
160
let lastChunkTimestamp = Date . now ( ) ;
153
- stuckResponseIntervalId = setInterval ( ( ) => {
161
+ cleanupRequestData . stuckResponseIntervalId = setInterval ( ( ) => {
154
162
if ( Date . now ( ) - lastChunkTimestamp > HttpClient . STUCK_RESPONSE_CHECK_INTERVAL ) {
155
163
if ( ( < any > response ) . destroy ) {
156
164
( < any > response ) . destroy ( ) ;
157
165
}
158
166
159
- this . setResponseResult ( promiseActions , timers , stuckResponseIntervalId , { err : new Error ( HttpClient . STUCK_RESPONSE_ERROR_MESSAGE ) } ) ;
167
+ this . setResponseResult ( promiseActions , cleanupRequestData , { err : new Error ( HttpClient . STUCK_RESPONSE_ERROR_MESSAGE ) } ) ;
160
168
}
161
169
} , HttpClient . STUCK_RESPONSE_CHECK_INTERVAL ) ;
162
170
const successful = helpers . isRequestSuccessful ( response ) ;
@@ -180,7 +188,7 @@ export class HttpClient implements Server.IHttpClient {
180
188
if ( pipeTo ) {
181
189
pipeTo . on ( "finish" , ( ) => {
182
190
this . $logger . trace ( "httpRequest: Piping done. code = %d" , response . statusCode . toString ( ) ) ;
183
- this . setResponseResult ( promiseActions , timers , stuckResponseIntervalId , { response } ) ;
191
+ this . setResponseResult ( promiseActions , cleanupRequestData , { response } ) ;
184
192
} ) ;
185
193
186
194
responseStream . pipe ( pipeTo ) ;
@@ -196,13 +204,13 @@ export class HttpClient implements Server.IHttpClient {
196
204
const responseBody = data . join ( "" ) ;
197
205
198
206
if ( successful ) {
199
- this . setResponseResult ( promiseActions , timers , stuckResponseIntervalId , { body : responseBody , response } ) ;
207
+ this . setResponseResult ( promiseActions , cleanupRequestData , { body : responseBody , response } ) ;
200
208
} else {
201
209
const errorMessage = this . getErrorMessage ( response . statusCode , responseBody ) ;
202
210
const err : any = new Error ( errorMessage ) ;
203
211
err . response = response ;
204
212
err . body = responseBody ;
205
- this . setResponseResult ( promiseActions , timers , stuckResponseIntervalId , { err } ) ;
213
+ this . setResponseResult ( promiseActions , cleanupRequestData , { err } ) ;
206
214
}
207
215
} ) ;
208
216
}
@@ -233,19 +241,8 @@ export class HttpClient implements Server.IHttpClient {
233
241
return response ;
234
242
}
235
243
236
- private setResponseResult ( result : IPromiseActions < Server . IResponse > , timers : number [ ] , stuckResponseIntervalId : NodeJS . Timer , resultData : { response ?: Server . IRequestResponseData , body ?: string , err ?: Error } ) : void {
237
- timers . forEach ( t => {
238
- if ( t ) {
239
- clearTimeout ( t ) ;
240
- t = null ;
241
- }
242
- } ) ;
243
-
244
- if ( stuckResponseIntervalId ) {
245
- clearInterval ( stuckResponseIntervalId ) ;
246
- stuckResponseIntervalId = null ;
247
- }
248
-
244
+ private setResponseResult ( result : IPromiseActions < Server . IResponse > , cleanupRequestData : ICleanupRequestData , resultData : { response ?: Server . IRequestResponseData , body ?: string , err ?: Error } ) : void {
245
+ this . cleanupAfterRequest ( cleanupRequestData ) ;
249
246
if ( ! result . isResolved ( ) ) {
250
247
result . isResolved = ( ) => true ;
251
248
if ( resultData . err ) {
@@ -317,5 +314,25 @@ export class HttpClient implements Server.IHttpClient {
317
314
this . $logger . trace ( "Using proxy: %s" , options . proxy ) ;
318
315
}
319
316
}
317
+
318
+ private cleanupAfterRequest ( data : ICleanupRequestData ) : void {
319
+ data . timers . forEach ( t => {
320
+ if ( t ) {
321
+ clearTimeout ( t ) ;
322
+ t = null ;
323
+ }
324
+ } ) ;
325
+
326
+ if ( data . stuckResponseIntervalId ) {
327
+ clearInterval ( data . stuckResponseIntervalId ) ;
328
+ data . stuckResponseIntervalId = null ;
329
+ }
330
+ }
320
331
}
332
+
333
+ interface ICleanupRequestData {
334
+ timers : number [ ] ;
335
+ stuckResponseIntervalId : NodeJS . Timer ;
336
+ }
337
+
321
338
$injector . register ( "httpClient" , HttpClient ) ;
0 commit comments