Author: ngn
Date: Wed Jun 23 21:24:39 2010
New Revision: 957353

URL: http://svn.apache.org/viewvc?rev=957353&view=rev
Log:
Foundation for SASL, HTTP queuing, access control for Ajax cross domain 
(VYSPER-213, by Bogdan Pistol)

Added:
    
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshResponse.java
Removed:
    
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshRequestContext.java
    
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/ContentType.java
Modified:
    
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/BoshDecoder.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/BoshSaxContentHandler.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/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=957353&r1=957352&r2=957353&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
 Wed Jun 23 21:24:39 2010
@@ -19,12 +19,20 @@
  */
 package org.apache.vysper.xmpp.extension.xep0124;
 
+import java.util.LinkedList;
+import java.util.Queue;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.vysper.xml.fragment.Renderer;
 import org.apache.vysper.xmpp.protocol.SessionStateHolder;
 import org.apache.vysper.xmpp.server.AbstractSessionContext;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.server.SessionState;
 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.ContinuationSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,32 +43,44 @@ import org.slf4j.LoggerFactory;
  */
 public class BoshBackedSessionContext extends AbstractSessionContext implements
         StanzaWriter {
-
-    private final static Logger LOGGER = LoggerFactory
-            .getLogger(BoshBackedSessionContext.class);
+    
+    private final static Logger LOGGER = 
LoggerFactory.getLogger(BoshBackedSessionContext.class);
+    
+    private final BoshHandler boshHandler;
 
     private final int inactivity = 60;
 
     private final int polling = 15;
 
     private final int requests = 2;
+    
+    private String boshVersion = "1.9";
 
-    private String ver = "1.9";
-
-    private String contentType = ContentType.XML_CONTENT_TYPE;
+    private String contentType = BoshServlet.XML_CONTENT_TYPE;
 
     private int wait = 60;
 
     private int hold = 1;
-
+    
+    private Queue<HttpServletRequest> requestQueue;
+    
+    private Queue<BoshResponse> delayedResponseQueue;
+    
     /**
      * Creates a new context for a session
      * @param serverRuntimeContext
      * @param boshHandler
      */
-    public BoshBackedSessionContext(ServerRuntimeContext serverRuntimeContext) 
{
+    public BoshBackedSessionContext(BoshHandler boshHandler, 
ServerRuntimeContext serverRuntimeContext) {
         super(serverRuntimeContext, new SessionStateHolder());
         sessionStateHolder.setState(SessionState.INITIATED);
+        this.boshHandler = boshHandler;
+        requestQueue = new LinkedList<HttpServletRequest>();
+        delayedResponseQueue = new LinkedList<BoshResponse>();
+    }
+    
+    public SessionStateHolder getStateHolder() {
+        return sessionStateHolder;
     }
 
     public StanzaWriter getResponseWriter() {
@@ -71,6 +91,18 @@ public class BoshBackedSessionContext ex
     }
 
     public void write(Stanza stanza) {
+        write(getResponse(stanza));
+    }
+    
+    public void write(BoshResponse resp) {
+        HttpServletRequest req = requestQueue.poll();
+        if (req == null) {
+            delayedResponseQueue.offer(resp);
+            return;
+        }
+        Continuation continuation = ContinuationSupport.getContinuation(req);
+        continuation.setAttribute("response", resp);
+        continuation.resume();
     }
 
     public void close() {
@@ -106,25 +138,24 @@ public class BoshBackedSessionContext ex
         return hold;
     }
 
-    public void setVer(String ver) {
-        String[] serverVer = this.ver.split("\\.");
-        int serverMajor = Integer.parseInt(serverVer[0]);
-        int serverMinor = Integer.parseInt(serverVer[1]);
-        String[] clientVer = ver.split("\\.");
+    public void setBoshVersion(String version) {
+        String[] v = boshVersion.split("\\.");
+        int major = Integer.parseInt(v[0]);
+        int minor = Integer.parseInt(v[1]);
+        v = version.split("\\.");
         
-        if (clientVer.length == 2) {
-            int clientMajor = Integer.parseInt(clientVer[0]);
-            int clientMinor = Integer.parseInt(clientVer[1]);
-
-            if (clientMajor < serverMajor
-                    || (clientMajor == serverMajor && clientMinor < 
serverMinor)) {
-                this.ver = ver;
+        if (v.length == 2) {
+            int clientMajor = Integer.parseInt(v[0]);
+            int clientMinor = Integer.parseInt(v[1]);
+
+            if (clientMajor < major || (clientMajor == major && clientMinor < 
minor)) {
+                boshVersion = version;
             }
         }
     }
 
-    public String getVer() {
-        return ver;
+    public String getBoshVersion() {
+        return boshVersion;
     }
 
     public int getInactivity() {
@@ -138,5 +169,41 @@ public class BoshBackedSessionContext ex
     public int getRequests() {
         return requests;
     }
+    
+    synchronized public void requestExpired(HttpServletRequest req) {
+        for (;;) {
+            HttpServletRequest r = requestQueue.peek();
+            if (r == null) {
+                return;
+            }
+            write(boshHandler.getEmptyStanza());
+            if (r == req) {
+                return;
+            }
+        }
+    }
+
+    public void addRequest(HttpServletRequest req) {
+        Continuation continuation = ContinuationSupport.getContinuation(req);
+        continuation.setTimeout(wait * 1000);
+        continuation.suspend();
+        continuation.setAttribute("session", this);
+        requestQueue.offer(req);
+        
+        BoshResponse resp = delayedResponseQueue.poll();
+        if (resp != null) {
+            write(resp);
+            return;
+        }
+        
+        if (requestQueue.size() > hold) {
+            write(boshHandler.getEmptyStanza());
+        }
+    }
+
+    public BoshResponse getResponse(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/BoshDecoder.java
URL: 
http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshDecoder.java?rev=957353&r1=957352&r2=957353&view=diff
==============================================================================
--- 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshDecoder.java
 (original)
+++ 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshDecoder.java
 Wed Jun 23 21:24:39 2010
@@ -44,16 +44,12 @@ public class BoshDecoder {
 
     private final NonBlockingXMLReader reader;
     
-    private final BoshRequestContext boshRequestContext;
+    private final HttpServletRequest request;
 
-    /**
-     * Creates a new decoder associated with a {...@link BoshRequestContext}
-     * @param boshHandler
-     */
-    public BoshDecoder(BoshHandler boshHandler, BoshRequestContext 
boshRequestContext) {
-        this.boshRequestContext = boshRequestContext;
+    public BoshDecoder(BoshHandler boshHandler, HttpServletRequest req) {
+        request = req;
         reader = new DefaultNonBlockingXMLReader();
-        ContentHandler contentHandler = new BoshSaxContentHandler(boshHandler, 
boshRequestContext);
+        ContentHandler contentHandler = new BoshSaxContentHandler(boshHandler, 
req);
         reader.setContentHandler(contentHandler);
     }
 
@@ -67,7 +63,7 @@ public class BoshDecoder {
         IoBuffer ioBuf = IoBuffer.allocate(1024);
         ioBuf.setAutoExpand(true);
         byte[] buf = new byte[1024];
-        InputStream in = boshRequestContext.getRequest().getInputStream();
+        InputStream in = request.getInputStream();
 
         for (;;) {
             int i = in.read(buf);

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=957353&r1=957352&r2=957353&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
 Wed Jun 23 21:24:39 2010
@@ -23,9 +23,10 @@ import java.io.IOException;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
-import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletRequest;
 
-import org.apache.vysper.xml.fragment.Renderer;
+import org.apache.vysper.xmpp.authorization.SASLMechanism;
+import org.apache.vysper.xmpp.protocol.NamespaceURIs;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.stanza.Stanza;
 import org.apache.vysper.xmpp.stanza.StanzaBuilder;
@@ -44,8 +45,6 @@ public class BoshHandler {
     
     private static final Logger LOGGER = 
LoggerFactory.getLogger(BoshHandler.class);
     
-    private static final String BOSH_NS = 
"http://jabber.org/protocol/httpbind";;
-    
     private ServerRuntimeContext serverRuntimeContext;
     
     private Map<String, BoshBackedSessionContext> sessions;
@@ -61,12 +60,12 @@ public class BoshHandler {
 
     /**
      * Processes BOSH stanzas concurrently
-     * @param boshRequestContext
+     * @param httpContext
      * @param stanza
      */
-    public void process(BoshRequestContext boshRequestContext, Stanza stanza) {
-        if (!stanza.getNamespaceURI().equalsIgnoreCase(BOSH_NS)) {
-            LOGGER.error("Invalid namespace for body wrapper '{}', should be 
'{}'!", stanza.getNamespaceURI(), BOSH_NS);
+    public void process(HttpServletRequest req, Stanza stanza) {
+        if 
(!stanza.getNamespaceURI().equalsIgnoreCase(NamespaceURIs.XEP0124_BOSH)) {
+            LOGGER.error("Invalid namespace for body wrapper '{}', must be 
'{}'!", stanza.getNamespaceURI(), NamespaceURIs.XEP0124_BOSH);
             return;
         }
         if (!stanza.getName().equalsIgnoreCase("body")) {
@@ -81,19 +80,18 @@ public class BoshHandler {
         if (stanza.getAttribute("sid") == null) {
             // the session creation request (first request) does not have a 
"sid" attribute
             try {
-                createSession(boshRequestContext, stanza);
+                createSession(req, stanza);
             } catch (IOException e) {
                 LOGGER.error("Exception thrown while processing the session 
creation request", e);
                 return;
             }
         } else {
-//            handleSession(boshRequestContext, stanza);
+//            handleSession(req, stanza);
         }
     }
 
-    private void createSession(BoshRequestContext boshRequestContext,
-            Stanza stanza) throws IOException {
-        BoshBackedSessionContext session = new 
BoshBackedSessionContext(serverRuntimeContext);
+    private void createSession(HttpServletRequest req, Stanza stanza) throws 
IOException {
+        BoshBackedSessionContext session = new BoshBackedSessionContext(this, 
serverRuntimeContext);
         if (stanza.getAttribute("content") != null) {
             session.setContentType(stanza.getAttributeValue("content"));
         }
@@ -107,30 +105,43 @@ public class BoshHandler {
         }
         if (stanza.getAttribute("ver") != null) {
             String ver = stanza.getAttributeValue("ver");
-            session.setVer(ver);
+            session.setBoshVersion(ver);
         }
+        session.addRequest(req);
         sessions.put(session.getSessionId(), session);
-        HttpServletResponse resp = boshRequestContext.getResponse();
-        resp.setContentType(session.getContentType());
-        String msg = new 
Renderer(getSessionCreationResponse(session)).getComplete();
-        resp.setContentLength(msg.length());
-        resp.addDateHeader("Date", System.currentTimeMillis());
-        resp.addHeader("Access-control-allow-origin", "*");
-        resp.addHeader("Access-control-allow-headers", "Content-Type");
-        resp.getWriter().print(msg);
-        resp.flushBuffer();
+        
+        session.write(getSessionCreationStanza(session));
     }
     
-    public Stanza getSessionCreationResponse(BoshBackedSessionContext session) 
{
-        StanzaBuilder stanzaBuilder = new StanzaBuilder("body", BOSH_NS);
-        stanzaBuilder.addAttribute("wait", 
Integer.toString(session.getWait()));
-        stanzaBuilder.addAttribute("inactivity", 
Integer.toString(session.getInactivity()));
-        stanzaBuilder.addAttribute("polling", 
Integer.toString(session.getPolling()));
-        stanzaBuilder.addAttribute("requests", 
Integer.toString(session.getRequests()));
-        stanzaBuilder.addAttribute("hold", 
Integer.toString(session.getHold()));
-        stanzaBuilder.addAttribute("sid", session.getSessionId());
-        stanzaBuilder.addAttribute("ver", session.getVer());
-        stanzaBuilder.addAttribute("from", 
session.getServerJID().getFullQualifiedName());
+    public Stanza getSessionCreationStanza(BoshBackedSessionContext session) {
+        StanzaBuilder body = new StanzaBuilder("body", 
NamespaceURIs.XEP0124_BOSH);
+        body.addAttribute("wait", Integer.toString(session.getWait()));
+        body.addAttribute("inactivity", 
Integer.toString(session.getInactivity()));
+        body.addAttribute("polling", Integer.toString(session.getPolling()));
+        body.addAttribute("requests", Integer.toString(session.getRequests()));
+        body.addAttribute("hold", Integer.toString(session.getHold()));
+        body.addAttribute("sid", session.getSessionId());
+        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());
+        return body.build();
+    }
+
+    public Stanza getEmptyStanza() {
+        StanzaBuilder stanzaBuilder = new StanzaBuilder("body", 
NamespaceURIs.XEP0124_BOSH);
         return stanzaBuilder.build();
     }
 

Added: 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshResponse.java
URL: 
http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshResponse.java?rev=957353&view=auto
==============================================================================
--- 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshResponse.java
 (added)
+++ 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshResponse.java
 Wed Jun 23 21:24:39 2010
@@ -0,0 +1,46 @@
+/*
+ *  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.
+ *
+ */
+package org.apache.vysper.xmpp.extension.xep0124;
+
+/**
+ * The response sent to BOSH clients
+ * 
+ * @author The Apache MINA Project ([email protected])
+ */
+public class BoshResponse {
+
+    private final String contentType;
+
+    private final byte[] content;
+
+    public BoshResponse(String contentType, byte[] content) {
+        this.contentType = contentType;
+        this.content = content;
+    }
+
+    public String getContentType() {
+        return contentType;
+    }
+
+    public byte[] getContent() {
+        return content;
+    }
+
+}

Modified: 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshSaxContentHandler.java
URL: 
http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshSaxContentHandler.java?rev=957353&r1=957352&r2=957353&view=diff
==============================================================================
--- 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshSaxContentHandler.java
 (original)
+++ 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshSaxContentHandler.java
 Wed Jun 23 21:24:39 2010
@@ -19,6 +19,8 @@
  */
 package org.apache.vysper.xmpp.extension.xep0124;
 
+import javax.servlet.http.HttpServletRequest;
+
 import org.apache.vysper.mina.codec.StanzaBuilderFactory;
 import org.apache.vysper.xml.decoder.XMLElementBuilderFactory;
 import org.apache.vysper.xml.decoder.XMPPContentHandler;
@@ -47,7 +49,7 @@ public class BoshSaxContentHandler imple
 
     private final BoshHandler boshHandler;
 
-    private final BoshRequestContext boshRequestContext;
+    private final HttpServletRequest request;
 
     private final XMLElementBuilderFactory builderFactory;
 
@@ -58,10 +60,9 @@ public class BoshSaxContentHandler imple
     
     private boolean isBodyPayloadDecoded = false;
 
-    public BoshSaxContentHandler(BoshHandler boshHandler,
-            BoshRequestContext boshRequestContext) {
+    public BoshSaxContentHandler(BoshHandler boshHandler, HttpServletRequest 
req) {
         this.boshHandler = boshHandler;
-        this.boshRequestContext = boshRequestContext;
+        request = req;
         builderFactory = new StanzaBuilderFactory();
     }
 
@@ -91,7 +92,7 @@ public class BoshSaxContentHandler imple
             LOGGER.debug("BOSH decoding stanza: {}",
                     new Renderer(element).getComplete());
         }
-        boshHandler.process(boshRequestContext, (Stanza) element);
+        boshHandler.process(request, (Stanza) element);
         builder = null;
     }
 

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=957353&r1=957352&r2=957353&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
 Wed Jun 23 21:24:39 2010
@@ -30,6 +30,7 @@ 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;
@@ -40,6 +41,12 @@ import org.xml.sax.SAXException;
  * @author The Apache MINA Project ([email protected])
  */
 public class BoshServlet extends HttpServlet {
+    
+    public static final String TXT_CONTENT_TYPE = "text/plain";
+    
+    public static final String HTML_CONTENT_TYPE = "text/html; charset=UTF-8";
+    
+    public static final String XML_CONTENT_TYPE = "text/xml; charset=UTF-8";
 
     private static final long serialVersionUID = 1979722775762481476L;
 
@@ -47,12 +54,20 @@ public class BoshServlet extends HttpSer
 
     private static final String INFO_GET = "This is an XMPP BOSH connection 
manager, you need to use a compatible BOSH client to use its services!";
     
+    private static final String SERVER_IDENTIFICATION = "Vysper/0.5";
+    
     private final Logger logger = LoggerFactory.getLogger(BoshServlet.class);
     
     private final BoshHandler boshHandler = new BoshHandler();
 
-    private ByteArrayOutputStream flashCrossDomainPolicy;
-
+    private byte[] flashCrossDomainPolicy;
+    
+    private String accessControlAllowOrigin = "*";
+    
+    private String accessControlMaxAge = "86400"; // one day in seconds
+    
+    private String accessControlAllowMethods = "GET, POST, OPTIONS";
+    
     /**
      * Setter for the {...@link ServerRuntimeContext}
      * @param serverRuntimeContext
@@ -70,41 +85,88 @@ public class BoshServlet extends HttpSer
     public void setFlashCrossDomainPolicy(String policyPath) throws 
IOException {
         BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
                 policyPath));
-        flashCrossDomainPolicy = new ByteArrayOutputStream();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
         byte[] buf = new byte[1024];
         for (;;) {
             int i = bis.read(buf);
             if (i == -1) {
                 break;
             }
-            flashCrossDomainPolicy.write(buf, 0, i);
+            baos.write(buf, 0, i);
         }
         bis.close();
+        flashCrossDomainPolicy = baos.toByteArray();
     }
 
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp)
             throws ServletException, IOException {
+        resp.addDateHeader("Date", System.currentTimeMillis());
+        resp.addHeader("Server", SERVER_IDENTIFICATION);
         if (FLASH_CROSS_DOMAIN_POLICY_URI.equals(req.getRequestURI())) {
-            resp.setContentType(ContentType.XML_CONTENT_TYPE);
-            flashCrossDomainPolicy.writeTo(resp.getOutputStream());
+            resp.setContentType(XML_CONTENT_TYPE);
+            resp.setContentLength(flashCrossDomainPolicy.length);
+            resp.getOutputStream().write(flashCrossDomainPolicy);
         } else {
-            resp.setContentType(ContentType.HTML_CONTENT_TYPE);
+            resp.setContentType(HTML_CONTENT_TYPE);
+            resp.setContentLength(INFO_GET.length());
             resp.getWriter().println(INFO_GET);
         }
         resp.flushBuffer();
     }
+    
+    @Override
+    protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        // used for preflighted requests
+        resp.addDateHeader("Date", System.currentTimeMillis());
+        resp.addHeader("Server", SERVER_IDENTIFICATION);
+        resp.setContentType(TXT_CONTENT_TYPE);
+        resp.setContentLength(0);
+        resp.addHeader("Access-Control-Allow-Origin", 
accessControlAllowOrigin);
+        resp.addHeader("Access-Control-Allow-Methods", 
accessControlAllowMethods);
+        resp.addHeader("Access-Control-Max-Age", accessControlMaxAge);
+        resp.flushBuffer();
+    }
 
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp)
             throws ServletException, IOException {
-        BoshRequestContext boshRequestContext = new BoshRequestContext(req, 
resp);
-        BoshDecoder boshDecoder = new BoshDecoder(boshHandler, 
boshRequestContext);
+        BoshResponse boshResponse = (BoshResponse) 
req.getAttribute("response");
+        if (boshResponse != null) {
+            // if continuation is resumed
+            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 {
-            boshDecoder.decode();
+            decoder.decode();
         } catch (SAXException e) {
             logger.error("Exception thrown while decoding XML", e);
         }
     }
+    
+    private void writeResponse(HttpServletResponse resp, BoshResponse 
respData) throws IOException {
+        resp.addDateHeader("Date", System.currentTimeMillis());
+        resp.addHeader("Server", SERVER_IDENTIFICATION);
+        resp.setContentType(respData.getContentType());
+        resp.setContentLength(respData.getContent().length);
+        resp.addHeader("Access-control-allow-origin", 
accessControlAllowOrigin);
+        resp.getOutputStream().write(respData.getContent());
+        resp.flushBuffer();
+    }
 
 }


Reply via email to