Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dbeaver/pro#3807 jakarta websocket #3141

Open
wants to merge 3 commits into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,33 @@
package io.cloudbeaver.model.session;

import jakarta.servlet.http.HttpServletRequest;
import org.jkiss.code.Nullable;

public class WebHttpRequestInfo {
public static final String USER_AGENT = "User-Agent";

@Nullable
private final String id;
@Nullable
private final Object locale;
@Nullable
private final String lastRemoteAddress;
@Nullable
private final String lastRemoteUserAgent;

public WebHttpRequestInfo(HttpServletRequest request) {
this.id = request.getSession().getId();
this.id = request.getSession() == null ? null : request.getSession().getId();
this.locale = request.getAttribute("locale");
this.lastRemoteAddress = request.getRemoteAddr();
this.lastRemoteUserAgent = request.getHeader("User-Agent");
this.lastRemoteUserAgent = request.getHeader(USER_AGENT);
}

public WebHttpRequestInfo(String id, Object locale, String lastRemoteAddress, String lastRemoteUserAgent) {
public WebHttpRequestInfo(
@Nullable String id,
@Nullable Object locale,
@Nullable String lastRemoteAddress,
@Nullable String lastRemoteUserAgent
) {
this.id = id;
this.locale = locale;
this.lastRemoteAddress = lastRemoteAddress;
Expand All @@ -43,14 +54,17 @@ public String getId() {
return id;
}

@Nullable
public Object getLocale() {
return locale;
}

@Nullable
public String getLastRemoteAddress() {
return lastRemoteAddress;
}

@Nullable
public String getLastRemoteUserAgent() {
return lastRemoteUserAgent;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import io.cloudbeaver.server.jobs.SessionStateJob;
import io.cloudbeaver.server.jobs.WebDataSourceMonitorJob;
import io.cloudbeaver.server.jobs.WebSessionMonitorJob;
import io.cloudbeaver.service.session.CBSessionManager;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.jkiss.code.NotNull;
Expand Down Expand Up @@ -84,6 +83,7 @@ protected synchronized void initialize() {
}

protected void scheduleServerJobs() {
super.scheduleServerJobs();
new WebSessionMonitorJob(this, application.getSessionManager())
.scheduleMonitor();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,22 @@
import io.cloudbeaver.registry.WebServiceRegistry;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.server.CBConstants;
import io.cloudbeaver.server.WebApplication;
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
import io.cloudbeaver.server.servlets.CBImageServlet;
import io.cloudbeaver.server.servlets.CBStaticServlet;
import io.cloudbeaver.server.servlets.WebStatusServlet;
import io.cloudbeaver.server.websockets.CBJettyWebSocketManager;
import io.cloudbeaver.server.websockets.CBEventsWebSocket;
import io.cloudbeaver.server.websockets.CBWebSocketServerConfigurator;
import io.cloudbeaver.service.DBWServiceBindingServlet;
import io.cloudbeaver.service.DBWServiceBindingWebSocket;
import jakarta.websocket.server.ServerEndpointConfig;
import org.eclipse.jetty.ee10.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
import org.eclipse.jetty.ee10.servlet.ServletMapping;
import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.session.DefaultSessionCache;
import org.eclipse.jetty.session.DefaultSessionIdManager;
import org.eclipse.jetty.session.NullSessionDataStore;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.websocket.server.WebSocketUpgradeHandler;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
Expand All @@ -48,7 +46,6 @@
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Arrays;

public class CBJettyServer {
Expand Down Expand Up @@ -137,7 +134,7 @@ public void runServer() {
}

CBJettyWebSocketContext webSocketContext = new CBJettyWebSocketContext(server, servletContextHandler);
for (DBWServiceBindingWebSocket<CBApplication> wsb : WebServiceRegistry.getInstance()
for (DBWServiceBindingWebSocket wsb : WebServiceRegistry.getInstance()
.getWebServices(DBWServiceBindingWebSocket.class)
) {
if (wsb.isApplicable(this.application)) {
Expand All @@ -149,16 +146,16 @@ public void runServer() {
}
}

WebSocketUpgradeHandler webSocketHandler = WebSocketUpgradeHandler.from(server, servletContextHandler, (wsContainer) -> {
wsContainer.setIdleTimeout(Duration.ofMinutes(5));
// Add websockets
wsContainer.addMapping(
serverConfiguration.getServicesURI() + "ws",
new CBJettyWebSocketManager(this.application.getSessionManager())
);
}
);
servletContextHandler.insertHandler(webSocketHandler);
JakartaWebSocketServletContainerInitializer.configure(servletContextHandler, (context, container) -> {
// Add echo endpoint to server container
ServerEndpointConfig eventWsEnpoint = ServerEndpointConfig.Builder
.create(
CBEventsWebSocket.class,
serverConfiguration.getServicesURI() + "ws"
).configurator(new CBWebSocketServerConfigurator(application.getSessionManager()))
.build();
container.addEndpoint(eventWsEnpoint);
});

JettyUtils.initSessionManager(
this.application.getMaxSessionIdleTime(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import io.cloudbeaver.registry.WebHandlerRegistry;
import io.cloudbeaver.registry.WebServletHandlerDescriptor;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.server.CBPlatform;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServletRequest;
Expand All @@ -49,7 +48,6 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
Expand Down Expand Up @@ -227,7 +225,7 @@ private void patchStaticContentIfNeeded(HttpServletRequest request, HttpServletR
response.setHeader(HttpHeader.CACHE_CONTROL.toString(), "no-cache, no-store, must-revalidate");
response.setHeader(HttpHeader.CONTENT_TYPE.toString(), MimeTypes.TEXT_HTML);
response.setHeader(HttpHeader.EXPIRES.toString(), "0");
response.getOutputStream().write(ByteBuffer.wrap(indexBytes));
response.getOutputStream().write(indexBytes);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,18 @@
import io.cloudbeaver.registry.WebHandlerRegistry;
import io.cloudbeaver.registry.WebSessionHandlerDescriptor;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.server.CBConstants;
import io.cloudbeaver.server.WebAppSessionManager;
import io.cloudbeaver.server.events.WSWebUtils;
import io.cloudbeaver.service.DBWSessionHandler;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Session;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.auth.SMAuthInfo;
import org.jkiss.dbeaver.model.security.user.SMAuthPermissions;
import org.jkiss.dbeaver.model.websocket.WSConstants;
import org.jkiss.dbeaver.model.websocket.event.WSUserDeletedEvent;
import org.jkiss.dbeaver.model.websocket.event.session.WSSessionStateEvent;
import org.jkiss.utils.CommonUtils;
Expand Down Expand Up @@ -163,15 +159,12 @@ public WebSession getWebSession(
* @return WebSession object or null, if session expired or invalid
*/
@Nullable
public WebSession getOrRestoreSession(@NotNull Request request) {
var sessionIdCookie = Request.getCookies(request).stream().filter(
c -> c.getName().equals(CBConstants.CB_SESSION_COOKIE_NAME)
).findAny().orElse(null);
if (sessionIdCookie == null) {
public WebSession getOrRestoreWebSession(@NotNull WebHttpRequestInfo requestInfo) {
final var sessionId = requestInfo.getId();
if (sessionId == null) {
log.debug("Http session is null. No Web Session returned");
return null;
}
var sessionId = sessionIdCookie.getValue();
WebSession webSession;
synchronized (sessionMap) {
if (sessionMap.containsKey(sessionId)) {
Expand All @@ -189,12 +182,7 @@ public WebSession getOrRestoreSession(@NotNull Request request) {
return null;
}

webSession = createWebSessionImpl(new WebHttpRequestInfo(
request.getId(),
request.getAttribute("locale"),
Request.getRemoteAddr(request),
request.getHeaders().get("User-Agent")
));
webSession = createWebSessionImpl(requestInfo);
restorePreviousUserSession(webSession, oldAuthInfo);

sessionMap.put(sessionId, webSession);
Expand Down Expand Up @@ -301,15 +289,18 @@ public Collection<BaseWebSession> getAllActiveSessions() {
}

@Nullable
public WebHeadlessSession getHeadlessSession(Request request, Session session, boolean create) throws DBException {
String smAccessToken = request.getHeaders().get(WSConstants.WS_AUTH_HEADER);
public WebHeadlessSession getHeadlessSession(
@Nullable String smAccessToken,
@NotNull WebHttpRequestInfo requestInfo,
boolean create
) throws DBException {
if (CommonUtils.isEmpty(smAccessToken)) {
return null;
}
synchronized (sessionMap) {
var tempCredProvider = new SMTokenCredentialProvider(smAccessToken);
SMAuthPermissions authPermissions = application.createSecurityController(tempCredProvider).getTokenPermissions();
var sessionId = session != null ? session.getId()
var sessionId = requestInfo.getId() != null ? requestInfo.getId()
: authPermissions.getSessionId();

var existSession = sessionMap.get(sessionId);
Expand Down
2 changes: 1 addition & 1 deletion server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Require-Bundle: org.eclipse.core.runtime;visibility:=reexport,
org.jkiss.utils;visibility:=reexport,
org.jkiss.dbeaver.model.sql;visibility:=reexport,
org.jkiss.dbeaver.data.gis,
org.jkiss.bundle.jetty.server;visibility:=reexport,
org.jkiss.bundle.jakarta.jetty.server;visibility:=reexport,
com.google.gson;visibility:=reexport,
org.jkiss.bundle.graphql.java;visibility:=reexport,
org.jkiss.bundle.apache.dbcp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.cloudbeaver.server;

import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.server.websockets.WebSocketPingPongJob;
import org.eclipse.core.runtime.Plugin;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
Expand Down Expand Up @@ -129,10 +130,12 @@
}
}

@NotNull

Check warning on line 133 in server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/BaseWebPlatform.java

View workflow job for this annotation

GitHub Actions / Server / Lint

[checkstyle] reported by reviewdog 🐶 Missing a Javadoc comment. Raw Output: /github/workspace/./server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/BaseWebPlatform.java:133:5: warning: Missing a Javadoc comment. (com.puppycrawl.tools.checkstyle.checks.javadoc.MissingJavadocMethodCheck)
public abstract WebApplication getApplication();

protected abstract void scheduleServerJobs();
protected void scheduleServerJobs() {
new WebSocketPingPongJob(WebAppUtils.getWebPlatform()).scheduleMonitor();
}

@Override
public synchronized void dispose() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.model.session.BaseWebSession;
import io.cloudbeaver.model.session.WebHeadlessSession;
import io.cloudbeaver.model.session.WebHttpRequestInfo;
import io.cloudbeaver.model.session.WebSession;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Session;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
Expand Down Expand Up @@ -54,13 +53,17 @@

WebSession findWebSession(HttpServletRequest request, boolean errorOnNoFound) throws DBWebException;

Collection<BaseWebSession> getAllActiveSessions();

Check warning on line 56 in server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/WebAppSessionManager.java

View workflow job for this annotation

GitHub Actions / Server / Lint

[checkstyle] reported by reviewdog 🐶 Missing a Javadoc comment. Raw Output: /github/workspace/./server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/WebAppSessionManager.java:56:5: warning: Missing a Javadoc comment. (com.puppycrawl.tools.checkstyle.checks.javadoc.MissingJavadocMethodCheck)

WebSession getOrRestoreSession(Request httpRequest);
WebSession getOrRestoreWebSession(WebHttpRequestInfo httpRequest);

Check warning on line 58 in server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/WebAppSessionManager.java

View workflow job for this annotation

GitHub Actions / Server / Lint

[checkstyle] reported by reviewdog 🐶 Missing a Javadoc comment. Raw Output: /github/workspace/./server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/WebAppSessionManager.java:58:5: warning: Missing a Javadoc comment. (com.puppycrawl.tools.checkstyle.checks.javadoc.MissingJavadocMethodCheck)

Check warning on line 58 in server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/WebAppSessionManager.java

View check run for this annotation

Jenkins-CI-integration / CheckStyle Java Report

server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/WebAppSessionManager.java#L58

Missing a Javadoc comment.

WebHeadlessSession getHeadlessSession(Request request, Session session, boolean create) throws DBException;
WebHeadlessSession getHeadlessSession(

Check warning on line 60 in server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/WebAppSessionManager.java

View workflow job for this annotation

GitHub Actions / Server / Lint

[checkstyle] reported by reviewdog 🐶 Missing a Javadoc comment. Raw Output: /github/workspace/./server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/WebAppSessionManager.java:60:5: warning: Missing a Javadoc comment. (com.puppycrawl.tools.checkstyle.checks.javadoc.MissingJavadocMethodCheck)

Check warning on line 60 in server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/WebAppSessionManager.java

View check run for this annotation

Jenkins-CI-integration / CheckStyle Java Report

server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/WebAppSessionManager.java#L60

Missing a Javadoc comment.
@Nullable String smAccessToken,
@NotNull WebHttpRequestInfo requestInfo,
boolean create
) throws DBException;

boolean touchSession(HttpServletRequest request, HttpServletResponse response) throws DBWebException;

Check warning on line 66 in server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/WebAppSessionManager.java

View workflow job for this annotation

GitHub Actions / Server / Lint

[checkstyle] reported by reviewdog 🐶 Missing a Javadoc comment. Raw Output: /github/workspace/./server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/WebAppSessionManager.java:66:5: warning: Missing a Javadoc comment. (com.puppycrawl.tools.checkstyle.checks.javadoc.MissingJavadocMethodCheck)

default void expireIdleSessions() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,34 @@
package io.cloudbeaver.server.jetty;

import io.cloudbeaver.service.DBWWebSocketContext;
import jakarta.websocket.server.ServerEndpointConfig;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.websocket.api.Configurable;
import org.eclipse.jetty.websocket.server.WebSocketCreator;
import org.eclipse.jetty.websocket.server.WebSocketUpgradeHandler;
import org.jkiss.code.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public class CBJettyWebSocketContext implements DBWWebSocketContext {
private final List<String> mappings = new ArrayList<>();

private final Server server;
private final ContextHandler handler;
private final ServletContextHandler servletContextHandler;

public CBJettyWebSocketContext(@NotNull Server server, @NotNull ContextHandler handler) {
public CBJettyWebSocketContext(@NotNull Server server, @NotNull ServletContextHandler servletContextHandler) {
this.server = server;
this.handler = handler;
this.servletContextHandler = servletContextHandler;
}


@Override
public void addWebSocket(@NotNull String mapping, @NotNull Function<Configurable, WebSocketCreator> configurator) {
handler.insertHandler(WebSocketUpgradeHandler.from(
server,
handler,
container -> container.addMapping(mapping, configurator.apply(container))
));
mappings.add(mapping);
public void addWebSocket(@NotNull ServerEndpointConfig endpointConfig) {
// Add jakarta.websocket support
JakartaWebSocketServletContainerInitializer.configure(servletContextHandler, (context, container) -> {
container.addEndpoint(endpointConfig);
this.mappings.add(endpointConfig.getPath());
});
}

@NotNull
Expand Down
Loading
Loading