blob: 5ad99f609737f3608dff8f6bc2ae5b649913d6eb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.coyote.http11.upgrade;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Selector;
import org.apache.tomcat.util.net.NioChannel;
import org.apache.tomcat.util.net.NioEndpoint;
import org.apache.tomcat.util.net.NioSelectorPool;
import org.apache.tomcat.util.net.SocketWrapper;
public class NioServletInputStream extends AbstractServletInputStream {
private final NioChannel channel;
private final NioSelectorPool pool;
public NioServletInputStream(SocketWrapper<NioChannel> wrapper,
NioSelectorPool pool) {
this.channel = wrapper.getSocket();
this.pool = pool;
}
@Override
protected boolean doIsReady() throws IOException {
ByteBuffer readBuffer = channel.getBufHandler().getReadBuffer();
if (readBuffer.remaining() > 0) {
return true;
}
readBuffer.clear();
fillReadBuffer(false);
boolean isReady = readBuffer.position() > 0;
readBuffer.flip();
return isReady;
}
@Override
protected int doRead(boolean block, byte[] b, int off, int len)
throws IOException {
ByteBuffer readBuffer = channel.getBufHandler().getReadBuffer();
int remaining = readBuffer.remaining();
// Is there enough data in the read buffer to satisfy this request?
if (remaining >= len) {
readBuffer.get(b, off, len);
return len;
}
// Copy what data there is in the read buffer to the byte array
int leftToWrite = len;
int newOffset = off;
if (remaining > 0) {
readBuffer.get(b, off, remaining);
leftToWrite -= remaining;
newOffset += remaining;
}
// Fill the read buffer as best we can
readBuffer.clear();
int nRead = fillReadBuffer(block);
// Full as much of the remaining byte array as possible with the data
// that was just read
if (nRead > 0) {
readBuffer.flip();
if (nRead > leftToWrite) {
readBuffer.get(b, newOffset, leftToWrite);
leftToWrite = 0;
} else {
readBuffer.get(b, newOffset, nRead);
leftToWrite -= nRead;
}
} else if (nRead == 0) {
readBuffer.flip();
} else if (nRead == -1) {
// TODO i18n
throw new EOFException();
}
return len - leftToWrite;
}
@Override
protected void doClose() throws IOException {
channel.close();
}
private int fillReadBuffer(boolean block) throws IOException {
int nRead;
if (block) {
Selector selector = null;
try {
selector = pool.get();
} catch ( IOException x ) {
// Ignore
}
try {
NioEndpoint.KeyAttachment att =
(NioEndpoint.KeyAttachment) channel.getAttachment();
if (att == null) {
throw new IOException("Key must be cancelled.");
}
nRead = pool.read(channel.getBufHandler().getReadBuffer(),
channel, selector, att.getTimeout());
} catch (EOFException eof) {
nRead = -1;
} finally {
if (selector != null) {
pool.put(selector);
}
}
} else {
nRead = channel.read(channel.getBufHandler().getReadBuffer());
}
return nRead;
}
}