Mercurial Hosting > luan
diff src/org/eclipse/jetty/http/HttpGenerator.java @ 877:fef4392f4905
remove sendServerVersion
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 04 Oct 2016 14:36:51 -0600 |
parents | 8e9db0bbf4f9 |
children | cb78ee27b0e0 |
line wrap: on
line diff
--- a/src/org/eclipse/jetty/http/HttpGenerator.java Tue Oct 04 14:05:45 2016 -0600 +++ b/src/org/eclipse/jetty/http/HttpGenerator.java Tue Oct 04 14:36:51 2016 -0600 @@ -41,1052 +41,1049 @@ */ public class HttpGenerator extends AbstractGenerator { - private static final Logger LOG = LoggerFactory.getLogger(HttpGenerator.class); + private static final Logger LOG = LoggerFactory.getLogger(HttpGenerator.class); - // Build cache of response lines for status - private static class Status - { - Buffer _reason; - Buffer _schemeCode; - Buffer _responseLine; - } - private static final Status[] __status = new Status[HttpStatus.MAX_CODE+1]; - static - { - int versionLength=HttpVersions.HTTP_1_1_BUFFER.length(); + // Build cache of response lines for status + private static class Status + { + Buffer _reason; + Buffer _schemeCode; + Buffer _responseLine; + } + private static final Status[] __status = new Status[HttpStatus.MAX_CODE+1]; + static + { + int versionLength=HttpVersions.HTTP_1_1_BUFFER.length(); - for (int i=0;i<__status.length;i++) - { - HttpStatus.Code code = HttpStatus.getCode(i); - if (code==null) - continue; - String reason=code.getMessage(); - byte[] bytes=new byte[versionLength+5+reason.length()+2]; - HttpVersions.HTTP_1_1_BUFFER.peek(0,bytes, 0, versionLength); - bytes[versionLength+0]=' '; - bytes[versionLength+1]=(byte)('0'+i/100); - bytes[versionLength+2]=(byte)('0'+(i%100)/10); - bytes[versionLength+3]=(byte)('0'+(i%10)); - bytes[versionLength+4]=' '; - for (int j=0;j<reason.length();j++) - bytes[versionLength+5+j]=(byte)reason.charAt(j); - bytes[versionLength+5+reason.length()]=HttpTokens.CARRIAGE_RETURN; - bytes[versionLength+6+reason.length()]=HttpTokens.LINE_FEED; + for (int i=0;i<__status.length;i++) + { + HttpStatus.Code code = HttpStatus.getCode(i); + if (code==null) + continue; + String reason=code.getMessage(); + byte[] bytes=new byte[versionLength+5+reason.length()+2]; + HttpVersions.HTTP_1_1_BUFFER.peek(0,bytes, 0, versionLength); + bytes[versionLength+0]=' '; + bytes[versionLength+1]=(byte)('0'+i/100); + bytes[versionLength+2]=(byte)('0'+(i%100)/10); + bytes[versionLength+3]=(byte)('0'+(i%10)); + bytes[versionLength+4]=' '; + for (int j=0;j<reason.length();j++) + bytes[versionLength+5+j]=(byte)reason.charAt(j); + bytes[versionLength+5+reason.length()]=HttpTokens.CARRIAGE_RETURN; + bytes[versionLength+6+reason.length()]=HttpTokens.LINE_FEED; - __status[i] = new Status(); - __status[i]._reason=new ByteArrayBuffer(bytes,versionLength+5,bytes.length-versionLength-7,Buffer.IMMUTABLE); - __status[i]._schemeCode=new ByteArrayBuffer(bytes,0,versionLength+5,Buffer.IMMUTABLE); - __status[i]._responseLine=new ByteArrayBuffer(bytes,0,bytes.length,Buffer.IMMUTABLE); - } - } + __status[i] = new Status(); + __status[i]._reason=new ByteArrayBuffer(bytes,versionLength+5,bytes.length-versionLength-7,Buffer.IMMUTABLE); + __status[i]._schemeCode=new ByteArrayBuffer(bytes,0,versionLength+5,Buffer.IMMUTABLE); + __status[i]._responseLine=new ByteArrayBuffer(bytes,0,bytes.length,Buffer.IMMUTABLE); + } + } - /* ------------------------------------------------------------------------------- */ - public static Buffer getReasonBuffer(int code) - { - Status status = code<__status.length?__status[code]:null; - if (status!=null) - return status._reason; - return null; - } + /* ------------------------------------------------------------------------------- */ + public static Buffer getReasonBuffer(int code) + { + Status status = code<__status.length?__status[code]:null; + if (status!=null) + return status._reason; + return null; + } - // common _content - private static final byte[] LAST_CHUNK = - { (byte) '0', (byte) '\015', (byte) '\012', (byte) '\015', (byte) '\012'}; - private static final byte[] CONTENT_LENGTH_0 = StringUtil.getBytes("Content-Length: 0\015\012"); - private static final byte[] CONNECTION_KEEP_ALIVE = StringUtil.getBytes("Connection: keep-alive\015\012"); - private static final byte[] CONNECTION_CLOSE = StringUtil.getBytes("Connection: close\015\012"); - private static final byte[] CONNECTION_ = StringUtil.getBytes("Connection: "); - private static final byte[] CRLF = StringUtil.getBytes("\015\012"); - private static final byte[] TRANSFER_ENCODING_CHUNKED = StringUtil.getBytes("Transfer-Encoding: chunked\015\012"); - private static byte[] SERVER = StringUtil.getBytes("Server: Jetty(7.0.x)\015\012"); + // common _content + private static final byte[] LAST_CHUNK = + { (byte) '0', (byte) '\015', (byte) '\012', (byte) '\015', (byte) '\012'}; + private static final byte[] CONTENT_LENGTH_0 = StringUtil.getBytes("Content-Length: 0\015\012"); + private static final byte[] CONNECTION_KEEP_ALIVE = StringUtil.getBytes("Connection: keep-alive\015\012"); + private static final byte[] CONNECTION_CLOSE = StringUtil.getBytes("Connection: close\015\012"); + private static final byte[] CONNECTION_ = StringUtil.getBytes("Connection: "); + private static final byte[] CRLF = StringUtil.getBytes("\015\012"); + private static final byte[] TRANSFER_ENCODING_CHUNKED = StringUtil.getBytes("Transfer-Encoding: chunked\015\012"); + private static byte[] SERVER = StringUtil.getBytes("Server: Jetty(7.0.x)\015\012"); - // other statics - private static final int CHUNK_SPACE = 12; + // other statics + private static final int CHUNK_SPACE = 12; - public static void setServerVersion(String version) - { - SERVER=StringUtil.getBytes("Server: Jetty("+version+")\015\012"); - } + public static void setServerVersion(String version) + { + SERVER=StringUtil.getBytes("Server: Jetty("+version+")\015\012"); + } - // data - protected boolean _bypass = false; // True if _content buffer can be written directly to endp and bypass the content buffer - private boolean _needCRLF = false; - private boolean _needEOC = false; - private boolean _bufferChunked = false; + // data + protected boolean _bypass = false; // True if _content buffer can be written directly to endp and bypass the content buffer + private boolean _needCRLF = false; + private boolean _needEOC = false; + private boolean _bufferChunked = false; - /* ------------------------------------------------------------------------------- */ - /** - * Constructor. - * - * @param buffers buffer pool - * @param io the end point to use - */ - public HttpGenerator(Buffers buffers, EndPoint io) - { - super(buffers,io); - } + /* ------------------------------------------------------------------------------- */ + /** + * Constructor. + * + * @param buffers buffer pool + * @param io the end point to use + */ + public HttpGenerator(Buffers buffers, EndPoint io) + { + super(buffers,io); + } - /* ------------------------------------------------------------------------------- */ - @Override - public void reset() - { - if (_persistent!=null && !_persistent && _endp!=null && !_endp.isOutputShutdown()) - { - try - { - _endp.shutdownOutput(); - } - catch(IOException e) - { - LOG.trace("",e); - } - } - super.reset(); - if (_buffer!=null) - _buffer.clear(); - if (_header!=null) - _header.clear(); - if (_content!=null) - _content=null; - _bypass = false; - _needCRLF = false; - _needEOC = false; - _bufferChunked=false; - _method=null; - _uri=null; - _noContent=false; - } + /* ------------------------------------------------------------------------------- */ + @Override + public void reset() + { + if (_persistent!=null && !_persistent && _endp!=null && !_endp.isOutputShutdown()) + { + try + { + _endp.shutdownOutput(); + } + catch(IOException e) + { + LOG.trace("",e); + } + } + super.reset(); + if (_buffer!=null) + _buffer.clear(); + if (_header!=null) + _header.clear(); + if (_content!=null) + _content=null; + _bypass = false; + _needCRLF = false; + _needEOC = false; + _bufferChunked=false; + _method=null; + _uri=null; + _noContent=false; + } - /* ------------------------------------------------------------ */ - /** - * Add content. - * - * @param content - * @param last - * @throws IllegalArgumentException if <code>content</code> is {@link Buffer#isImmutable immutable}. - * @throws IllegalStateException If the request is not expecting any more content, - * or if the buffers are full and cannot be flushed. - * @throws IOException if there is a problem flushing the buffers. - */ - public void addContent(Buffer content, boolean last) throws IOException - { - if (_noContent) - throw new IllegalStateException("NO CONTENT"); + /* ------------------------------------------------------------ */ + /** + * Add content. + * + * @param content + * @param last + * @throws IllegalArgumentException if <code>content</code> is {@link Buffer#isImmutable immutable}. + * @throws IllegalStateException If the request is not expecting any more content, + * or if the buffers are full and cannot be flushed. + * @throws IOException if there is a problem flushing the buffers. + */ + public void addContent(Buffer content, boolean last) throws IOException + { + if (_noContent) + throw new IllegalStateException("NO CONTENT"); - if (_last || _state==STATE_END) - { - LOG.warn("Ignoring extra content {}",content); - content.clear(); - return; - } - _last = last; + if (_last || _state==STATE_END) + { + LOG.warn("Ignoring extra content {}",content); + content.clear(); + return; + } + _last = last; - // Handle any unfinished business? - if (_content!=null && _content.length()>0 || _bufferChunked) - { - if (_endp.isOutputShutdown()) - throw new EofException(); - flushBuffer(); - if (_content != null && _content.length()>0) - { - if (_bufferChunked) - { - Buffer nc=_buffers.getBuffer(_content.length()+CHUNK_SPACE+content.length()); - nc.put(_content); - nc.put(HttpTokens.CRLF); - BufferUtil.putHexInt(nc, content.length()); - nc.put(HttpTokens.CRLF); - nc.put(content); - content=nc; - } - else - { - Buffer nc=_buffers.getBuffer(_content.length()+content.length()); - nc.put(_content); - nc.put(content); - content=nc; - } - } - } + // Handle any unfinished business? + if (_content!=null && _content.length()>0 || _bufferChunked) + { + if (_endp.isOutputShutdown()) + throw new EofException(); + flushBuffer(); + if (_content != null && _content.length()>0) + { + if (_bufferChunked) + { + Buffer nc=_buffers.getBuffer(_content.length()+CHUNK_SPACE+content.length()); + nc.put(_content); + nc.put(HttpTokens.CRLF); + BufferUtil.putHexInt(nc, content.length()); + nc.put(HttpTokens.CRLF); + nc.put(content); + content=nc; + } + else + { + Buffer nc=_buffers.getBuffer(_content.length()+content.length()); + nc.put(_content); + nc.put(content); + content=nc; + } + } + } - _content = content; - _contentWritten += content.length(); + _content = content; + _contentWritten += content.length(); - // Handle the _content - if (_head) - { - content.clear(); - _content=null; - } - else if (_endp != null && (_buffer==null || _buffer.length()==0) && _content.length() > 0 && (_last || isCommitted() && _content.length()>1024)) - { - _bypass = true; - } - else if (!_bufferChunked) - { - // Yes - so we better check we have a buffer - if (_buffer == null) - _buffer = _buffers.getBuffer(); + // Handle the _content + if (_head) + { + content.clear(); + _content=null; + } + else if (_endp != null && (_buffer==null || _buffer.length()==0) && _content.length() > 0 && (_last || isCommitted() && _content.length()>1024)) + { + _bypass = true; + } + else if (!_bufferChunked) + { + // Yes - so we better check we have a buffer + if (_buffer == null) + _buffer = _buffers.getBuffer(); - // Copy _content to buffer; - int len=_buffer.put(_content); - _content.skip(len); - if (_content.length() == 0) - _content = null; - } - } + // Copy _content to buffer; + int len=_buffer.put(_content); + _content.skip(len); + if (_content.length() == 0) + _content = null; + } + } - /* ------------------------------------------------------------ */ - /** - * send complete response. - * - * @param response - */ - public void sendResponse(Buffer response) throws IOException - { - if (_noContent || _state!=STATE_HEADER || _content!=null && _content.length()>0 || _bufferChunked || _head ) - throw new IllegalStateException(); + /* ------------------------------------------------------------ */ + /** + * send complete response. + * + * @param response + */ + public void sendResponse(Buffer response) throws IOException + { + if (_noContent || _state!=STATE_HEADER || _content!=null && _content.length()>0 || _bufferChunked || _head ) + throw new IllegalStateException(); - _last = true; + _last = true; - _content = response; - _bypass = true; - _state = STATE_FLUSHING; + _content = response; + _bypass = true; + _state = STATE_FLUSHING; - // TODO this is not exactly right, but should do. - _contentLength =_contentWritten = response.length(); + // TODO this is not exactly right, but should do. + _contentLength =_contentWritten = response.length(); - } + } - /* ------------------------------------------------------------ */ - /** Prepare buffer for unchecked writes. - * Prepare the generator buffer to receive unchecked writes - * @return the available space in the buffer. - * @throws IOException - */ - @Override - public int prepareUncheckedAddContent() throws IOException - { - if (_noContent) - return -1; + /* ------------------------------------------------------------ */ + /** Prepare buffer for unchecked writes. + * Prepare the generator buffer to receive unchecked writes + * @return the available space in the buffer. + * @throws IOException + */ + @Override + public int prepareUncheckedAddContent() throws IOException + { + if (_noContent) + return -1; - if (_last || _state==STATE_END) - return -1; + if (_last || _state==STATE_END) + return -1; - // Handle any unfinished business? - Buffer content = _content; - if (content != null && content.length()>0 || _bufferChunked) - { - flushBuffer(); - if (content != null && content.length()>0 || _bufferChunked) - throw new IllegalStateException("FULL"); - } + // Handle any unfinished business? + Buffer content = _content; + if (content != null && content.length()>0 || _bufferChunked) + { + flushBuffer(); + if (content != null && content.length()>0 || _bufferChunked) + throw new IllegalStateException("FULL"); + } - // we better check we have a buffer - if (_buffer == null) - _buffer = _buffers.getBuffer(); + // we better check we have a buffer + if (_buffer == null) + _buffer = _buffers.getBuffer(); - _contentWritten-=_buffer.length(); + _contentWritten-=_buffer.length(); - // Handle the _content - if (_head) - return Integer.MAX_VALUE; + // Handle the _content + if (_head) + return Integer.MAX_VALUE; - return _buffer.space()-(_contentLength == HttpTokens.CHUNKED_CONTENT?CHUNK_SPACE:0); - } + 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); - } + /* ------------------------------------------------------------ */ + @Override + public boolean isBufferFull() + { + // Should we flush the buffers? + return super.isBufferFull() || _bufferChunked || _bypass || (_contentLength == HttpTokens.CHUNKED_CONTENT && _buffer != null && _buffer.space() < CHUNK_SPACE); + } - /* ------------------------------------------------------------ */ - public void send1xx(int code) throws IOException - { - if (_state != STATE_HEADER) - return; + /* ------------------------------------------------------------ */ + public void send1xx(int code) throws IOException + { + if (_state != STATE_HEADER) + return; - if (code<100||code>199) - throw new IllegalArgumentException("!1xx"); - Status status=__status[code]; - if (status==null) - throw new IllegalArgumentException(code+"?"); + if (code<100||code>199) + throw new IllegalArgumentException("!1xx"); + Status status=__status[code]; + if (status==null) + throw new IllegalArgumentException(code+"?"); - // get a header buffer - if (_header == null) - _header = _buffers.getHeader(); + // get a header buffer + if (_header == null) + _header = _buffers.getHeader(); - _header.put(status._responseLine); - _header.put(HttpTokens.CRLF); + _header.put(status._responseLine); + _header.put(HttpTokens.CRLF); - try - { - // nasty semi busy flush! - while(_header.length()>0) - { - int len = _endp.flush(_header); - if (len<0) - throw new EofException(); - if (len==0) - Thread.sleep(100); - } - } - catch(InterruptedException e) - { - LOG.debug("",e); - throw new InterruptedIOException(e.toString()); - } - } + try + { + // nasty semi busy flush! + while(_header.length()>0) + { + int len = _endp.flush(_header); + if (len<0) + throw new EofException(); + if (len==0) + Thread.sleep(100); + } + } + catch(InterruptedException e) + { + LOG.debug("",e); + throw new InterruptedIOException(e.toString()); + } + } - /* ------------------------------------------------------------ */ - @Override - public boolean isRequest() - { - return _method!=null; - } + /* ------------------------------------------------------------ */ + @Override + public boolean isRequest() + { + return _method!=null; + } - /* ------------------------------------------------------------ */ - @Override - public boolean isResponse() - { - return _method==null; - } + /* ------------------------------------------------------------ */ + @Override + public boolean isResponse() + { + return _method==null; + } - /* ------------------------------------------------------------ */ - @Override - public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException - { - if (_state != STATE_HEADER) - return; + /* ------------------------------------------------------------ */ + @Override + public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException + { + if (_state != STATE_HEADER) + return; - // handle a reset - if (isResponse() && _status==0) - throw new EofException(); + // handle a reset + if (isResponse() && _status==0) + throw new EofException(); - if (_last && !allContentAdded) - throw new IllegalStateException("last?"); - _last = _last | allContentAdded; + if (_last && !allContentAdded) + throw new IllegalStateException("last?"); + _last = _last | allContentAdded; - // get a header buffer - if (_header == null) - _header = _buffers.getHeader(); + // get a header buffer + if (_header == null) + _header = _buffers.getHeader(); - boolean has_server = false; + boolean has_server = false; - try - { - if (isRequest()) - { - _persistent=true; + try + { + if (isRequest()) + { + _persistent=true; - if (_version == HttpVersions.HTTP_0_9_ORDINAL) - { - _contentLength = HttpTokens.NO_CONTENT; - _header.put(_method); - _header.put((byte)' '); - _header.put(_uri.getBytes("UTF-8")); // TODO check - _header.put(HttpTokens.CRLF); - _state = STATE_FLUSHING; - _noContent=true; - return; - } - else - { - _header.put(_method); - _header.put((byte)' '); - _header.put(_uri.getBytes("UTF-8")); // TODO check - _header.put((byte)' '); - _header.put(_version==HttpVersions.HTTP_1_0_ORDINAL?HttpVersions.HTTP_1_0_BUFFER:HttpVersions.HTTP_1_1_BUFFER); - _header.put(HttpTokens.CRLF); - } - } - else - { - // Responses - if (_version == HttpVersions.HTTP_0_9_ORDINAL) - { - _persistent = false; - _contentLength = HttpTokens.EOF_CONTENT; - _state = STATE_CONTENT; - return; - } - else - { - if (_persistent==null) - _persistent= (_version > HttpVersions.HTTP_1_0_ORDINAL); + if (_version == HttpVersions.HTTP_0_9_ORDINAL) + { + _contentLength = HttpTokens.NO_CONTENT; + _header.put(_method); + _header.put((byte)' '); + _header.put(_uri.getBytes("UTF-8")); // TODO check + _header.put(HttpTokens.CRLF); + _state = STATE_FLUSHING; + _noContent=true; + return; + } + else + { + _header.put(_method); + _header.put((byte)' '); + _header.put(_uri.getBytes("UTF-8")); // TODO check + _header.put((byte)' '); + _header.put(_version==HttpVersions.HTTP_1_0_ORDINAL?HttpVersions.HTTP_1_0_BUFFER:HttpVersions.HTTP_1_1_BUFFER); + _header.put(HttpTokens.CRLF); + } + } + else + { + // Responses + if (_version == HttpVersions.HTTP_0_9_ORDINAL) + { + _persistent = false; + _contentLength = HttpTokens.EOF_CONTENT; + _state = STATE_CONTENT; + return; + } + else + { + if (_persistent==null) + _persistent= (_version > HttpVersions.HTTP_1_0_ORDINAL); - // add response line - Status status = _status<__status.length?__status[_status]:null; + // add response line + Status status = _status<__status.length?__status[_status]:null; - if (status==null) - { - _header.put(HttpVersions.HTTP_1_1_BUFFER); - _header.put((byte) ' '); - _header.put((byte) ('0' + _status / 100)); - _header.put((byte) ('0' + (_status % 100) / 10)); - _header.put((byte) ('0' + (_status % 10))); - _header.put((byte) ' '); - if (_reason==null) - { - _header.put((byte) ('0' + _status / 100)); - _header.put((byte) ('0' + (_status % 100) / 10)); - _header.put((byte) ('0' + (_status % 10))); - } - else - _header.put(_reason); - _header.put(HttpTokens.CRLF); - } - else - { - if (_reason==null) - _header.put(status._responseLine); - else - { - _header.put(status._schemeCode); - _header.put(_reason); - _header.put(HttpTokens.CRLF); - } - } + if (status==null) + { + _header.put(HttpVersions.HTTP_1_1_BUFFER); + _header.put((byte) ' '); + _header.put((byte) ('0' + _status / 100)); + _header.put((byte) ('0' + (_status % 100) / 10)); + _header.put((byte) ('0' + (_status % 10))); + _header.put((byte) ' '); + if (_reason==null) + { + _header.put((byte) ('0' + _status / 100)); + _header.put((byte) ('0' + (_status % 100) / 10)); + _header.put((byte) ('0' + (_status % 10))); + } + else + _header.put(_reason); + _header.put(HttpTokens.CRLF); + } + else + { + if (_reason==null) + _header.put(status._responseLine); + else + { + _header.put(status._schemeCode); + _header.put(_reason); + _header.put(HttpTokens.CRLF); + } + } - if (_status<200 && _status>=100 ) - { - _noContent=true; - _content=null; - if (_buffer!=null) - _buffer.clear(); - // end the header. + if (_status<200 && _status>=100 ) + { + _noContent=true; + _content=null; + if (_buffer!=null) + _buffer.clear(); + // end the header. - if (_status!=101 ) - { - _header.put(HttpTokens.CRLF); - _state = STATE_CONTENT; - return; - } - } - else if (_status==204 || _status==304) - { - _noContent=true; - _content=null; - if (_buffer!=null) - _buffer.clear(); - } - } - } + if (_status!=101 ) + { + _header.put(HttpTokens.CRLF); + _state = STATE_CONTENT; + return; + } + } + else if (_status==204 || _status==304) + { + _noContent=true; + _content=null; + if (_buffer!=null) + _buffer.clear(); + } + } + } - // Add headers - if (_status>=200 && _date!=null) - { - _header.put(HttpHeaders.DATE_BUFFER); - _header.put((byte)':'); - _header.put((byte)' '); - _header.put(_date); - _header.put(CRLF); - } + // Add headers + if (_status>=200 && _date!=null) + { + _header.put(HttpHeaders.DATE_BUFFER); + _header.put((byte)':'); + _header.put((byte)' '); + _header.put(_date); + _header.put(CRLF); + } - // key field values - HttpFields.Field content_length = null; - HttpFields.Field transfer_encoding = null; - boolean keep_alive = false; - boolean close=false; - boolean content_type=false; - StringBuilder connection = null; + // key field values + HttpFields.Field content_length = null; + HttpFields.Field transfer_encoding = null; + boolean keep_alive = false; + boolean close=false; + boolean content_type=false; + StringBuilder connection = null; - if (fields != null) - { - int s=fields.size(); - for (int f=0;f<s;f++) - { - HttpFields.Field field = fields.getField(f); - if (field==null) - continue; + if (fields != null) + { + int s=fields.size(); + for (int f=0;f<s;f++) + { + HttpFields.Field field = fields.getField(f); + if (field==null) + continue; - switch (field.getNameOrdinal()) - { - case HttpHeaders.CONTENT_LENGTH_ORDINAL: - content_length = field; - _contentLength = field.getLongValue(); + switch (field.getNameOrdinal()) + { + case HttpHeaders.CONTENT_LENGTH_ORDINAL: + content_length = field; + _contentLength = field.getLongValue(); - if (_contentLength < _contentWritten || _last && _contentLength != _contentWritten) - content_length = null; + if (_contentLength < _contentWritten || _last && _contentLength != _contentWritten) + content_length = null; - // write the field to the header buffer - field.putTo(_header); - break; + // write the field to the header buffer + field.putTo(_header); + break; - case HttpHeaders.CONTENT_TYPE_ORDINAL: - if (BufferUtil.isPrefix(MimeTypes.MULTIPART_BYTERANGES_BUFFER, field.getValueBuffer())) _contentLength = HttpTokens.SELF_DEFINING_CONTENT; + case HttpHeaders.CONTENT_TYPE_ORDINAL: + if (BufferUtil.isPrefix(MimeTypes.MULTIPART_BYTERANGES_BUFFER, field.getValueBuffer())) _contentLength = HttpTokens.SELF_DEFINING_CONTENT; - // write the field to the header buffer - content_type=true; - field.putTo(_header); - break; + // write the field to the header buffer + content_type=true; + field.putTo(_header); + break; - case HttpHeaders.TRANSFER_ENCODING_ORDINAL: - if (_version == HttpVersions.HTTP_1_1_ORDINAL) - transfer_encoding = field; - // Do NOT add yet! - break; + case HttpHeaders.TRANSFER_ENCODING_ORDINAL: + if (_version == HttpVersions.HTTP_1_1_ORDINAL) + transfer_encoding = field; + // Do NOT add yet! + break; - case HttpHeaders.CONNECTION_ORDINAL: - if (isRequest()) - field.putTo(_header); + case HttpHeaders.CONNECTION_ORDINAL: + if (isRequest()) + field.putTo(_header); - int connection_value = field.getValueOrdinal(); - switch (connection_value) - { - case -1: - { - String[] values = field.getValue().split(","); - for (int i=0;values!=null && i<values.length;i++) - { - CachedBuffer cb = HttpHeaderValues.CACHE.get(values[i].trim()); + int connection_value = field.getValueOrdinal(); + switch (connection_value) + { + case -1: + { + String[] values = field.getValue().split(","); + for (int i=0;values!=null && i<values.length;i++) + { + CachedBuffer cb = HttpHeaderValues.CACHE.get(values[i].trim()); - if (cb!=null) - { - switch(cb.getOrdinal()) - { - case HttpHeaderValues.CLOSE_ORDINAL: - close=true; - if (isResponse()) - _persistent=false; - keep_alive=false; - if (!_persistent && isResponse() && _contentLength == HttpTokens.UNKNOWN_CONTENT) - _contentLength = HttpTokens.EOF_CONTENT; - break; + if (cb!=null) + { + switch(cb.getOrdinal()) + { + case HttpHeaderValues.CLOSE_ORDINAL: + close=true; + if (isResponse()) + _persistent=false; + keep_alive=false; + if (!_persistent && isResponse() && _contentLength == HttpTokens.UNKNOWN_CONTENT) + _contentLength = HttpTokens.EOF_CONTENT; + break; - case HttpHeaderValues.KEEP_ALIVE_ORDINAL: - if (_version == HttpVersions.HTTP_1_0_ORDINAL) - { - keep_alive = true; - if (isResponse()) - _persistent = true; - } - break; + case HttpHeaderValues.KEEP_ALIVE_ORDINAL: + if (_version == HttpVersions.HTTP_1_0_ORDINAL) + { + keep_alive = true; + if (isResponse()) + _persistent = true; + } + break; - default: - if (connection==null) - connection=new StringBuilder(); - else - connection.append(','); - connection.append(values[i]); - } - } - else - { - if (connection==null) - connection=new StringBuilder(); - else - connection.append(','); - connection.append(values[i]); - } - } + default: + if (connection==null) + connection=new StringBuilder(); + else + connection.append(','); + connection.append(values[i]); + } + } + else + { + if (connection==null) + connection=new StringBuilder(); + else + connection.append(','); + connection.append(values[i]); + } + } - break; - } - case HttpHeaderValues.UPGRADE_ORDINAL: - { - // special case for websocket connection ordering - if (isResponse()) - { - field.putTo(_header); - continue; - } - } - case HttpHeaderValues.CLOSE_ORDINAL: - { - close=true; - if (isResponse()) - _persistent=false; - if (!_persistent && isResponse() && _contentLength == HttpTokens.UNKNOWN_CONTENT) - _contentLength = HttpTokens.EOF_CONTENT; - break; - } - case HttpHeaderValues.KEEP_ALIVE_ORDINAL: - { - if (_version == HttpVersions.HTTP_1_0_ORDINAL) - { - keep_alive = true; - if (isResponse()) - _persistent=true; - } - break; - } - default: - { - if (connection==null) - connection=new StringBuilder(); - else - connection.append(','); - connection.append(field.getValue()); - } - } + break; + } + case HttpHeaderValues.UPGRADE_ORDINAL: + { + // special case for websocket connection ordering + if (isResponse()) + { + field.putTo(_header); + continue; + } + } + case HttpHeaderValues.CLOSE_ORDINAL: + { + close=true; + if (isResponse()) + _persistent=false; + if (!_persistent && isResponse() && _contentLength == HttpTokens.UNKNOWN_CONTENT) + _contentLength = HttpTokens.EOF_CONTENT; + break; + } + case HttpHeaderValues.KEEP_ALIVE_ORDINAL: + { + if (_version == HttpVersions.HTTP_1_0_ORDINAL) + { + keep_alive = true; + if (isResponse()) + _persistent=true; + } + break; + } + default: + { + if (connection==null) + connection=new StringBuilder(); + else + connection.append(','); + connection.append(field.getValue()); + } + } - // Do NOT add yet! - break; + // Do NOT add yet! + break; - case HttpHeaders.SERVER_ORDINAL: - if (getSendServerVersion()) - { - has_server=true; - field.putTo(_header); - } - break; + case HttpHeaders.SERVER_ORDINAL: + has_server=true; + field.putTo(_header); + break; - default: - // write the field to the header buffer - field.putTo(_header); - } - } - } + default: + // write the field to the header buffer + field.putTo(_header); + } + } + } - // Calculate how to end _content and connection, _content length and transfer encoding - // settings. - // From RFC 2616 4.4: - // 1. No body for 1xx, 204, 304 & HEAD response - // 2. Force _content-length? - // 3. If Transfer-Encoding!=identity && HTTP/1.1 && !HttpConnection==close then chunk - // 4. Content-Length - // 5. multipart/byteranges - // 6. close - switch ((int) _contentLength) - { - case HttpTokens.UNKNOWN_CONTENT: - // It may be that we have no _content, or perhaps _content just has not been - // written yet? + // Calculate how to end _content and connection, _content length and transfer encoding + // settings. + // From RFC 2616 4.4: + // 1. No body for 1xx, 204, 304 & HEAD response + // 2. Force _content-length? + // 3. If Transfer-Encoding!=identity && HTTP/1.1 && !HttpConnection==close then chunk + // 4. Content-Length + // 5. multipart/byteranges + // 6. close + switch ((int) _contentLength) + { + case HttpTokens.UNKNOWN_CONTENT: + // It may be that we have no _content, or perhaps _content just has not been + // written yet? - // Response known not to have a body - if (_contentWritten == 0 && isResponse() && (_status < 200 || _status == 204 || _status == 304)) - _contentLength = HttpTokens.NO_CONTENT; - else if (_last) - { - // we have seen all the _content there is - _contentLength = _contentWritten; - if (content_length == null && (isResponse() || _contentLength>0 || content_type ) && !_noContent) - { - // known length but not actually set. - _header.put(HttpHeaders.CONTENT_LENGTH_BUFFER); - _header.put(HttpTokens.COLON); - _header.put((byte) ' '); - BufferUtil.putDecLong(_header, _contentLength); - _header.put(HttpTokens.CRLF); - } - } - else - { - // No idea, so we must assume that a body is coming - _contentLength = (!_persistent || _version < HttpVersions.HTTP_1_1_ORDINAL ) ? HttpTokens.EOF_CONTENT : HttpTokens.CHUNKED_CONTENT; - if (isRequest() && _contentLength==HttpTokens.EOF_CONTENT) - { - _contentLength=HttpTokens.NO_CONTENT; - _noContent=true; - } - } - break; + // Response known not to have a body + if (_contentWritten == 0 && isResponse() && (_status < 200 || _status == 204 || _status == 304)) + _contentLength = HttpTokens.NO_CONTENT; + else if (_last) + { + // we have seen all the _content there is + _contentLength = _contentWritten; + if (content_length == null && (isResponse() || _contentLength>0 || content_type ) && !_noContent) + { + // known length but not actually set. + _header.put(HttpHeaders.CONTENT_LENGTH_BUFFER); + _header.put(HttpTokens.COLON); + _header.put((byte) ' '); + BufferUtil.putDecLong(_header, _contentLength); + _header.put(HttpTokens.CRLF); + } + } + else + { + // No idea, so we must assume that a body is coming + _contentLength = (!_persistent || _version < HttpVersions.HTTP_1_1_ORDINAL ) ? HttpTokens.EOF_CONTENT : HttpTokens.CHUNKED_CONTENT; + if (isRequest() && _contentLength==HttpTokens.EOF_CONTENT) + { + _contentLength=HttpTokens.NO_CONTENT; + _noContent=true; + } + } + break; - case HttpTokens.NO_CONTENT: - if (content_length == null && isResponse() && _status >= 200 && _status != 204 && _status != 304) - _header.put(CONTENT_LENGTH_0); - break; + case HttpTokens.NO_CONTENT: + if (content_length == null && isResponse() && _status >= 200 && _status != 204 && _status != 304) + _header.put(CONTENT_LENGTH_0); + break; - case HttpTokens.EOF_CONTENT: - _persistent = isRequest(); - break; + case HttpTokens.EOF_CONTENT: + _persistent = isRequest(); + break; - case HttpTokens.CHUNKED_CONTENT: - break; + case HttpTokens.CHUNKED_CONTENT: + break; - default: - // TODO - maybe allow forced chunking by setting te ??? - break; - } + default: + // TODO - maybe allow forced chunking by setting te ??? + break; + } - // Add transfer_encoding if needed - if (_contentLength == HttpTokens.CHUNKED_CONTENT) - { - // try to use user supplied encoding as it may have other values. - if (transfer_encoding != null && HttpHeaderValues.CHUNKED_ORDINAL != transfer_encoding.getValueOrdinal()) - { - String c = transfer_encoding.getValue(); - if (c.endsWith(HttpHeaderValues.CHUNKED)) - transfer_encoding.putTo(_header); - else - throw new IllegalArgumentException("BAD TE"); - } - else - _header.put(TRANSFER_ENCODING_CHUNKED); - } + // Add transfer_encoding if needed + if (_contentLength == HttpTokens.CHUNKED_CONTENT) + { + // try to use user supplied encoding as it may have other values. + if (transfer_encoding != null && HttpHeaderValues.CHUNKED_ORDINAL != transfer_encoding.getValueOrdinal()) + { + String c = transfer_encoding.getValue(); + if (c.endsWith(HttpHeaderValues.CHUNKED)) + transfer_encoding.putTo(_header); + else + throw new IllegalArgumentException("BAD TE"); + } + else + _header.put(TRANSFER_ENCODING_CHUNKED); + } - // Handle connection if need be - if (_contentLength==HttpTokens.EOF_CONTENT) - { - keep_alive=false; - _persistent=false; - } + // Handle connection if need be + if (_contentLength==HttpTokens.EOF_CONTENT) + { + keep_alive=false; + _persistent=false; + } - if (isResponse()) - { - if (!_persistent && (close || _version > HttpVersions.HTTP_1_0_ORDINAL)) - { - _header.put(CONNECTION_CLOSE); - if (connection!=null) - { - _header.setPutIndex(_header.putIndex()-2); - _header.put((byte)','); - _header.put(connection.toString().getBytes()); - _header.put(CRLF); - } - } - else if (keep_alive) - { - _header.put(CONNECTION_KEEP_ALIVE); - if (connection!=null) - { - _header.setPutIndex(_header.putIndex()-2); - _header.put((byte)','); - _header.put(connection.toString().getBytes()); - _header.put(CRLF); - } - } - else if (connection!=null) - { - _header.put(CONNECTION_); - _header.put(connection.toString().getBytes()); - _header.put(CRLF); - } - } + if (isResponse()) + { + if (!_persistent && (close || _version > HttpVersions.HTTP_1_0_ORDINAL)) + { + _header.put(CONNECTION_CLOSE); + if (connection!=null) + { + _header.setPutIndex(_header.putIndex()-2); + _header.put((byte)','); + _header.put(connection.toString().getBytes()); + _header.put(CRLF); + } + } + else if (keep_alive) + { + _header.put(CONNECTION_KEEP_ALIVE); + if (connection!=null) + { + _header.setPutIndex(_header.putIndex()-2); + _header.put((byte)','); + _header.put(connection.toString().getBytes()); + _header.put(CRLF); + } + } + else if (connection!=null) + { + _header.put(CONNECTION_); + _header.put(connection.toString().getBytes()); + _header.put(CRLF); + } + } - if (!has_server && _status>199 && getSendServerVersion()) - _header.put(SERVER); + if (!has_server && _status>199) + _header.put(SERVER); - // end the header. - _header.put(HttpTokens.CRLF); - _state = STATE_CONTENT; + // end the header. + _header.put(HttpTokens.CRLF); + _state = STATE_CONTENT; - } - catch(ArrayIndexOutOfBoundsException e) - { - throw new RuntimeException("Header>"+_header.capacity(),e); - } - } + } + catch(ArrayIndexOutOfBoundsException e) + { + throw new RuntimeException("Header>"+_header.capacity(),e); + } + } - /* ------------------------------------------------------------ */ - /** - * Complete the message. - * - * @throws IOException - */ - @Override - public void complete() throws IOException - { - if (_state == STATE_END) - return; + /* ------------------------------------------------------------ */ + /** + * Complete the message. + * + * @throws IOException + */ + @Override + public void complete() throws IOException + { + if (_state == STATE_END) + return; - super.complete(); + super.complete(); - if (_state < STATE_FLUSHING) - { - _state = STATE_FLUSHING; - if (_contentLength == HttpTokens.CHUNKED_CONTENT) - _needEOC = true; - } + if (_state < STATE_FLUSHING) + { + _state = STATE_FLUSHING; + if (_contentLength == HttpTokens.CHUNKED_CONTENT) + _needEOC = true; + } - flushBuffer(); - } + flushBuffer(); + } - /* ------------------------------------------------------------ */ - @Override - public int flushBuffer() throws IOException - { - try - { + /* ------------------------------------------------------------ */ + @Override + public int flushBuffer() throws IOException + { + try + { - if (_state == STATE_HEADER) - throw new IllegalStateException("State==HEADER"); + if (_state == STATE_HEADER) + throw new IllegalStateException("State==HEADER"); - prepareBuffers(); + prepareBuffers(); - if (_endp == null) - { - if (_needCRLF && _buffer!=null) - _buffer.put(HttpTokens.CRLF); - if (_needEOC && _buffer!=null && !_head) - _buffer.put(LAST_CHUNK); - _needCRLF=false; - _needEOC=false; - return 0; - } + if (_endp == null) + { + if (_needCRLF && _buffer!=null) + _buffer.put(HttpTokens.CRLF); + if (_needEOC && _buffer!=null && !_head) + _buffer.put(LAST_CHUNK); + _needCRLF=false; + _needEOC=false; + return 0; + } - int total= 0; + int total= 0; - int len = -1; - int to_flush = flushMask(); - int last_flush; + int len = -1; + int to_flush = flushMask(); + int last_flush; - do - { - last_flush=to_flush; - switch (to_flush) - { - case 7: - throw new IllegalStateException(); // should never happen! - case 6: - len = _endp.flush(_header, _buffer, null); - break; - case 5: - len = _endp.flush(_header, _content, null); - break; - case 4: - len = _endp.flush(_header); - break; - case 3: - len = _endp.flush(_buffer, _content, null); - break; - case 2: - len = _endp.flush(_buffer); - break; - case 1: - len = _endp.flush(_content); - break; - case 0: - { - len=0; - // Nothing more we can write now. - if (_header != null) - _header.clear(); + do + { + last_flush=to_flush; + switch (to_flush) + { + case 7: + throw new IllegalStateException(); // should never happen! + case 6: + len = _endp.flush(_header, _buffer, null); + break; + case 5: + len = _endp.flush(_header, _content, null); + break; + case 4: + len = _endp.flush(_header); + break; + case 3: + len = _endp.flush(_buffer, _content, null); + break; + case 2: + len = _endp.flush(_buffer); + break; + case 1: + len = _endp.flush(_content); + break; + case 0: + { + len=0; + // Nothing more we can write now. + if (_header != null) + _header.clear(); - _bypass = false; - _bufferChunked = false; + _bypass = false; + _bufferChunked = false; - if (_buffer != null) - { - _buffer.clear(); - if (_contentLength == HttpTokens.CHUNKED_CONTENT) - { - // reserve some space for the chunk header - _buffer.setPutIndex(CHUNK_SPACE); - _buffer.setGetIndex(CHUNK_SPACE); + if (_buffer != null) + { + _buffer.clear(); + if (_contentLength == HttpTokens.CHUNKED_CONTENT) + { + // reserve some space for the chunk header + _buffer.setPutIndex(CHUNK_SPACE); + _buffer.setGetIndex(CHUNK_SPACE); - // Special case handling for small left over buffer from - // an addContent that caused a buffer flush. - if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING) - { - _buffer.put(_content); - _content.clear(); - _content=null; - } - } - } + // Special case handling for small left over buffer from + // an addContent that caused a buffer flush. + if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING) + { + _buffer.put(_content); + _content.clear(); + _content=null; + } + } + } - // Are we completely finished for now? - if (!_needCRLF && !_needEOC && (_content==null || _content.length()==0)) - { - if (_state == STATE_FLUSHING) - _state = STATE_END; + // Are we completely finished for now? + if (!_needCRLF && !_needEOC && (_content==null || _content.length()==0)) + { + if (_state == STATE_FLUSHING) + _state = STATE_END; - if (_state==STATE_END && _persistent != null && !_persistent && _status!=100 && _method==null) - _endp.shutdownOutput(); - } - else - // Try to prepare more to write. - prepareBuffers(); - } + if (_state==STATE_END && _persistent != null && !_persistent && _status!=100 && _method==null) + _endp.shutdownOutput(); + } + else + // Try to prepare more to write. + prepareBuffers(); + } - } + } - if (len > 0) - total+=len; + if (len > 0) + total+=len; - to_flush = flushMask(); - } - // loop while progress is being made (OR we have prepared some buffers that might make progress) - while (len>0 || (to_flush!=0 && last_flush==0)); + to_flush = flushMask(); + } + // loop while progress is being made (OR we have prepared some buffers that might make progress) + while (len>0 || (to_flush!=0 && last_flush==0)); - return total; - } - catch (IOException e) - { - LOG.trace("",e); - throw (e instanceof EofException) ? e:new EofException(e); - } - } + return total; + } + catch (IOException e) + { + LOG.trace("",e); + throw (e instanceof EofException) ? e:new EofException(e); + } + } - /* ------------------------------------------------------------ */ - private int flushMask() - { - return ((_header != null && _header.length() > 0)?4:0) - | ((_buffer != null && _buffer.length() > 0)?2:0) - | ((_bypass && _content != null && _content.length() > 0)?1:0); - } + /* ------------------------------------------------------------ */ + private int flushMask() + { + return ((_header != null && _header.length() > 0)?4:0) + | ((_buffer != null && _buffer.length() > 0)?2:0) + | ((_bypass && _content != null && _content.length() > 0)?1:0); + } - /* ------------------------------------------------------------ */ - private void prepareBuffers() - { - // if we are not flushing an existing chunk - if (!_bufferChunked) - { - // Refill buffer if possible - if (!_bypass && _content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0) - { - int len = _buffer.put(_content); - _content.skip(len); - if (_content.length() == 0) - _content = null; - } + /* ------------------------------------------------------------ */ + private void prepareBuffers() + { + // if we are not flushing an existing chunk + if (!_bufferChunked) + { + // Refill buffer if possible + if (!_bypass && _content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0) + { + int len = _buffer.put(_content); + _content.skip(len); + if (_content.length() == 0) + _content = null; + } - // Chunk buffer if need be - if (_contentLength == HttpTokens.CHUNKED_CONTENT) - { - if (_bypass && (_buffer==null||_buffer.length()==0) && _content!=null) - { - // this is a bypass write - int size = _content.length(); - _bufferChunked = true; + // Chunk buffer if need be + if (_contentLength == HttpTokens.CHUNKED_CONTENT) + { + if (_bypass && (_buffer==null||_buffer.length()==0) && _content!=null) + { + // this is a bypass write + int size = _content.length(); + _bufferChunked = true; - if (_header == null) - _header = _buffers.getHeader(); + if (_header == null) + _header = _buffers.getHeader(); - // if we need CRLF add this to header - if (_needCRLF) - { - if (_header.length() > 0) throw new IllegalStateException("EOC"); - _header.put(HttpTokens.CRLF); - _needCRLF = false; - } - // Add the chunk size to the header - BufferUtil.putHexInt(_header, size); - _header.put(HttpTokens.CRLF); + // if we need CRLF add this to header + if (_needCRLF) + { + if (_header.length() > 0) throw new IllegalStateException("EOC"); + _header.put(HttpTokens.CRLF); + _needCRLF = false; + } + // Add the chunk size to the header + BufferUtil.putHexInt(_header, size); + _header.put(HttpTokens.CRLF); - // Need a CRLF after the content - _needCRLF=true; - } - else if (_buffer!=null) - { - int size = _buffer.length(); - if (size > 0) - { - // Prepare a chunk! - _bufferChunked = true; + // Need a CRLF after the content + _needCRLF=true; + } + else if (_buffer!=null) + { + int size = _buffer.length(); + if (size > 0) + { + // Prepare a chunk! + _bufferChunked = true; - // Did we leave space at the start of the buffer. - //noinspection ConstantConditions - if (_buffer.getIndex() == CHUNK_SPACE) - { - // Oh yes, goodie! let's use it then! - _buffer.poke(_buffer.getIndex() - 2, HttpTokens.CRLF, 0, 2); - _buffer.setGetIndex(_buffer.getIndex() - 2); - BufferUtil.prependHexInt(_buffer, size); + // Did we leave space at the start of the buffer. + //noinspection ConstantConditions + if (_buffer.getIndex() == CHUNK_SPACE) + { + // Oh yes, goodie! let's use it then! + _buffer.poke(_buffer.getIndex() - 2, HttpTokens.CRLF, 0, 2); + _buffer.setGetIndex(_buffer.getIndex() - 2); + BufferUtil.prependHexInt(_buffer, size); - if (_needCRLF) - { - _buffer.poke(_buffer.getIndex() - 2, HttpTokens.CRLF, 0, 2); - _buffer.setGetIndex(_buffer.getIndex() - 2); - _needCRLF = false; - } - } - else - { - // No space so lets use a header buffer. - if (_header == null) - _header = _buffers.getHeader(); + if (_needCRLF) + { + _buffer.poke(_buffer.getIndex() - 2, HttpTokens.CRLF, 0, 2); + _buffer.setGetIndex(_buffer.getIndex() - 2); + _needCRLF = false; + } + } + else + { + // No space so lets use a header buffer. + if (_header == null) + _header = _buffers.getHeader(); - if (_needCRLF) - { - if (_header.length() > 0) throw new IllegalStateException("EOC"); - _header.put(HttpTokens.CRLF); - _needCRLF = false; - } - BufferUtil.putHexInt(_header, size); - _header.put(HttpTokens.CRLF); - } + if (_needCRLF) + { + if (_header.length() > 0) throw new IllegalStateException("EOC"); + _header.put(HttpTokens.CRLF); + _needCRLF = false; + } + BufferUtil.putHexInt(_header, size); + _header.put(HttpTokens.CRLF); + } - // Add end chunk trailer. - if (_buffer.space() >= 2) - _buffer.put(HttpTokens.CRLF); - else - _needCRLF = true; - } - } + // Add end chunk trailer. + if (_buffer.space() >= 2) + _buffer.put(HttpTokens.CRLF); + else + _needCRLF = true; + } + } - // If we need EOC and everything written - if (_needEOC && (_content == null || _content.length() == 0)) - { - if (_header == null && _buffer == null) - _header = _buffers.getHeader(); + // If we need EOC and everything written + if (_needEOC && (_content == null || _content.length() == 0)) + { + if (_header == null && _buffer == null) + _header = _buffers.getHeader(); - if (_needCRLF) - { - if (_buffer == null && _header != null && _header.space() >= HttpTokens.CRLF.length) - { - _header.put(HttpTokens.CRLF); - _needCRLF = false; - } - else if (_buffer!=null && _buffer.space() >= HttpTokens.CRLF.length) - { - _buffer.put(HttpTokens.CRLF); - _needCRLF = false; - } - } + if (_needCRLF) + { + if (_buffer == null && _header != null && _header.space() >= HttpTokens.CRLF.length) + { + _header.put(HttpTokens.CRLF); + _needCRLF = false; + } + else if (_buffer!=null && _buffer.space() >= HttpTokens.CRLF.length) + { + _buffer.put(HttpTokens.CRLF); + _needCRLF = false; + } + } - if (!_needCRLF && _needEOC) - { - if (_buffer == null && _header != null && _header.space() >= LAST_CHUNK.length) - { - if (!_head) - { - _header.put(LAST_CHUNK); - _bufferChunked=true; - } - _needEOC = false; - } - else if (_buffer!=null && _buffer.space() >= LAST_CHUNK.length) - { - if (!_head) - { - _buffer.put(LAST_CHUNK); - _bufferChunked=true; - } - _needEOC = false; - } - } - } - } - } + if (!_needCRLF && _needEOC) + { + if (_buffer == null && _header != null && _header.space() >= LAST_CHUNK.length) + { + if (!_head) + { + _header.put(LAST_CHUNK); + _bufferChunked=true; + } + _needEOC = false; + } + else if (_buffer!=null && _buffer.space() >= LAST_CHUNK.length) + { + if (!_head) + { + _buffer.put(LAST_CHUNK); + _bufferChunked=true; + } + _needEOC = false; + } + } + } + } + } - if (_content != null && _content.length() == 0) - _content = null; + if (_content != null && _content.length() == 0) + _content = null; - } + } - public int getBytesBuffered() - { - return(_header==null?0:_header.length())+ - (_buffer==null?0:_buffer.length())+ - (_content==null?0:_content.length()); - } + public int getBytesBuffered() + { + return(_header==null?0:_header.length())+ + (_buffer==null?0:_buffer.length())+ + (_content==null?0:_content.length()); + } - public boolean isEmpty() - { - return (_header==null||_header.length()==0) && - (_buffer==null||_buffer.length()==0) && - (_content==null||_content.length()==0); - } + public boolean isEmpty() + { + return (_header==null||_header.length()==0) && + (_buffer==null||_buffer.length()==0) && + (_content==null||_content.length()==0); + } - @Override - public String toString() - { - Buffer header=_header; - Buffer buffer=_buffer; - Buffer content=_content; - return String.format("%s{s=%d,h=%d,b=%d,c=%d}", - getClass().getSimpleName(), - _state, - header == null ? -1 : header.length(), - buffer == null ? -1 : buffer.length(), - content == null ? -1 : content.length()); - } + @Override + public String toString() + { + Buffer header=_header; + Buffer buffer=_buffer; + Buffer content=_content; + return String.format("%s{s=%d,h=%d,b=%d,c=%d}", + getClass().getSimpleName(), + _state, + header == null ? -1 : header.length(), + buffer == null ? -1 : buffer.length(), + content == null ? -1 : content.length()); + } }