Add ability to compress and skip unserializable session attributes (#10747)
* Add ability to compress and skip unserializable session attributes
This commit is contained in:
parent
f6d1ca9a71
commit
a5f06fceaf
|
@ -39,6 +39,7 @@ import org.eclipse.jetty.http3.server.AbstractHTTP3ServerConnectionFactory;
|
|||
import org.eclipse.jetty.http3.server.internal.HTTP3SessionServer;
|
||||
import org.eclipse.jetty.quic.client.ClientQuicSession;
|
||||
import org.eclipse.jetty.quic.common.QuicSession;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
@ -365,6 +366,7 @@ public class ClientServerTest extends AbstractClientServerTest
|
|||
}
|
||||
|
||||
@Test
|
||||
@Tag("flaky")
|
||||
public void testRequestHeadersTooLarge() throws Exception
|
||||
{
|
||||
start(new Session.Server.Listener()
|
||||
|
|
|
@ -13,10 +13,16 @@
|
|||
|
||||
package org.eclipse.jetty.session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.io.FileInputStream;
|
|||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.FileVisitOption;
|
||||
|
@ -32,7 +33,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||
import org.eclipse.jetty.util.ExceptionUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
|
@ -46,7 +46,7 @@ import org.slf4j.LoggerFactory;
|
|||
* A file-based store of session data.
|
||||
*/
|
||||
@ManagedObject
|
||||
public class FileSessionDataStore extends AbstractSessionDataStore
|
||||
public class FileSessionDataStore extends ObjectStreamSessionDataStore
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FileSessionDataStore.class);
|
||||
protected File _storeDir;
|
||||
|
@ -464,7 +464,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
* @param id identity of the session
|
||||
* @param data the info of the session
|
||||
*/
|
||||
protected void save(OutputStream os, String id, SessionData data) throws IOException
|
||||
protected void save(OutputStream os, String id, SessionData data) throws Exception
|
||||
{
|
||||
DataOutputStream out = new DataOutputStream(os);
|
||||
out.writeUTF(id);
|
||||
|
@ -478,8 +478,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
out.writeLong(data.getExpiry());
|
||||
out.writeLong(data.getMaxInactiveMs());
|
||||
|
||||
ObjectOutputStream oos = new ObjectOutputStream(out);
|
||||
SessionData.serializeAttributes(data, oos);
|
||||
serializeAttributes(data, out);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -623,8 +622,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
data.setMaxInactiveMs(maxIdle);
|
||||
|
||||
// Attributes
|
||||
ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is);
|
||||
SessionData.deserializeAttributes(data, ois);
|
||||
deserializeAttributes(data, is);
|
||||
return data;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -16,6 +16,7 @@ package org.eclipse.jetty.session;
|
|||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
|
@ -26,7 +27,6 @@ import java.sql.Statement;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
|
@ -39,7 +39,7 @@ import org.slf4j.LoggerFactory;
|
|||
* Session data stored in database
|
||||
*/
|
||||
@ManagedObject
|
||||
public class JDBCSessionDataStore extends AbstractSessionDataStore
|
||||
public class JDBCSessionDataStore extends ObjectStreamSessionDataStore
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JDBCSessionDataStore.class);
|
||||
|
||||
|
@ -662,10 +662,9 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
data.setContextPath(_context.getCanonicalContextPath());
|
||||
data.setVhost(_context.getVhost());
|
||||
|
||||
try (InputStream is = _dbAdaptor.getBlobInputStream(result, _sessionTableSchema.getMapColumn());
|
||||
ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is))
|
||||
try (InputStream is = _dbAdaptor.getBlobInputStream(result, _sessionTableSchema.getMapColumn()))
|
||||
{
|
||||
SessionData.deserializeAttributes(data, ois);
|
||||
deserializeAttributes(data, is);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -741,10 +740,10 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
statement.setLong(10, data.getExpiry());
|
||||
statement.setLong(11, data.getMaxInactiveMs());
|
||||
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos))
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();)
|
||||
{
|
||||
SessionData.serializeAttributes(data, oos);
|
||||
serializeAttributes(data, baos);
|
||||
|
||||
byte[] bytes = baos.toByteArray();
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
statement.setBinaryStream(12, bais, bytes.length); //attribute map as blob
|
||||
|
@ -772,10 +771,10 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
statement.setLong(5, data.getExpiry());
|
||||
statement.setLong(6, data.getMaxInactiveMs());
|
||||
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos))
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();)
|
||||
{
|
||||
SessionData.serializeAttributes(data, oos);
|
||||
serializeAttributes(data, baos);
|
||||
|
||||
byte[] bytes = baos.toByteArray();
|
||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes))
|
||||
{
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||
|
||||
public abstract class ObjectStreamSessionDataStore extends AbstractSessionDataStore
|
||||
{
|
||||
/**
|
||||
* Get an ObjectOutputStream suitable to serialize SessionData objects
|
||||
* into the provided OutputStream.
|
||||
* <br/>
|
||||
* By default, an ObjectObjectStream is returned.
|
||||
* <br/>
|
||||
* Override this method to provide a custom ObjectOutputStream, and/or to
|
||||
* chain other OutputStreams to perform such tasks as compressing the serialized
|
||||
* data, for example:
|
||||
* <br/>
|
||||
* <code>
|
||||
* GZIPOutputStream gos = new GZIPOutputStream(os);
|
||||
* return new ObjectOutputStream(gos);
|
||||
* </code>
|
||||
* @param os an output stream to which to serialize the session data
|
||||
* @return an ObjectOutputStream wrapping the OutputStream
|
||||
* @throws IOException if the stream cannot be created
|
||||
*/
|
||||
public ObjectOutputStream newObjectOutputStream(OutputStream os) throws IOException
|
||||
{
|
||||
return new ObjectOutputStream(os);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an ObjectInputStream that is capable of deserializing the session data
|
||||
* present in the provided InputStream.
|
||||
* <br/>
|
||||
* By default, a Classloader-aware ObjectInputStream is used, however, you
|
||||
* can return your own specialized ObjectInputStream, or chain other InputStreams
|
||||
* together to perform such tasks as data decompression, for example:
|
||||
* <br/>
|
||||
* <code>
|
||||
* GZIPInputStream gis = new GZIPInputStream(is);
|
||||
* return new ClassLoadingObjectInputStream(is)
|
||||
* </code>
|
||||
* @param is an input stream for accessing the session data to be deserialized
|
||||
* @return an ObjectInputStream that can deserialize the session data
|
||||
* @throws IOException if the stream cannot be created
|
||||
*/
|
||||
protected ObjectInputStream newObjectInputStream(InputStream is) throws IOException
|
||||
{
|
||||
return new ClassLoadingObjectInputStream(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the attribute map of the SessionData into the OutputStream provided.
|
||||
* @param data the SessionData whose attributes are to be serialized
|
||||
* @param os the OutputStream to receive the serialized attributes
|
||||
* @throws Exception if the attributes cannot be serialized
|
||||
*/
|
||||
protected void serializeAttributes(SessionData data, OutputStream os) throws Exception
|
||||
{
|
||||
Objects.requireNonNull(data);
|
||||
Objects.requireNonNull(os);
|
||||
try (ObjectOutputStream oos = newObjectOutputStream(os))
|
||||
{
|
||||
SessionData.serializeAttributes(data, oos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize the attribute map from the InputStream provided and store into the SessionData.
|
||||
* @param data the SessionData into which to deserialize the attributes
|
||||
* @param is the InputStream for reading the serialized attributes
|
||||
* @throws Exception if the attributes cannot be deserialized
|
||||
*/
|
||||
protected void deserializeAttributes(SessionData data, InputStream is) throws Exception
|
||||
{
|
||||
Objects.requireNonNull(data);
|
||||
Objects.requireNonNull(is);
|
||||
try (ObjectInputStream ois = newObjectInputStream(is))
|
||||
{
|
||||
SessionData.deserializeAttributes(data, ois);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -144,7 +144,8 @@ public class SessionData implements Serializable
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Deserialize {} isServerLoader={} serverLoader={} tccl={}", name, isServerClassLoader, serverLoader, contextLoader);
|
||||
Object value = ((ClassLoadingObjectInputStream)in).readObject(isServerClassLoader ? serverLoader : contextLoader);
|
||||
data._attributes.put(name, value);
|
||||
if (value != null)
|
||||
data._attributes.put(name, value);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -456,10 +456,9 @@ public abstract class AbstractSessionDataStoreTest
|
|||
long now = System.currentTimeMillis();
|
||||
SessionData data = store.newSessionData("aaa6", 100, now, now - 1, -1);
|
||||
data.setLastNode(_sessionIdManager.getWorkerName());
|
||||
//persistSession(data);
|
||||
store.store("aaa6", data);
|
||||
_server.stop();
|
||||
_server.start(); //reindex files
|
||||
_server.start();
|
||||
store = _sessionManager.getSessionCache().getSessionDataStore();
|
||||
|
||||
//test that we can retrieve it
|
||||
|
|
|
@ -15,8 +15,12 @@ package org.eclipse.jetty.session;
|
|||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
|
@ -25,6 +29,8 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -129,14 +135,75 @@ public class JdbcTestHelper
|
|||
/**
|
||||
* @return a fresh JDBCSessionDataStoreFactory
|
||||
*/
|
||||
public static SessionDataStoreFactory newSessionDataStoreFactory(String sessionTableName)
|
||||
public static SessionDataStoreFactory newSessionDataStoreFactory(String sessionTableName, boolean compress)
|
||||
{
|
||||
return newSessionDataStoreFactory(buildDatabaseAdaptor(), sessionTableName);
|
||||
return newSessionDataStoreFactory(buildDatabaseAdaptor(), sessionTableName, compress);
|
||||
}
|
||||
|
||||
public static SessionDataStoreFactory newSessionDataStoreFactory(DatabaseAdaptor da, String sessionTableName)
|
||||
public static ObjectOutputStream newObjectOutputStream(OutputStream os, boolean compress) throws IOException
|
||||
{
|
||||
JDBCSessionDataStoreFactory factory = new JDBCSessionDataStoreFactory();
|
||||
if (!compress)
|
||||
return new ObjectOutputStream(os);
|
||||
|
||||
GZIPOutputStream gos = new GZIPOutputStream(os, 1024);
|
||||
class SkipUnserializableObjectOutputStream extends ObjectOutputStream
|
||||
{
|
||||
public SkipUnserializableObjectOutputStream(OutputStream out) throws IOException
|
||||
{
|
||||
super(out);
|
||||
enableReplaceObject(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object replaceObject(Object obj) throws IOException
|
||||
{
|
||||
if (obj instanceof Serializable)
|
||||
return obj;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return new SkipUnserializableObjectOutputStream(gos);
|
||||
}
|
||||
|
||||
public static ObjectInputStream newObjectInputStream(InputStream is, boolean compress) throws IOException
|
||||
{
|
||||
if (!compress)
|
||||
return new ClassLoadingObjectInputStream(is);
|
||||
|
||||
GZIPInputStream gis = new GZIPInputStream(is, 1024);
|
||||
return new ClassLoadingObjectInputStream(gis);
|
||||
}
|
||||
|
||||
public static SessionDataStoreFactory newSessionDataStoreFactory(DatabaseAdaptor da, String sessionTableName, boolean compress)
|
||||
{
|
||||
JDBCSessionDataStoreFactory factory = new JDBCSessionDataStoreFactory()
|
||||
{
|
||||
@Override
|
||||
public SessionDataStore getSessionDataStore(SessionManager manager)
|
||||
{
|
||||
JDBCSessionDataStore ds = new JDBCSessionDataStore()
|
||||
{
|
||||
@Override
|
||||
public ObjectOutputStream newObjectOutputStream(OutputStream os) throws IOException
|
||||
{
|
||||
return JdbcTestHelper.newObjectOutputStream(os, compress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInputStream newObjectInputStream(InputStream is) throws IOException
|
||||
{
|
||||
return JdbcTestHelper.newObjectInputStream(is, compress);
|
||||
}
|
||||
};
|
||||
ds.setDatabaseAdaptor(_adaptor);
|
||||
ds.setSessionTableSchema(_schema);
|
||||
ds.setGracePeriodSec(getGracePeriodSec());
|
||||
ds.setSavePeriodSec(getSavePeriodSec());
|
||||
return ds;
|
||||
}
|
||||
};
|
||||
factory.setDatabaseAdaptor(da);
|
||||
JDBCSessionDataStore.SessionTableSchema sessionTableSchema = newSessionTableSchema(sessionTableName);
|
||||
factory.setSessionTableSchema(sessionTableSchema);
|
||||
|
@ -224,7 +291,7 @@ public class JdbcTestHelper
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static boolean checkSessionPersisted(SessionData data, String sessionTableName)
|
||||
public static boolean checkSessionPersisted(SessionData data, String sessionTableName, boolean compress)
|
||||
throws Exception
|
||||
{
|
||||
PreparedStatement statement = null;
|
||||
|
@ -266,9 +333,10 @@ public class JdbcTestHelper
|
|||
if (blob.length() > 0)
|
||||
{
|
||||
try (InputStream is = blob.getBinaryStream();
|
||||
ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is))
|
||||
ObjectInputStream ois = JdbcTestHelper.newObjectInputStream(is, compress))
|
||||
{
|
||||
SessionData.deserializeAttributes(tmp, ois);
|
||||
ois.close();
|
||||
}
|
||||
}
|
||||
//same number of attributes
|
||||
|
@ -292,7 +360,7 @@ public class JdbcTestHelper
|
|||
return true;
|
||||
}
|
||||
|
||||
public static void insertSession(SessionData data, String sessionTableName) throws Exception
|
||||
public static void insertSession(SessionData data, String sessionTableName, boolean compress) throws Exception
|
||||
{
|
||||
try (Connection con = getConnection())
|
||||
{
|
||||
|
@ -317,14 +385,15 @@ public class JdbcTestHelper
|
|||
statement.setLong(11, data.getMaxInactiveMs());
|
||||
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);)
|
||||
ObjectOutputStream oos = newObjectOutputStream(baos, compress);)
|
||||
{
|
||||
SessionData.serializeAttributes(data, oos);
|
||||
oos.close();
|
||||
byte[] bytes = baos.toByteArray();
|
||||
|
||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);)
|
||||
{
|
||||
statement.setBinaryStream(12, bais, bytes.length);
|
||||
statement.setBinaryStream(12, bais);
|
||||
}
|
||||
}
|
||||
statement.execute();
|
||||
|
|
|
@ -44,6 +44,6 @@ public class ClusteredInvalidationSessionTest extends AbstractClusteredInvalidat
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class ClusteredOrphanedSessionTest extends AbstractClusteredOrphanedSessi
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
|
@ -64,7 +64,7 @@ public class ClusteredSessionMigrationTest extends AbstractSessionTestBase
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
|
@ -37,7 +37,7 @@ public class ClusteredSessionScavengingTest extends AbstractClusteredSessionScav
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.session.jdbc;
|
||||
|
||||
import org.eclipse.jetty.session.AbstractSessionDataStoreTest;
|
||||
import org.eclipse.jetty.session.JdbcTestHelper;
|
||||
import org.eclipse.jetty.session.SessionData;
|
||||
import org.eclipse.jetty.session.SessionDataStore;
|
||||
import org.eclipse.jetty.session.SessionDataStoreFactory;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
public class JDBCSessionDataStoreCompressTest extends AbstractSessionDataStoreTest
|
||||
{
|
||||
public static final boolean COMPRESS = true;
|
||||
|
||||
class NonSerializable
|
||||
{
|
||||
int x = 10;
|
||||
}
|
||||
|
||||
public JDBCSessionDataStoreCompressTest() throws Exception
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
private String sessionTableName;
|
||||
|
||||
@BeforeEach
|
||||
public void setupSessionTableName() throws Exception
|
||||
{
|
||||
this.sessionTableName = getClass().getSimpleName() + "_" + System.nanoTime();
|
||||
JdbcTestHelper.prepareTables(sessionTableName);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
JdbcTestHelper.shutdown(sessionTableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, COMPRESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void persistSession(SessionData data)
|
||||
throws Exception
|
||||
{
|
||||
JdbcTestHelper.insertSession(data, sessionTableName, COMPRESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void persistUnreadableSession(SessionData data) throws Exception
|
||||
{
|
||||
JdbcTestHelper.insertUnreadableSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(),
|
||||
data.getCreated(), data.getAccessed(), data.getLastAccessed(),
|
||||
data.getMaxInactiveMs(), data.getExpiry(), data.getCookieSet(),
|
||||
data.getLastSaved(), sessionTableName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanOrphans() throws Exception
|
||||
{
|
||||
super.testCleanOrphans();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkSessionExists(SessionData data) throws Exception
|
||||
{
|
||||
return JdbcTestHelper.existsInSessionTable(data.getId(), false, sessionTableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkSessionPersisted(SessionData data) throws Exception
|
||||
{
|
||||
ClassLoader old = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(_contextClassLoader);
|
||||
try
|
||||
{
|
||||
return JdbcTestHelper.checkSessionPersisted(data, sessionTableName, COMPRESS);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(old);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnserializableSession() throws Exception
|
||||
{
|
||||
setUp();
|
||||
_server.start();
|
||||
|
||||
SessionDataStore store = _sessionManager.getSessionCache().getSessionDataStore();
|
||||
|
||||
//persist a session that has an unserializable attribute
|
||||
long now = System.currentTimeMillis();
|
||||
SessionData data = store.newSessionData("xxx999", 100, now, now - 1, -1); //never expires
|
||||
data.setLastNode(_sessionIdManager.getWorkerName());
|
||||
data.setAttribute("bad", new NonSerializable());
|
||||
|
||||
store.store("xxx999", data);
|
||||
|
||||
data = store.load("xxx999");
|
||||
Assertions.assertNull(data.getAttribute("bad"));
|
||||
}
|
||||
}
|
|
@ -13,21 +13,36 @@
|
|||
|
||||
package org.eclipse.jetty.ee10.session.jdbc;
|
||||
|
||||
import java.io.NotSerializableException;
|
||||
|
||||
import org.eclipse.jetty.session.AbstractSessionDataStoreTest;
|
||||
import org.eclipse.jetty.session.JdbcTestHelper;
|
||||
import org.eclipse.jetty.session.SessionData;
|
||||
import org.eclipse.jetty.session.SessionDataStore;
|
||||
import org.eclipse.jetty.session.SessionDataStoreFactory;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
/**
|
||||
* JDBCSessionDataStoreTest
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
public class JDBCSessionDataStoreTest extends AbstractSessionDataStoreTest
|
||||
{
|
||||
|
||||
class NonSerializable
|
||||
{
|
||||
int x = 10;
|
||||
}
|
||||
|
||||
public JDBCSessionDataStoreTest() throws Exception
|
||||
{
|
||||
super();
|
||||
|
@ -51,14 +66,14 @@ public class JDBCSessionDataStoreTest extends AbstractSessionDataStoreTest
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void persistSession(SessionData data)
|
||||
throws Exception
|
||||
{
|
||||
JdbcTestHelper.insertSession(data, sessionTableName);
|
||||
JdbcTestHelper.insertSession(data, sessionTableName, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,11 +104,28 @@ public class JDBCSessionDataStoreTest extends AbstractSessionDataStoreTest
|
|||
Thread.currentThread().setContextClassLoader(_contextClassLoader);
|
||||
try
|
||||
{
|
||||
return JdbcTestHelper.checkSessionPersisted(data, sessionTableName);
|
||||
return JdbcTestHelper.checkSessionPersisted(data, sessionTableName, false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(old);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnserializableSession() throws Exception
|
||||
{
|
||||
setUp();
|
||||
_server.start();
|
||||
|
||||
SessionDataStore store = _sessionManager.getSessionCache().getSessionDataStore();
|
||||
|
||||
//persist a session that has an unserializable attribute
|
||||
long now = System.currentTimeMillis();
|
||||
final SessionData data = store.newSessionData("xxx999", 100, now, now - 1, -1); //never expires
|
||||
data.setLastNode(_sessionIdManager.getWorkerName());
|
||||
data.setAttribute("bad", new NonSerializable());
|
||||
|
||||
assertThrows(NotSerializableException.class, () -> store.store("xxx999", data));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ public class ReloadedSessionMissingClassTest
|
|||
|
||||
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
|
||||
cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
|
||||
SessionDataStoreFactory storeFactory = JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
SessionDataStoreFactory storeFactory = JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(SessionTestSupport.DEFAULT_SCAVENGE_SEC);
|
||||
|
||||
SessionTestSupport server1 = new SessionTestSupport(0, SessionTestSupport.DEFAULT_MAX_INACTIVE, SessionTestSupport.DEFAULT_SCAVENGE_SEC, cacheFactory, storeFactory);
|
||||
|
|
|
@ -41,7 +41,7 @@ public class WebAppObjectInSessionTest extends AbstractWebAppObjectInSessionTest
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -44,6 +44,6 @@ public class ClusteredInvalidationSessionTest extends AbstractClusteredInvalidat
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class ClusteredOrphanedSessionTest extends AbstractClusteredOrphanedSessi
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
|
@ -64,7 +64,7 @@ public class ClusteredSessionMigrationTest extends AbstractSessionTestBase
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
|
@ -37,7 +37,7 @@ public class ClusteredSessionScavengingTest extends AbstractClusteredSessionScav
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
|
@ -51,14 +51,14 @@ public class JDBCSessionDataStoreTest extends AbstractSessionDataStoreTest
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void persistSession(SessionData data)
|
||||
throws Exception
|
||||
{
|
||||
JdbcTestHelper.insertSession(data, sessionTableName);
|
||||
JdbcTestHelper.insertSession(data, sessionTableName, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,7 +89,7 @@ public class JDBCSessionDataStoreTest extends AbstractSessionDataStoreTest
|
|||
Thread.currentThread().setContextClassLoader(_contextClassLoader);
|
||||
try
|
||||
{
|
||||
return JdbcTestHelper.checkSessionPersisted(data, sessionTableName);
|
||||
return JdbcTestHelper.checkSessionPersisted(data, sessionTableName, false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -97,7 +97,7 @@ public class ReloadedSessionMissingClassTest
|
|||
|
||||
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
|
||||
cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
|
||||
SessionDataStoreFactory storeFactory = JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
SessionDataStoreFactory storeFactory = JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(SessionTestSupport.DEFAULT_SCAVENGE_SEC);
|
||||
|
||||
SessionTestSupport server1 = new SessionTestSupport(0, SessionTestSupport.DEFAULT_MAX_INACTIVE, SessionTestSupport.DEFAULT_SCAVENGE_SEC, cacheFactory, storeFactory);
|
||||
|
|
|
@ -40,7 +40,7 @@ public class WebAppObjectInSessionTest extends AbstractWebAppObjectInSessionTest
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName);
|
||||
return JdbcTestHelper.newSessionDataStoreFactory(sessionTableName, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -16,13 +16,13 @@ package org.eclipse.jetty.nosql;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.session.AbstractSessionDataStore;
|
||||
import org.eclipse.jetty.session.ObjectStreamSessionDataStore;
|
||||
import org.eclipse.jetty.session.SessionData;
|
||||
|
||||
/**
|
||||
* NoSqlSessionDataStore
|
||||
*/
|
||||
public abstract class NoSqlSessionDataStore extends AbstractSessionDataStore
|
||||
public abstract class NoSqlSessionDataStore extends ObjectStreamSessionDataStore
|
||||
{
|
||||
|
||||
public class NoSqlSessionData extends SessionData
|
||||
|
|
|
@ -15,6 +15,7 @@ package org.eclipse.jetty.nosql.mongodb;
|
|||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -34,7 +35,6 @@ import org.eclipse.jetty.nosql.NoSqlSessionDataStore;
|
|||
import org.eclipse.jetty.session.SessionContext;
|
||||
import org.eclipse.jetty.session.SessionData;
|
||||
import org.eclipse.jetty.session.UnreadableSessionDataException;
|
||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
|
@ -239,10 +239,9 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
|
|||
else
|
||||
{
|
||||
//attributes have special serialized format
|
||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(attributes);
|
||||
ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(bais);)
|
||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(attributes);)
|
||||
{
|
||||
SessionData.deserializeAttributes(data, ois);
|
||||
deserializeAttributes(data, bais);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -514,10 +513,9 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
|
|||
sets.put(__ACCESSED, data.getAccessed());
|
||||
sets.put(__LAST_ACCESSED, data.getLastAccessed());
|
||||
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);)
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();)
|
||||
{
|
||||
SessionData.serializeAttributes(data, oos);
|
||||
serializeAttributes(data, baos);
|
||||
sets.put(getContextSubfield(__ATTRIBUTES), baos.toByteArray());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue