25
25
import java .util .List ;
26
26
import java .util .Map ;
27
27
28
+ import javax .annotation .Priority ;
28
29
import javax .ws .rs .Priorities ;
29
30
import javax .ws .rs .client .Client ;
30
- import javax .ws .rs .client .ClientBuilder ;
31
31
import javax .ws .rs .client .ClientRequestContext ;
32
32
import javax .ws .rs .client .ClientRequestFilter ;
33
33
import javax .ws .rs .client .ClientResponseContext ;
42
42
import javax .ws .rs .core .MultivaluedMap ;
43
43
import javax .ws .rs .core .Response ;
44
44
45
- import javax .annotation .Priority ;
46
-
47
45
import org .glassfish .jersey .client .ClientProperties ;
48
46
import org .glassfish .jersey .client .internal .LocalizationMessages ;
49
47
@@ -270,8 +268,16 @@ private void updateCache(ClientRequestContext request, boolean success, Type ope
270
268
* {@code false} otherwise).
271
269
*/
272
270
static boolean repeatRequest (ClientRequestContext request , ClientResponseContext response , String newAuthorizationHeader ) {
273
- Client client = request .getClient ();
271
+ // If the failed response has an entity stream, close it. We must do this to avoid leaking a connection
272
+ // when we replace the entity stream of the failed response with that of the repeated response (see below).
273
+ // Notice that by closing the entity stream before sending the repeated request we allow the connection allocated
274
+ // to the failed request to be reused, if possible, for the repeated request.
275
+ if (response .hasEntity ()) {
276
+ discardInputAndClose (response .getEntityStream ());
277
+ response .setEntityStream (null );
278
+ }
274
279
280
+ Client client = request .getClient ();
275
281
String method = request .getMethod ();
276
282
MediaType mediaType = request .getMediaType ();
277
283
URI lUri = request .getUri ();
@@ -294,6 +300,12 @@ static boolean repeatRequest(ClientRequestContext request, ClientResponseContext
294
300
295
301
builder .property (REQUEST_PROPERTY_FILTER_REUSED , "true" );
296
302
303
+ // Copy other properties, if any, from the original request
304
+ for (String propertyName : request .getPropertyNames ()) {
305
+ Object propertyValue = request .getProperty (propertyName );
306
+ builder .property (propertyName , propertyValue );
307
+ }
308
+
297
309
Invocation invocation ;
298
310
if (request .getEntity () == null ) {
299
311
invocation = builder .build (method );
@@ -419,4 +431,23 @@ static Credentials getCredentials(ClientRequestContext request, Credentials defa
419
431
return specificCredentials != null ? specificCredentials : defaultCredentials ;
420
432
}
421
433
}
434
+
435
+ private static void discardInputAndClose (InputStream is ) {
436
+ byte [] buf = new byte [4096 ];
437
+ try {
438
+ while (true ) {
439
+ if (is .read (buf ) <= 0 ) {
440
+ break ;
441
+ }
442
+ }
443
+ } catch (IOException ex ) {
444
+ // ignore
445
+ } finally {
446
+ try {
447
+ is .close ();
448
+ } catch (IOException ex ) {
449
+ // ignore
450
+ }
451
+ }
452
+ }
422
453
}
0 commit comments