SocketIOServlet.java 8.11 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  javax.servlet.ServletException
 *  javax.servlet.ServletOutputStream
 *  javax.servlet.http.HttpServletRequest
 *  javax.servlet.http.HttpServletResponse
 *  org.apache.commons.io.IOUtils
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.sling.SlingServlet
 *  org.apache.sling.api.SlingHttpServletRequest
 *  org.apache.sling.api.request.RequestPathInfo
 *  org.apache.sling.commons.json.JSONException
 *  org.apache.sling.commons.json.io.JSONWriter
 *  org.eclipse.jetty.websocket.api.WebSocketPolicy
 *  org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest
 *  org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse
 *  org.eclipse.jetty.websocket.servlet.WebSocketCreator
 *  org.eclipse.jetty.websocket.servlet.WebSocketServlet
 *  org.eclipse.jetty.websocket.servlet.WebSocketServletFactory
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.granite.socketio.impl;

import com.adobe.granite.socketio.impl.engine.EIOService;
import com.adobe.granite.socketio.impl.engine.EIOSocket;
import com.adobe.granite.socketio.impl.engine.EIOTransport;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.security.Principal;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.request.RequestPathInfo;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.io.JSONWriter;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@SlingServlet(paths={"/bin/granite/socket.io", "/bin/granite/socket.io/socket.io.js", "/bin/granite/socket.io/validate.json"})
public class SocketIOServlet
extends WebSocketServlet
implements WebSocketCreator {
    public static final String SOCKET_IO_PATH = "/bin/granite/socket.io";
    public static final String SOCKET_IO_TOKEN_JSON_PATH = "/bin/granite/socket.io/validate.json";
    public static final String SOCKET_IO_JS_PATH = "/bin/granite/socket.io/socket.io.js";
    public static final String SOCKET_IO_JS_RESOURCE = "socket.io-1.3.5-min.js";
    public static final String GRANITE_IO_JS_RESOURCE = "granite-socket.io.js";
    private byte[] socket_io_js;
    private long socket_io_js_date;
    private static final Logger log = LoggerFactory.getLogger(SocketIOServlet.class);
    @Reference
    private EIOService engine;

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public void init() throws ServletException {
        ClassLoader old = Thread.currentThread().getContextClassLoader();
        try {
            Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
            super.init();
        }
        finally {
            Thread.currentThread().setContextClassLoader(old);
        }
    }

    public void configure(WebSocketServletFactory factory) {
        factory.getPolicy().setIdleTimeout(this.engine.getPingTimeout());
        factory.setCreator((WebSocketCreator)this);
    }

    public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp) {
        try {
            HttpServletRequest request = req.getHttpServletRequest();
            String transport = request.getParameter("transport");
            if (transport == null) {
                log.error("engine.io request does not contain 'transport' request parameter.");
                resp.sendError(404, "NOT FOUND");
                return null;
            }
            if (!this.engine.isTransportSupported(transport)) {
                log.error("transport '{}' is not supported.");
                resp.sendError(404, "NOT FOUND");
                return null;
            }
            EIOSocket socket = null;
            String sid = request.getParameter("sid");
            if (sid != null) {
                socket = this.engine.getSocket(sid);
                if (socket == null) {
                    log.error("unknown session id {}", (Object)sid);
                    resp.sendError(403, "FORBIDDEN");
                }
            } else {
                String token = request.getParameter("token");
                if (token != null) {
                    sid = this.engine.validateToken(token, request);
                    socket = this.engine.createSocket(sid, transport, request.getUserPrincipal());
                    log.debug("creating new client {}", (Object)socket.getId());
                } else {
                    log.warn("initial engine.io request does not contain a 'token' request parameter.");
                    resp.sendError(403, "FORBIDDEN");
                }
            }
            return socket == null ? null : socket.getTransport();
        }
        catch (IOException e) {
            log.error("internal error", (Throwable)e);
            return null;
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
        SlingHttpServletRequest req = (SlingHttpServletRequest)request;
        String path = req.getRequestPathInfo().getResourcePath();
        if ("/bin/granite/socket.io/socket.io.js".equals(path)) {
            long ifms;
            if (this.socket_io_js == null) {
                this.socket_io_js_date = System.currentTimeMillis() / 1000 * 1000;
                InputStream is0 = this.getClass().getResourceAsStream("socket.io-1.3.5-min.js");
                InputStream is1 = this.getClass().getResourceAsStream("granite-socket.io.js");
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                IOUtils.copy((InputStream)is0, (OutputStream)out);
                IOUtils.copy((InputStream)is1, (OutputStream)out);
                IOUtils.closeQuietly((InputStream)is0);
                IOUtils.closeQuietly((InputStream)is1);
                this.socket_io_js = out.toByteArray();
            }
            if ((ifms = req.getDateHeader("If-Modified-Since")) >= this.socket_io_js_date) {
                resp.setStatus(304);
                resp.flushBuffer();
                return;
            }
            resp.setContentType("application/x-javascript");
            resp.setCharacterEncoding("utf-8");
            resp.setContentLength(this.socket_io_js.length);
            resp.setDateHeader("Last-Modified", this.socket_io_js_date);
            resp.getOutputStream().write(this.socket_io_js);
        } else if ("/bin/granite/socket.io/validate.json".equals(path)) {
            String token = this.engine.createSessionToken(request);
            resp.setContentType("application/json");
            resp.setCharacterEncoding("utf-8");
            resp.setHeader("Cache-Control", "private, max-age=0, no-cache");
            try {
                JSONWriter w = new JSONWriter((Writer)resp.getWriter());
                w.object();
                w.key("token").value((Object)(token == null ? "" : token));
                w.key("success").value((Object)"ok");
                w.endObject();
            }
            catch (JSONException e) {
                throw new IOException((Throwable)e);
            }
            resp.flushBuffer();
        } else {
            resp.sendError(404);
        }
    }

    protected void bindEngine(EIOService eIOService) {
        this.engine = eIOService;
    }

    protected void unbindEngine(EIOService eIOService) {
        if (this.engine == eIOService) {
            this.engine = null;
        }
    }
}