use of java.util.concurrent.atomic.AtomicReference in project jetty.project by eclipse.
the class FlowControlStrategyTest method testServerTwoDataFramesWithStalledStream.
// TODO
// Since we changed the API to disallow consecutive data() calls without waiting
// for the callback, it is now not possible to have DATA1, DATA2 in the queue for
// the same stream. Perhaps this test should just be deleted.
@Ignore
@Test
public void testServerTwoDataFramesWithStalledStream() throws Exception {
// Frames in queue = DATA1, DATA2.
// Server writes part of DATA1, then stalls.
// A window update unstalls the session, verify that the data is correctly sent.
Random random = new Random();
final byte[] chunk1 = new byte[1024];
random.nextBytes(chunk1);
final byte[] chunk2 = new byte[2048];
random.nextBytes(chunk2);
// Two SETTINGS frames: the initial after the preface,
// and the explicit where we set the stream window size to zero.
final AtomicReference<CountDownLatch> settingsLatch = new AtomicReference<>(new CountDownLatch(2));
final CountDownLatch dataLatch = new CountDownLatch(1);
start(new ServerSessionListener.Adapter() {
@Override
public void onSettings(Session session, SettingsFrame frame) {
settingsLatch.get().countDown();
}
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) {
stream.data(new DataFrame(stream.getId(), ByteBuffer.wrap(chunk1), false), Callback.NOOP);
stream.data(new DataFrame(stream.getId(), ByteBuffer.wrap(chunk2), true), Callback.NOOP);
dataLatch.countDown();
return null;
}
});
Session session = newClient(new Session.Listener.Adapter());
Map<Integer, Integer> settings = new HashMap<>();
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, 0);
session.settings(new SettingsFrame(settings, false), Callback.NOOP);
Assert.assertTrue(settingsLatch.get().await(5, TimeUnit.SECONDS));
byte[] content = new byte[chunk1.length + chunk2.length];
final ByteBuffer buffer = ByteBuffer.wrap(content);
MetaData.Request metaData = newRequest("GET", new HttpFields());
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
final CountDownLatch responseLatch = new CountDownLatch(1);
session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter() {
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
buffer.put(frame.getData());
callback.succeeded();
if (frame.isEndStream())
responseLatch.countDown();
}
});
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
// Now we have the 2 DATA frames queued in the server.
// Unstall the stream window.
settingsLatch.set(new CountDownLatch(1));
settings.clear();
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, chunk1.length / 2);
session.settings(new SettingsFrame(settings, false), Callback.NOOP);
Assert.assertTrue(settingsLatch.get().await(5, TimeUnit.SECONDS));
Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
// Check that the data is sent correctly.
byte[] expected = new byte[content.length];
System.arraycopy(chunk1, 0, expected, 0, chunk1.length);
System.arraycopy(chunk2, 0, expected, chunk1.length, chunk2.length);
Assert.assertArrayEquals(expected, content);
}
use of java.util.concurrent.atomic.AtomicReference in project jetty.project by eclipse.
the class PrefaceTest method testOnPrefaceNotifiedForStandardUpgrade.
@Test
public void testOnPrefaceNotifiedForStandardUpgrade() throws Exception {
Integer maxConcurrentStreams = 128;
AtomicReference<CountDownLatch> serverPrefaceLatch = new AtomicReference<>(new CountDownLatch(1));
AtomicReference<CountDownLatch> serverSettingsLatch = new AtomicReference<>(new CountDownLatch(1));
HttpConfiguration config = new HttpConfiguration();
prepareServer(new HttpConnectionFactory(config), new HTTP2CServerConnectionFactory(config) {
@Override
protected ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint) {
return new ServerSessionListener.Adapter() {
@Override
public Map<Integer, Integer> onPreface(Session session) {
Map<Integer, Integer> serverSettings = new HashMap<>();
serverSettings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, maxConcurrentStreams);
serverPrefaceLatch.get().countDown();
return serverSettings;
}
@Override
public void onSettings(Session session, SettingsFrame frame) {
serverSettingsLatch.get().countDown();
}
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) {
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
return null;
}
};
}
});
server.start();
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
try (SocketChannel socket = SocketChannel.open()) {
socket.connect(new InetSocketAddress("localhost", connector.getLocalPort()));
String upgradeRequest = "" + "GET /one HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: Upgrade, HTTP2-Settings\r\n" + "Upgrade: h2c\r\n" + "HTTP2-Settings: \r\n" + "\r\n";
ByteBuffer upgradeBuffer = ByteBuffer.wrap(upgradeRequest.getBytes(StandardCharsets.ISO_8859_1));
socket.write(upgradeBuffer);
// Make sure onPreface() is called on server.
Assert.assertTrue(serverPrefaceLatch.get().await(5, TimeUnit.SECONDS));
Assert.assertTrue(serverSettingsLatch.get().await(5, TimeUnit.SECONDS));
// The 101 response is the reply to the client preface SETTINGS frame.
ByteBuffer buffer = byteBufferPool.acquire(1024, true);
http1: while (true) {
BufferUtil.clearToFill(buffer);
int read = socket.read(buffer);
BufferUtil.flipToFlush(buffer, 0);
if (read < 0)
Assert.fail();
int crlfs = 0;
while (buffer.hasRemaining()) {
byte b = buffer.get();
if (b == '\r' || b == '\n')
++crlfs;
else
crlfs = 0;
if (crlfs == 4)
break http1;
}
}
// Reset the latches on server.
serverPrefaceLatch.set(new CountDownLatch(1));
serverSettingsLatch.set(new CountDownLatch(1));
// After the 101, the client must send the connection preface.
Generator generator = new Generator(byteBufferPool);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
Map<Integer, Integer> clientSettings = new HashMap<>();
clientSettings.put(SettingsFrame.ENABLE_PUSH, 1);
generator.control(lease, new SettingsFrame(clientSettings, false));
List<ByteBuffer> buffers = lease.getByteBuffers();
socket.write(buffers.toArray(new ByteBuffer[buffers.size()]));
// However, we should not call onPreface() again.
Assert.assertFalse(serverPrefaceLatch.get().await(1, TimeUnit.SECONDS));
// Although we should notify of the SETTINGS frame.
Assert.assertTrue(serverSettingsLatch.get().await(5, TimeUnit.SECONDS));
CountDownLatch clientSettingsLatch = new CountDownLatch(1);
AtomicBoolean responded = new AtomicBoolean();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() {
@Override
public void onSettings(SettingsFrame frame) {
if (frame.isReply())
return;
Assert.assertEquals(maxConcurrentStreams, frame.getSettings().get(SettingsFrame.MAX_CONCURRENT_STREAMS));
clientSettingsLatch.countDown();
}
@Override
public void onHeaders(HeadersFrame frame) {
if (frame.isEndStream())
responded.set(true);
}
}, 4096, 8192);
// HTTP/2 parsing.
while (true) {
parser.parse(buffer);
if (responded.get())
break;
BufferUtil.clearToFill(buffer);
int read = socket.read(buffer);
BufferUtil.flipToFlush(buffer, 0);
if (read < 0)
Assert.fail();
}
Assert.assertTrue(clientSettingsLatch.await(5, TimeUnit.SECONDS));
}
}
use of java.util.concurrent.atomic.AtomicReference in project jetty.project by eclipse.
the class StreamResetTest method testStreamReceivingResetIsRemoved.
@Test
public void testStreamReceivingResetIsRemoved() throws Exception {
final AtomicReference<Stream> streamRef = new AtomicReference<>();
final CountDownLatch resetLatch = new CountDownLatch(1);
start(new ServerSessionListener.Adapter() {
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) {
return new Stream.Listener.Adapter() {
@Override
public void onReset(Stream stream, ResetFrame frame) {
Assert.assertNotNull(stream);
Assert.assertTrue(stream.isReset());
streamRef.set(stream);
resetLatch.countDown();
}
};
}
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
HeadersFrame requestFrame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(requestFrame, promise, new Stream.Listener.Adapter());
Stream stream = promise.get(5, TimeUnit.SECONDS);
ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code);
stream.reset(resetFrame, Callback.NOOP);
Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
// Wait a while to let the server remove the
// stream after returning from onReset().
Thread.sleep(1000);
Stream serverStream = streamRef.get();
Assert.assertEquals(0, serverStream.getSession().getStreams().size());
}
use of java.util.concurrent.atomic.AtomicReference in project jetty.project by eclipse.
the class MongoSessionDataStore method load.
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#load(String)
*/
@Override
public SessionData load(String id) throws Exception {
final AtomicReference<SessionData> reference = new AtomicReference<SessionData>();
final AtomicReference<Exception> exception = new AtomicReference<Exception>();
Runnable r = new Runnable() {
public void run() {
try {
DBObject sessionDocument = _dbSessions.findOne(new BasicDBObject(__ID, id));
if (LOG.isDebugEnabled())
LOG.debug("id={} loaded={}", id, sessionDocument);
if (sessionDocument == null)
return;
Boolean valid = (Boolean) sessionDocument.get(__VALID);
if (LOG.isDebugEnabled())
LOG.debug("id={} valid={}", id, valid);
if (valid == null || !valid)
return;
Object version = getNestedValue(sessionDocument, getContextSubfield(__VERSION));
Long lastSaved = (Long) getNestedValue(sessionDocument, getContextSubfield(__LASTSAVED));
String lastNode = (String) getNestedValue(sessionDocument, getContextSubfield(__LASTNODE));
Long created = (Long) sessionDocument.get(__CREATED);
Long accessed = (Long) sessionDocument.get(__ACCESSED);
Long maxInactive = (Long) sessionDocument.get(__MAX_IDLE);
Long expiry = (Long) sessionDocument.get(__EXPIRY);
NoSqlSessionData data = null;
// get the session for the context
DBObject sessionSubDocumentForContext = (DBObject) getNestedValue(sessionDocument, getContextField());
if (LOG.isDebugEnabled())
LOG.debug("attrs {}", sessionSubDocumentForContext);
if (sessionSubDocumentForContext != null) {
if (LOG.isDebugEnabled())
LOG.debug("Session {} present for context {}", id, _context);
//only load a session if it exists for this context
data = (NoSqlSessionData) newSessionData(id, created, accessed, accessed, maxInactive);
data.setVersion(version);
data.setExpiry(expiry);
data.setContextPath(_context.getCanonicalContextPath());
data.setVhost(_context.getVhost());
data.setLastSaved(lastSaved);
data.setLastNode(lastNode);
HashMap<String, Object> attributes = new HashMap<>();
for (String name : sessionSubDocumentForContext.keySet()) {
//skip special metadata attribute which is not one of the actual session attributes
if (__METADATA.equals(name))
continue;
String attr = decodeName(name);
Object value = decodeValue(sessionSubDocumentForContext.get(name));
attributes.put(attr, value);
}
data.putAllAttributes(attributes);
} else {
if (LOG.isDebugEnabled())
LOG.debug("Session {} not present for context {}", id, _context);
}
reference.set(data);
} catch (Exception e) {
exception.set(e);
}
}
};
_context.run(r);
if (exception.get() != null)
throw exception.get();
return reference.get();
}
use of java.util.concurrent.atomic.AtomicReference in project jetty.project by eclipse.
the class JDBCSessionDataStore method load.
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#load(java.lang.String)
*/
@Override
public SessionData load(String id) throws Exception {
final AtomicReference<SessionData> reference = new AtomicReference<SessionData>();
final AtomicReference<Exception> exception = new AtomicReference<Exception>();
Runnable r = new Runnable() {
public void run() {
try (Connection connection = _dbAdaptor.getConnection();
PreparedStatement statement = _sessionTableSchema.getLoadStatement(connection, id, _context);
ResultSet result = statement.executeQuery()) {
SessionData data = null;
if (result.next()) {
data = newSessionData(id, result.getLong(_sessionTableSchema.getCreateTimeColumn()), result.getLong(_sessionTableSchema.getAccessTimeColumn()), result.getLong(_sessionTableSchema.getLastAccessTimeColumn()), result.getLong(_sessionTableSchema.getMaxIntervalColumn()));
data.setCookieSet(result.getLong(_sessionTableSchema.getCookieTimeColumn()));
data.setLastNode(result.getString(_sessionTableSchema.getLastNodeColumn()));
data.setLastSaved(result.getLong(_sessionTableSchema.getLastSavedTimeColumn()));
data.setExpiry(result.getLong(_sessionTableSchema.getExpiryTimeColumn()));
//TODO needed? this is part of the key now
data.setContextPath(result.getString(_sessionTableSchema.getContextPathColumn()));
//TODO needed??? this is part of the key now
data.setVhost(result.getString(_sessionTableSchema.getVirtualHostColumn()));
try (InputStream is = _dbAdaptor.getBlobInputStream(result, _sessionTableSchema.getMapColumn());
ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is)) {
Object o = ois.readObject();
data.putAllAttributes((Map<String, Object>) o);
} catch (Exception e) {
throw new UnreadableSessionDataException(id, _context, e);
}
if (LOG.isDebugEnabled())
LOG.debug("LOADED session {}", data);
} else if (LOG.isDebugEnabled())
LOG.debug("No session {}", id);
reference.set(data);
} catch (Exception e) {
exception.set(e);
}
}
};
//ensure this runs with context classloader set
_context.run(r);
if (exception.get() != null)
throw exception.get();
return reference.get();
}
Aggregations