/**
* Copyright (C) Zhang,Yuexiang (xfeep)
*
*For reuse some classes from tomcat8 we have to use this package
*/
package org.apache.coyote.http11;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import nginx.clojure.MiniConstants;
import nginx.clojure.NginxClojureRT;
import nginx.clojure.NginxHttpServerChannel;
import nginx.clojure.java.Constants;
import nginx.clojure.java.NginxJavaRequest;
import org.apache.coyote.InputBuffer;
import org.apache.coyote.Request;
import org.apache.coyote.http11.AbstractNioInputBuffer;
import org.apache.coyote.http11.InternalNioInputBuffer.SocketInputBuffer;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.net.SocketWrapper;
public class InternalNginxInputBuffer extends AbstractNioInputBuffer<NginxChannel> {
private static final Log log =
LogFactory.getLog(InternalNginxInputBuffer.class);
protected InputStream body;
protected NginxChannel socket;
public InternalNginxInputBuffer(Request request, int headerBufferSize) {
super(request, headerBufferSize);
inputStreamInputBuffer = new SocketInputBuffer();
}
@Override
protected boolean fill(boolean block) throws IOException {
if (!parsingHeader) {
lastValid = pos = end;
}
int nRead = 0;
ByteBuffer readBuffer = socket.getBufHandler().getReadBuffer();
readBuffer.clear();
nRead = body == null ? -1 : body.read(readBuffer.array(), 0, readBuffer.limit());
if (nRead > 0) {
readBuffer.flip();
readBuffer.limit(nRead);
expand(nRead + pos);
readBuffer.get(buf, pos, nRead);
lastValid = pos + nRead;
} else if (nRead == -1) {
//return false;
throw new EOFException(sm.getString("iib.eof.error"));
}
return nRead > 0;
}
@Override
public boolean isFinished() {
if (lastValid > pos) {
// Data to read in the buffer so not finished
return false;
}
try {
return body == null || body.available() == 0;
} catch (IOException e) {
return true;
}
}
protected void init(NginxChannel sc) throws IOException {
this.socket = sc;
NginxJavaRequest jreq = (NginxJavaRequest) sc.getIOChannel().request();
//fill header buffer
if (buf == null) {
buf = new byte[headerBufferSize*2];
}
body = (InputStream) jreq.get(Constants.BODY);
lastValid = (int)NginxClojureRT.ngx_http_clojure_mem_copy_header_buf(jreq.nativeRequest(), buf, MiniConstants.BYTE_ARRAY_OFFSET, headerBufferSize);
}
@Override
protected void init(
SocketWrapper<NginxChannel> socketWrapper,
AbstractEndpoint<NginxChannel> endpoint)
throws IOException {
init(socketWrapper.getSocket());
}
@Override
protected Log getLog() {
return log;
}
public int doRead(ByteChunk chunk, Request request) throws IOException {
if (body == null) {
return -1;
}
lastValid = pos = end;
int len = body.read(buf, lastValid, buf.length - lastValid);
if (len == 0) {
return -1;
}
chunk.setBytes(buf, lastValid, len);
return len;
}
@Override
public void recycle() {
super.recycle();
body = null;
}
protected class SocketInputBuffer
implements InputBuffer {
/**
* Read bytes into the specified chunk.
*/
@Override
public int doRead(ByteChunk chunk, Request req )
throws IOException {
if (pos >= lastValid) {
if (!fill(true)) //read body, must be blocking, as the thread is inside the app
return -1;
}
int length = lastValid - pos;
chunk.setBytes(buf, pos, length);
pos = lastValid;
return (length);
}
}
}