Commit d4876701 authored by guus's avatar guus

OF-558: Applying patch by Ashley Ward aimed at improving robustness of BOSH sessions.

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13075 b35dd754-fafc-0310-a699-88a17e54d16e
parent 24d8bc2d
......@@ -178,7 +178,7 @@ public class HttpBindServlet extends HttpServlet {
}
synchronized (session) {
try {
respond(session, response, session.getResponse((Long) request.getAttribute("request")),
respond(session, response, session.consumeResponse((HttpConnection) request.getAttribute("connection")),
request.getMethod());
}
catch (HttpBindException e) {
......@@ -281,8 +281,9 @@ public class HttpBindServlet extends HttpServlet {
connection.setContinuation(ContinuationSupport.getContinuation(request));
request.setAttribute("request-session", connection.getSession());
request.setAttribute("request", connection.getRequestId());
request.setAttribute("connection", connection);
try {
respond(session, response, session.getResponse(connection.getRequestId()),
respond(session, response, session.consumeResponse(connection),
request.getMethod());
}
catch (HttpBindException e) {
......
......@@ -123,7 +123,7 @@ public class HttpConnection {
isClosed = true;
}
if (continuation != null) {
if (continuation != null && continuation.isSuspended()) {
continuation.setAttribute("response-body", body);
continuation.resume();
session.incrementServerPacketCount();
......@@ -154,6 +154,9 @@ public class HttpConnection {
else if (body == null) {
throw new IllegalStateException("Continuation not set, cannot wait for deliverable.");
}
else if(CONNECTION_CLOSED.equals(body)) {
return null;
}
return body;
}
......@@ -199,9 +202,9 @@ public class HttpConnection {
private String waitForResponse() throws HttpBindTimeoutException {
// we enter this method when we have no messages pending delivery
// when we resume a suspended continuation, or when we time out
if (!Boolean.TRUE.equals(continuation.getAttribute(SUSPENDED))) {
continuation.setTimeout(session.getWait() * JiveConstants.SECOND);
// when we resume a suspended continuation, or when we time out
if (!Boolean.TRUE.equals(continuation.getAttribute(SUSPENDED))) {
continuation.setTimeout(session.getWait() * JiveConstants.SECOND);
continuation.suspend();
continuation.setAttribute(SUSPENDED, Boolean.TRUE);
continuation.undispatch();
......
......@@ -567,6 +567,10 @@ public class HttpSession extends LocalClientSession {
this.lastResponseEmpty = lastResponseEmpty;
}
/**
* @deprecated Doesn't make sense if we have multiple connections with the same rid in the queue.
* Use {@link #consumeResponse(HttpConnection)} instead
*/
public String getResponse(long requestID) throws HttpBindException {
for (HttpConnection connection : connectionQueue) {
if (connection.getRequestId() == requestID) {
......@@ -582,6 +586,28 @@ public class HttpSession extends LocalClientSession {
}
throw new InternalError("Could not locate connection: " + requestID);
}
/**
* Similar to {@link #getResponse(long)} but returns the response for a specific connection instance
* rather than looking up on the request id. This is because it is possible for there to be multiple
* connections in the queue for the same rid so we need to be careful that we are accessing the correct
* connection.
* <p><b>Note that this method also removes the connection from the internal connection queue.</b>
*
* @param connection the connection for which to get the response.
* @return the response from the connection
* @throws HttpBindException
*/
protected String consumeResponse(HttpConnection connection) throws HttpBindException {
Log.debug("consumeResponse: " + connection);
if(connectionQueue.contains(connection)) {
String response = getResponse(connection);
connectionQueue.remove(connection);
fireConnectionClosed(connection);
return response;
}
throw new InternalError("Could not locate connection: " + connection);
}
private String getResponse(HttpConnection connection) throws HttpBindException {
String response = null;
......@@ -685,6 +711,7 @@ public class HttpSession extends LocalClientSession {
BoshBindingError.itemNotFound);
}
connection.deliverBody(createDeliverable(deliverable.deliverables));
addConnection(connection, isPoll);
return connection;
}
else if (rid > (lastRequestID + maxRequests)) {
......@@ -714,14 +741,54 @@ public class HttpSession extends LocalClientSession {
if (connection == null) {
throw new IllegalArgumentException("Connection cannot be null.");
}
checkOveractivity(isPoll);
if (isSecure && !connection.isSecure()) {
throw new HttpBindException("Session was started from secure connection, all " +
"connections on this session must be secured.", BoshBindingError.badRequest);
}
final long rid = connection.getRequestId();
/*
* Search through the connection queue to see if this rid already exists on it. If it does then we
* will close and deliver the existing connection (if appropriate), and close and deliver the same
* deliverable on the new connection. This is under the assumption that a connection has been dropped,
* and re-requested before jetty has realised.
*/
for (HttpConnection queuedConnection : connectionQueue) {
if (queuedConnection.getRequestId() == rid) {
if(Log.isDebugEnabled()) {
Log.debug("Found previous connection in queue with rid " + rid);
}
if(queuedConnection.isClosed()) {
if(Log.isDebugEnabled()) {
Log.debug("It's closed - copying deliverables");
}
Delivered deliverable = retrieveDeliverable(rid);
if (deliverable == null) {
Log.warn("Deliverable unavailable for " + rid);
throw new HttpBindException("Unexpected RID error.",
BoshBindingError.itemNotFound);
}
connection.deliverBody(createDeliverable(deliverable.deliverables));
} else {
if(Log.isDebugEnabled()) {
Log.debug("It's still open - calling close()");
}
deliver(queuedConnection, Collections.singleton(new Deliverable("")));
connection.close();
if(rid == (lastRequestID + 1)) {
lastRequestID = rid;
}
}
break;
}
}
checkOveractivity(isPoll);
sslCertificates = connection.getPeerCertificates();
connection.setSession(this);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment