use of org.xnio.conduits.ConduitStreamSinkChannel in project undertow by undertow-io.
the class ContentEncodedResourceManager method getResource.
/**
* Gets a pre-encoded resource.
* <p>
* TODO: blocking / non-blocking semantics
*
* @param resource
* @param exchange
* @return
* @throws IOException
*/
public ContentEncodedResource getResource(final Resource resource, final HttpServerExchange exchange) throws IOException {
final String path = resource.getPath();
Path file = resource.getFilePath();
if (file == null) {
return null;
}
if (minResourceSize > 0 && resource.getContentLength() < minResourceSize || maxResourceSize > 0 && resource.getContentLength() > maxResourceSize || !(encodingAllowed == null || encodingAllowed.resolve(exchange))) {
return null;
}
AllowedContentEncodings encodings = contentEncodingRepository.getContentEncodings(exchange);
if (encodings == null || encodings.isNoEncodingsAllowed()) {
return null;
}
EncodingMapping encoding = encodings.getEncoding();
if (encoding == null || encoding.getName().equals(ContentEncodingRepository.IDENTITY)) {
return null;
}
String newPath = path + ".undertow.encoding." + encoding.getName();
Resource preCompressed = encoded.getResource(newPath);
if (preCompressed != null) {
return new ContentEncodedResource(preCompressed, encoding.getName());
}
final LockKey key = new LockKey(path, encoding.getName());
if (fileLocks.putIfAbsent(key, this) != null) {
//we don't do anything fancy here, just return and serve non-compressed content
return null;
}
FileChannel targetFileChannel = null;
FileChannel sourceFileChannel = null;
try {
//double check, the compressing thread could have finished just before we acquired the lock
preCompressed = encoded.getResource(newPath);
if (preCompressed != null) {
return new ContentEncodedResource(preCompressed, encoding.getName());
}
final Path finalTarget = encodedResourcesRoot.resolve(newPath);
final Path tempTarget = encodedResourcesRoot.resolve(newPath);
//horrible hack to work around XNIO issue
OutputStream tmp = Files.newOutputStream(tempTarget);
try {
tmp.close();
} finally {
IoUtils.safeClose(tmp);
}
targetFileChannel = FileChannel.open(tempTarget, StandardOpenOption.READ, StandardOpenOption.WRITE);
sourceFileChannel = FileChannel.open(file, StandardOpenOption.READ);
StreamSinkConduit conduit = encoding.getEncoding().getResponseWrapper().wrap(new ImmediateConduitFactory<StreamSinkConduit>(new FileConduitTarget(targetFileChannel, exchange)), exchange);
final ConduitStreamSinkChannel targetChannel = new ConduitStreamSinkChannel(null, conduit);
long transferred = sourceFileChannel.transferTo(0, resource.getContentLength(), targetChannel);
targetChannel.shutdownWrites();
org.xnio.channels.Channels.flushBlocking(targetChannel);
if (transferred != resource.getContentLength()) {
UndertowLogger.REQUEST_LOGGER.failedToWritePreCachedFile();
}
Files.move(tempTarget, finalTarget);
encoded.invalidate(newPath);
final Resource encodedResource = encoded.getResource(newPath);
return new ContentEncodedResource(encodedResource, encoding.getName());
} finally {
IoUtils.safeClose(targetFileChannel);
IoUtils.safeClose(sourceFileChannel);
fileLocks.remove(key);
}
}
use of org.xnio.conduits.ConduitStreamSinkChannel in project undertow by undertow-io.
the class HttpClientConnection method initiateRequest.
private void initiateRequest(HttpClientExchange httpClientExchange) {
this.requestCount++;
currentRequest = httpClientExchange;
pendingResponse = new HttpResponseBuilder();
ClientRequest request = httpClientExchange.getRequest();
String connectionString = request.getRequestHeaders().getFirst(CONNECTION);
if (connectionString != null) {
HttpString connectionHttpString = new HttpString(connectionString);
if (connectionHttpString.equals(CLOSE)) {
state |= CLOSE_REQ;
} else if (connectionHttpString.equals(UPGRADE)) {
state |= UPGRADE_REQUESTED;
}
} else if (request.getProtocol() != Protocols.HTTP_1_1) {
state |= CLOSE_REQ;
}
if (request.getRequestHeaders().contains(UPGRADE)) {
state |= UPGRADE_REQUESTED;
}
if (request.getMethod().equals(Methods.CONNECT)) {
//we treat CONNECT like upgrade requests
state |= UPGRADE_REQUESTED;
}
//setup the client request conduits
final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel();
sourceChannel.setReadListener(clientReadListener);
sourceChannel.resumeReads();
ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel();
StreamSinkConduit conduit = originalSinkConduit;
conduit = new HttpRequestConduit(conduit, bufferPool, request);
String fixedLengthString = request.getRequestHeaders().getFirst(CONTENT_LENGTH);
String transferEncodingString = request.getRequestHeaders().getLast(TRANSFER_ENCODING);
boolean hasContent = true;
if (fixedLengthString != null) {
try {
long length = Long.parseLong(fixedLengthString);
conduit = new ClientFixedLengthStreamSinkConduit(conduit, length, false, false, currentRequest);
hasContent = length != 0;
} catch (NumberFormatException e) {
handleError(new IOException(e));
return;
}
} else if (transferEncodingString != null) {
if (!transferEncodingString.toLowerCase(Locale.ENGLISH).contains(Headers.CHUNKED.toString())) {
handleError(UndertowClientMessages.MESSAGES.unknownTransferEncoding(transferEncodingString));
return;
}
conduit = new ChunkedStreamSinkConduit(conduit, httpClientExchange.getConnection().getBufferPool(), false, false, httpClientExchange.getRequest().getRequestHeaders(), requestFinishListener, httpClientExchange);
} else {
conduit = new ClientFixedLengthStreamSinkConduit(conduit, 0, false, false, currentRequest);
hasContent = false;
}
sinkChannel.setConduit(conduit);
httpClientExchange.invokeReadReadyCallback();
if (!hasContent) {
//otherwise it is up to the user
try {
sinkChannel.shutdownWrites();
if (!sinkChannel.flush()) {
sinkChannel.setWriteListener(ChannelListeners.flushingChannelListener(null, new ChannelExceptionHandler<ConduitStreamSinkChannel>() {
@Override
public void handleException(ConduitStreamSinkChannel channel, IOException exception) {
handleError(exception);
}
}));
sinkChannel.resumeWrites();
}
} catch (IOException e) {
handleError(e);
}
}
}
use of org.xnio.conduits.ConduitStreamSinkChannel in project undertow by undertow-io.
the class Http2PriorKnowledgeClientProvider method handleConnected.
private void handleConnected(final StreamConnection connection, final ClientCallback<ClientConnection> listener, final ByteBufferPool bufferPool, final OptionMap options, final String defaultHost) {
try {
final ClientStatisticsImpl clientStatistics;
//first we set up statistics, if required
if (options.get(UndertowOptions.ENABLE_STATISTICS, false)) {
clientStatistics = new ClientStatisticsImpl();
connection.getSinkChannel().setConduit(new BytesSentStreamSinkConduit(connection.getSinkChannel().getConduit(), new ByteActivityCallback() {
@Override
public void activity(long bytes) {
clientStatistics.written += bytes;
}
}));
connection.getSourceChannel().setConduit(new BytesReceivedStreamSourceConduit(connection.getSourceChannel().getConduit(), new ByteActivityCallback() {
@Override
public void activity(long bytes) {
clientStatistics.read += bytes;
}
}));
} else {
clientStatistics = null;
}
final ByteBuffer pri = ByteBuffer.wrap(PRI_REQUEST);
pri.flip();
ConduitStreamSinkChannel sink = connection.getSinkChannel();
sink.write(pri);
if (pri.hasRemaining()) {
sink.setWriteListener(new ChannelListener<ConduitStreamSinkChannel>() {
@Override
public void handleEvent(ConduitStreamSinkChannel channel) {
try {
channel.write(pri);
if (pri.hasRemaining()) {
return;
}
listener.completed(new Http2ClientConnection(new Http2Channel(connection, null, bufferPool, null, true, false, options), false, defaultHost, clientStatistics, false));
} catch (IOException e) {
listener.failed(e);
}
}
});
return;
}
listener.completed(new Http2ClientConnection(new Http2Channel(connection, null, bufferPool, null, true, false, options), false, defaultHost, clientStatistics, false));
} catch (IOException e) {
listener.failed(e);
}
}
use of org.xnio.conduits.ConduitStreamSinkChannel in project undertow by undertow-io.
the class HttpReadListener method exchangeComplete.
public void exchangeComplete(final HttpServerExchange exchange) {
connection.clearChannel();
final HttpServerConnection connection = this.connection;
if (exchange.isPersistent() && !isUpgradeOrConnect(exchange)) {
final StreamConnection channel = connection.getChannel();
if (connection.getExtraBytes() == null) {
//we have to resume from with the io thread
if (exchange.isInIoThread()) {
//no need for CAS, we are in the IO thread
newRequest();
channel.getSourceChannel().setReadListener(HttpReadListener.this);
channel.getSourceChannel().resumeReads();
requestStateUpdater.set(this, 0);
} else {
while (true) {
if (connection.getOriginalSourceConduit().isReadShutdown() || connection.getOriginalSinkConduit().isWriteShutdown()) {
channel.getSourceChannel().suspendReads();
channel.getSinkChannel().suspendWrites();
IoUtils.safeClose(connection);
return;
} else {
if (requestStateUpdater.compareAndSet(this, 1, 2)) {
try {
newRequest();
channel.getSourceChannel().setReadListener(HttpReadListener.this);
channel.getSourceChannel().resumeReads();
} finally {
requestStateUpdater.set(this, 0);
}
break;
}
}
}
}
} else {
if (exchange.isInIoThread()) {
//no need to CAS, as we don't actually resume
requestStateUpdater.set(this, 0);
newRequest();
//no need to suspend reads here, the task will always run before the read listener anyway
channel.getIoThread().execute(this);
} else {
while (true) {
if (connection.getOriginalSinkConduit().isWriteShutdown()) {
channel.getSourceChannel().suspendReads();
channel.getSinkChannel().suspendWrites();
IoUtils.safeClose(connection);
return;
} else if (requestStateUpdater.compareAndSet(this, 1, 2)) {
try {
newRequest();
channel.getSourceChannel().suspendReads();
} finally {
requestStateUpdater.set(this, 0);
}
break;
}
}
Executor executor = exchange.getDispatchExecutor();
if (executor == null) {
executor = exchange.getConnection().getWorker();
}
executor.execute(this);
}
}
} else if (!exchange.isPersistent()) {
ConnectionUtils.cleanClose(connection.getChannel(), connection);
} else {
//upgrade or connect handling
if (connection.getExtraBytes() != null) {
connection.getChannel().getSourceChannel().setConduit(new ReadDataStreamSourceConduit(connection.getChannel().getSourceChannel().getConduit(), connection));
}
try {
if (!connection.getChannel().getSinkChannel().flush()) {
connection.getChannel().getSinkChannel().setWriteListener(ChannelListeners.flushingChannelListener(new ChannelListener<ConduitStreamSinkChannel>() {
@Override
public void handleEvent(ConduitStreamSinkChannel conduitStreamSinkChannel) {
connection.getUpgradeListener().handleUpgrade(connection.getChannel(), exchange);
}
}, new ClosingChannelExceptionHandler<ConduitStreamSinkChannel>(connection)));
connection.getChannel().getSinkChannel().resumeWrites();
return;
}
connection.getUpgradeListener().handleUpgrade(connection.getChannel(), exchange);
} catch (IOException e) {
UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
IoUtils.safeClose(connection);
}
}
}
use of org.xnio.conduits.ConduitStreamSinkChannel in project undertow by undertow-io.
the class AjpReadListener method handleCPing.
private void handleCPing() {
state = new AjpRequestParseState();
final StreamConnection underlyingChannel = connection.getChannel();
underlyingChannel.getSourceChannel().suspendReads();
final ByteBuffer buffer = ByteBuffer.wrap(CPONG);
int res;
try {
do {
res = underlyingChannel.getSinkChannel().write(buffer);
if (res == 0) {
underlyingChannel.getSinkChannel().setWriteListener(new ChannelListener<ConduitStreamSinkChannel>() {
@Override
public void handleEvent(ConduitStreamSinkChannel channel) {
int res;
do {
try {
res = channel.write(buffer);
if (res == 0) {
return;
}
} catch (IOException e) {
UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
safeClose(connection);
}
} while (buffer.hasRemaining());
channel.suspendWrites();
AjpReadListener.this.handleEvent(underlyingChannel.getSourceChannel());
}
});
underlyingChannel.getSinkChannel().resumeWrites();
return;
}
} while (buffer.hasRemaining());
AjpReadListener.this.handleEvent(underlyingChannel.getSourceChannel());
} catch (IOException e) {
UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
safeClose(connection);
}
}
Aggregations