use of java.nio.channels.WritePendingException in project jetty.project by eclipse.
the class HTTP2Test method testInvalidAPIUsageOnServer.
@Test
public void testInvalidAPIUsageOnServer() throws Exception {
long sleep = 1000;
CountDownLatch completeLatch = new CountDownLatch(2);
start(new ServerSessionListener.Adapter() {
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) {
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
DataFrame dataFrame = new DataFrame(stream.getId(), BufferUtil.EMPTY_BUFFER, true);
// The call to headers() is legal, but slow.
new Thread(() -> {
stream.headers(new HeadersFrame(stream.getId(), response, null, false) {
@Override
public MetaData getMetaData() {
sleep(2 * sleep);
return super.getMetaData();
}
}, new Callback() {
@Override
public void succeeded() {
stream.data(dataFrame, NOOP);
}
});
}).start();
// Wait for the headers() call to happen.
sleep(sleep);
// This data call is illegal because it does not
// wait for the previous callback to complete.
stream.data(dataFrame, new Callback() {
@Override
public void failed(Throwable x) {
if (x instanceof WritePendingException) {
// Expected.
completeLatch.countDown();
}
}
});
return null;
}
});
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", new HttpFields());
HeadersFrame frame = new HeadersFrame(metaData, null, true);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter() {
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
callback.succeeded();
if (frame.isEndStream())
completeLatch.countDown();
}
});
Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
}
use of java.nio.channels.WritePendingException in project tomcat by apache.
the class SecureNio2Channel method close.
/**
* Sends a SSL close message, will not physically close the connection here.<br>
* To close the connection, you could do something like
* <pre><code>
* close();
* while (isOpen() && !myTimeoutFunction()) Thread.sleep(25);
* if ( isOpen() ) close(true); //forces a close if you timed out
* </code></pre>
* @throws IOException if an I/O error occurs
* @throws IOException if there is data on the outgoing network buffer and we are unable to flush it
*/
@Override
public void close() throws IOException {
if (closing)
return;
closing = true;
sslEngine.closeOutbound();
try {
if (!flush().get(endpoint.getConnectionTimeout(), TimeUnit.MILLISECONDS).booleanValue()) {
throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"));
}
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"), e);
} catch (WritePendingException e) {
throw new IOException(sm.getString("channel.nio.ssl.pendingWriteDuringClose"), e);
}
//prep the buffer for the close message
netOutBuffer.clear();
//perform the close, since we called sslEngine.closeOutbound
SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer);
//we should be in a close state
if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) {
throw new IOException(sm.getString("channel.nio.ssl.invalidCloseState"));
}
//prepare the buffer for writing
netOutBuffer.flip();
//if there is data to be written
try {
if (!flush().get(endpoint.getConnectionTimeout(), TimeUnit.MILLISECONDS).booleanValue()) {
throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"));
}
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"), e);
} catch (WritePendingException e) {
throw new IOException(sm.getString("channel.nio.ssl.pendingWriteDuringClose"), e);
}
//is the channel closed?
closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP));
}
use of java.nio.channels.WritePendingException in project tomcat by apache.
the class WsSession method sendCloseMessage.
private void sendCloseMessage(CloseReason closeReason) {
// 125 is maximum size for the payload of a control message
ByteBuffer msg = ByteBuffer.allocate(125);
CloseCode closeCode = closeReason.getCloseCode();
// CLOSED_ABNORMALLY should not be put on the wire
if (closeCode == CloseCodes.CLOSED_ABNORMALLY) {
// PROTOCOL_ERROR is probably better than GOING_AWAY here
msg.putShort((short) CloseCodes.PROTOCOL_ERROR.getCode());
} else {
msg.putShort((short) closeCode.getCode());
}
String reason = closeReason.getReasonPhrase();
if (reason != null && reason.length() > 0) {
appendCloseReasonWithTruncation(msg, reason);
}
msg.flip();
try {
wsRemoteEndpoint.sendMessageBlock(Constants.OPCODE_CLOSE, msg, true);
} catch (IOException | WritePendingException e) {
// deal with the Exception
if (log.isDebugEnabled()) {
log.debug(sm.getString("wsSession.sendCloseFail", id), e);
}
wsRemoteEndpoint.close();
// error handling
if (closeCode != CloseCodes.CLOSED_ABNORMALLY) {
localEndpoint.onError(this, e);
}
} finally {
webSocketContainer.unregisterSession(localEndpoint, this);
}
}
use of java.nio.channels.WritePendingException in project jetty.project by eclipse.
the class GzipHttpOutputInterceptor method commit.
protected void commit(ByteBuffer content, boolean complete, Callback callback) {
// Are we excluding because of status?
Response response = _channel.getResponse();
int sc = response.getStatus();
if (sc > 0 && (sc < 200 || sc == 204 || sc == 205 || sc >= 300)) {
LOG.debug("{} exclude by status {}", this, sc);
noCompression();
if (sc == 304) {
String request_etags = (String) _channel.getRequest().getAttribute("o.e.j.s.h.gzip.GzipHandler.etag");
String response_etag = response.getHttpFields().get(HttpHeader.ETAG);
if (request_etags != null && response_etag != null) {
String response_etag_gzip = etagGzip(response_etag);
if (request_etags.contains(response_etag_gzip))
response.getHttpFields().put(HttpHeader.ETAG, response_etag_gzip);
}
}
_interceptor.write(content, complete, callback);
return;
}
// Are we excluding because of mime-type?
String ct = response.getContentType();
if (ct != null) {
ct = MimeTypes.getContentTypeWithoutCharset(ct);
if (!_factory.isMimeTypeGzipable(StringUtil.asciiToLowerCase(ct))) {
LOG.debug("{} exclude by mimeType {}", this, ct);
noCompression();
_interceptor.write(content, complete, callback);
return;
}
}
// Has the Content-Encoding header already been set?
HttpFields fields = response.getHttpFields();
String ce = fields.get(HttpHeader.CONTENT_ENCODING);
if (ce != null) {
LOG.debug("{} exclude by content-encoding {}", this, ce);
noCompression();
_interceptor.write(content, complete, callback);
return;
}
// Are we the thread that commits?
if (_state.compareAndSet(GZState.MIGHT_COMPRESS, GZState.COMMITTING)) {
// We are varying the response due to accept encoding header.
if (_vary != null) {
if (fields.contains(HttpHeader.VARY))
fields.addCSV(HttpHeader.VARY, _vary.getValues());
else
fields.add(_vary);
}
long content_length = response.getContentLength();
if (content_length < 0 && complete)
content_length = content.remaining();
_deflater = _factory.getDeflater(_channel.getRequest(), content_length);
if (_deflater == null) {
LOG.debug("{} exclude no deflater", this);
_state.set(GZState.NOT_COMPRESSING);
_interceptor.write(content, complete, callback);
return;
}
fields.put(GZIP._contentEncoding);
_crc.reset();
_buffer = _channel.getByteBufferPool().acquire(_bufferSize, false);
BufferUtil.fill(_buffer, GZIP_HEADER, 0, GZIP_HEADER.length);
// Adjust headers
response.setContentLength(-1);
String etag = fields.get(HttpHeader.ETAG);
if (etag != null)
fields.put(HttpHeader.ETAG, etagGzip(etag));
LOG.debug("{} compressing {}", this, _deflater);
_state.set(GZState.COMPRESSING);
gzip(content, complete, callback);
} else
callback.failed(new WritePendingException());
}
use of java.nio.channels.WritePendingException in project jetty.project by eclipse.
the class HttpOutput method write.
@Override
public void write(byte[] b, int off, int len) throws IOException {
// Async or Blocking ?
while (true) {
switch(_state.get()) {
case OPEN:
// process blocking below
break;
case ASYNC:
throw new IllegalStateException("isReady() not called");
case READY:
if (!_state.compareAndSet(OutputState.READY, OutputState.PENDING))
continue;
// Should we aggregate?
boolean last = isLastContentToWrite(len);
if (!last && len <= _commitSize) {
if (_aggregate == null)
_aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), _interceptor.isOptimizedForDirectBuffers());
// YES - fill the aggregate with content from the buffer
int filled = BufferUtil.fill(_aggregate, b, off, len);
// return if we are not complete, not full and filled all the content
if (filled == len && !BufferUtil.isFull(_aggregate)) {
if (!_state.compareAndSet(OutputState.PENDING, OutputState.ASYNC))
throw new IllegalStateException();
return;
}
// adjust offset/length
off += filled;
len -= filled;
}
// Do the asynchronous writing from the callback
new AsyncWrite(b, off, len, last).iterate();
return;
case PENDING:
case UNREADY:
throw new WritePendingException();
case ERROR:
throw new EofException(_onError);
case CLOSED:
throw new EofException("Closed");
default:
throw new IllegalStateException();
}
break;
}
// handle blocking write
// Should we aggregate?
int capacity = getBufferSize();
boolean last = isLastContentToWrite(len);
if (!last && len <= _commitSize) {
if (_aggregate == null)
_aggregate = _channel.getByteBufferPool().acquire(capacity, _interceptor.isOptimizedForDirectBuffers());
// YES - fill the aggregate with content from the buffer
int filled = BufferUtil.fill(_aggregate, b, off, len);
// return if we are not complete, not full and filled all the content
if (filled == len && !BufferUtil.isFull(_aggregate))
return;
// adjust offset/length
off += filled;
len -= filled;
}
// flush any content from the aggregate
if (BufferUtil.hasContent(_aggregate)) {
write(_aggregate, last && len == 0);
// should we fill aggregate again from the buffer?
if (len > 0 && !last && len <= _commitSize && len <= BufferUtil.space(_aggregate)) {
BufferUtil.append(_aggregate, b, off, len);
return;
}
}
// write any remaining content in the buffer directly
if (len > 0) {
// write a buffer capacity at a time to avoid JVM pooling large direct buffers
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6210541
ByteBuffer view = ByteBuffer.wrap(b, off, len);
while (len > getBufferSize()) {
int p = view.position();
int l = p + getBufferSize();
view.limit(p + getBufferSize());
write(view, false);
len -= getBufferSize();
view.limit(l + Math.min(len, getBufferSize()));
view.position(l);
}
write(view, last);
} else if (last) {
write(BufferUtil.EMPTY_BUFFER, true);
}
if (last)
closed();
}
Aggregations