Mercurial Hosting > luan
diff src/org/eclipse/jetty/http/AbstractGenerator.java @ 802:3428c60d7cfc
replace jetty jars with source
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 07 Sep 2016 21:15:48 -0600 |
parents | |
children | 8e9db0bbf4f9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/eclipse/jetty/http/AbstractGenerator.java Wed Sep 07 21:15:48 2016 -0600 @@ -0,0 +1,532 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 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.http; + +import java.io.IOException; + +import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.Buffers; +import org.eclipse.jetty.io.ByteArrayBuffer; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.io.View; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +/* ------------------------------------------------------------ */ +/** + * Abstract Generator. Builds HTTP Messages. + * + * Currently this class uses a system parameter "jetty.direct.writers" to control + * two optional writer to byte conversions. buffer.writers=true will probably be + * faster, but will consume more memory. This option is just for testing and tuning. + * + */ +public abstract class AbstractGenerator implements Generator +{ + private static final Logger LOG = Log.getLogger(AbstractGenerator.class); + + // states + public final static int STATE_HEADER = 0; + public final static int STATE_CONTENT = 2; + public final static int STATE_FLUSHING = 3; + public final static int STATE_END = 4; + + public static final byte[] NO_BYTES = {}; + + // data + + protected final Buffers _buffers; // source of buffers + protected final EndPoint _endp; + + protected int _state = STATE_HEADER; + + protected int _status = 0; + protected int _version = HttpVersions.HTTP_1_1_ORDINAL; + protected Buffer _reason; + protected Buffer _method; + protected String _uri; + + protected long _contentWritten = 0; + protected long _contentLength = HttpTokens.UNKNOWN_CONTENT; + protected boolean _last = false; + protected boolean _head = false; + protected boolean _noContent = false; + protected Boolean _persistent = null; + + protected Buffer _header; // Buffer for HTTP header (and maybe small _content) + protected Buffer _buffer; // Buffer for copy of passed _content + protected Buffer _content; // Buffer passed to addContent + + protected Buffer _date; + + private boolean _sendServerVersion; + + + /* ------------------------------------------------------------------------------- */ + /** + * Constructor. + * + * @param buffers buffer pool + * @param io the end point + */ + public AbstractGenerator(Buffers buffers, EndPoint io) + { + this._buffers = buffers; + this._endp = io; + } + + /* ------------------------------------------------------------------------------- */ + public abstract boolean isRequest(); + + /* ------------------------------------------------------------------------------- */ + public abstract boolean isResponse(); + + /* ------------------------------------------------------------------------------- */ + public boolean isOpen() + { + return _endp.isOpen(); + } + + /* ------------------------------------------------------------------------------- */ + public void reset() + { + _state = STATE_HEADER; + _status = 0; + _version = HttpVersions.HTTP_1_1_ORDINAL; + _reason = null; + _last = false; + _head = false; + _noContent=false; + _persistent = null; + _contentWritten = 0; + _contentLength = HttpTokens.UNKNOWN_CONTENT; + _date = null; + + _content = null; + _method=null; + } + + /* ------------------------------------------------------------------------------- */ + public void returnBuffers() + { + if (_buffer!=null && _buffer.length()==0) + { + _buffers.returnBuffer(_buffer); + _buffer=null; + } + + if (_header!=null && _header.length()==0) + { + _buffers.returnBuffer(_header); + _header=null; + } + } + + /* ------------------------------------------------------------------------------- */ + public 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 int getContentBufferSize() + { + if (_buffer==null) + _buffer=_buffers.getBuffer(); + return _buffer.capacity(); + } + + /* ------------------------------------------------------------ */ + /** + * @param contentBufferSize The contentBufferSize to set. + */ + public void increaseContentBufferSize(int contentBufferSize) + { + if (_buffer==null) + _buffer=_buffers.getBuffer(); + if (contentBufferSize > _buffer.capacity()) + { + Buffer nb = _buffers.getBuffer(contentBufferSize); + nb.put(_buffer); + _buffers.returnBuffer(_buffer); + _buffer = nb; + } + } + + /* ------------------------------------------------------------ */ + public Buffer getUncheckedBuffer() + { + return _buffer; + } + + /* ------------------------------------------------------------ */ + public boolean getSendServerVersion () + { + return _sendServerVersion; + } + + /* ------------------------------------------------------------ */ + public void setSendServerVersion (boolean sendServerVersion) + { + _sendServerVersion = sendServerVersion; + } + + /* ------------------------------------------------------------ */ + public int getState() + { + return _state; + } + + /* ------------------------------------------------------------ */ + public boolean isState(int state) + { + return _state == state; + } + + /* ------------------------------------------------------------ */ + public boolean isComplete() + { + return _state == STATE_END; + } + + /* ------------------------------------------------------------ */ + public boolean isIdle() + { + return _state == STATE_HEADER && _method==null && _status==0; + } + + /* ------------------------------------------------------------ */ + public boolean isCommitted() + { + return _state != STATE_HEADER; + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the head. + */ + public boolean isHead() + { + return _head; + } + + /* ------------------------------------------------------------ */ + public void setContentLength(long value) + { + if (value<0) + _contentLength=HttpTokens.UNKNOWN_CONTENT; + else + _contentLength=value; + } + + /* ------------------------------------------------------------ */ + /** + * @param head The head to set. + */ + public 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 boolean isPersistent() + { + return _persistent!=null + ?_persistent.booleanValue() + :(isRequest()?true:_version>HttpVersions.HTTP_1_0_ORDINAL); + } + + /* ------------------------------------------------------------ */ + public 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 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; + } + + /* ------------------------------------------------------------ */ + public int getVersion() + { + return _version; + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.http.Generator#setDate(org.eclipse.jetty.io.Buffer) + */ + public void setDate(Buffer timeStampBuffer) + { + _date=timeStampBuffer; + } + + /* ------------------------------------------------------------ */ + /** + */ + public void setRequest(String method, String uri) + { + if (method==null || HttpMethods.GET.equals(method) ) + _method=HttpMethods.GET_BUFFER; + else + _method=HttpMethods.CACHE.lookup(method); + _uri=uri; + if (_version==HttpVersions.HTTP_0_9_ORDINAL) + _noContent=true; + } + + /* ------------------------------------------------------------ */ + /** + * @param status The status code to send. + * @param reason the status message to send. + */ + public 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=new ByteArrayBuffer(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)' '); + } + } + } + + /* ------------------------------------------------------------ */ + /** Prepare buffer for unchecked writes. + * Prepare the generator buffer to receive unchecked writes + * @return the available space in the buffer. + * @throws IOException + */ + public abstract int prepareUncheckedAddContent() throws IOException; + + /* ------------------------------------------------------------ */ + void uncheckedAddContent(int b) + { + _buffer.put((byte)b); + } + + /* ------------------------------------------------------------ */ + public void completeUncheckedAddContent() + { + if (_noContent) + { + if(_buffer!=null) + _buffer.clear(); + } + else + { + _contentWritten+=_buffer.length(); + if (_head) + _buffer.clear(); + } + } + + /* ------------------------------------------------------------ */ + public boolean isBufferFull() + { + if (_buffer != null && _buffer.space()==0) + { + if (_buffer.length()==0 && !_buffer.isImmutable()) + _buffer.compact(); + return _buffer.space()==0; + } + + return _content!=null && _content.length()>0; + } + + /* ------------------------------------------------------------ */ + public boolean isWritten() + { + return _contentWritten>0; + } + + /* ------------------------------------------------------------ */ + public boolean isAllContentWritten() + { + return _contentLength>=0 && _contentWritten>=_contentLength; + } + + /* ------------------------------------------------------------ */ + public abstract void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException; + + /* ------------------------------------------------------------ */ + /** + * Complete the message. + * + * @throws IOException + */ + public void complete() 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 abstract int flushBuffer() throws IOException; + + + /* ------------------------------------------------------------ */ + public void flush(long maxIdleTime) throws IOException + { + // block until everything is flushed + long now=System.currentTimeMillis(); + long end=now+maxIdleTime; + Buffer content = _content; + Buffer buffer = _buffer; + if (content!=null && content.length()>0 || buffer!=null && buffer.length()>0 || isBufferFull()) + { + flushBuffer(); + + while (now<end && (content!=null && content.length()>0 ||buffer!=null && buffer.length()>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 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(new View(new ByteArrayBuffer(content)), Generator.LAST); + } + else if (code>=400) + { + completeHeader(null, false); + addContent(new View(new ByteArrayBuffer("Error: "+(reason==null?(""+code):reason))), Generator.LAST); + } + else + { + completeHeader(null, true); + } + complete(); + } + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the contentWritten. + */ + public long getContentWritten() + { + return _contentWritten; + } + + + + /* ------------------------------------------------------------ */ + public 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(); + } + } + +}