You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2016/11/09 20:37:53 UTC
svn commit: r1769014 - in /httpcomponents/httpcore/trunk:
httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/
httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/
httpcore5-testing/src/test/java/org/apache/hc/core5/testing/n...
Author: olegk
Date: Wed Nov 9 20:37:53 2016
New Revision: 1769014
URL: http://svn.apache.org/viewvc?rev=1769014&view=rev
Log:
Expect-continue handshake logic moved from server stream handlers to server exchange handlers; client stream handlers changed to propagate informational response messages to client exchange handlers; fixed potential race conditions in stream handlers
Removed:
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ExpectationChannel.java
Modified:
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttp2StreamHandler.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java
httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/EchoHandler.java
httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/Http1IntegrationTest.java
httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http2/Http2IntegrationTest.java
httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncReverseProxyExample.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractClassicServerExchangeHandler.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncClientExchangeHandler.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncServerExchangeHandler.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ResponseChannel.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicClientExchangeHandler.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java
Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttp2StreamHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttp2StreamHandler.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttp2StreamHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttp2StreamHandler.java Wed Nov 9 20:37:53 2016
@@ -42,6 +42,7 @@ import org.apache.hc.core5.http.HttpStat
import org.apache.hc.core5.http.HttpVersion;
import org.apache.hc.core5.http.ProtocolException;
import org.apache.hc.core5.http.impl.BasicHttpConnectionMetrics;
+import org.apache.hc.core5.http.impl.LazyEntityDetails;
import org.apache.hc.core5.http.impl.nio.MessageState;
import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
import org.apache.hc.core5.http.nio.DataStreamChannel;
@@ -53,7 +54,6 @@ import org.apache.hc.core5.http2.H2Conne
import org.apache.hc.core5.http2.H2Error;
import org.apache.hc.core5.http2.impl.DefaultH2RequestConverter;
import org.apache.hc.core5.http2.impl.DefaultH2ResponseConverter;
-import org.apache.hc.core5.http.impl.LazyEntityDetails;
class ClientHttp2StreamHandler implements Http2StreamHandler {
@@ -142,7 +142,12 @@ class ClientHttp2StreamHandler implement
} else {
final Header h = request.getFirstHeader(HttpHeaders.EXPECT);
final boolean expectContinue = h != null && "100-continue".equalsIgnoreCase(h.getValue());
- requestState = expectContinue ? MessageState.ACK : MessageState.BODY;
+ if (expectContinue) {
+ requestState = MessageState.ACK;
+ } else {
+ requestState = MessageState.BODY;
+ exchangeHandler.produce(dataChannel);
+ }
}
} else {
throw new H2ConnectionException(H2Error.INTERNAL_ERROR, "Request already committed");
@@ -180,16 +185,24 @@ class ClientHttp2StreamHandler implement
throw new ProtocolException("Unexpected message headers");
}
final HttpResponse response = DefaultH2ResponseConverter.INSTANCE.convert(headers);
- final EntityDetails entityDetails = endStream ? null : new LazyEntityDetails(response);
-
- if (response.getCode() < 200) {
- if (response.getCode() == HttpStatus.SC_CONTINUE && requestState == MessageState.ACK) {
+ final int status = response.getCode();
+ if (status < HttpStatus.SC_INFORMATIONAL) {
+ throw new ProtocolException("Invalid response: " + status);
+ }
+ if (status < HttpStatus.SC_SUCCESS) {
+ exchangeHandler.consumeInformation(response);
+ }
+ if (requestState == MessageState.ACK) {
+ if (status == HttpStatus.SC_CONTINUE || status >= HttpStatus.SC_SUCCESS) {
requestState = MessageState.BODY;
exchangeHandler.produce(dataChannel);
}
+ }
+ if (status < HttpStatus.SC_SUCCESS) {
return;
}
+ final EntityDetails entityDetails = endStream ? null : new LazyEntityDetails(response);
context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
httpProcessor.process(response, entityDetails, context);
connMetrics.incrementResponseCount();
Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttp2StreamHandler.java Wed Nov 9 20:37:53 2016
@@ -35,7 +35,6 @@ import org.apache.hc.core5.http.EntityDe
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpConnection;
import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.HttpStatus;
@@ -44,11 +43,9 @@ import org.apache.hc.core5.http.Protocol
import org.apache.hc.core5.http.impl.BasicHttpConnectionMetrics;
import org.apache.hc.core5.http.impl.LazyEntityDetails;
import org.apache.hc.core5.http.impl.nio.MessageState;
-import org.apache.hc.core5.http.message.BasicHttpResponse;
import org.apache.hc.core5.http.nio.AsyncPushProducer;
import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
import org.apache.hc.core5.http.nio.DataStreamChannel;
-import org.apache.hc.core5.http.nio.ExpectationChannel;
import org.apache.hc.core5.http.nio.HandlerFactory;
import org.apache.hc.core5.http.nio.ResponseChannel;
import org.apache.hc.core5.http.protocol.HttpCoreContext;
@@ -119,11 +116,27 @@ public class ServerHttp2StreamHandler im
this.responseState = MessageState.IDLE;
}
+ private void commitInformation(final HttpResponse response) throws IOException, HttpException {
+ if (responseCommitted.get()) {
+ throw new H2ConnectionException(H2Error.INTERNAL_ERROR, "Response already committed");
+ }
+ final int status = response.getCode();
+ if (status < HttpStatus.SC_INFORMATIONAL || status >= HttpStatus.SC_SUCCESS) {
+ throw new HttpException("Invalid intermediate response: " + status);
+ }
+ final List<Header> responseHeaders = DefaultH2ResponseConverter.INSTANCE.convert(response);
+ outputChannel.submit(responseHeaders, false);
+ }
+
private void commitResponse(
final HttpResponse response,
final EntityDetails responseEntityDetails) throws HttpException, IOException {
if (responseCommitted.compareAndSet(false, true)) {
+ final int status = response.getCode();
+ if (status < HttpStatus.SC_SUCCESS) {
+ throw new HttpException("Invalid response: " + status);
+ }
context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
httpProcessor.process(response, responseEntityDetails, context);
@@ -135,7 +148,7 @@ public class ServerHttp2StreamHandler im
responseState = MessageState.COMPLETE;
} else {
responseState = MessageState.BODY;
- exchangeHandler.produce(dataChannel);
+ exchangeHandler.produce(outputChannel);
}
} else {
throw new H2ConnectionException(H2Error.INTERNAL_ERROR, "Response already committed");
@@ -153,13 +166,6 @@ public class ServerHttp2StreamHandler im
connMetrics.incrementRequestCount();
}
- private void commitContinue() throws IOException, HttpException {
- final HttpResponse ack = new BasicHttpResponse(HttpStatus.SC_CONTINUE);
- final List<Header> responseHeaders = DefaultH2ResponseConverter.INSTANCE.convert(ack);
-
- outputChannel.submit(responseHeaders, false);
- }
-
@Override
public void consumePromise(final List<Header> headers) throws HttpException, IOException {
throw new ProtocolException("Unexpected message promise");
@@ -184,10 +190,6 @@ public class ServerHttp2StreamHandler im
if (handler == null) {
throw new H2StreamResetException(H2Error.REFUSED_STREAM, "Stream refused");
}
- if (handler == null) {
- throw new H2ConnectionException(H2Error.INTERNAL_ERROR,
- "Unable to handle " + request.getMethod() + " " + request.getPath());
- }
exchangeHandler = handler;
context.setProtocolVersion(HttpVersion.HTTP_2);
@@ -198,61 +200,26 @@ public class ServerHttp2StreamHandler im
httpProcessor.process(request, requestEntityDetails, context);
connMetrics.incrementRequestCount();
- boolean expectContinue = false;
- if (requestEntityDetails != null) {
- final Header h = request.getFirstHeader(HttpHeaders.EXPECT);
- if (h != null && "100-continue".equalsIgnoreCase(h.getValue())) {
- expectContinue = true;
- }
- }
-
- if (expectContinue) {
- exchangeHandler.verify(request, requestEntityDetails, new ExpectationChannel() {
-
- @Override
- public void sendResponse(
- final HttpResponse response, final EntityDetails responseEntityDetails) throws HttpException, IOException {
- commitResponse(response, responseEntityDetails);
- }
-
- @Override
- public void sendContinue() throws HttpException, IOException {
- commitContinue();
- exchangeHandler.handleRequest(request, requestEntityDetails, new ResponseChannel() {
-
- @Override
- public void sendResponse(
- final HttpResponse response, final EntityDetails responseEntityDetails) throws HttpException, IOException {
- commitResponse(response, responseEntityDetails);
- }
-
- @Override
- public void pushPromise(
- final HttpRequest promise, final AsyncPushProducer pushProducer) throws HttpException, IOException {
- commitPromise(promise, pushProducer);
- }
+ exchangeHandler.handleRequest(request, requestEntityDetails, new ResponseChannel() {
- });
- }
+ @Override
+ public void sendInformation(final HttpResponse response) throws HttpException, IOException {
+ commitInformation(response);
+ }
- });
- } else {
- exchangeHandler.handleRequest(request, requestEntityDetails, new ResponseChannel() {
+ @Override
+ public void sendResponse(
+ final HttpResponse response, final EntityDetails responseEntityDetails) throws HttpException, IOException {
+ commitResponse(response, responseEntityDetails);
+ }
- @Override
- public void sendResponse(
- final HttpResponse response, final EntityDetails responseEntityDetails) throws HttpException, IOException {
- commitResponse(response, responseEntityDetails);
- }
-
- @Override
- public void pushPromise(
- final HttpRequest promise, final AsyncPushProducer pushProducer) throws HttpException, IOException {
- commitPromise(promise, pushProducer);
- }
+ @Override
+ public void pushPromise(
+ final HttpRequest promise, final AsyncPushProducer pushProducer) throws HttpException, IOException {
+ commitPromise(promise, pushProducer);
+ }
- });
- }
+ });
}
@Override
Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerPushHttp2StreamHandler.java Wed Nov 9 20:37:53 2016
@@ -37,6 +37,7 @@ import org.apache.hc.core5.http.HttpConn
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.HttpVersion;
import org.apache.hc.core5.http.ProtocolException;
import org.apache.hc.core5.http.impl.BasicHttpConnectionMetrics;
@@ -46,6 +47,8 @@ import org.apache.hc.core5.http.nio.Data
import org.apache.hc.core5.http.nio.ResponseChannel;
import org.apache.hc.core5.http.protocol.HttpCoreContext;
import org.apache.hc.core5.http.protocol.HttpProcessor;
+import org.apache.hc.core5.http2.H2ConnectionException;
+import org.apache.hc.core5.http2.H2Error;
import org.apache.hc.core5.http2.impl.DefaultH2RequestConverter;
import org.apache.hc.core5.http2.impl.DefaultH2ResponseConverter;
@@ -58,6 +61,7 @@ class ServerPushHttp2StreamHandler imple
private final BasicHttpConnectionMetrics connMetrics;
private final AsyncPushProducer pushProducer;
private final HttpCoreContext context;
+ private final AtomicBoolean responseCommitted;
private final AtomicBoolean done;
private volatile MessageState requestState;
@@ -100,6 +104,7 @@ class ServerPushHttp2StreamHandler imple
this.connMetrics = connMetrics;
this.pushProducer = pushProducer;
this.context = HttpCoreContext.create();
+ this.responseCommitted = new AtomicBoolean(false);
this.done = new AtomicBoolean(false);
this.requestState = MessageState.COMPLETE;
this.responseState = MessageState.IDLE;
@@ -136,6 +141,55 @@ class ServerPushHttp2StreamHandler imple
}
}
+ private void commitInformation(final HttpResponse response) throws IOException, HttpException {
+ if (responseCommitted.get()) {
+ throw new H2ConnectionException(H2Error.INTERNAL_ERROR, "Response already committed");
+ }
+ final int status = response.getCode();
+ if (status < HttpStatus.SC_INFORMATIONAL || status >= HttpStatus.SC_SUCCESS) {
+ throw new HttpException("Invalid intermediate response: " + status);
+ }
+ final List<Header> responseHeaders = DefaultH2ResponseConverter.INSTANCE.convert(response);
+ outputChannel.submit(responseHeaders, false);
+ }
+
+ private void commitResponse(
+ final HttpResponse response,
+ final EntityDetails responseEntityDetails) throws HttpException, IOException {
+ if (responseCommitted.compareAndSet(false, true)) {
+
+ context.setProtocolVersion(HttpVersion.HTTP_2);
+ context.setAttribute(HttpCoreContext.HTTP_CONNECTION, connection);
+ context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
+ httpProcessor.process(response, responseEntityDetails, context);
+
+ final List<Header> headers = DefaultH2ResponseConverter.INSTANCE.convert(response);
+ outputChannel.submit(headers, responseEntityDetails == null);
+ connMetrics.incrementResponseCount();
+ if (responseEntityDetails == null) {
+ responseState = MessageState.COMPLETE;
+ } else {
+ responseState = MessageState.BODY;
+ pushProducer.produce(outputChannel);
+ }
+ }
+ }
+
+ private void commitPromise(
+ final HttpRequest promise,
+ final AsyncPushProducer pushProducer) throws HttpException, IOException {
+
+ context.setProtocolVersion(HttpVersion.HTTP_2);
+ context.setAttribute(HttpCoreContext.HTTP_CONNECTION, connection);
+ context.setAttribute(HttpCoreContext.HTTP_REQUEST, promise);
+ httpProcessor.process(promise, null, context);
+
+ final List<Header> headers = DefaultH2RequestConverter.INSTANCE.convert(promise);
+
+ outputChannel.push(headers, pushProducer);
+ connMetrics.incrementRequestCount();
+ }
+
@Override
public void produceOutput() throws HttpException, IOException {
switch (responseState) {
@@ -143,38 +197,21 @@ class ServerPushHttp2StreamHandler imple
responseState = MessageState.HEADERS;
pushProducer.produceResponse(new ResponseChannel() {
- private final AtomicBoolean responseCommitted = new AtomicBoolean(false);
+ @Override
+ public void sendInformation(final HttpResponse response) throws HttpException, IOException {
+ commitInformation(response);
+ }
@Override
public void sendResponse(
final HttpResponse response, final EntityDetails entityDetails) throws HttpException, IOException {
- if (responseCommitted.compareAndSet(false, true)) {
-
- context.setProtocolVersion(HttpVersion.HTTP_2);
- context.setAttribute(HttpCoreContext.HTTP_CONNECTION, connection);
- context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
- httpProcessor.process(response, entityDetails, context);
-
- final List<Header> headers = DefaultH2ResponseConverter.INSTANCE.convert(response);
- outputChannel.submit(headers, entityDetails == null);
- responseState = entityDetails == null ? MessageState.COMPLETE : MessageState.BODY;
- connMetrics.incrementResponseCount();
- }
+ commitResponse(response, entityDetails);
}
@Override
public void pushPromise(
final HttpRequest promise, final AsyncPushProducer pushProducer) throws HttpException, IOException {
-
- context.setProtocolVersion(HttpVersion.HTTP_2);
- context.setAttribute(HttpCoreContext.HTTP_CONNECTION, connection);
- context.setAttribute(HttpCoreContext.HTTP_REQUEST, promise);
- httpProcessor.process(promise, null, context);
-
- final List<Header> headers = DefaultH2RequestConverter.INSTANCE.convert(promise);
-
- outputChannel.push(headers, pushProducer);
- connMetrics.incrementRequestCount();
+ commitPromise(promise, pushProducer);
}
});
Modified: httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/EchoHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/EchoHandler.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/EchoHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/EchoHandler.java Wed Nov 9 20:37:53 2016
@@ -33,6 +33,7 @@ import java.util.List;
import org.apache.hc.core5.http.EntityDetails;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.HttpStatus;
@@ -40,7 +41,6 @@ import org.apache.hc.core5.http.message.
import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
import org.apache.hc.core5.http.nio.CapacityChannel;
import org.apache.hc.core5.http.nio.DataStreamChannel;
-import org.apache.hc.core5.http.nio.ExpectationChannel;
import org.apache.hc.core5.http.nio.ResponseChannel;
import org.apache.hc.core5.http.protocol.HttpContext;
@@ -69,18 +69,16 @@ public class EchoHandler implements Asyn
}
@Override
- public void verify(
- final HttpRequest request,
- final EntityDetails entityDetails,
- final ExpectationChannel expectationChannel) throws HttpException, IOException {
- expectationChannel.sendContinue();
- }
-
- @Override
public void handleRequest(
final HttpRequest request,
final EntityDetails entityDetails,
final ResponseChannel responseChannel) throws HttpException, IOException {
+ if (entityDetails != null) {
+ final Header h = request.getFirstHeader(HttpHeaders.EXPECT);
+ if (h != null && "100-continue".equalsIgnoreCase(h.getValue())) {
+ responseChannel.sendInformation(new BasicHttpResponse(HttpStatus.SC_CONTINUE));
+ }
+ }
final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
responseChannel.sendResponse(response, entityDetails);
}
Modified: httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/Http1IntegrationTest.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/Http1IntegrationTest.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/Http1IntegrationTest.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http/Http1IntegrationTest.java Wed Nov 9 20:37:53 2016
@@ -93,7 +93,6 @@ import org.apache.hc.core5.http.nio.Basi
import org.apache.hc.core5.http.nio.CapacityChannel;
import org.apache.hc.core5.http.nio.ContentEncoder;
import org.apache.hc.core5.http.nio.DataStreamChannel;
-import org.apache.hc.core5.http.nio.ExpectationChannel;
import org.apache.hc.core5.http.nio.HandlerFactory;
import org.apache.hc.core5.http.nio.NHttpMessageParser;
import org.apache.hc.core5.http.nio.NHttpMessageWriter;
@@ -708,7 +707,7 @@ public class Http1IntegrationTest extend
final Future<Message<HttpResponse, String>> future2 = streamEndpoint.execute(
new BasicRequestProducer(request2, new MultiLineEntityProducer("0123456789abcdef", 5000)),
new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
- final Message<HttpResponse, String> result2 = future2.get(50000, TimeUnit.SECONDS);
+ final Message<HttpResponse, String> result2 = future2.get(TIMEOUT, TimeUnit.SECONDS);
Assert.assertNotNull(result2);
final HttpResponse response2 = result2.getHead();
Assert.assertNotNull(response2);
@@ -762,29 +761,29 @@ public class Http1IntegrationTest extend
}
@Override
- public void verify(
+ public void handleRequest(
final HttpRequest request,
final EntityDetails entityDetails,
- final ExpectationChannel expectationChannel) throws HttpException, IOException {
+ final ResponseChannel responseChannel) throws HttpException, IOException {
+
Executors.newSingleThreadExecutor().execute(new Runnable() {
@Override
public void run() {
try {
- Thread.sleep(random.nextInt(1000));
- expectationChannel.sendContinue();
+ if (entityDetails != null) {
+ final Header h = request.getFirstHeader(HttpHeaders.EXPECT);
+ if (h != null && "100-continue".equalsIgnoreCase(h.getValue())) {
+ Thread.sleep(random.nextInt(1000));
+ responseChannel.sendInformation(new BasicHttpResponse(HttpStatus.SC_CONTINUE));
+ }
+ final HttpResponse response = new BasicHttpResponse(200);
+ responseChannel.sendResponse(response, entityProducer);
+ }
} catch (Exception ignore) {
}
}
});
- }
- @Override
- public void handleRequest(
- final HttpRequest request,
- final EntityDetails entityDetails,
- final ResponseChannel responseChannel) throws HttpException, IOException {
- final HttpResponse response = new BasicHttpResponse(200);
- responseChannel.sendResponse(response, entityProducer);
}
@Override
@@ -803,12 +802,16 @@ public class Http1IntegrationTest extend
@Override
public int available() {
- return entityProducer.available();
+ synchronized (entityProducer) {
+ return entityProducer.available();
+ }
}
@Override
public void produce(final DataStreamChannel channel) throws IOException {
- entityProducer.produce(channel);
+ synchronized (entityProducer) {
+ entityProducer.produce(channel);
+ }
}
@Override
@@ -863,11 +866,19 @@ public class Http1IntegrationTest extend
}
@Override
- public void verify(
+ public void handleRequest(
final HttpRequest request,
final EntityDetails entityDetails,
- final ExpectationChannel expectationChannel) throws HttpException, IOException {
- expectationChannel.sendContinue();
+ final ResponseChannel responseChannel) throws HttpException, IOException {
+ final AsyncResponseProducer producer;
+ final Header h = request.getFirstHeader("password");
+ if (h != null && "secret".equals(h.getValue())) {
+ producer = new BasicResponseProducer(HttpStatus.SC_OK, "All is well");
+ } else {
+ producer = new BasicResponseProducer(HttpStatus.SC_UNAUTHORIZED, "You shall not pass");
+ }
+ responseProducer.set(producer);
+ responseChannel.sendResponse(producer.produceResponse(), producer.getEntityDetails());
}
@Override
@@ -885,22 +896,6 @@ public class Http1IntegrationTest extend
}
@Override
- public void handleRequest(
- final HttpRequest request,
- final EntityDetails entityDetails,
- final ResponseChannel responseChannel) throws HttpException, IOException {
- final AsyncResponseProducer producer;
- final Header h = request.getFirstHeader("password");
- if (h != null && "secret".equals(h.getValue())) {
- producer = new BasicResponseProducer(HttpStatus.SC_OK, "All is well");
- } else {
- producer = new BasicResponseProducer(HttpStatus.SC_UNAUTHORIZED, "You shall not pass");
- }
- responseProducer.set(producer);
- responseChannel.sendResponse(producer.produceResponse(), producer.getEntityDetails());
- }
-
- @Override
public int available() {
final AsyncResponseProducer producer = responseProducer.get();
return producer.available();
Modified: httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http2/Http2IntegrationTest.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http2/Http2IntegrationTest.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http2/Http2IntegrationTest.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/http2/Http2IntegrationTest.java Wed Nov 9 20:37:53 2016
@@ -75,7 +75,6 @@ import org.apache.hc.core5.http.nio.Basi
import org.apache.hc.core5.http.nio.BasicResponseProducer;
import org.apache.hc.core5.http.nio.CapacityChannel;
import org.apache.hc.core5.http.nio.DataStreamChannel;
-import org.apache.hc.core5.http.nio.ExpectationChannel;
import org.apache.hc.core5.http.nio.ResponseChannel;
import org.apache.hc.core5.http.nio.Supplier;
import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
@@ -736,14 +735,6 @@ public class Http2IntegrationTest extend
}
@Override
- public void verify(
- final HttpRequest request,
- final EntityDetails entityDetails,
- final ExpectationChannel expectationChannel) throws HttpException, IOException {
- expectationChannel.sendContinue();
- }
-
- @Override
public void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
capacityChannel.update(Integer.MAX_VALUE);
}
Modified: httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncReverseProxyExample.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncReverseProxyExample.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncReverseProxyExample.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncReverseProxyExample.java Wed Nov 9 20:37:53 2016
@@ -75,7 +75,6 @@ import org.apache.hc.core5.http.nio.Asyn
import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
import org.apache.hc.core5.http.nio.CapacityChannel;
import org.apache.hc.core5.http.nio.DataStreamChannel;
-import org.apache.hc.core5.http.nio.ExpectationChannel;
import org.apache.hc.core5.http.nio.RequestChannel;
import org.apache.hc.core5.http.nio.ResponseChannel;
import org.apache.hc.core5.http.nio.Supplier;
@@ -286,14 +285,6 @@ public class AsyncReverseProxyExample {
}
@Override
- public void verify(
- final HttpRequest request,
- final EntityDetails entityDetails,
- final ExpectationChannel expectationChannel) throws HttpException, IOException {
- expectationChannel.sendContinue();
- }
-
- @Override
public void handleRequest(
final HttpRequest incomingRequest,
final EntityDetails entityDetails,
@@ -305,6 +296,13 @@ public class AsyncReverseProxyExample {
exchangeState.request = incomingRequest;
exchangeState.inputEnd = entityDetails == null;
exchangeState.responseMessageChannel = responseChannel;
+
+ if (entityDetails != null) {
+ final Header h = incomingRequest.getFirstHeader(HttpHeaders.EXPECT);
+ if (h != null && "100-continue".equalsIgnoreCase(h.getValue())) {
+ responseChannel.sendInformation(new BasicHttpResponse(HttpStatus.SC_CONTINUE));
+ }
+ }
}
System.out.println("[proxy->origin] " + exchangeState.id + " request connection to " + targetHost);
Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractClassicServerExchangeHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractClassicServerExchangeHandler.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractClassicServerExchangeHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractClassicServerExchangeHandler.java Wed Nov 9 20:37:53 2016
@@ -52,7 +52,6 @@ import org.apache.hc.core5.http.message.
import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
import org.apache.hc.core5.http.nio.CapacityChannel;
import org.apache.hc.core5.http.nio.DataStreamChannel;
-import org.apache.hc.core5.http.nio.ExpectationChannel;
import org.apache.hc.core5.http.nio.ResponseChannel;
import org.apache.hc.core5.http.nio.entity.ContentInputStream;
import org.apache.hc.core5.http.nio.entity.ContentOutputStream;
@@ -98,19 +97,17 @@ public abstract class AbstractClassicSer
HttpContext context) throws IOException, HttpException;
@Override
- public final void verify(
- final HttpRequest request,
- final EntityDetails entityDetails,
- final ExpectationChannel expectationChannel) throws HttpException, IOException {
- expectationChannel.sendContinue();
- }
-
- @Override
public final void handleRequest(
final HttpRequest request,
final EntityDetails entityDetails,
final ResponseChannel responseChannel) throws HttpException, IOException {
+ if (entityDetails != null) {
+ final Header h = request.getFirstHeader(HttpHeaders.EXPECT);
+ if (h != null && "100-continue".equalsIgnoreCase(h.getValue())) {
+ responseChannel.sendInformation(new BasicHttpResponse(HttpStatus.SC_CONTINUE));
+ }
+ }
final AtomicBoolean responseCommitted = new AtomicBoolean(false);
final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java Wed Nov 9 20:37:53 2016
@@ -35,6 +35,7 @@ import java.nio.channels.ClosedChannelEx
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.WritableByteChannel;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -81,6 +82,7 @@ abstract class AbstractHttp1StreamDuplex
private final NHttpMessageWriter<OutgoingMessage> outgoingMessageWriter;
private final ConnectionListener connectionListener;
private final Lock outputLock;
+ private final AtomicInteger outputRequests;
private volatile Message<IncomingMessage, ContentDecoder> incomingMessage;
private volatile Message<OutgoingMessage, ContentEncoder> outgoingMessage;
@@ -109,6 +111,7 @@ abstract class AbstractHttp1StreamDuplex
this.outgoingMessageWriter = outgoingMessageWriter;
this.connectionListener = connectionListener;
this.outputLock = new ReentrantLock();
+ this.outputRequests = new AtomicInteger(0);
this.connState = ConnectionState.READY;
}
@@ -218,6 +221,7 @@ abstract class AbstractHttp1StreamDuplex
break;
} else {
inputEnd();
+ ioSession.setEvent(SelectionKey.OP_READ);
}
}
} while (bytesRead > 0);
@@ -238,6 +242,7 @@ abstract class AbstractHttp1StreamDuplex
if (contentDecoder.isCompleted()) {
incomingMessage = null;
inputEnd();
+ ioSession.setEvent(SelectionKey.OP_READ);
}
if (bytesRead == 0) {
break;
@@ -262,15 +267,21 @@ abstract class AbstractHttp1StreamDuplex
if (isOutputReady()) {
produceOutput();
} else {
+ final int pendingOutputRequests = outputRequests.get();
+ final boolean outputPending;
outputLock.lock();
try {
- if (!outbuf.hasData()) {
- ioSession.clearEvent(SelectionKey.OP_WRITE);
- }
+ outputPending = outbuf.hasData();
} finally {
outputLock.unlock();
}
+ if (!outputPending && outputRequests.compareAndSet(pendingOutputRequests, 0)) {
+ ioSession.clearEvent(SelectionKey.OP_WRITE);
+ } else {
+ outputRequests.addAndGet(-pendingOutputRequests);
+ }
}
+
outputLock.lock();
final boolean outputEnd;
try {
@@ -280,21 +291,17 @@ abstract class AbstractHttp1StreamDuplex
}
if (outputEnd) {
outputEnd();
- processCommands();
+ if (connState.compareTo(ConnectionState.ACTIVE) == 0) {
+ processCommands();
+ } else if (connState.compareTo(ConnectionState.GRACEFUL_SHUTDOWN) >= 0 && inputIdle() && outputIdle()) {
+ connState = ConnectionState.SHUTDOWN;
+ }
}
}
- outputLock.lock();
- try {
- if (connState.compareTo(ConnectionState.GRACEFUL_SHUTDOWN) >= 0 && inputIdle() && outputIdle()) {
- connState = ConnectionState.SHUTDOWN;
- }
- if (!outbuf.hasData() && connState.compareTo(ConnectionState.SHUTDOWN) >= 0) {
- ioSession.close();
- cancelPendingCommands();
- releaseResources();
- }
- } finally {
- outputLock.unlock();
+ if (connState.compareTo(ConnectionState.SHUTDOWN) >= 0) {
+ ioSession.close();
+ cancelPendingCommands();
+ releaseResources();
}
}
@@ -371,6 +378,7 @@ abstract class AbstractHttp1StreamDuplex
}
void requestSessionOutput() {
+ outputRequests.incrementAndGet();
ioSession.setEvent(SelectionKey.OP_WRITE);
}
Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java Wed Nov 9 20:37:53 2016
@@ -175,6 +175,7 @@ class ClientHttp1StreamHandler implement
connection.setSocketTimeout(h1Config.getWaitForContinueTimeout());
} else {
requestState = MessageState.BODY;
+ exchangeHandler.produce(internalDataChannel);
}
}
} else {
@@ -204,36 +205,32 @@ class ClientHttp1StreamHandler implement
}
}
- private void validateStatus(final HttpResponse response) throws ProtocolException {
- if (response.getCode() < HttpStatus.SC_INFORMATIONAL) {
- throw new ProtocolException("Invalid response code");
- }
- if (response.getCode() < HttpStatus.SC_SUCCESS) {
- if (response.getCode() != HttpStatus.SC_CONTINUE) {
- throw new ProtocolException("Unsupported intermediate response code");
- }
- }
- }
-
void consumeHeader(final HttpResponse response, final boolean endStream) throws HttpException, IOException {
if (done.get() || responseState != MessageState.HEADERS) {
throw new ProtocolException("Unexpected message head");
}
- validateStatus(response);
-
+ final int status = response.getCode();
+ if (status < HttpStatus.SC_INFORMATIONAL) {
+ throw new ProtocolException("Invalid response: " + status);
+ }
+ if (status < HttpStatus.SC_SUCCESS) {
+ exchangeHandler.consumeInformation(response);
+ }
if (requestState == MessageState.ACK) {
- connection.setSocketTimeout(timeout);
- requestState = MessageState.BODY;
- if (response.getCode() < HttpStatus.SC_CLIENT_ERROR) {
- exchangeHandler.produce(internalDataChannel);
+ if (status == HttpStatus.SC_CONTINUE || status >= HttpStatus.SC_SUCCESS) {
+ connection.setSocketTimeout(timeout);
+ requestState = MessageState.BODY;
+ if (status < HttpStatus.SC_CLIENT_ERROR) {
+ exchangeHandler.produce(internalDataChannel);
+ }
}
}
- if (response.getCode() == HttpStatus.SC_CONTINUE) {
+ if (status < HttpStatus.SC_SUCCESS) {
return;
}
if (requestState == MessageState.BODY) {
- boolean keepAlive = response.getCode() < HttpStatus.SC_CLIENT_ERROR;
+ boolean keepAlive = status < HttpStatus.SC_CLIENT_ERROR;
if (keepAlive) {
final Header h = response.getFirstHeader(HttpHeaders.CONNECTION);
if (h != null && HeaderElements.CLOSE.equalsIgnoreCase(h.getValue())) {
Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java Wed Nov 9 20:37:53 2016
@@ -36,7 +36,6 @@ import org.apache.hc.core5.http.EntityDe
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpConnection;
import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.HttpStatus;
@@ -47,14 +46,12 @@ import org.apache.hc.core5.http.Protocol
import org.apache.hc.core5.http.ProtocolVersion;
import org.apache.hc.core5.http.UnsupportedHttpVersionException;
import org.apache.hc.core5.http.impl.LazyEntityDetails;
-import org.apache.hc.core5.http.message.BasicHttpResponse;
import org.apache.hc.core5.http.nio.AsyncPushProducer;
import org.apache.hc.core5.http.nio.AsyncResponseProducer;
import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
import org.apache.hc.core5.http.nio.BasicResponseProducer;
import org.apache.hc.core5.http.nio.ContentDecoder;
import org.apache.hc.core5.http.nio.DataStreamChannel;
-import org.apache.hc.core5.http.nio.ExpectationChannel;
import org.apache.hc.core5.http.nio.HandlerFactory;
import org.apache.hc.core5.http.nio.ResourceHolder;
import org.apache.hc.core5.http.nio.ResponseChannel;
@@ -145,6 +142,11 @@ class ServerHttp1StreamHandler implement
final EntityDetails responseEntityDetails) throws HttpException, IOException {
if (responseCommitted.compareAndSet(false, true)) {
+ final int status = response.getCode();
+ if (status < HttpStatus.SC_SUCCESS) {
+ throw new HttpException("Invalid response: " + status);
+ }
+
Asserts.notNull(receivedRequest, "Received request");
final String method = receivedRequest.getMethod();
context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
@@ -164,14 +166,19 @@ class ServerHttp1StreamHandler implement
}
}
- private void commitContinue() throws IOException, HttpException {
- final HttpResponse ack = new BasicHttpResponse(HttpStatus.SC_CONTINUE);
- outputChannel.submit(ack, false);
- responseState = MessageState.ACK;
+ private void commitInformation(final HttpResponse response) throws IOException, HttpException {
+ if (responseCommitted.get()) {
+ throw new HttpException("Response already committed");
+ }
+ final int status = response.getCode();
+ if (status < HttpStatus.SC_INFORMATIONAL || status >= HttpStatus.SC_SUCCESS) {
+ throw new HttpException("Invalid intermediate response: " + status);
+ }
+ outputChannel.submit(response, true);
}
private void commitPromise() throws HttpException {
- throw new ProtocolException("HTTP/1.1 does not support server push");
+ throw new HttpException("HTTP/1.1 does not support server push");
}
void activateChannel() throws IOException, HttpException {
@@ -218,15 +225,6 @@ class ServerHttp1StreamHandler implement
receivedRequest = request;
requestState = requestEndStream ? MessageState.COMPLETE : MessageState.BODY;
- final EntityDetails requestEntityDetails = requestEndStream ? null : new LazyEntityDetails(request);
- boolean expectContinue = false;
- if (requestEntityDetails != null) {
- final Header h = request.getFirstHeader(HttpHeaders.EXPECT);
- if (h != null && "100-continue".equalsIgnoreCase(h.getValue())) {
- expectContinue = true;
- }
- }
-
AsyncServerExchangeHandler handler;
try {
handler = exchangeHandlerFactory.create(request);
@@ -248,54 +246,41 @@ class ServerHttp1StreamHandler implement
exchangeHandler.setContext(context);
+ final EntityDetails requestEntityDetails = requestEndStream ? null : new LazyEntityDetails(request);
try {
httpProcessor.process(request, requestEntityDetails, context);
} catch (HttpException ex) {
- expectContinue = false;
final AsyncResponseProducer responseProducer = handleException(ex);
exchangeHandler = new ImmediateResponseExchangeHandler(responseProducer);
+ exchangeHandler.setContext(context);
}
- if (expectContinue) {
- exchangeHandler.verify(request, requestEntityDetails, new ExpectationChannel() {
-
- @Override
- public void sendResponse(
- final HttpResponse response, final EntityDetails responseEntityDetails) throws HttpException, IOException {
- validateResponse(response, responseEntityDetails);
- commitResponse(response, responseEntityDetails);
- }
+ exchangeHandler.handleRequest(request, requestEntityDetails, new ResponseChannel() {
- @Override
- public void sendContinue() throws HttpException, IOException {
- commitContinue();
- }
+ @Override
+ public void sendInformation(final HttpResponse response) throws HttpException, IOException {
+ commitInformation(response);
+ }
- });
- } else {
- exchangeHandler.handleRequest(request, requestEntityDetails, new ResponseChannel() {
+ @Override
+ public void sendResponse(
+ final HttpResponse response, final EntityDetails responseEntityDetails) throws HttpException, IOException {
+ validateResponse(response, responseEntityDetails);
+ commitResponse(response, responseEntityDetails);
+ }
- @Override
- public void sendResponse(
- final HttpResponse response, final EntityDetails responseEntityDetails) throws HttpException, IOException {
- validateResponse(response, responseEntityDetails);
- commitResponse(response, responseEntityDetails);
- }
+ @Override
+ public void pushPromise(
+ final HttpRequest promise, final AsyncPushProducer pushProducer) throws HttpException, IOException {
+ commitPromise();
+ }
- @Override
- public void pushPromise(
- final HttpRequest promise, final AsyncPushProducer pushProducer) throws HttpException, IOException {
- commitPromise();
- }
+ });
- });
- }
}
boolean isOutputReady() {
switch (responseState) {
- case ACK:
- return true;
case BODY:
return exchangeHandler.available() > 0;
default:
@@ -305,26 +290,6 @@ class ServerHttp1StreamHandler implement
void produceOutput() throws HttpException, IOException {
switch (responseState) {
- case ACK:
- responseState = MessageState.HEADERS;
- Asserts.notNull(receivedRequest, "Received request");
- exchangeHandler.handleRequest(receivedRequest, new LazyEntityDetails(receivedRequest), new ResponseChannel() {
-
- @Override
- public void sendResponse(
- final HttpResponse response, final EntityDetails responseEntityDetails) throws HttpException, IOException {
- validateResponse(response, responseEntityDetails);
- commitResponse(response, responseEntityDetails);
- }
-
- @Override
- public void pushPromise(
- final HttpRequest promise, final AsyncPushProducer pushProducer) throws HttpException, IOException {
- commitPromise();
- }
-
- });
- break;
case BODY:
exchangeHandler.produce(internalDataChannel);
break;
Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncClientExchangeHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncClientExchangeHandler.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncClientExchangeHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncClientExchangeHandler.java Wed Nov 9 20:37:53 2016
@@ -44,6 +44,8 @@ public interface AsyncClientExchangeHand
void consumeResponse(HttpResponse response, EntityDetails entityDetails) throws HttpException, IOException;
+ void consumeInformation(HttpResponse response) throws HttpException, IOException;
+
void failed(Exception cause);
void cancel();
Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncServerExchangeHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncServerExchangeHandler.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncServerExchangeHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/AsyncServerExchangeHandler.java Wed Nov 9 20:37:53 2016
@@ -43,11 +43,6 @@ public interface AsyncServerExchangeHand
void setContext(HttpContext context);
- void verify(
- HttpRequest request,
- EntityDetails entityDetails,
- ExpectationChannel expectationChannel) throws HttpException, IOException;
-
void handleRequest(
HttpRequest request,
EntityDetails entityDetails,
Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ResponseChannel.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ResponseChannel.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ResponseChannel.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/ResponseChannel.java Wed Nov 9 20:37:53 2016
@@ -46,6 +46,8 @@ import org.apache.hc.core5.http.HttpResp
@Contract(threading = ThreadingBehavior.SAFE)
public interface ResponseChannel {
+ void sendInformation(HttpResponse response) throws HttpException, IOException;
+
void sendResponse(HttpResponse response, EntityDetails entityDetails) throws HttpException, IOException;
void pushPromise(HttpRequest promise, AsyncPushProducer pushProducer) throws HttpException, IOException;
Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AbstractServerExchangeHandler.java Wed Nov 9 20:37:53 2016
@@ -35,8 +35,10 @@ import org.apache.hc.core5.concurrent.Fu
import org.apache.hc.core5.http.EntityDetails;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.message.BasicHttpResponse;
import org.apache.hc.core5.http.nio.AsyncPushProducer;
import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
import org.apache.hc.core5.http.nio.AsyncResponseProducer;
@@ -44,7 +46,6 @@ import org.apache.hc.core5.http.nio.Asyn
import org.apache.hc.core5.http.nio.BasicResponseProducer;
import org.apache.hc.core5.http.nio.CapacityChannel;
import org.apache.hc.core5.http.nio.DataStreamChannel;
-import org.apache.hc.core5.http.nio.ExpectationChannel;
import org.apache.hc.core5.http.nio.ResponseChannel;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.util.Asserts;
@@ -86,21 +87,6 @@ public abstract class AbstractServerExch
}
@Override
- public final void verify(
- final HttpRequest request,
- final EntityDetails entityDetails,
- final ExpectationChannel expectationChannel) throws HttpException, IOException {
- final AsyncResponseProducer producer = verify(request, context);
- if (producer != null) {
- expectationFailed = true;
- responseProducerRef.set(producer);
- expectationChannel.sendResponse(producer.produceResponse(), producer.getEntityDetails());
- } else {
- expectationChannel.sendContinue();
- }
- }
-
- @Override
public final void handleRequest(
final HttpRequest request,
final EntityDetails entityDetails,
@@ -111,6 +97,21 @@ public abstract class AbstractServerExch
throw new HttpException("Unable to handle request");
}
requestConsumerRef.set(requestConsumer);
+
+ if (entityDetails != null) {
+ final Header h = request.getFirstHeader(HttpHeaders.EXPECT);
+ if (h != null && "100-continue".equalsIgnoreCase(h.getValue())) {
+ final AsyncResponseProducer producer = verify(request, context);
+ if (producer != null) {
+ expectationFailed = true;
+ responseProducerRef.set(producer);
+ responseChannel.sendResponse(producer.produceResponse(), producer.getEntityDetails());
+ return;
+ } else {
+ responseChannel.sendInformation(new BasicHttpResponse(HttpStatus.SC_CONTINUE));
+ }
+ }
+ }
final ResponseTrigger responseTrigger = new ResponseTrigger() {
@Override
Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicClientExchangeHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicClientExchangeHandler.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicClientExchangeHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/BasicClientExchangeHandler.java Wed Nov 9 20:37:53 2016
@@ -88,6 +88,10 @@ public class BasicClientExchangeHandler<
}
@Override
+ public void consumeInformation(final HttpResponse response) throws HttpException, IOException {
+ }
+
+ @Override
public void consumeResponse(final HttpResponse response, final EntityDetails entityDetails) throws HttpException, IOException {
if (response.getCode() >= HttpStatus.SC_CLIENT_ERROR) {
outputTerminated.set(true);
Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java?rev=1769014&r1=1769013&r2=1769014&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/ImmediateResponseExchangeHandler.java Wed Nov 9 20:37:53 2016
@@ -42,7 +42,6 @@ import org.apache.hc.core5.http.nio.Asyn
import org.apache.hc.core5.http.nio.BasicResponseProducer;
import org.apache.hc.core5.http.nio.CapacityChannel;
import org.apache.hc.core5.http.nio.DataStreamChannel;
-import org.apache.hc.core5.http.nio.ExpectationChannel;
import org.apache.hc.core5.http.nio.ResponseChannel;
import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
import org.apache.hc.core5.http.protocol.HttpContext;
@@ -80,14 +79,6 @@ public final class ImmediateResponseExch
}
@Override
- public void verify(
- final HttpRequest request,
- final EntityDetails entityDetails,
- final ExpectationChannel expectationChannel) throws HttpException, IOException {
- expectationChannel.sendContinue();
- }
-
- @Override
public void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
capacityChannel.update(Integer.MAX_VALUE);
}