* @throws ParseException
*/
public ConnectionHeader handshake( final ConnectionHeader header, SocketChannel channel, byte[] prereadHead,
long timeout ) throws IOException, ParseException
{
ConnectionHeader receiverHeader;
String host = null;
ByteBuffer magicBuf = null;
ByteBuffer hBuffer = null;
// shall we act as clientside and initialize the handshake?
if ( header.isClient() )
{
// create a new HTTP HEAD operation and send our client header and the requested adapter (if any)
hBuffer = new HttpRequest( header, HttpRequest.HTTP_HEAD ).toByteBuffer();
semiBlockingWrite( channel, hBuffer, timeout );
// something strange happened - at least the handshake data must be written in one operation
if ( hBuffer.hasRemaining() ) return null;
}
// read and parse the HTTP header - this can also preread one or more bytes of none-header-data (content)
HttpHeaderParser parser = readHttpHeader( channel, prereadHead, timeout, header.isClient() );
// little bit paranoia
if ( parser == null )
{
return null;
}
// get the read ByteBuffer
magicBuf = parser.getByteHeader();
if ( header.isClient() )
{
// did the HTTP parser already read the content? if so the ByteBuffer has already the required size.
if ( magicBuf == null )
{
// allocate an appropiate ByteBuffer
magicBuf = ByteBufferAllocator.allocate( parser.getContentLength() );
}
// did the HTTP parser already read the complete content (the eight bits of the header byte)?
if ( magicBuf.position() < (parser.getContentLength() - 1) )
{
// read the data part
semiBlockingRead( channel, magicBuf, timeout );
if ( magicBuf.hasRemaining() ) return null;
}
magicBuf.flip();
if ( logger.isLoggable( Level.FINEST ) )
{
logger.log( Level.FINEST, "HTTP-Header read: "
+ IOUtil.bBitsToSBits( IOUtil.byteToBBits( magicBuf.get() ) ) );
magicBuf.rewind();
}
receiverHeader = new ConnectionHeader( channel, host, header.isClient(), magicBuf.get() );
}
// shall we act as server side and answer to the handshake request?
else
{
receiverHeader = new ConnectionHeader( channel, host, header.isClient() );
// the HTTP header must contain the eight header bits in the requested URI
receiverHeader.fromString( ((HttpRequestParser) parser).getUri() );
// does the http header overwrite the compression setting?
receiverHeader.setCompression( header.hasCompression() && parser.hasCompression() );
// does the http header overwrite the setting for using a persistent connection?
receiverHeader.setPersistent( parser.isPersistentConnection() && header.isPersistent() );
// answer to the client request and send our serverside headerbyte
// clients as browsers (IE, Firefox, Opera) or similiar doesn't understand our handshake
// hence we send our handshake response only when the client tells us that it is able
// to parse our response
if ( receiverHeader.isHandshakeResponseAware() )
{
// create a HTTP response with just our server header byte as content
HttpResponse response = new HttpResponse( header, HttpResponse.HTTP_OK );
response.addData( header.toByte() );
logger.log( Level.FINEST, "Sending server headerbyte: " + header );
hBuffer = response.toByteBuffer();
semiBlockingWrite( channel, hBuffer, timeout );
if ( hBuffer.hasRemaining() ) return null;
}
// ok, a unknown client which might have already send some content with it's first request
else if ( parser.hasPrereadContent() )
{
receiverHeader.setWaitingBuffer( parser.getByteHeader() );
}
}
receiverHeader.setHttp( true );
receiverHeader.setConnected( true );
return receiverHeader;
}