{
buffer.flip(); // turn the writeable buffer into a "readable" one
final ByteBuffer writeableBuf=ByteBuffer.allocate(buffer.remaining());
writeableBuf.put(buffer);
writeableBuf.flip();
forwarder.writeBytesToChannel(new CWDataBuffers(writeableBuf,0,false));
buffer.clear();
}
break;
}
default:
{
buffer.flip(); // turn the writeable buffer into a "readable" one
int lastEOLIndex = 0; // the marker for the last place an EOLN was found
char c; // current character being examined
while(buffer.position() < buffer.limit())
{
c=(char)buffer.get();
switch(state)
{
case CHUNKED_ENDER_INLINE:
{
if(c=='\r')
state=ParseState.CHUNKED_ENDER_EOLN;
else
throw HTTPException.standardException(HTTPStatus.S400_BAD_REQUEST);
break;
}
case CHUNKED_ENDER_EOLN:
{
if(c=='\n')
{
lastEOLIndex=buffer.position();
state=ParseState.CHUNKED_HEADER_INLINE;
}
else
throw HTTPException.standardException(HTTPStatus.S400_BAD_REQUEST);
break;
}
case CHUNKED_HEADER_INLINE:
{
if(c=='\r')
state=ParseState.CHUNKED_HEADER_EOLN;
break;
}
case CHUNKED_HEADER_EOLN:
{
if (c=='\n')
{
final String chunkSizeStr = new String(Arrays.copyOfRange(buffer.array(), lastEOLIndex, buffer.position()-2),utf8).trim();
lastEOLIndex=buffer.position();
if (chunkSizeStr.length()>0)
{
final String[] parts=chunkSizeStr.split(";");
this.nextChunkSize = Integer.parseInt(parts[0],16);
if(this.nextChunkSize == 0) // we've reached the last chunk
{
buffer = currentReq.setToReceiveContentChunkedBody((int)config.getRequestLineBufBytes());
buffer.flip();
lastEOLIndex=0;
state=ParseState.CHUNKED_TRAILER_INLINE;
}
else
{
// check for illegal request
if((this.nextChunkSize + currentReq.getBufferSize()) > config.getRequestMaxBodyBytes())
{
throw HTTPException.standardException(HTTPStatus.S413_REQUEST_ENTITY_TOO_LARGE);
}
buffer = currentReq.setToReceiveContentChunkedBody(this.nextChunkSize);
buffer.flip();
lastEOLIndex=0;
state=ParseState.CHUNKED_BODY;
}
}
else
throw HTTPException.standardException(HTTPStatus.S400_BAD_REQUEST);
}
else
throw HTTPException.standardException(HTTPStatus.S400_BAD_REQUEST);
break;
}
case REQ_INLINE:
if(c=='\r')
state=ParseState.REQ_EOLN;
break;
case REQ_EOLN:
{
if (c=='\n')
{
final String requestLine = new String(Arrays.copyOfRange(buffer.array(), lastEOLIndex, buffer.position()-2),utf8);
lastEOLIndex=buffer.position();
state=ParseState.HDR_INLINE;
if (requestLine.length()>0)
{
try
{
currentReq.parseRequest(requestLine);
}
catch(final NumberFormatException ne)
{
throw HTTPException.standardException(HTTPStatus.S400_BAD_REQUEST);
}
}
else
{
// ignore blank lines here -- perhaps someone telnetted in.
}
}
else // an error! Ignore this line!
{
lastEOLIndex=buffer.position();
state=ParseState.REQ_INLINE;
}
break;
}
case HDR_INLINE:
if(c=='\r')
state=ParseState.HDR_EOLN;
break;
case CHUNKED_TRAILER_INLINE:
if(c=='\r')
state=ParseState.CHUNKED_TRAILER_EOLN;
break;
case CHUNKED_TRAILER_EOLN:
case HDR_EOLN:
{
if (c=='\n')
{
final String headerLine = new String(Arrays.copyOfRange(buffer.array(), lastEOLIndex, buffer.position()-2),utf8);
lastEOLIndex=buffer.position();
if(headerLine.length()>0)
{
String host = currentReq.parseHeaderLine(headerLine);
if (state == ParseState.CHUNKED_TRAILER_EOLN)
state=ParseState.CHUNKED_TRAILER_INLINE;
else
state=ParseState.HDR_INLINE;
if(host!=null)
{
final int x=host.indexOf(':');
if(x>0) host=host.substring(0, x); // we only care about the host, we KNOW the port.
final Pair<String,WebAddress> forward=config.getPortForward(host,currentReq.getClientPort(),currentReq.getUrlPath());
if((forward != null) && (state != ParseState.CHUNKED_TRAILER_INLINE))
{
final String requestLine=startPortForwarding(forward.second, forward.first);
if(forwarder!=null)
{
final DataBuffers out=new CWDataBuffers();
out.add(ByteBuffer.wrap(requestLine.getBytes()),0,false);
final ByteBuffer writeableBuf=ByteBuffer.allocate(buffer.remaining());
writeableBuf.put(buffer);
writeableBuf.flip();
out.add(writeableBuf,0,false);
forwarder.writeBytesToChannel(out);
buffer.clear();
state=ParseState.FORWARD;
}
}
outputThrottle = config.getResponseThrottle(host,currentReq.getClientPort(),currentReq.getUrlPath());
currentReq.getAllHeaderReferences(true);
}
}
else // a blank line means the end of the header section!!!
{
if(state == ParseState.CHUNKED_TRAILER_EOLN)
{
currentReq.finishRequest();
state=ParseState.DONE;
}
else
if("chunked".equalsIgnoreCase(currentReq.getHeader(HTTPHeader.TRANSFER_ENCODING.lowerCaseName())))
{
state=ParseState.CHUNKED_HEADER_INLINE;
buffer = currentReq.setToReceiveContentChunkedBody(0); // prepare for chunk length/headers
buffer.flip();
lastEOLIndex=0;
}
else
{
//the headers will tell you what to do next "BODY" is too vague
final String contentLengthStr=currentReq.getHeader(HTTPHeader.CONTENT_LENGTH.lowerCaseName());
if(contentLengthStr!=null)
{
try
{
// moment of truth, do we have a body forthcoming?
final int contentLength = Integer.parseInt(contentLengthStr);
if ((contentLength < 0) || (contentLength > config.getRequestMaxBodyBytes())) // illegal request
{
throw HTTPException.standardException(HTTPStatus.S413_REQUEST_ENTITY_TOO_LARGE);
}
else
if(contentLength == 0) // no content means we are done .. finish the request
{
currentReq.setToReceiveContentBody(contentLength);
currentReq.finishRequest();
state=ParseState.DONE;
}
else // a positive content length means we should prepare to receive the body
{
currentReq.setToReceiveContentBody(contentLength);
state=ParseState.BODY;
// the line buffer might have contained the entire body, so check for that state and finish
// if necessary
if(currentReq.getBuffer().position() >= currentReq.getBuffer().capacity())
{
currentReq.finishRequest();
state=ParseState.DONE;
}
}
}
catch(final NumberFormatException ne)
{
throw HTTPException.standardException(HTTPStatus.S411_LENGTH_REQUIRED);
}
}
else
{
// we have an http exception for this, but why be a jerk
currentReq.finishRequest();
state=ParseState.DONE;
}
}
}
// continue
if((state != ParseState.DONE)
&&(currentReq.isExpect("100-continue")))
{
if(currentReq.getHttpVer()>1.0)
writeBytesToChannel(new CWDataBuffers(ByteBuffer.wrap(HTTPIOHandler.CONT_RESPONSE),0,false));
}
}
else // an error! Ignore this line!
{
lastEOLIndex=buffer.position();