Skip to content

Commit aaf7c17

Browse files
author
oleksiys
committed
[master] fix issue AsyncHttpClient#549
AsyncHttpClient#549 "[grizzly-provider] connection abort, when neither transfer-encoding nor content-length is specified"
1 parent 368fb57 commit aaf7c17

File tree

6 files changed

+110
-10
lines changed

6 files changed

+110
-10
lines changed

providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013 Sonatype, Inc. All rights reserved.
2+
* Copyright (c) 2013-2014 Sonatype, Inc. All rights reserved.
33
*
44
* This program is licensed to you under the Apache License Version 2.0,
55
* and you may not use this file except in compliance with the Apache License Version 2.0.
@@ -163,8 +163,9 @@ public void onInitialLineParsed(HttpHeader httpHeader, FilterChainContext ctx) {
163163
}
164164
}
165165
}
166-
final GrizzlyResponseStatus responseStatus = new GrizzlyResponseStatus((HttpResponsePacket) httpHeader, context.getRequest()
167-
.getURI(), config);
166+
final GrizzlyResponseStatus responseStatus =
167+
new GrizzlyResponseStatus((HttpResponsePacket) httpHeader,
168+
context.getRequest().getURI(), config);
168169
context.setResponseStatus(responseStatus);
169170
if (context.getStatusHandler() != null) {
170171
return;

providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012 Sonatype, Inc. All rights reserved.
2+
* Copyright (c) 2012-2014 Sonatype, Inc. All rights reserved.
33
*
44
* This program is licensed to you under the Apache License Version 2.0,
55
* and you may not use this file except in compliance with the Apache License Version 2.0.
@@ -38,7 +38,8 @@ public class GrizzlyResponseStatus extends HttpResponseStatus {
3838
private final int majorVersion;
3939
private final int minorVersion;
4040
private final String protocolText;
41-
41+
private final HttpResponsePacket response;
42+
4243
// ------------------------------------------------------------ Constructors
4344

4445
public GrizzlyResponseStatus(final HttpResponsePacket response, final URI uri, AsyncHttpClientConfig config) {
@@ -49,6 +50,8 @@ public GrizzlyResponseStatus(final HttpResponsePacket response, final URI uri, A
4950
majorVersion = response.getProtocol().getMajorVersion();
5051
minorVersion = response.getProtocol().getMinorVersion();
5152
protocolText = response.getProtocolString();
53+
54+
this.response = response;
5255
}
5356

5457
// ----------------------------------------- Methods from HttpResponseStatus
@@ -105,4 +108,11 @@ public int getProtocolMinorVersion() {
105108
public String getProtocolText() {
106109
return protocolText;
107110
}
111+
112+
/**
113+
* @return internal Grizzly {@link HttpResponsePacket}
114+
*/
115+
public HttpResponsePacket getResponse() {
116+
return response;
117+
}
108118
}

providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013 Sonatype, Inc. All rights reserved.
2+
* Copyright (c) 2013-2014 Sonatype, Inc. All rights reserved.
33
*
44
* This program is licensed to you under the Apache License Version 2.0,
55
* and you may not use this file except in compliance with the Apache License Version 2.0.
@@ -33,6 +33,10 @@
3333
import java.io.IOException;
3434
import java.util.concurrent.atomic.AtomicInteger;
3535
import java.util.concurrent.atomic.AtomicLong;
36+
import org.asynchttpclient.providers.grizzly.filters.events.GracefulCloseEvent;
37+
import org.glassfish.grizzly.Connection;
38+
import org.glassfish.grizzly.filterchain.FilterChain;
39+
import org.glassfish.grizzly.http.HttpResponsePacket;
3640

3741
public final class HttpTxContext {
3842

@@ -62,10 +66,21 @@ public final class HttpTxContext {
6266
private HandShake handshake;
6367
private ProtocolHandler protocolHandler;
6468
private WebSocket webSocket;
65-
private CloseListener listener = new CloseListener<Closeable, CloseType>() {
69+
private final CloseListener listener = new CloseListener<Closeable, CloseType>() {
6670
@Override
6771
public void onClosed(Closeable closeable, CloseType type) throws IOException {
68-
if (CloseType.REMOTELY.equals(type)) {
72+
if (isGracefullyFinishResponseOnClose()) {
73+
// Connection was closed.
74+
// This event is fired only for responses, which don't have
75+
// associated transfer-encoding or content-length.
76+
// We have to complete such a request-response processing gracefully.
77+
final Connection c = responseStatus.getResponse()
78+
.getRequest().getConnection();
79+
final FilterChain fc = (FilterChain) c.getProcessor();
80+
81+
fc.fireEventUpstream(c,
82+
new GracefulCloseEvent(HttpTxContext.this), null);
83+
} else if (CloseType.REMOTELY.equals(type)) {
6984
abort(AsyncHttpProviderUtils.REMOTELY_CLOSED_EXCEPTION);
7085
}
7186
}
@@ -252,6 +267,12 @@ public void setWebSocket(WebSocket webSocket) {
252267
this.webSocket = webSocket;
253268
}
254269

270+
private boolean isGracefullyFinishResponseOnClose() {
271+
final HttpResponsePacket response = responseStatus.getResponse();
272+
return !response.getProcessingState().isKeepAlive() &&
273+
!response.isChunked() && response.getContentLength() == -1;
274+
}
275+
255276
// ------------------------------------------------- Package Private Methods
256277

257278
public HttpTxContext copy() {

providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013 Sonatype, Inc. All rights reserved.
2+
* Copyright (c) 2013-2014 Sonatype, Inc. All rights reserved.
33
*
44
* This program is licensed to you under the Apache License Version 2.0,
55
* and you may not use this file except in compliance with the Apache License Version 2.0.
@@ -21,6 +21,10 @@
2121
import org.glassfish.grizzly.http.HttpHeader;
2222

2323
import java.io.IOException;
24+
import org.asynchttpclient.providers.grizzly.filters.events.GracefulCloseEvent;
25+
import org.glassfish.grizzly.filterchain.FilterChainEvent;
26+
import org.glassfish.grizzly.filterchain.NextAction;
27+
import org.glassfish.grizzly.http.HttpResponsePacket;
2428

2529
/**
2630
* Extension of the {@link HttpClientFilter} that is responsible for handling
@@ -45,6 +49,28 @@ public AsyncHttpClientEventFilter(final EventHandler eventHandler, final int max
4549
this.eventHandler = eventHandler;
4650
}
4751

52+
@Override
53+
public NextAction handleEvent(final FilterChainContext ctx,
54+
final FilterChainEvent event) throws IOException {
55+
if (event.type() == GracefulCloseEvent.class) {
56+
// Connection was closed.
57+
// This event is fired only for responses, which don't have
58+
// associated transfer-encoding or content-length.
59+
// We have to complete such a request-response processing gracefully.
60+
final GracefulCloseEvent closeEvent = (GracefulCloseEvent) event;
61+
final HttpResponsePacket response = closeEvent.getHttpTxContext()
62+
.getResponseStatus().getResponse();
63+
response.getProcessingState().getHttpContext().attach(ctx);
64+
65+
onHttpPacketParsed(response, ctx);
66+
67+
return ctx.getStopAction();
68+
}
69+
70+
return ctx.getInvokeAction();
71+
}
72+
73+
4874
@Override
4975
public void exceptionOccurred(FilterChainContext ctx, Throwable error) {
5076
eventHandler.exceptionOccurred(ctx, error);

providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013 Sonatype, Inc. All rights reserved.
2+
* Copyright (c) 2013-2014 Sonatype, Inc. All rights reserved.
33
*
44
* This program is licensed to you under the Apache License Version 2.0,
55
* and you may not use this file except in compliance with the Apache License Version 2.0.
@@ -299,6 +299,7 @@ private boolean sendAsGrizzlyRequest(final RequestInfoHolder requestInfoHolder,
299299
httpCtx.attach(ctx);
300300
HttpTxContext.set(ctx, httpTxContext);
301301
requestPacketLocal.getProcessingState().setHttpContext(httpCtx);
302+
requestPacketLocal.setConnection(c);
302303

303304
return sendRequest(sendingCtx, request, requestPacketLocal);
304305
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (c) 2014 Sonatype, Inc. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
7+
*
8+
* Unless required by applicable law or agreed to in writing,
9+
* software distributed under the Apache License Version 2.0 is distributed on an
10+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
12+
*/
13+
14+
package org.asynchttpclient.providers.grizzly.filters.events;
15+
16+
import org.asynchttpclient.providers.grizzly.HttpTxContext;
17+
import org.glassfish.grizzly.filterchain.FilterChainEvent;
18+
19+
/**
20+
* {@link FilterChainEvent} to gracefully complete the request-response processing
21+
* when {@link Connection} is getting closed by the remote host.
22+
*
23+
* @since 1.8.7
24+
* @author The Grizzly Team
25+
*/
26+
public class GracefulCloseEvent implements FilterChainEvent {
27+
private final HttpTxContext httpTxContext;
28+
29+
public GracefulCloseEvent(HttpTxContext httpTxContext) {
30+
this.httpTxContext = httpTxContext;
31+
}
32+
33+
public HttpTxContext getHttpTxContext() {
34+
return httpTxContext;
35+
}
36+
37+
@Override
38+
public Object type() {
39+
return GracefulCloseEvent.class;
40+
}
41+
}

0 commit comments

Comments
 (0)