From b471b0c0b3cbc1bd1de299e774dca0a840bc98b6 Mon Sep 17 00:00:00 2001 From: aalku Date: Sat, 9 Dec 2023 22:53:14 +0100 Subject: [PATCH] WebSockets support in http(s) shares. --- pom.xml | 12 +- .../config/WebSecurityConfiguration.java | 1 + .../cloud/service/sharing/SharingManager.java | 5 + .../sharing/http/HttpProxyManager.java | 376 +++++++++++++++++- .../cloud/web/jwt/JoatseTokenManager.java | 2 +- .../jetty/client/SwitchboardConnection.java | 3 + src/main/resources/logback.xml | 5 +- 7 files changed, 394 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 359bc1f..1edd34f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,12 +4,12 @@ org.springframework.boot spring-boot-starter-parent - 3.1.2 + 3.1.6 org.aalku.joatse joatse-cloud - 0.0.20-SNAPSHOT + 0.0.21-SNAPSHOT joatse-cloud Tunnel Router @@ -118,6 +118,14 @@ org.eclipse.jetty jetty-servlet + + org.eclipse.jetty.websocket + websocket-jetty-server + + + org.eclipse.jetty.websocket + websocket-jetty-client + org.springframework.boot diff --git a/src/main/java/org/aalku/joatse/cloud/config/WebSecurityConfiguration.java b/src/main/java/org/aalku/joatse/cloud/config/WebSecurityConfiguration.java index 9ca926c..45612ed 100644 --- a/src/main/java/org/aalku/joatse/cloud/config/WebSecurityConfiguration.java +++ b/src/main/java/org/aalku/joatse/cloud/config/WebSecurityConfiguration.java @@ -72,6 +72,7 @@ SecurityFilterChain filterChain(HttpSecurity http, JWTAuthorizationFilter jwtAut .addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class) .authorizeHttpRequests(t -> t.requestMatchers(WebSocketConfig.CONNECTION_HTTP_PATH).anonymous() // + .requestMatchers(HttpMethod.GET, "/ws-test.html").permitAll() .requestMatchers(HttpMethod.GET, "/login.html", "/css/**", "/header.js", "/lib/*.js").permitAll() .requestMatchers(HttpMethod.GET, "/user").permitAll() .requestMatchers("/error").permitAll() diff --git a/src/main/java/org/aalku/joatse/cloud/service/sharing/SharingManager.java b/src/main/java/org/aalku/joatse/cloud/service/sharing/SharingManager.java index 05bd214..7b2d881 100644 --- a/src/main/java/org/aalku/joatse/cloud/service/sharing/SharingManager.java +++ b/src/main/java/org/aalku/joatse/cloud/service/sharing/SharingManager.java @@ -416,4 +416,9 @@ public HttpTunnel getTunnelForHttpRequest(InetAddress remoteAddress, int serverP return null; } } + + public HttpTunnel getHttpTunnelById(UUID uuid, long httpTunnelId) { + HttpTunnel res = tunnelRegistry.getHttpTunnel(uuid, httpTunnelId); + return res; + } } diff --git a/src/main/java/org/aalku/joatse/cloud/service/sharing/http/HttpProxyManager.java b/src/main/java/org/aalku/joatse/cloud/service/sharing/http/HttpProxyManager.java index 9603542..ddbd65a 100644 --- a/src/main/java/org/aalku/joatse/cloud/service/sharing/http/HttpProxyManager.java +++ b/src/main/java/org/aalku/joatse/cloud/service/sharing/http/HttpProxyManager.java @@ -9,9 +9,11 @@ import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringWriter; +import java.lang.ref.WeakReference; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLEncoder; import java.net.UnknownHostException; @@ -27,7 +29,16 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -51,6 +62,7 @@ import org.eclipse.jetty.client.SwitchboardConnection; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; @@ -72,6 +84,15 @@ import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.WebSocketListener; +import org.eclipse.jetty.websocket.api.exceptions.CloseException; +import org.eclipse.jetty.websocket.api.exceptions.UpgradeException; +import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; +import org.eclipse.jetty.websocket.client.WebSocketClient; +import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents; +import org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer; +import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; @@ -83,6 +104,7 @@ import org.springframework.stereotype.Component; import org.springframework.web.util.HtmlUtils; +import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; @@ -93,12 +115,122 @@ @Component public class HttpProxyManager implements InitializingBean, DisposableBean { + private CopyOnWriteArrayList> wsClients = new CopyOnWriteArrayList<>(); + private ScheduledExecutorService scheduler; + + public class ServerSideWsHandler implements WebSocketListener { + private CompletableFuture cfOnConnect = new CompletableFuture<>(); + private CompletableFuture cfOnClose = new CompletableFuture<>(); + private Consumer textMessageHandler; + private Consumer binaryMessageHandler; + @Override + public void onWebSocketConnect(Session session) { + log.info(String.format("S onWebSocketConnect: %s", session.getUpgradeRequest().getRequestURI())); + cfOnConnect.complete(session); + } + @Override + public void onWebSocketClose(int statusCode, String reason) { + log.info(String.format("S onWebSocketClose: %s, %s", statusCode, reason)); + cfOnClose.complete(null); + } + @Override + public void onWebSocketError(Throwable cause) { + log.info(String.format("S onWebSocketError: %s", cause)); + cfOnConnect.completeExceptionally(cause); + } + @Override + public void onWebSocketText(String message) { + log.info(String.format("S onWebSocketText: %s", message)); + textMessageHandler.accept(message); + } + @Override + public void onWebSocketBinary(byte[] payload, int offset, int len) { + log.info(String.format("S onWebSocketBinary")); + byte[] m = new byte[len]; + System.arraycopy(payload, offset, m, 0, len); + binaryMessageHandler.accept(m); + } + public void setTextMessageHandler(Consumer textMessageHandler) { + this.textMessageHandler = textMessageHandler; + } + public void setBinaryMessageHandler(Consumer binaryMessageHandler) { + this.binaryMessageHandler = binaryMessageHandler; + } + public void setCloseHandler(Runnable task) { + cfOnClose.thenRun(task); + } + public CompletableFuture getSession() { + return cfOnConnect; + } + } + + public class ClientSideWsHandler implements WebSocketListener { + private CompletableFuture cfOnConnect = new CompletableFuture<>(); + private CompletableFuture cfOnClose = new CompletableFuture<>(); + private Consumer textMessageHandler; + private Consumer binaryMessageHandler; + private CompletableFuture cfErrorCode = new CompletableFuture<>(); + public ClientSideWsHandler() { + } + @Override + public void onWebSocketConnect(Session session) { + log.info(String.format("C onWebSocketConnect: %s", session.getUpgradeRequest().getRequestURI())); + cfOnConnect.complete(session); + } + @Override + public void onWebSocketClose(int statusCode, String reason) { + log.info(String.format("C onWebSocketClose: %s, %s", statusCode, reason)); + cfOnClose.complete(null); + } + @Override + public void onWebSocketError(Throwable cause) { + log.info(String.format("C onWebSocketError: %s", cause)); + + if (cause instanceof UpgradeException) { + cfErrorCode.complete(((UpgradeException) cause).getResponseStatusCode()); + } else if (cause instanceof CloseException) { + cfErrorCode.complete(((CloseException) cause).getStatusCode()); + } + cfOnConnect.completeExceptionally(cause); + } + @Override + public void onWebSocketText(String message) { + log.info(String.format("C onWebSocketText: %s", message)); + textMessageHandler.accept(message); + } + @Override + public void onWebSocketBinary(byte[] payload, int offset, int len) { + log.info(String.format("C onWebSocketBinary")); + byte[] m = new byte[len]; + System.arraycopy(payload, offset, m, 0, len); + binaryMessageHandler.accept(m); + } + public void setTextMessageHandler(Consumer textMessageHandler) { + this.textMessageHandler = textMessageHandler; + } + public void setBinaryMessageHandler(Consumer binaryMessageHandler) { + this.binaryMessageHandler = binaryMessageHandler; + } + public void setCloseHandler(Runnable task) { + cfOnClose.thenRun(task); + } + public CompletableFuture getSession() { + return cfOnConnect; + } + public Future getErrorCode() { + return cfErrorCode; + } + } + + private static final String COOKIE_JOATSE_HTTP_TUNNEL_TARGET_ID = "JoatseHttpTunnelTargetId"; private static final String REQUEST_KEY_HTTPTUNNEL = "httpTunnel"; private static final String REQUEST_KEY_REWRITE_HEADERS = "rewriteHeaders"; private static final String REQUEST_KEY_HIDE_PROXY = "hideProxy"; private static final String REQUEST_KEY_JOATSE_CLEAR_COOKIES = "JOATSE_CLEAR_COOKIES"; + + private static final String REQUEST_PROXY_HEADER_HTTPTUNNEL = "joatse-header-httptunnel-" + System.currentTimeMillis(); protected static final Set REVERSE_PROXY_HEADERS = new LinkedHashSet<>( Arrays.asList("Location", "Content-Location", "URI")); @@ -114,10 +246,21 @@ public static class UrlRewriteConfig { private final class AsyncMiddleManServletExtension extends AsyncMiddleManServlet { private static final long serialVersionUID = 1L; private boolean unsafeHttpClient; +// private WebSocketComponents wsComponents; +// private WebSocketMappings wsMapping; public AsyncMiddleManServletExtension(boolean unsafeHttpClient) { this.unsafeHttpClient = unsafeHttpClient; } + + @Override + public void init() throws ServletException { + super.init(); + ServletContext servletContext = getServletContext(); +// wsComponents = + WebSocketServerComponents.getWebSocketComponents(servletContext); +// wsMapping = new WebSocketMappings(wsComponents); + } @Override protected Logger createLogger() { @@ -126,19 +269,128 @@ protected Logger createLogger() { @Override protected HttpClient newHttpClient(ClientConnector clientConnector) { - HttpClient client = super.newHttpClient(clientConnector); + HttpClient client = new HttpClient(new HttpClientTransportOverHTTP(clientConnector) { + @Override + public Origin newOrigin(HttpRequest request) { + request.headers(h->{ + String ht = h.get(REQUEST_PROXY_HEADER_HTTPTUNNEL); + if (ht != null) { + h.remove(REQUEST_PROXY_HEADER_HTTPTUNNEL); + if (request.getTag() == null) { + HttpTunnel tunnel = tunnelFromHeader(ht); + request.tag(tunnel); + } + } + }); + Origin origin = super.newOrigin(request); + return origin; + } + }); client.getSslContextFactory().setTrustAll(unsafeHttpClient); - client.getProxyConfiguration().getProxies() - .add(new JoatseProxy( + client.getProxyConfiguration().addProxy(new JoatseProxy( new Origin.Address("localhost", switchboardPortListener.getAddress().getPort()), false, null, null)); return client; } + private HttpTunnel tunnelFromHeader(String headerValue) { + String[] a = headerValue.split(":"); + UUID uuid = UUID.fromString(a[0]); + long id = Long.parseLong(a[1], 16); + HttpTunnel httpTunnelById = sharingManager.getHttpTunnelById(uuid, id); + return httpTunnelById; + } + @Override public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { try { - InetAddress remoteAddress = InetAddress.getByName(request.getRemoteAddr()); + HttpServletRequest servletRequest = (HttpServletRequest) request; + HttpServletResponse servletResponse = (HttpServletResponse) response; + ServletContext servletContext = servletRequest.getServletContext(); + + if (Optional.ofNullable(servletRequest.getHeader("Upgrade")).filter(x->x.equals("websocket")).isPresent()) { + + InetAddress remoteAddress = InetAddress.getByName(request.getRemoteAddr()); + int serverPort = request.getServerPort(); + String serverName = request.getServerName(); + String scheme = request.getScheme(); + HttpTunnel httpTunnel = sharingManager.getTunnelForHttpRequest(remoteAddress, serverPort, serverName, scheme); + + if (httpTunnel == null) { + servletResponse.sendError(404); + return; + } + + JettyWebSocketServerContainer container = JettyWebSocketServerContainer + .getContainer(servletContext); + + URI mappedUri = setWebSocketScheme(new URI(rewriteUrl(new URL(servletRequest.getRequestURL().toString()), httpTunnel))); + + log.debug(String.format("WebSockets proxy connection to %s", mappedUri)); + ClientUpgradeRequest clientUpgradeRequest = newProxyClientUpgradeRequest(servletRequest, httpTunnel); + WebSocketClient client = newWsClient(); + + ServerSideWsHandler serverSideWsHandler = new ServerSideWsHandler(); + ClientSideWsHandler clientSideHandler = new ClientSideWsHandler(); + serverSideWsHandler.setCloseHandler(()->IOTools.runFailable(()->client.stop())); + clientSideHandler.getSession().thenAccept(s->{ + serverSideWsHandler.setTextMessageHandler(m->{ + try { + s.getRemote().sendString(m); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }); + // TODO + }); + serverSideWsHandler.getSession().thenAccept(s->{ + clientSideHandler.setTextMessageHandler(m->{ + try { + s.getRemote().sendString(m); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }); + // TODO + }); + + + CompletableFuture futureConnect = client.connect(clientSideHandler, mappedUri, clientUpgradeRequest); + boolean clientConnected = futureConnect.handle((s,e)->{ + if (e != null) { + IOTools.runFailable(()->client.stop()); + return false; + } else { + clientSideHandler.setCloseHandler(()->IOTools.runFailable(()->client.stop())); + return true; + } + }).get(); + if (clientConnected) { + boolean ok = container.upgrade((upgradeRequest, upgradeResponse) -> { + return serverSideWsHandler; + }, servletRequest, servletResponse); + if (!ok) { + IOTools.runFailable(()->client.stop()); + throw new IOException("Unable to upgrade WebSocket connection"); + } + } else { + int errorCode; + try { + errorCode = clientSideHandler.getErrorCode().get(2, TimeUnit.SECONDS); + } catch (TimeoutException x) { + log.error("Error waiting for an error event on a failed WS connection"); + errorCode = 500; + } + log.warn("Coudn't connect WS to server so we replicate the error code to the client: {}", errorCode); + servletResponse.sendError(errorCode); + return; + } + return; + } + + InetAddress remoteAddress = InetAddress.getByName(request.getRemoteAddr()); HttpServletRequest httpServletRequest = (HttpServletRequest) request; int serverPort = request.getServerPort(); String serverName = request.getServerName(); @@ -190,6 +442,29 @@ public void service(ServletRequest request, ServletResponse response) throws Ser } } + private WebSocketClient newWsClient() throws ServletException { + WebSocketClient client = new WebSocketClient(newHttpClient()); + wsClients.add(new WeakReference(client)); + try { + client.setStopAtShutdown(false); // <- Prevents GC + client.setConnectTimeout(10000); + client.setStopTimeout(5000); + client.start(); + } catch (Exception e) { + throw new ServletException("Error starting WebSocket client", e); + } + return client; + } + + private URI setWebSocketScheme(URI mappedUriA) throws URISyntaxException { + boolean isSecure = mappedUriA.getScheme().equals("https"); + String schemeB = isSecure ? "wss" : "ws"; + URI mappedUriB = new URI(schemeB, + mappedUriA.getSchemeSpecificPart(), + mappedUriA.getFragment()); + return mappedUriB; + } + private StringBuilder getPublicCloudUrl() { StringBuilder loginUrlSB = new StringBuilder(); if (webListenerConfigurationDetector.getSslRequired()) { @@ -215,11 +490,52 @@ protected void addProxyHeaders(HttpServletRequest clientRequest, Request proxyRe protected HttpRequest newProxyRequest(HttpServletRequest request, String rewrittenTarget) { HttpRequest proxyRequest = (HttpRequest) super.newProxyRequest(request, rewrittenTarget); HttpTunnel hTunnel = (HttpTunnel) request.getAttribute(REQUEST_KEY_HTTPTUNNEL); + if (hTunnel == null) { + log.warn("request attribute REQUEST_KEY_HTTPTUNNEL is null"); + } if (hTunnel != null) { proxyRequest.tag(hTunnel); } return proxyRequest; } + + protected ClientUpgradeRequest newProxyClientUpgradeRequest(HttpServletRequest servletRequest, HttpTunnel hTunnel) { + ClientUpgradeRequest res = new ClientUpgradeRequest(); + Map> reqHeaders = Collections.list(servletRequest.getHeaderNames()).stream() + .collect(Collectors.toMap(k -> k, k -> Collections.list(servletRequest.getHeaders(k)))); + // rewrite urls in headers + /* + * Same algorithm as copyRequestHeaders, more or less + */ + reqHeaders.remove("Origin"); // Compatibility + reqHeaders.remove("Host"); // Compatibility + reqHeaders.keySet().removeIf(h->h.startsWith("Sec-WebSocket-")); // Compatibility + for (String fieldName: new ArrayList<>(reqHeaders.keySet())) { + boolean change = false; + List oldList = reqHeaders.get(fieldName); + List newList = new ArrayList<>(oldList.size()); + for (String field: oldList) { + StringWriter out = new StringWriter(); + CharBuffer buffer = CharBuffer.allocate(field.length()); + buffer.put(field); + boolean match = IOTools.rewriteStringContent(buffer, new PrintWriter(out), true, PATTERN_URL_PREFFIX, hTunnel.getUrlReverseRewriteFunction()); + change = change || match; + newList.add(out.toString()); + } + if (change) { // replace all headers with that name if any change + log.debug("Changing header {} from {} to {}", fieldName, reqHeaders.get(fieldName), newList); + reqHeaders.put(fieldName, newList); + } + } + // Set them + log.debug("WS Headers = {}", reqHeaders); + res.setHeaders(reqHeaders); + // Trick so that the proxy ahead know where to send this request to + res.setHeader(REQUEST_PROXY_HEADER_HTTPTUNNEL, + hTunnel.getTunnel().getUuid() + ":" + Long.toHexString(hTunnel.getTargetId())); + return res; + } + @Override protected void copyRequestHeaders(HttpServletRequest clientRequest, Request proxyRequest) { @@ -227,6 +543,9 @@ protected void copyRequestHeaders(HttpServletRequest clientRequest, Request prox super.copyRequestHeaders(clientRequest, proxyRequest); if ((boolean)clientRequest.getAttribute(REQUEST_KEY_REWRITE_HEADERS)) { // rewrite urls in headers + /* + * Same algorithm as newProxyClientUpgradeRequest, more or less + */ proxyRequest.headers((HttpFields.Mutable m)->{ Set fieldNames = m.getFieldNamesCollection(); for (String fieldName: fieldNames) { @@ -392,7 +711,7 @@ protected ContentTransformer newServerResponseContentTransformer(HttpServletRequ public boolean transform(Source source, Sink sink) throws IOException { String contentType = proxyResponse.getContentType(); String contentEncoding = Optional.ofNullable(proxyResponse.getHeader("Content-Encoding")).orElse("identity"); - if (Arrays.asList("identity", "gzip").contains(contentEncoding) + if (Arrays.asList("identity", "gzip").contains(contentEncoding) && contentType != null && PATTERN_CONTENT_TYPE_TEXT.matcher(contentType).matches()) { log.info("transform.response {}: {}-->{} {} {}", tunnel.getUuid(), @@ -463,12 +782,13 @@ public ClientConnectionFactory newClientConnectionFactory(ClientConnectionFactor return new ClientConnectionFactory() { @Override public Connection newConnection(EndPoint endPoint, Map context) throws IOException { - log.debug("newConnection. EndPoint={}; Context=\r\n{};", endPoint, mapToString(context)); @SuppressWarnings("unchecked") Promise promise = (Promise) context .get(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY); HttpDestination destination = (HttpDestination) context .get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY); + log.debug("newConnection. EndPoint={}; Context=\r\n{}; Destination=\r\n{}", endPoint, + mapToString(context), destination); Executor executor = destination.getHttpClient().getExecutor(); SwitchboardConnection connection = new SwitchboardConnection(endPoint, executor, destination, promise, connectionFactory, context); @@ -513,6 +833,7 @@ public Connection newConnection(EndPoint endPoint, Map context) @Override public void destroy() throws Exception { + scheduler.shutdownNow(); if (normalProxyServer != null) { normalProxyServer.stop(); } @@ -553,6 +874,22 @@ public String rewriteCookieDomain(HttpTunnel tunnel, String headerValue) { @Override public void afterPropertiesSet() throws Exception { + + scheduler = Executors.newScheduledThreadPool(2); + scheduler.scheduleWithFixedDelay(()->{ + if (log.isDebugEnabled()) { + StringBuilder sb = new StringBuilder(); + String lf = String.format("%n\t"); + for (WeakReference c: wsClients) { + sb.append(Optional.ofNullable(c.get()).map(x -> x.getState()).orElse("-")).append(lf); + } + if (sb.length() > 0) { + log.debug("WebSocketClients: {}{}", lf, sb); + } + } + wsClients.removeIf(r->r.get() == null); + }, 5, 20, TimeUnit.SECONDS); + this.normalProxyServer = buildProxyServer(httpPortRange, webListenerConfigurationDetector.isSslEnabled(), false); this.unsafeClientProxyServer = buildProxyServer(httpUnsafePortRange, webListenerConfigurationDetector.isSslEnabled(), true); this.normalProxyServer.start(); @@ -608,10 +945,37 @@ private static ServletHolder proxyHolder(AbstractProxyServlet proxyServlet) { return proxyHolder; } +// private static class MyWebSocketListener implements WebSocketListener { +// @Override +// public void onWebSocketText(java.lang.String message) { +// System.out.println(message); +// WebSocketListener.super.onWebSocketText(message); +// } +// +// @Override +// public void onWebSocketBinary(byte[] payload, int offset, int len) { +// System.out.println("binaryMessage"); +// WebSocketListener.super.onWebSocketBinary(payload, offset, len); +// } +// } + private static ServletContextHandler servletContextHandler(AbstractProxyServlet servlet) { final ServletContextHandler servletContextHandler = new ServletContextHandler(); servletContextHandler.setContextPath("/"); +// Servlet websocketServlet = new JettyWebSocketServlet() { +// private static final long serialVersionUID = 1L; +// @Override protected void configure(JettyWebSocketServletFactory factory) { +// factory.addMapping("/", new JettyWebSocketCreator() { +// @Override +// public Object createWebSocket(JettyServerUpgradeRequest req, JettyServerUpgradeResponse resp) { +// return new MyWebSocketListener(); +// } +// }); +// } +// }; +// servletContextHandler.addServlet(new ServletHolder(websocketServlet), "ws://*"); servletContextHandler.addServlet(proxyHolder(servlet), "/*"); + JettyWebSocketServletContainerInitializer.configure(servletContextHandler, null); return servletContextHandler; } diff --git a/src/main/java/org/aalku/joatse/cloud/web/jwt/JoatseTokenManager.java b/src/main/java/org/aalku/joatse/cloud/web/jwt/JoatseTokenManager.java index 8084558..4fb0eda 100644 --- a/src/main/java/org/aalku/joatse/cloud/web/jwt/JoatseTokenManager.java +++ b/src/main/java/org/aalku/joatse/cloud/web/jwt/JoatseTokenManager.java @@ -51,7 +51,7 @@ public JoatseTokenManager() { public Map verifyToken(String token) { try { Claims claims = (Claims)parser.parse(token).getBody(); - log.info("Verified token {}", claims); + log.debug("Verified token {}", claims); return claims; } catch (SignatureException | ExpiredJwtException | MalformedJwtException | IllegalArgumentException | ClassCastException e) { log.warn("Invalid token: " + token); diff --git a/src/main/java/org/eclipse/jetty/client/SwitchboardConnection.java b/src/main/java/org/eclipse/jetty/client/SwitchboardConnection.java index 19083f9..8b10135 100644 --- a/src/main/java/org/eclipse/jetty/client/SwitchboardConnection.java +++ b/src/main/java/org/eclipse/jetty/client/SwitchboardConnection.java @@ -57,6 +57,9 @@ public void removeEventListener(EventListener listener) { @Override public void onOpen() { HttpTunnel tunnel = (HttpTunnel) destination.getOrigin().getTag(); + if (tunnel == null) { + log.error("HttpTunnel is not tagged"); + } UUID uuid = tunnel.getTunnel().getUuid(); log.info("onOpen. HttpTunnel= {} --> {}", uuid, tunnel.getTargetURL().toString()); super.onOpen(); diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index b133df6..d7aa572 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -14,10 +14,13 @@ - + + + +