Author: ngn
Date: Tue Jun 29 20:38:59 2010
New Revision: 959093
URL: http://svn.apache.org/viewvc?rev=959093&view=rev
Log:
Better continuation implementation
Full SASL auth
Improved merged responses
Stanza routing
(VYSPER-213, by Bogdan Pistol)
Modified:
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/response/ServerResponses.java
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshServlet.java
Modified:
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java?rev=959093&r1=959092&r2=959093&view=diff
==============================================================================
---
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java
(original)
+++
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java
Tue Jun 29 20:38:59 2010
@@ -67,6 +67,8 @@ public class NamespaceURIs {
public static final String URN_XMPP_PING = "urn:xmpp:ping";
public static final String URN_XMPP_DELAY = "urn:xmpp:delay";
+
+ public static final String URN_XMPP_XBOSH = "urn:xmpp:xbosh";
public static final String VCARD_TEMP = "vcard-temp";
@@ -93,5 +95,4 @@ public class NamespaceURIs {
public static final String XEP0060_PUBSUB_ERRORS =
"http://jabber.org/protocol/pubsub#errors";
public static final String XEP0124_BOSH =
"http://jabber.org/protocol/httpbind";
-
}
Modified:
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/response/ServerResponses.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/response/ServerResponses.java?rev=959093&r1=959092&r2=959093&view=diff
==============================================================================
---
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/response/ServerResponses.java
(original)
+++
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/response/ServerResponses.java
Tue Jun 29 20:38:59 2010
@@ -108,7 +108,7 @@ public class ServerResponses {
return stanzaBuilder.build();
}
- private Stanza getFeaturesForSession() {
+ public Stanza getFeaturesForSession() {
StanzaBuilder stanzaBuilder = startFeatureStanza();
stanzaBuilder.startInnerElement("bind",
NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_BIND).startInnerElement(
Modified:
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java?rev=959093&r1=959092&r2=959093&view=diff
==============================================================================
---
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java
(original)
+++
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java
Tue Jun 29 20:38:59 2010
@@ -32,6 +32,7 @@ import org.apache.vysper.xmpp.server.Ses
import org.apache.vysper.xmpp.stanza.Stanza;
import org.apache.vysper.xmpp.writer.StanzaWriter;
import org.eclipse.jetty.continuation.Continuation;
+import org.eclipse.jetty.continuation.ContinuationListener;
import org.eclipse.jetty.continuation.ContinuationSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,7 +64,7 @@ public class BoshBackedSessionContext ex
private Queue<HttpServletRequest> requestQueue;
- private Queue<BoshResponse> delayedResponseQueue;
+ private Queue<Stanza> delayedResponseQueue;
/**
* Creates a new context for a session
@@ -72,10 +73,10 @@ public class BoshBackedSessionContext ex
*/
public BoshBackedSessionContext(BoshHandler boshHandler,
ServerRuntimeContext serverRuntimeContext) {
super(serverRuntimeContext, new SessionStateHolder());
- sessionStateHolder.setState(SessionState.INITIATED);
+ sessionStateHolder.setState(SessionState.ENCRYPTED);
this.boshHandler = boshHandler;
requestQueue = new LinkedList<HttpServletRequest>();
- delayedResponseQueue = new LinkedList<BoshResponse>();
+ delayedResponseQueue = new LinkedList<Stanza>();
}
public SessionStateHolder getStateHolder() {
@@ -89,18 +90,25 @@ public class BoshBackedSessionContext ex
public void setIsReopeningXMLStream() {
}
- public void write(Stanza stanza) {
- write(getResponse(stanza));
+ synchronized public void write(Stanza stanza) {
+ write0(boshHandler.wrapStanza(stanza));
}
- public void write(BoshResponse resp) {
+ /*
+ * package access
+ */
+ void write0(Stanza boshStanza) {
HttpServletRequest req = requestQueue.poll();
if (req == null) {
- delayedResponseQueue.offer(resp);
+ delayedResponseQueue.offer(boshStanza);
return;
}
+ BoshResponse boshResponse = getBoshResponse(boshStanza);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("BOSH writing stanza: {}", new
String(boshResponse.getContent()));
+ }
Continuation continuation = ContinuationSupport.getContinuation(req);
- continuation.setAttribute("response", resp);
+ continuation.setAttribute("response", boshResponse);
continuation.resume();
}
@@ -169,15 +177,21 @@ public class BoshBackedSessionContext ex
return requests;
}
- synchronized public void requestExpired(HttpServletRequest req) {
+ synchronized public void requestExpired(Continuation continuation) {
+ HttpServletRequest req = (HttpServletRequest)
continuation.getAttribute("request");
+ if (req == null) {
+ LOGGER.warn("Continuation expired without having an associated
request!");
+ return;
+ }
+ continuation.setAttribute("response",
getBoshResponse(boshHandler.getEmptyStanza()));
for (;;) {
HttpServletRequest r = requestQueue.peek();
if (r == null) {
- return;
+ break;
}
- write(boshHandler.getEmptyStanza());
+ write0(boshHandler.getEmptyStanza());
if (r == req) {
- return;
+ break;
}
}
}
@@ -186,21 +200,37 @@ public class BoshBackedSessionContext ex
Continuation continuation = ContinuationSupport.getContinuation(req);
continuation.setTimeout(wait * 1000);
continuation.suspend();
- continuation.setAttribute("session", this);
+ continuation.setAttribute("request", req);
requestQueue.offer(req);
- BoshResponse resp = delayedResponseQueue.poll();
- if (resp != null) {
- write(resp);
+ continuation.addContinuationListener(new ContinuationListener() {
+
+ public void onTimeout(Continuation continuation) {
+ requestExpired(continuation);
+ }
+
+ public void onComplete(Continuation continuation) {
+ // ignore
+ }
+
+ });
+
+ Stanza delayedStanza;
+ Stanza mergedStanza = null;
+ while ((delayedStanza = delayedResponseQueue.poll()) != null) {
+ mergedStanza = boshHandler.mergeStanzas(mergedStanza,
delayedStanza);
+ }
+ if (mergedStanza != null) {
+ write0(mergedStanza);
return;
}
if (requestQueue.size() > hold) {
- write(boshHandler.getEmptyStanza());
+ write0(boshHandler.getEmptyStanza());
}
}
-
- public BoshResponse getResponse(Stanza stanza) {
+
+ private BoshResponse getBoshResponse(Stanza stanza) {
byte[] content = new Renderer(stanza).getComplete().getBytes();
return new BoshResponse(contentType, content);
}
Modified:
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java?rev=959093&r1=959092&r2=959093&view=diff
==============================================================================
---
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java
(original)
+++
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java
Tue Jun 29 20:38:59 2010
@@ -25,9 +25,11 @@ import java.util.concurrent.ConcurrentHa
import javax.servlet.http.HttpServletRequest;
-import org.apache.vysper.xmpp.authorization.SASLMechanism;
+import org.apache.vysper.xml.fragment.XMLElement;
import org.apache.vysper.xmpp.protocol.NamespaceURIs;
import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.apache.vysper.xmpp.server.SessionState;
+import org.apache.vysper.xmpp.server.response.ServerResponses;
import org.apache.vysper.xmpp.stanza.Stanza;
import org.apache.vysper.xmpp.stanza.StanzaBuilder;
import org.slf4j.Logger;
@@ -86,10 +88,54 @@ public class BoshHandler {
return;
}
} else {
- // handleSession(req, stanza);
+ BoshBackedSessionContext session =
sessions.get(stanza.getAttributeValue("sid"));
+ if (session == null) {
+ LOGGER.warn("Received an invalid 'sid'!");
+ return;
+ }
+ synchronized (session) {
+ session.addRequest(req);
+ processSession(session, stanza);
+ }
+ }
+ }
+
+ private void processSession(BoshBackedSessionContext session, Stanza
stanza) {
+ if (session.getState() == SessionState.ENCRYPTED) {
+ if (stanza.getInnerElements().isEmpty()) {
+ // session needs authentication
+ return;
+ }
+ for (XMLElement element : stanza.getInnerElements()) {
+ if
(element.getNamespaceURI().equals(NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_SASL))
{
+ processStanza(session, element);
+ }
+ }
+ } else if (session.getState() == SessionState.AUTHENTICATED) {
+ if
("true".equals(stanza.getAttributeValue(NamespaceURIs.URN_XMPP_XBOSH,
"restart"))) {
+ // restart request
+ session.write0(getRestartResponseStanza());
+ } else {
+ // any other request
+ for (XMLElement element : stanza.getInnerElements()) {
+ processStanza(session, element);
+ }
+ }
}
}
+ private void processStanza(BoshBackedSessionContext session, XMLElement
element) {
+ Stanza innerStanza;
+ if (element instanceof Stanza) {
+ innerStanza = (Stanza) element;
+ } else {
+ innerStanza = new Stanza(element.getNamespaceURI(),
element.getName(), element.getNamespacePrefix(),
+ element.getAttributes(), element.getInnerFragments());
+ }
+
serverRuntimeContext.getStanzaProcessor().processStanza(serverRuntimeContext,
session, innerStanza,
+ session.getStateHolder());
+ }
+
private void createSession(HttpServletRequest req, Stanza stanza) throws
IOException {
BoshBackedSessionContext session = new BoshBackedSessionContext(this,
serverRuntimeContext);
if (stanza.getAttribute("content") != null) {
@@ -110,7 +156,7 @@ public class BoshHandler {
session.addRequest(req);
sessions.put(session.getSessionId(), session);
- session.write(getSessionCreationStanza(session));
+ session.write0(getSessionCreationStanza(session));
}
public Stanza getSessionCreationStanza(BoshBackedSessionContext session) {
@@ -124,15 +170,9 @@ public class BoshHandler {
body.addAttribute("ver", session.getBoshVersion());
body.addAttribute("from",
session.getServerJID().getFullQualifiedName());
- StanzaBuilder features = new StanzaBuilder("features",
NamespaceURIs.HTTP_ETHERX_JABBER_ORG_STREAMS, "stream");
- features.startInnerElement("mechanisms",
NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_SASL);
- for (SASLMechanism authenticationMethod :
serverRuntimeContext.getServerFeatures().getAuthenticationMethods()) {
- features.startInnerElement("mechanism",
NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_SASL).addText(
- authenticationMethod.getName()).endInnerElement();
- }
- features.endInnerElement();
-
- body.addPreparedElement(features.build());
+ Stanza features = new
ServerResponses().getFeaturesForAuthentication(serverRuntimeContext.getServerFeatures()
+ .getAuthenticationMethods());
+ body.addPreparedElement(features);
return body.build();
}
@@ -141,4 +181,35 @@ public class BoshHandler {
return stanzaBuilder.build();
}
+ public Stanza wrapStanza(Stanza stanza) {
+ StanzaBuilder body = new StanzaBuilder("body",
NamespaceURIs.XEP0124_BOSH);
+ body.addPreparedElement(stanza);
+ return body.build();
+ }
+
+ public Stanza mergeStanzas(Stanza stanza1, Stanza stanza2) {
+ if (stanza1 == null && stanza2 == null) {
+ return null;
+ }
+ if (stanza1 == null) {
+ return stanza2;
+ }
+ if (stanza2 == null) {
+ return stanza1;
+ }
+ StanzaBuilder body = new StanzaBuilder("body",
NamespaceURIs.XEP0124_BOSH);
+ for (XMLElement element : stanza1.getInnerElements()) {
+ body.addPreparedElement(element);
+ }
+ for (XMLElement element : stanza2.getInnerElements()) {
+ body.addPreparedElement(element);
+ }
+ return body.build();
+ }
+
+ private Stanza getRestartResponseStanza() {
+ Stanza features = new ServerResponses().getFeaturesForSession();
+ return wrapStanza(features);
+ }
+
}
Modified:
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshServlet.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshServlet.java?rev=959093&r1=959092&r2=959093&view=diff
==============================================================================
---
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshServlet.java
(original)
+++
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshServlet.java
Tue Jun 29 20:38:59 2010
@@ -30,7 +30,6 @@ import javax.servlet.http.HttpServletReq
import javax.servlet.http.HttpServletResponse;
import org.apache.vysper.xmpp.server.ServerRuntimeContext;
-import org.eclipse.jetty.continuation.ContinuationSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
@@ -129,23 +128,11 @@ public class BoshServlet extends HttpSer
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
BoshResponse boshResponse = (BoshResponse)
req.getAttribute("response");
if (boshResponse != null) {
- // if continuation is resumed
+ // if continuation is resumed or expired
writeResponse(resp, boshResponse);
return;
}
- if (ContinuationSupport.getContinuation(req).isExpired()) {
- // BOSH wait time is reached
- BoshBackedSessionContext session = (BoshBackedSessionContext)
req.getAttribute("session");
- if (session == null) {
- logger.error("Continuation expired without having a session
associated!");
- return;
- }
- session.requestExpired(req);
- // writeResponse(resp,
session.getResponse(boshHandler.getEmptyStanza()));
- return;
- }
-
BoshDecoder decoder = new BoshDecoder(boshHandler, req);
try {
decoder.decode();