diff src/org/eclipse/jetty/http/HttpGenerator.java @ 1057:afc9610dc12e

remove AbstractGenerator
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 08 Nov 2016 04:05:04 -0700
parents 2b769da7f67d
children 419bf9c03d84
line wrap: on
line diff
--- a/src/org/eclipse/jetty/http/HttpGenerator.java	Tue Nov 08 01:19:36 2016 -0700
+++ b/src/org/eclipse/jetty/http/HttpGenerator.java	Tue Nov 08 04:05:04 2016 -0700
@@ -39,7 +39,7 @@
  *
  *
  */
-public final class HttpGenerator extends AbstractGenerator
+public final class HttpGenerator
 {
 	private static final Logger LOG = LoggerFactory.getLogger(HttpGenerator.class);
 
@@ -101,11 +101,6 @@
 	private boolean _bufferChunked = false;
 
 
-	public HttpGenerator(Buffers buffers, EndPoint io)
-	{
-		super(buffers,io);
-	}
-
 	public void shutdown() {
 		if (_persistent!=null && !_persistent && _endp!=null && !_endp.isOutputShutdown())
 		{
@@ -235,11 +230,10 @@
 		return _buffer.space()-(_contentLength == HttpTokens.CHUNKED_CONTENT?CHUNK_SPACE:0);
 	}
 
-	@Override
 	public boolean isBufferFull()
 	{
 		// Should we flush the buffers?
-		return super.isBufferFull() || _bufferChunked || _bypass  || (_contentLength == HttpTokens.CHUNKED_CONTENT && _buffer != null && _buffer.space() < CHUNK_SPACE);
+		return isBufferFull2() || _bufferChunked || _bypass  || (_contentLength == HttpTokens.CHUNKED_CONTENT && _buffer != null && _buffer.space() < CHUNK_SPACE);
 	}
 
 	public void send1xx(int code) throws IOException
@@ -279,7 +273,6 @@
 		}
 	}
 
-	@Override
 	boolean isRequest()
 	{
 		return _method!=null;
@@ -290,7 +283,6 @@
 		return _method==null;
 	}
 
-	@Override
 	public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
 	{
 		if (_state != STATE_HEADER)
@@ -701,13 +693,12 @@
 	 *
 	 * @throws IOException
 	 */
-	@Override
 	public void complete() throws IOException
 	{
 		if (_state == STATE_END)
 			return;
 
-		super.complete();
+		complete2();
 
 		if (_state < STATE_FLUSHING)
 		{
@@ -719,7 +710,6 @@
 		flushBuffer();
 	}
 
-	@Override
 	public int flushBuffer() throws IOException
 	{
 		try
@@ -993,4 +983,327 @@
 				buffer == null ? -1 : buffer.remaining(),
 				content == null ? -1 : content.remaining());
 	}
+
+
+
+
+
+
+
+
+
+
+
+
+	// AbstractGenerator
+
+	public static final boolean LAST=true;
+	public static final boolean MORE=false;
+
+	// states
+	private final static int STATE_HEADER = 0;
+	private final static int STATE_CONTENT = 2;
+	private final static int STATE_FLUSHING = 3;
+	private final static int STATE_END = 4;
+
+	// data
+
+	private final Buffers _buffers; // source of buffers
+	private final EndPoint _endp;
+
+	private int _state = STATE_HEADER;
+
+	private int _status = 0;
+	private int _version = HttpVersions.HTTP_1_1_ORDINAL;
+	private JBuffer _reason;
+	private JBuffer _method;
+	private String _uri;
+
+	private long _contentWritten = 0;
+	private long _contentLength = HttpTokens.UNKNOWN_CONTENT;
+	private boolean _last = false;
+	private boolean _head = false;
+	private boolean _noContent = false;
+	private Boolean _persistent = null;
+
+	private JBuffer _header; // JBuffer for HTTP header (and maybe small _content)
+	private JBuffer _buffer; // JBuffer for copy of passed _content
+	private JBuffer _content; // JBuffer passed to addContent
+
+
+	public HttpGenerator(Buffers buffers, EndPoint io)
+	{
+		this._buffers = buffers;
+		this._endp = io;
+	}
+
+	public final boolean isOpen()
+	{
+		return _endp.isOpen();
+	}
+
+	public final void resetBuffer()
+	{
+		if(_state>=STATE_FLUSHING)
+			throw new IllegalStateException("Flushed");
+
+		_last = false;
+		_persistent = null;
+		_contentWritten = 0;
+		_contentLength = HttpTokens.UNKNOWN_CONTENT;
+		_content=null;
+		if (_buffer!=null)
+			_buffer.clear();
+	}
+
+	/* ------------------------------------------------------------ */
+	/**
+	 * @return Returns the contentBufferSize.
+	 */
+	public final int getContentBufferSize()
+	{
+		if (_buffer==null)
+			_buffer = _buffers.getBuffer();
+		return _buffer.capacity();
+	}
+
+	public final JBuffer getUncheckedBuffer()
+	{
+		return _buffer;
+	}
+
+	public final boolean isComplete()
+	{
+		return _state == STATE_END;
+	}
+
+	public final boolean isIdle()
+	{
+		return _state == STATE_HEADER && _method==null && _status==0;
+	}
+
+	public final boolean isCommitted()
+	{
+		return _state != STATE_HEADER;
+	}
+
+	public final void setContentLength(long value)
+	{
+		if (value<0)
+			_contentLength=HttpTokens.UNKNOWN_CONTENT;
+		else
+			_contentLength=value;
+	}
+
+	public final void setHead(boolean head)
+	{
+		_head = head;
+	}
+
+	/* ------------------------------------------------------------ */
+	/**
+	 * @return <code>false</code> if the connection should be closed after a request has been read,
+	 * <code>true</code> if it should be used for additional requests.
+	 */
+	public final boolean isPersistent()
+	{
+		return _persistent!=null
+		?_persistent.booleanValue()
+		:(isRequest()?true:_version>HttpVersions.HTTP_1_0_ORDINAL);
+	}
+
+	public final void setPersistent(boolean persistent)
+	{
+		_persistent = persistent;
+	}
+
+	/* ------------------------------------------------------------ */
+	/**
+	 * @param version The version of the client the response is being sent to (NB. Not the version
+	 *            in the response, which is the version of the server).
+	 */
+	public final void setVersion(int version)
+	{
+		if (_state != STATE_HEADER)
+			throw new IllegalStateException("STATE!=START "+_state);
+		_version = version;
+		if (_version==HttpVersions.HTTP_0_9_ORDINAL && _method!=null)
+			_noContent=true;
+	}
+
+	/* ------------------------------------------------------------ */
+	/**
+	 * @param status The status code to send.
+	 * @param reason the status message to send.
+	 */
+	public final void setResponse(int status, String reason)
+	{
+		if (_state != STATE_HEADER) throw new IllegalStateException("STATE!=START");
+		_method=null;
+		_status = status;
+		if (reason!=null)
+		{
+			int len=reason.length();
+
+			// TODO don't hard code
+			if (len>1024)
+				len=1024;
+			_reason = BufferUtil.newBuffer(len);
+			for (int i=0;i<len;i++)
+			{
+				char ch = reason.charAt(i);
+				if (ch!='\r'&&ch!='\n')
+					_reason.put((byte)ch);
+				else
+					_reason.put((byte)' ');
+			}
+		}
+	}
+
+	public final void completeUncheckedAddContent()
+	{
+		if (_noContent)
+		{
+			if(_buffer!=null)
+				_buffer.clear();
+		}
+		else
+		{
+			_contentWritten+=_buffer.remaining();
+			if (_head)
+				_buffer.clear();
+		}
+	}
+
+	private boolean isBufferFull2()
+	{
+		if (_buffer != null && _buffer.space()==0)
+		{
+			if (_buffer.remaining()==0)
+				_buffer.compact();
+			return _buffer.space()==0;
+		}
+
+		return _content!=null && _content.remaining()>0;
+	}
+
+	public final boolean isWritten()
+	{
+		return _contentWritten>0;
+	}
+
+	public final boolean isAllContentWritten()
+	{
+		return _contentLength>=0 && _contentWritten>=_contentLength;
+	}
+
+
+	private void complete2() throws IOException
+	{
+		if (_state == STATE_HEADER)
+		{
+			throw new IllegalStateException("State==HEADER");
+		}
+
+		if (_contentLength >= 0 && _contentLength != _contentWritten && !_head)
+		{
+			if (LOG.isDebugEnabled())
+				LOG.debug("ContentLength written=="+_contentWritten+" != contentLength=="+_contentLength);
+			_persistent = false;
+		}
+	}
+
+
+	public final void flush(long maxIdleTime) throws IOException
+	{
+		// block until everything is flushed
+		long now=System.currentTimeMillis();
+		long end=now+maxIdleTime;
+		JBuffer content = _content;
+		JBuffer buffer = _buffer;
+		if (content!=null && content.remaining()>0 || buffer!=null && buffer.remaining()>0 || isBufferFull())
+		{
+			flushBuffer();
+
+			while (now<end && (content!=null && content.remaining()>0 ||buffer!=null && buffer.remaining()>0) && _endp.isOpen()&& !_endp.isOutputShutdown())
+			{
+				blockForOutput(end-now);
+				now=System.currentTimeMillis();
+			}
+		}
+	}
+
+	/* ------------------------------------------------------------ */
+	/**
+	 * Utility method to send an error response. If the builder is not committed, this call is
+	 * equivalent to a setResponse, addContent and complete call.
+	 *
+	 * @param code The error code
+	 * @param reason The error reason
+	 * @param content Contents of the error page
+	 * @param close True if the connection should be closed
+	 * @throws IOException if there is a problem flushing the response
+	 */
+	public final void sendError(int code, String reason, String content, boolean close) throws IOException
+	{
+		if (close)
+			_persistent=false;
+		if (isCommitted())
+		{
+			LOG.debug("sendError on committed: {} {}",code,reason);
+		}
+		else
+		{
+			LOG.debug("sendError: {} {}",code,reason);
+			setResponse(code, reason);
+			if (content != null)
+			{
+				completeHeader(null, false);
+				addContent(BufferUtil.wrap(content), LAST);
+			}
+			else if (code>=400)
+			{
+				completeHeader(null, false);
+				addContent(BufferUtil.wrap("Error: "+(reason==null?(""+code):reason)), LAST);
+			}
+			else
+			{
+				completeHeader(null, true);
+			}
+			complete();
+		}
+	}
+
+	public final long getContentWritten()
+	{
+		return _contentWritten;
+	}
+
+
+	public final void blockForOutput(long maxIdleTime) throws IOException
+	{
+		if (_endp.isBlocking())
+		{
+			try
+			{
+				flushBuffer();
+			}
+			catch(IOException e)
+			{
+				_endp.close();
+				throw e;
+			}
+		}
+		else
+		{
+			if (!_endp.blockWritable(maxIdleTime))
+			{
+				_endp.close();
+				throw new EofException("timeout");
+			}
+
+			flushBuffer();
+		}
+	}
+
 }