jetty-9 work in progress jetty-server

This commit is contained in:
Greg Wilkins 2012-03-08 21:37:03 +11:00
parent 872282c34c
commit e757e5e54d
7 changed files with 57 additions and 517 deletions

View File

@ -1086,7 +1086,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
HttpHeader header = HttpHeader.CACHE.get(_name);
if (header!=null)
{
buffer.put(header.toBytesColonSpace());
buffer.put(header.getBytesColonSpace());
if (HttpHeaderValue.hasKnownValues(header))
{

View File

@ -74,9 +74,9 @@ public class HttpGenerator
// states
enum Action { FLUSH, COMPLETE, PREPARE };
enum State { START, COMMITTING, COMMITTING_COMPLETING, COMMITTED, COMPLETING, END };
enum Result { NEED_CHUNK,NEED_HEADER,NEED_BUFFER,FLUSH,FLUSH_CONTENT,OK,SHUTDOWN_OUT};
public enum Action { FLUSH, COMPLETE, PREPARE };
public enum State { START, COMMITTING, COMMITTING_COMPLETING, COMMITTED, COMPLETING, END };
public enum Result { NEED_CHUNK,NEED_HEADER,NEED_BUFFER,FLUSH,FLUSH_CONTENT,OK,SHUTDOWN_OUT};
public static final byte[] NO_BYTES = {};
@ -308,7 +308,7 @@ public class HttpGenerator
{
if (_state != State.START)
throw new IllegalStateException("STATE!=START "+_state);
_method=method.toBytes();
_method=method.getBytes();
_uri=StringUtil.getUtf8Bytes(uri);
setVersion(version);
}
@ -705,7 +705,7 @@ public class HttpGenerator
// Add Date header
if (_status>=200 && _date!=null)
{
header.put(HttpHeader.DATE.toBytesColonSpace());
header.put(HttpHeader.DATE.getBytesColonSpace());
header.put(_date);
header.put(CRLF);
}
@ -744,7 +744,7 @@ public class HttpGenerator
else
{
// write the field to the header
header.put(HttpHeader.CONTENT_LENGTH.toBytesColonSpace());
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
BufferUtil.putDecLong(header,length);
BufferUtil.putCRLF(header);
_contentLength=length;
@ -802,7 +802,7 @@ public class HttpGenerator
case UPGRADE:
{
// special case for websocket connection ordering
header.put(HttpHeader.CONNECTION.toBytesColonSpace()).put(HttpHeader.UPGRADE.toBytes());
header.put(HttpHeader.CONNECTION.getBytesColonSpace()).put(HttpHeader.UPGRADE.getBytes());
break;
}
@ -858,7 +858,7 @@ public class HttpGenerator
field.putTo(header);
else
{
header.put(name.toBytesColonSpace());
header.put(name.getBytesColonSpace());
field.putValueTo(header);
header.put(CRLF);
}
@ -893,7 +893,7 @@ public class HttpGenerator
if (!content_length && (isResponse() || _contentLength>0 || content_type ) && !_noContent)
{
// known length but not actually set.
header.put(HttpHeader.CONTENT_LENGTH.toBytesColonSpace());
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
BufferUtil.putDecLong(header, _contentLength);
header.put(HttpTokens.CRLF);
}

View File

@ -136,13 +136,13 @@ public enum HttpHeader
}
/* ------------------------------------------------------------ */
public byte[] toBytes()
public byte[] getBytes()
{
return _bytes;
}
/* ------------------------------------------------------------ */
public byte[] toBytesColonSpace()
public byte[] getBytesColonSpace()
{
return _bytesColonSpace;
}
@ -154,13 +154,5 @@ public enum HttpHeader
return _string;
}
public static void main (String[] args)
{
for (HttpHeader h : HttpHeader.values())
{
System.err.println("\n\n"+h);
CACHE.get(h.toString());
}
}
}

View File

@ -54,7 +54,7 @@ public enum HttpMethod
}
/* ------------------------------------------------------------ */
public byte[] toBytes()
public byte[] getBytes()
{
return _bytes;
}

View File

@ -1,132 +0,0 @@
// ========================================================================
// Copyright (c) 2006-2011 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server;
import java.io.IOException;
import org.eclipse.jetty.http.Generator;
import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.Parser;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------ */
/** Blocking Server HTTP Connection
*/
public class BlockingHttpConnection extends AbstractHttpConnection
{
private static final Logger LOG = Log.getLogger(BlockingHttpConnection.class);
public BlockingHttpConnection(Connector connector, EndPoint endpoint, Server server)
{
super(connector,endpoint,server);
}
public BlockingHttpConnection(Connector connector, EndPoint endpoint, Server server, Parser parser, Generator generator, Request request)
{
super(connector,endpoint,server,parser,generator,request);
}
@Override
protected void handleRequest() throws IOException
{
super.handleRequest();
}
public Connection handle() throws IOException
{
Connection connection = this;
try
{
setCurrentConnection(this);
// do while the endpoint is open
// AND the connection has not changed
while (_endp.isOpen() && connection==this)
{
try
{
// If we are not ended then parse available
if (!_parser.isComplete() && !_endp.isInputShutdown())
_parser.parseAvailable();
// Do we have more generating to do?
// Loop here because some writes may take multiple steps and
// we need to flush them all before potentially blocking in the
// next loop.
if (_generator.isCommitted() && !_generator.isComplete() && !_endp.isOutputShutdown())
_generator.flushBuffer();
// Flush buffers
_endp.flush();
}
catch (HttpException e)
{
if (LOG.isDebugEnabled())
{
LOG.debug("uri="+_uri);
LOG.debug("fields="+_requestFields);
LOG.debug(e);
}
_generator.sendError(e.getStatus(), e.getReason(), null, true);
_parser.reset();
_endp.shutdownOutput();
}
finally
{
// Is this request/response round complete and are fully flushed?
if (_parser.isComplete() && _generator.isComplete())
{
// Reset the parser/generator
reset();
// look for a switched connection instance?
if (_response.getStatus()==HttpStatus.SWITCHING_PROTOCOLS_101)
{
Connection switched=(Connection)_request.getAttribute("org.eclipse.jetty.io.Connection");
if (switched!=null)
connection=switched;
}
// TODO Is this required?
if (!_generator.isPersistent() && !_endp.isOutputShutdown())
{
LOG.warn("Safety net oshut!!! Please open a bugzilla");
_endp.shutdownOutput();
}
}
// If we don't have a committed response and we are not suspended
if (_endp.isInputShutdown() && _generator.isIdle() && !_request.getAsyncContinuation().isSuspended())
{
// then no more can happen, so close.
_endp.close();
}
}
}
return connection;
}
finally
{
setCurrentConnection(null);
_parser.returnBuffers();
_generator.returnBuffers();
}
}
}

View File

@ -1,361 +0,0 @@
// ========================================================================
// Copyright (c) 2003-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.ByteChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;
import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.io.ConnectedEndPoint;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.nio.ChannelEndPoint;
import org.eclipse.jetty.server.BlockingHttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------------------------- */
/** Blocking NIO connector.
* This connector uses efficient NIO buffers with a traditional blocking thread model.
* Direct NIO buffers are used and a thread is allocated per connections.
*
* This connector is best used when there are a few very active connections.
*
* @org.apache.xbean.XBean element="blockingNioConnector" description="Creates a blocking NIO based socket connector"
*
*
*
*/
public class BlockingChannelConnector extends AbstractNIOConnector
{
private static final Logger LOG = Log.getLogger(BlockingChannelConnector.class);
private transient ServerSocketChannel _acceptChannel;
private final Set<BlockingChannelEndPoint> _endpoints = new ConcurrentHashSet<BlockingChannelEndPoint>();
/* ------------------------------------------------------------ */
/** Constructor.
*
*/
public BlockingChannelConnector()
{
}
/* ------------------------------------------------------------ */
public Object getConnection()
{
return _acceptChannel;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.AbstractConnector#doStart()
*/
@Override
protected void doStart() throws Exception
{
super.doStart();
getThreadPool().dispatch(new Runnable()
{
public void run()
{
while (isRunning())
{
try
{
Thread.sleep(400);
long now=System.currentTimeMillis();
for (BlockingChannelEndPoint endp : _endpoints)
{
endp.checkIdleTimestamp(now);
}
}
catch(InterruptedException e)
{
LOG.ignore(e);
}
catch(Exception e)
{
LOG.warn(e);
}
}
}
});
}
/* ------------------------------------------------------------ */
public void open() throws IOException
{
// Create a new server socket and set to non blocking mode
_acceptChannel= ServerSocketChannel.open();
_acceptChannel.configureBlocking(true);
// Bind the server socket to the local host and port
InetSocketAddress addr = getHost()==null?new InetSocketAddress(getPort()):new InetSocketAddress(getHost(),getPort());
_acceptChannel.socket().bind(addr,getAcceptQueueSize());
}
/* ------------------------------------------------------------ */
public void close() throws IOException
{
if (_acceptChannel != null)
_acceptChannel.close();
_acceptChannel=null;
}
/* ------------------------------------------------------------ */
@Override
public void accept(int acceptorID)
throws IOException, InterruptedException
{
SocketChannel channel = _acceptChannel.accept();
channel.configureBlocking(true);
Socket socket=channel.socket();
configure(socket);
BlockingChannelEndPoint connection=new BlockingChannelEndPoint(channel);
connection.dispatch();
}
/* ------------------------------------------------------------------------------- */
@Override
public void customize(EndPoint endpoint, Request request)
throws IOException
{
super.customize(endpoint, request);
endpoint.setMaxIdleTime(_maxIdleTime);
configure(((SocketChannel)endpoint.getTransport()).socket());
}
/* ------------------------------------------------------------------------------- */
public int getLocalPort()
{
if (_acceptChannel==null || !_acceptChannel.isOpen())
return -1;
return _acceptChannel.socket().getLocalPort();
}
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
private class BlockingChannelEndPoint extends ChannelEndPoint implements Runnable, ConnectedEndPoint
{
private Connection _connection;
private int _timeout;
private volatile long _idleTimestamp;
BlockingChannelEndPoint(ByteChannel channel)
throws IOException
{
super(channel,BlockingChannelConnector.this._maxIdleTime);
_connection = new BlockingHttpConnection(BlockingChannelConnector.this,this,getServer());
}
/* ------------------------------------------------------------ */
/** Get the connection.
* @return the connection
*/
public Connection getConnection()
{
return _connection;
}
/* ------------------------------------------------------------ */
public void setConnection(Connection connection)
{
_connection=connection;
}
/* ------------------------------------------------------------ */
public void checkIdleTimestamp(long now)
{
if (_idleTimestamp!=0 && _timeout>0 && now>(_idleTimestamp+_timeout))
{
idleExpired();
}
}
/* ------------------------------------------------------------ */
protected void idleExpired()
{
try
{
super.close();
}
catch (IOException e)
{
LOG.ignore(e);
}
}
/* ------------------------------------------------------------ */
void dispatch() throws IOException
{
if (!getThreadPool().dispatch(this))
{
LOG.warn("dispatch failed for {}",_connection);
super.close();
}
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.io.nio.ChannelEndPoint#fill(org.eclipse.jetty.io.ByteBuffer)
*/
@Override
public int fill(ByteBuffer buffer) throws IOException
{
_idleTimestamp=System.currentTimeMillis();
return super.fill(buffer);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.io.nio.ChannelEndPoint#flush(org.eclipse.jetty.io.ByteBuffer)
*/
@Override
public int flush(ByteBuffer buffer) throws IOException
{
_idleTimestamp=System.currentTimeMillis();
return super.flush(buffer);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.io.nio.ChannelEndPoint#flush(org.eclipse.jetty.io.ByteBuffer, org.eclipse.jetty.io.ByteBuffer, org.eclipse.jetty.io.ByteBuffer)
*/
@Override
public int flush(ByteBuffer header, ByteBuffer buffer, ByteBuffer trailer) throws IOException
{
_idleTimestamp=System.currentTimeMillis();
return super.flush(header,buffer,trailer);
}
/* ------------------------------------------------------------ */
public void run()
{
try
{
_timeout=getMaxIdleTime();
connectionOpened(_connection);
_endpoints.add(this);
while (isOpen())
{
_idleTimestamp=System.currentTimeMillis();
if (_connection.isIdle())
{
if (getServer().getThreadPool().isLowOnThreads())
{
int lrmit = getLowResourcesMaxIdleTime();
if (lrmit>=0 && _timeout!= lrmit)
{
_timeout=lrmit;
}
}
}
else
{
if (_timeout!=getMaxIdleTime())
{
_timeout=getMaxIdleTime();
}
}
_connection = _connection.handle();
}
}
catch (EofException e)
{
LOG.debug("EOF", e);
try{BlockingChannelEndPoint.this.close();}
catch(IOException e2){LOG.ignore(e2);}
}
catch (HttpException e)
{
LOG.debug("BAD", e);
try{super.close();}
catch(IOException e2){LOG.ignore(e2);}
}
catch(Throwable e)
{
LOG.warn("handle failed",e);
try{super.close();}
catch(IOException e2){LOG.ignore(e2);}
}
finally
{
connectionClosed(_connection);
_endpoints.remove(this);
// wait for client to close, but if not, close ourselves.
try
{
if (!_socket.isClosed())
{
long timestamp=System.currentTimeMillis();
int max_idle=getMaxIdleTime();
_socket.setSoTimeout(getMaxIdleTime());
int c=0;
do
{
c = _socket.getInputStream().read();
}
while (c>=0 && (System.currentTimeMillis()-timestamp)<max_idle);
if (!_socket.isClosed())
_socket.close();
}
}
catch(IOException e)
{
LOG.ignore(e);
}
}
}
/* ------------------------------------------------------------ */
@Override
public String toString()
{
return String.format("BCEP@%x{l(%s)<->r(%s),open=%b,ishut=%b,oshut=%b}-{%s}",
hashCode(),
_socket.getRemoteSocketAddress(),
_socket.getLocalSocketAddress(),
isOpen(),
isInputShutdown(),
isOutputShutdown(),
_connection);
}
}
}

View File

@ -13,9 +13,15 @@
package org.eclipse.jetty.util;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.ByteChannel;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.charset.Charset;
import javax.swing.text.Position;
@ -59,6 +65,7 @@ public class BufferUtil
{ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D',
(byte)'E', (byte)'F' };
public static final ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(new byte[0]);
/* ------------------------------------------------------------ */
/** Allocate ByteBuffer in flush mode.
@ -280,6 +287,31 @@ public class BufferUtil
}
}
public static void readFrom(File file, ByteBuffer buffer) throws IOException
{
RandomAccessFile raf = new RandomAccessFile(file,"r");
FileChannel channel = raf.getChannel();
long needed=raf.length();
while (needed>0 && buffer.hasRemaining())
needed=needed-channel.read(buffer);
}
public static void readFrom(InputStream is, int needed, ByteBuffer buffer) throws IOException
{
ByteBuffer tmp = allocate(8192);
while (needed>0 && buffer.hasRemaining())
{
int l = is.read(tmp.array(),0,8192);
if (l<0)
break;
tmp.position(0);
tmp.limit(l);
buffer.put(tmp);
}
}
/* ------------------------------------------------------------ */
/** Convert the buffer to an ISO-8859-1 String
* @param buffer The buffer to convert in flush mode. The buffer is unchanged
@ -577,6 +609,13 @@ public class BufferUtil
return ByteBuffer.wrap(s.getBytes(charset));
}
public static ByteBuffer toBuffer(File file) throws IOException
{
RandomAccessFile raf = new RandomAccessFile(file,"r");
MappedByteBuffer buffer=raf.getChannel().map(MapMode.READ_ONLY,0,raf.length());
return buffer;
}
public static String toSummaryString(ByteBuffer buffer)
{
if (buffer==null)
@ -692,4 +731,6 @@ public class BufferUtil
return false;
return true;
}
}