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 { ...@@ -178,7 +178,7 @@ public class HttpBindServlet extends HttpServlet {
} }
synchronized (session) { synchronized (session) {
try { try {
respond(session, response, session.getResponse((Long) request.getAttribute("request")), respond(session, response, session.consumeResponse((HttpConnection) request.getAttribute("connection")),
request.getMethod()); request.getMethod());
} }
catch (HttpBindException e) { catch (HttpBindException e) {
...@@ -281,8 +281,9 @@ public class HttpBindServlet extends HttpServlet { ...@@ -281,8 +281,9 @@ public class HttpBindServlet extends HttpServlet {
connection.setContinuation(ContinuationSupport.getContinuation(request)); connection.setContinuation(ContinuationSupport.getContinuation(request));
request.setAttribute("request-session", connection.getSession()); request.setAttribute("request-session", connection.getSession());
request.setAttribute("request", connection.getRequestId()); request.setAttribute("request", connection.getRequestId());
request.setAttribute("connection", connection);
try { try {
respond(session, response, session.getResponse(connection.getRequestId()), respond(session, response, session.consumeResponse(connection),
request.getMethod()); request.getMethod());
} }
catch (HttpBindException e) { catch (HttpBindException e) {
......
...@@ -123,7 +123,7 @@ public class HttpConnection { ...@@ -123,7 +123,7 @@ public class HttpConnection {
isClosed = true; isClosed = true;
} }
if (continuation != null) { if (continuation != null && continuation.isSuspended()) {
continuation.setAttribute("response-body", body); continuation.setAttribute("response-body", body);
continuation.resume(); continuation.resume();
session.incrementServerPacketCount(); session.incrementServerPacketCount();
...@@ -154,6 +154,9 @@ public class HttpConnection { ...@@ -154,6 +154,9 @@ public class HttpConnection {
else if (body == null) { else if (body == null) {
throw new IllegalStateException("Continuation not set, cannot wait for deliverable."); throw new IllegalStateException("Continuation not set, cannot wait for deliverable.");
} }
else if(CONNECTION_CLOSED.equals(body)) {
return null;
}
return body; return body;
} }
...@@ -199,9 +202,9 @@ public class HttpConnection { ...@@ -199,9 +202,9 @@ public class HttpConnection {
private String waitForResponse() throws HttpBindTimeoutException { private String waitForResponse() throws HttpBindTimeoutException {
// we enter this method when we have no messages pending delivery // we enter this method when we have no messages pending delivery
// when we resume a suspended continuation, or when we time out // when we resume a suspended continuation, or when we time out
if (!Boolean.TRUE.equals(continuation.getAttribute(SUSPENDED))) { if (!Boolean.TRUE.equals(continuation.getAttribute(SUSPENDED))) {
continuation.setTimeout(session.getWait() * JiveConstants.SECOND); continuation.setTimeout(session.getWait() * JiveConstants.SECOND);
continuation.suspend(); continuation.suspend();
continuation.setAttribute(SUSPENDED, Boolean.TRUE); continuation.setAttribute(SUSPENDED, Boolean.TRUE);
continuation.undispatch(); continuation.undispatch();
......
...@@ -567,6 +567,10 @@ public class HttpSession extends LocalClientSession { ...@@ -567,6 +567,10 @@ public class HttpSession extends LocalClientSession {
this.lastResponseEmpty = lastResponseEmpty; 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 { public String getResponse(long requestID) throws HttpBindException {
for (HttpConnection connection : connectionQueue) { for (HttpConnection connection : connectionQueue) {
if (connection.getRequestId() == requestID) { if (connection.getRequestId() == requestID) {
...@@ -582,6 +586,28 @@ public class HttpSession extends LocalClientSession { ...@@ -582,6 +586,28 @@ public class HttpSession extends LocalClientSession {
} }
throw new InternalError("Could not locate connection: " + requestID); 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 { private String getResponse(HttpConnection connection) throws HttpBindException {
String response = null; String response = null;
...@@ -685,6 +711,7 @@ public class HttpSession extends LocalClientSession { ...@@ -685,6 +711,7 @@ public class HttpSession extends LocalClientSession {
BoshBindingError.itemNotFound); BoshBindingError.itemNotFound);
} }
connection.deliverBody(createDeliverable(deliverable.deliverables)); connection.deliverBody(createDeliverable(deliverable.deliverables));
addConnection(connection, isPoll);
return connection; return connection;
} }
else if (rid > (lastRequestID + maxRequests)) { else if (rid > (lastRequestID + maxRequests)) {
...@@ -714,14 +741,54 @@ public class HttpSession extends LocalClientSession { ...@@ -714,14 +741,54 @@ public class HttpSession extends LocalClientSession {
if (connection == null) { if (connection == null) {
throw new IllegalArgumentException("Connection cannot be null."); throw new IllegalArgumentException("Connection cannot be null.");
} }
checkOveractivity(isPoll);
if (isSecure && !connection.isSecure()) { if (isSecure && !connection.isSecure()) {
throw new HttpBindException("Session was started from secure connection, all " + throw new HttpBindException("Session was started from secure connection, all " +
"connections on this session must be secured.", BoshBindingError.badRequest); "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(); sslCertificates = connection.getPeerCertificates();
connection.setSession(this); 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