
io.jsync.sockjs.impl.BaseTransport Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsync.io Show documentation
Show all versions of jsync.io Show documentation
jsync.io is a non-blocking, event-driven networking framework for Java
/*
* Copyright (c) 2011-2013 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.jsync.sockjs.impl;
import io.jsync.Handler;
import io.jsync.MultiMap;
import io.jsync.VoidHandler;
import io.jsync.http.HttpServerRequest;
import io.jsync.http.HttpServerResponse;
import io.jsync.impl.AsyncInternal;
import io.jsync.json.JsonArray;
import io.jsync.json.JsonObject;
import io.jsync.logging.Logger;
import io.jsync.logging.impl.LoggerFactory;
import io.jsync.sockjs.SockJSSocket;
import io.jsync.utils.StringEscapeUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Random;
/**
* @author Tim Fox
*/
class BaseTransport {
protected static final String COMMON_PATH_ELEMENT_RE = "\\/[^\\/\\.]+\\/([^\\/\\.]+)\\/";
private static final Logger log = LoggerFactory.getLogger(BaseTransport.class);
private static final long RAND_OFFSET = 2L << 30;
protected final AsyncInternal async;
protected final Map sessions;
protected JsonObject config;
public BaseTransport(AsyncInternal async, Map sessions, JsonObject config) {
this.async = async;
this.sessions = sessions;
this.config = config;
}
static void setJSESSIONID(JsonObject config, HttpServerRequest req) {
String cookies = req.headers().get("cookie");
if (config.getBoolean("insert_JSESSIONID")) {
//Preserve existing JSESSIONID, if any
if (cookies != null) {
String[] parts;
if (cookies.contains(";")) {
parts = cookies.split(";");
} else {
parts = new String[]{cookies};
}
for (String part : parts) {
if (part.startsWith("JSESSIONID")) {
cookies = part + "; path=/";
break;
}
}
}
if (cookies == null) {
cookies = "JSESSIONID=dummy; path=/";
}
req.response().headers().set("Set-Cookie", cookies);
}
}
static void setCORS(HttpServerRequest req) {
String origin = req.headers().get("origin");
if (origin == null || "null".equals(origin)) {
origin = "*";
}
req.response().headers().set("Access-Control-Allow-Origin", origin);
req.response().headers().set("Access-Control-Allow-Credentials", "true");
String hdr = req.headers().get("Access-Control-Request-Headers");
if (hdr != null) {
req.response().headers().set("Access-Control-Allow-Headers", hdr);
}
}
static Handler createInfoHandler(final JsonObject config) {
return new Handler() {
boolean websocket = !config.getArray("disabled_transports").contains(Transport.WEBSOCKET.toString());
public void handle(HttpServerRequest req) {
if (log.isTraceEnabled()) log.trace("In Info handler");
req.response().headers().set("Content-Type", "application/json; charset=UTF-8");
setNoCacheHeaders(req);
JsonObject json = new JsonObject();
json.putBoolean("websocket", websocket);
json.putBoolean("cookie_needed", config.getBoolean("insert_JSESSIONID"));
json.putArray("origins", new JsonArray().add("*:*"));
// Java ints are signed, so we need to use a long and add the offset so
// the result is not negative
json.putNumber("entropy", RAND_OFFSET + new Random().nextInt());
setCORS(req);
req.response().end(json.encode());
}
};
}
static void setNoCacheHeaders(HttpServerRequest req) {
req.response().headers().set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
}
static Handler createCORSOptionsHandler(final JsonObject config, final String methods) {
return new Handler() {
public void handle(HttpServerRequest req) {
if (log.isTraceEnabled()) log.trace("In CORS options handler");
req.response().headers().set("Cache-Control", "public,max-age=31536000");
long oneYearSeconds = 365 * 24 * 60 * 60;
long oneYearms = oneYearSeconds * 1000;
String expires = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").format(new Date(System.currentTimeMillis() + oneYearms));
req.response().headers().set("Expires", expires);
req.response().headers().set("Access-Control-Allow-Methods", methods);
req.response().headers().set("Access-Control-Max-Age", String.valueOf(oneYearSeconds));
setCORS(req);
setJSESSIONID(config, req);
req.response().setStatusCode(204);
req.response().end();
}
};
}
// We remove cookie headers for security reasons. See https://github.com/sockjs/sockjs-node section on
// Authorisation
static MultiMap removeCookieHeaders(MultiMap headers) {
return headers.remove("cookie");
}
protected Session getSession(final long timeout, final long heartbeatPeriod, final String sessionID,
Handler sockHandler) {
Session session = sessions.get(sessionID);
if (session == null) {
session = new Session(async, sessions, sessionID, timeout, heartbeatPeriod, sockHandler);
sessions.put(sessionID, session);
}
return session;
}
protected void sendInvalidJSON(HttpServerResponse response) {
if (log.isTraceEnabled()) log.trace("Broken JSON");
response.setStatusCode(500);
response.end("Broken JSON encoding.");
}
protected String escapeForJavaScript(String str) {
try {
str = StringEscapeUtils.escapeJavaScript(str);
} catch (Exception e) {
log.error("Failed to escape", e);
str = null;
}
return str;
}
protected static abstract class BaseListener implements TransportListener {
protected void addCloseHandler(HttpServerResponse resp, final Session session) {
resp.closeHandler(new VoidHandler() {
public void handle() {
if (log.isTraceEnabled()) log.trace("Connection closed (from client?), closing session");
// Connection has been closed fron the client or network error so
// we remove the session
session.shutdown();
close();
}
});
}
public void sessionClosed() {
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy