Skip to content

Commit

Permalink
Added a fix for cases where closed remote connections effectively sig…
Browse files Browse the repository at this point in the history
…nal HTTP responses to requests we're awaiting responses for, allowing us to close client connections properly in certain cases
  • Loading branch information
Adam Fisk committed May 28, 2011
1 parent c048340 commit 51d977d
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 14 deletions.
12 changes: 5 additions & 7 deletions src/main/java/org/littleshoot/proxy/HttpRelayingHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ public void channelClosed(final ChannelHandlerContext ctx,
// here, as there can be multiple connections to external sites for
// a single connection from the browser.
this.relayListener.onRelayChannelClose(browserToProxyChannel,
this.hostAndPort);
this.hostAndPort, this.requestQueue.size());
}

@Override
Expand All @@ -385,12 +385,10 @@ public void exceptionCaught(final ChannelHandlerContext ctx,
log.warn("Closing open connection");
ProxyUtils.closeOnFlush(e.getChannel());
}
else {
// We've seen odd cases where channels seem to continually attempt
// connections. Make sure we explicitly close the connection here.
log.warn("Closing connection even though isOpen is false");
e.getChannel().close();
}
// This can happen if we couldn't make the initial connection due
// to something like an unresolved address, for example, or a timeout.
// There will not have been be any requests written on an unopened
// connection, so there should not be any further action to take here.
}

private final Queue<HttpRequest> requestQueue =
Expand Down
14 changes: 10 additions & 4 deletions src/main/java/org/littleshoot/proxy/HttpRequestHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@
import org.jboss.netty.handler.codec.http.HttpChunk;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.util.HashedWheelTimer;
import org.jboss.netty.util.Timer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -54,7 +52,6 @@ public class HttpRequestHandler extends SimpleChannelUpstreamHandler

private final static Logger log =
LoggerFactory.getLogger(HttpRequestHandler.class);
protected static final Timer timer = new HashedWheelTimer();
private volatile boolean readingChunks;

private static volatile int totalBrowserToProxyConnections = 0;
Expand Down Expand Up @@ -388,6 +385,9 @@ private void writeConnectResponse(final ChannelHandlerContext ctx,
ctx.getPipeline().remove("decoder");
ctx.getPipeline().remove("handler");

// Note there are two HttpConnectRelayingHandler for each HTTP
// CONNECT tunnel -- one writing to the browser, and one writing
// to the remote host.
ctx.getPipeline().addLast("handler",
new HttpConnectRelayingHandler(outgoingChannel, this.channelGroup));

Expand Down Expand Up @@ -493,9 +493,15 @@ public void channelClosed(final ChannelHandlerContext ctx,
}

public void onRelayChannelClose(final Channel browserToProxyChannel,
final String key) {
final String key, final int unansweredRequestsOnChannel) {
this.receivedChannelClosed = true;
this.numWebConnections--;

// The closed channel may have had outstanding requests we haven't
// properly accounted for. The channel closing effectively marks those
// requests as "answered," potentially resulting in the closing of the
// client/browser connection here.
this.unansweredRequestCount -= unansweredRequestsOnChannel;
if (this.numWebConnections == 0 || this.unansweredRequestCount == 0) {
if (!browserChannelClosed.getAndSet(true)) {
log.info("Closing browser to proxy channel");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ protected Object encode(final ChannelHandlerContext ctx,
// The relaying handler needs to know all the headers, including
// hop-by-hop headers, of the original request, particularly
// for determining whether or not to close the connection to the
// browser, so we give it the original and modify the original
// just before writing it on the wire.
// browser, so we give it the original and copy the original
// to modify it just before writing it on the wire.
final HttpRequest request = (HttpRequest) msg;
this.relayingHandler.requestEncoded(request);

Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/littleshoot/proxy/RelayListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
*/
public interface RelayListener {

void onRelayChannelClose(Channel browserToProxyChannel, String hostAndPort);
void onRelayChannelClose(Channel browserToProxyChannel, String hostAndPort,
int unansweredRequests);

void onRelayHttpResponse(Channel browserToProxyChannel, String hostAndPort,
HttpRequest httpRequest);
Expand Down

0 comments on commit 51d977d

Please sign in to comment.