diff --git a/httpclient/src/main/java/org/apache/http/conn/EofSensorInputStream.java b/httpclient/src/main/java/org/apache/http/conn/EofSensorInputStream.java index 8957f8c87..47287a63b 100644 --- a/httpclient/src/main/java/org/apache/http/conn/EofSensorInputStream.java +++ b/httpclient/src/main/java/org/apache/http/conn/EofSensorInputStream.java @@ -33,14 +33,8 @@ import org.apache.http.annotation.NotThreadSafe; /** * A stream wrapper that triggers actions on {@link #close close()} and EOF. - * Primarily used to auto-release an underlying - * {@link ManagedClientConnection connection} - * when the response body is consumed or no longer needed. - *
- * This class is based on AutoCloseInputStream
in HttpClient 3.1,
- * but has notable differences. It does not allow mark/reset, distinguishes
- * different kinds of event, and does not always close the underlying stream
- * on EOF. That decision is left to the {@link EofSensorWatcher watcher}.
+ * Primarily used to auto-release an underlying managed connection when the response
+ * body is consumed or no longer needed.
*
* @see EofSensorWatcher
*
@@ -87,15 +81,21 @@ public class EofSensorInputStream extends InputStream implements ConnectionRelea
public EofSensorInputStream(final InputStream in,
final EofSensorWatcher watcher) {
if (in == null) {
- throw new IllegalArgumentException
- ("Wrapped stream may not be null.");
+ throw new IllegalArgumentException("Wrapped stream may not be null");
}
-
wrappedStream = in;
selfClosed = false;
eofWatcher = watcher;
}
+ boolean isSelfClosed() {
+ return selfClosed;
+ }
+
+ InputStream getWrappedStream() {
+ return wrappedStream;
+ }
+
/**
* Checks whether the underlying stream can be read from.
*
@@ -148,18 +148,7 @@ public class EofSensorInputStream extends InputStream implements ConnectionRelea
@Override
public int read(byte[] b) throws IOException {
- int l = -1;
-
- if (isReadAllowed()) {
- try {
- l = wrappedStream.read(b);
- checkEOF(l);
- } catch (IOException ex) {
- checkAbort();
- throw ex;
- }
- }
- return l;
+ return read(b, 0, b.length);
}
@Override
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/builder/ConnectionReleaseTriggerImpl.java b/httpclient/src/main/java/org/apache/http/impl/client/builder/ConnectionReleaseTriggerImpl.java
index 2a2ce4593..cdb92be57 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/builder/ConnectionReleaseTriggerImpl.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/builder/ConnectionReleaseTriggerImpl.java
@@ -95,8 +95,22 @@ class ConnectionReleaseTriggerImpl implements ConnectionReleaseTrigger, Cancella
return;
}
this.released = true;
- this.manager.releaseConnection(this.managedConn,
- this.state, this.validDuration, this.tunit);
+ if (this.reusable) {
+ this.manager.releaseConnection(this.managedConn,
+ this.state, this.validDuration, this.tunit);
+ } else {
+ try {
+ this.managedConn.close();
+ log.debug("Connection discarded");
+ } catch (IOException ex) {
+ if (this.log.isDebugEnabled()) {
+ this.log.debug(ex.getMessage(), ex);
+ }
+ } finally {
+ this.manager.releaseConnection(
+ this.managedConn, null, 0, TimeUnit.MILLISECONDS);
+ }
+ }
}
}
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/builder/HttpRequestWrapper.java b/httpclient/src/main/java/org/apache/http/impl/client/builder/HttpRequestWrapper.java
index 340f1d96b..3458b019d 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/builder/HttpRequestWrapper.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/builder/HttpRequestWrapper.java
@@ -27,11 +27,7 @@
package org.apache.http.impl.client.builder;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.net.URI;
-import java.net.URISyntaxException;
import org.apache.http.annotation.NotThreadSafe;
@@ -44,10 +40,8 @@ import org.apache.http.ProtocolException;
import org.apache.http.ProtocolVersion;
import org.apache.http.RequestLine;
import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.message.AbstractHttpMessage;
import org.apache.http.message.BasicRequestLine;
-import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
/**
@@ -62,34 +56,22 @@ class HttpRequestWrapper extends AbstractHttpMessage implements HttpRequest {
private final HttpRequest original;
private URI uri;
- private String method;
- private ProtocolVersion version;
private HttpHost virtualHost;
- private HttpRequestWrapper(
- final ProtocolVersion version,
- final URI uri,
- final String method,
- final HttpRequest request) {
+ private HttpRequestWrapper(final HttpRequest request) {
super();
this.original = request;
- this.uri = uri;
- this.method = method;
- this.version = version;
+ if (request instanceof HttpUriRequest) {
+ this.uri = ((HttpUriRequest) request).getURI();
+ } else {
+ this.uri = null;
+ }
setParams(request.getParams());
setHeaders(request.getAllHeaders());
}
public ProtocolVersion getProtocolVersion() {
- if (this.version != null) {
- return this.version;
- } else {
- return HttpProtocolParams.getVersion(getParams());
- }
- }
-
- public void setProtocolVersion(final ProtocolVersion version) {
- this.version = version;
+ return this.original.getProtocolVersion();
}
public URI getURI() {
@@ -101,18 +83,18 @@ class HttpRequestWrapper extends AbstractHttpMessage implements HttpRequest {
}
public RequestLine getRequestLine() {
+ ProtocolVersion version = this.original.getRequestLine().getProtocolVersion();
+ String method = this.original.getRequestLine().getMethod();
String uritext = null;
if (this.uri != null) {
- uritext = uri.toASCIIString();
+ uritext = this.uri.toASCIIString();
+ } else {
+ uritext = this.original.getRequestLine().getUri();
}
if (uritext == null || uritext.length() == 0) {
uritext = "/";
}
- return new BasicRequestLine(this.method, uritext, getProtocolVersion());
- }
-
- public String getMethod() {
- return this.method;
+ return new BasicRequestLine(method, uritext, version);
}
public HttpRequest getOriginal() {
@@ -133,22 +115,17 @@ class HttpRequestWrapper extends AbstractHttpMessage implements HttpRequest {
@Override
public String toString() {
- return this.method + " " + this.uri + " " + this.headergroup;
+ return getRequestLine() + " " + this.headergroup;
}
static class HttpEntityEnclosingRequestWrapper extends HttpRequestWrapper
implements HttpEntityEnclosingRequest {
private HttpEntity entity;
- private boolean consumed;
- public HttpEntityEnclosingRequestWrapper(
- final ProtocolVersion version,
- final URI uri,
- final String method,
- final HttpEntityEnclosingRequest request)
+ public HttpEntityEnclosingRequestWrapper(final HttpEntityEnclosingRequest request)
throws ProtocolException {
- super(version, uri, method, request);
+ super(request);
setEntity(request.getEntity());
}
@@ -157,7 +134,7 @@ class HttpRequestWrapper extends AbstractHttpMessage implements HttpRequest {
}
public void setEntity(final HttpEntity entity) {
- this.entity = entity != null ? new EntityWrapper(entity) : null;
+ this.entity = entity != null ? new RequestEntityWrapper(entity) : null;
}
public boolean expectContinue() {
@@ -167,32 +144,7 @@ class HttpRequestWrapper extends AbstractHttpMessage implements HttpRequest {
@Override
public boolean isRepeatable() {
- return this.entity == null || this.entity.isRepeatable() || !this.consumed;
- }
-
- class EntityWrapper extends HttpEntityWrapper {
-
- EntityWrapper(final HttpEntity entity) {
- super(entity);
- }
-
- @Deprecated
- @Override
- public void consumeContent() throws IOException {
- consumed = true;
- super.consumeContent();
- }
-
- @Override
- public InputStream getContent() throws IOException {
- return super.getContent();
- }
-
- @Override
- public void writeTo(final OutputStream outstream) throws IOException {
- consumed = true;
- super.writeTo(outstream);
- }
+ return this.entity == null || this.entity.isRepeatable();
}
}
@@ -201,28 +153,10 @@ class HttpRequestWrapper extends AbstractHttpMessage implements HttpRequest {
if (request == null) {
return null;
}
- ProtocolVersion version;
- URI uri;
- String method;
- if (request instanceof HttpUriRequest) {
- version = ((HttpUriRequest) request).getProtocolVersion();
- uri = ((HttpUriRequest) request).getURI();
- method = ((HttpUriRequest) request).getMethod();
- } else {
- RequestLine requestLine = request.getRequestLine();
- version = request.getProtocolVersion();
- try {
- uri = new URI(requestLine.getUri());
- } catch (URISyntaxException ex) {
- throw new ProtocolException("Invalid request URI: " + requestLine.getUri(), ex);
- }
- method = request.getRequestLine().getMethod();
- }
if (request instanceof HttpEntityEnclosingRequest) {
- return new HttpEntityEnclosingRequestWrapper(version, uri, method,
- (HttpEntityEnclosingRequest) request);
+ return new HttpEntityEnclosingRequestWrapper((HttpEntityEnclosingRequest) request);
} else {
- return new HttpRequestWrapper(version, uri, method, request);
+ return new HttpRequestWrapper(request);
}
}
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/builder/ProtocolExec.java b/httpclient/src/main/java/org/apache/http/impl/client/builder/ProtocolExec.java
index 2f821c52e..c359460b0 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/builder/ProtocolExec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/builder/ProtocolExec.java
@@ -78,23 +78,25 @@ class ProtocolExec implements ClientExecChain {
final HttpRoute route) throws ProtocolException {
try {
URI uri = request.getURI();
- if (route.getProxyHost() != null && !route.isTunnelled()) {
- // Make sure the request URI is absolute
- if (!uri.isAbsolute()) {
- HttpHost target = route.getTargetHost();
- uri = URIUtils.rewriteURI(uri, target, true);
+ if (uri != null) {
+ if (route.getProxyHost() != null && !route.isTunnelled()) {
+ // Make sure the request URI is absolute
+ if (!uri.isAbsolute()) {
+ HttpHost target = route.getTargetHost();
+ uri = URIUtils.rewriteURI(uri, target, true);
+ } else {
+ uri = URIUtils.rewriteURI(uri);
+ }
} else {
- uri = URIUtils.rewriteURI(uri);
- }
- } else {
- // Make sure the request URI is relative
- if (uri.isAbsolute()) {
- uri = URIUtils.rewriteURI(uri, null);
- } else {
- uri = URIUtils.rewriteURI(uri);
+ // Make sure the request URI is relative
+ if (uri.isAbsolute()) {
+ uri = URIUtils.rewriteURI(uri, null);
+ } else {
+ uri = URIUtils.rewriteURI(uri);
+ }
}
+ request.setURI(uri);
}
- request.setURI(uri);
} catch (URISyntaxException ex) {
throw new ProtocolException("Invalid URI: " +
request.getRequestLine().getUri(), ex);
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/builder/RequestEntityWrapper.java b/httpclient/src/main/java/org/apache/http/impl/client/builder/RequestEntityWrapper.java
new file mode 100644
index 000000000..b1e513385
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/client/builder/RequestEntityWrapper.java
@@ -0,0 +1,50 @@
+package org.apache.http.impl.client.builder;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.entity.HttpEntityWrapper;
+
+/**
+ * A wrapper class for {@link HttpEntity} enclosed in a request message.
+ *
+ * @since 4.3
+ */
+@NotThreadSafe
+class RequestEntityWrapper extends HttpEntityWrapper {
+
+ private boolean consumed = false;
+
+ RequestEntityWrapper(final HttpEntity entity) {
+ super(entity);
+ }
+
+ @Override
+ public boolean isRepeatable() {
+ if (!this.consumed) {
+ return true;
+ } else {
+ return super.isRepeatable();
+ }
+ }
+
+ @Deprecated
+ @Override
+ public void consumeContent() throws IOException {
+ consumed = true;
+ super.consumeContent();
+ }
+
+ @Override
+ public void writeTo(final OutputStream outstream) throws IOException {
+ consumed = true;
+ super.writeTo(outstream);
+ }
+
+ public boolean isConsumed() {
+ return consumed;
+ }
+
+}
\ No newline at end of file
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/builder/ResponseEntityWrapper.java b/httpclient/src/main/java/org/apache/http/impl/client/builder/ResponseEntityWrapper.java
index fff998e07..b6dcb70c4 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/builder/ResponseEntityWrapper.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/builder/ResponseEntityWrapper.java
@@ -37,10 +37,9 @@ import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.conn.EofSensorInputStream;
import org.apache.http.conn.EofSensorWatcher;
import org.apache.http.entity.HttpEntityWrapper;
-import org.apache.http.util.EntityUtils;
/**
- * A wrapper class for {@link HttpEntity} encloded in a response message.
+ * A wrapper class for {@link HttpEntity} enclosed in a response message.
*
* @since 4.3
*/
@@ -66,7 +65,6 @@ class ResponseEntityWrapper extends HttpEntityWrapper implements EofSensorWatche
if (this.connReleaseTrigger != null) {
try {
if (this.connReleaseTrigger.isReusable()) {
- EntityUtils.consume(this.wrappedEntity);
this.connReleaseTrigger.releaseConnection();
}
} finally {
@@ -93,8 +91,12 @@ class ResponseEntityWrapper extends HttpEntityWrapper implements EofSensorWatche
@Override
public void writeTo(final OutputStream outstream) throws IOException {
- this.wrappedEntity.writeTo(outstream);
- releaseConnection();
+ try {
+ this.wrappedEntity.writeTo(outstream);
+ releaseConnection();
+ } finally {
+ cleanup();
+ }
}
public boolean eofDetected(final InputStream wrapped) throws IOException {
diff --git a/httpclient/src/test/java/org/apache/http/conn/TestEofSensorInputStream.java b/httpclient/src/test/java/org/apache/http/conn/TestEofSensorInputStream.java
new file mode 100644
index 000000000..59a018b3c
--- /dev/null
+++ b/httpclient/src/test/java/org/apache/http/conn/TestEofSensorInputStream.java
@@ -0,0 +1,227 @@
+/*
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ *