| // ======================================================================== |
| // Copyright (c) 2010-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.nested; |
| |
| import java.io.IOException; |
| |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.eclipse.jetty.http.AbstractGenerator; |
| import org.eclipse.jetty.http.HttpFields; |
| import org.eclipse.jetty.http.HttpHeaders; |
| import org.eclipse.jetty.http.HttpVersions; |
| import org.eclipse.jetty.io.Buffer; |
| import org.eclipse.jetty.io.Buffers; |
| import org.eclipse.jetty.io.EndPoint; |
| import org.eclipse.jetty.server.Server; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| |
| public class NestedGenerator extends AbstractGenerator |
| { |
| private static final Logger LOG = Log.getLogger(NestedGenerator.class); |
| |
| final HttpServletResponse _response; |
| final String _nestedIn; |
| |
| public NestedGenerator(Buffers buffers, EndPoint io, HttpServletResponse response, String nestedIn) |
| { |
| super(buffers,io); |
| _response=response; |
| _nestedIn=nestedIn; |
| } |
| |
| public void addContent(Buffer content, boolean last) throws IOException |
| { |
| LOG.debug("addContent {} {}",content.length(),last); |
| if (_noContent) |
| { |
| content.clear(); |
| return; |
| } |
| |
| if (content.isImmutable()) |
| throw new IllegalArgumentException("immutable"); |
| |
| if (_last || _state == STATE_END) |
| { |
| LOG.debug("Ignoring extra content {}", content); |
| content.clear(); |
| return; |
| } |
| _last = last; |
| |
| if(!_endp.isOpen()) |
| { |
| _state = STATE_END; |
| return; |
| } |
| |
| // Handle any unfinished business? |
| if (_content != null && _content.length() > 0) |
| { |
| flushBuffer(); |
| if (_content != null && _content.length() > 0) |
| throw new IllegalStateException("FULL"); |
| } |
| |
| _content = content; |
| |
| _contentWritten += content.length(); |
| |
| // Handle the _content |
| if (_head) |
| { |
| content.clear(); |
| _content = null; |
| } |
| else if (!last || _buffer!=null) |
| { |
| // Yes - so we better check we have a buffer |
| initBuffer(); |
| // Copy _content to buffer; |
| int len = 0; |
| len = _buffer.put(_content); |
| |
| // make sure there is space for a trailing null (???) |
| if (len > 0 && _buffer.space() == 0) |
| { |
| len--; |
| _buffer.setPutIndex(_buffer.putIndex() - 1); |
| } |
| |
| LOG.debug("copied {} to buffer",len); |
| |
| _content.skip(len); |
| |
| if (_content.length() == 0) |
| _content = null; |
| } |
| } |
| |
| public boolean addContent(byte b) throws IOException |
| { |
| // LOG.debug("addContent 1"); |
| if (_noContent) |
| return false; |
| |
| if (_last || _state == STATE_END) |
| throw new IllegalStateException("Closed"); |
| |
| |
| if(!_endp.isOpen()) |
| { |
| _state = STATE_END; |
| return false; |
| } |
| |
| // Handle any unfinished business? |
| if (_content != null && _content.length() > 0) |
| { |
| flushBuffer(); |
| if (_content != null && _content.length() > 0) |
| throw new IllegalStateException("FULL"); |
| } |
| |
| _contentWritten++; |
| |
| // Handle the _content |
| if (_head) |
| return false; |
| |
| // we better check we have a buffer |
| initBuffer(); |
| |
| // Copy _content to buffer; |
| |
| _buffer.put(b); |
| |
| return _buffer.space() <= 1; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| private void initBuffer() throws IOException |
| { |
| if (_buffer == null) |
| { |
| // LOG.debug("initContent"); |
| _buffer = _buffers.getBuffer(); |
| } |
| } |
| |
| /* ------------------------------------------------------------ */ |
| @Override |
| public boolean isRequest() |
| { |
| return false; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| @Override |
| public boolean isResponse() |
| { |
| return true; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| @Override |
| public int prepareUncheckedAddContent() throws IOException |
| { |
| initBuffer(); |
| return _buffer.space(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| @Override |
| public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException |
| { |
| if (LOG.isDebugEnabled()) |
| LOG.debug("completeHeader: {}",fields.toString().trim().replace("\r\n","|")); |
| if (_state != STATE_HEADER) |
| return; |
| |
| if (_last && !allContentAdded) |
| throw new IllegalStateException("last?"); |
| _last = _last | allContentAdded; |
| |
| if (_persistent==null) |
| _persistent=(_version > HttpVersions.HTTP_1_0_ORDINAL); |
| |
| |
| if (_reason == null) |
| _response.setStatus(_status); |
| else |
| _response.setStatus(_status,_reason.toString()); |
| |
| if (_status == 100 || _status == 204 || _status == 304) |
| { |
| _noContent = true; |
| _content = null; |
| } |
| |
| |
| boolean has_server = false; |
| if (fields != null) |
| { |
| // Add headers |
| int s=fields.size(); |
| for (int f=0;f<s;f++) |
| { |
| HttpFields.Field field = fields.getField(f); |
| if (field==null) |
| continue; |
| _response.setHeader(field.getName(),field.getValue()); |
| } |
| } |
| |
| if (!has_server && _status > 100 && getSendServerVersion()) |
| _response.setHeader(HttpHeaders.SERVER,"Jetty("+Server.getVersion()+",nested in "+_nestedIn+")"); |
| |
| _state = STATE_CONTENT; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Complete the message. |
| * |
| * @throws IOException |
| */ |
| @Override |
| public void complete() throws IOException |
| { |
| if (_state == STATE_END) |
| return; |
| |
| super.complete(); |
| |
| if (_state < STATE_FLUSHING) |
| _state = STATE_FLUSHING; |
| |
| flushBuffer(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| @Override |
| public int flushBuffer() throws IOException |
| { |
| if (_state == STATE_HEADER) |
| throw new IllegalStateException("State==HEADER"); |
| |
| int len = 0; |
| |
| if (_buffer==null) |
| { |
| |
| if (_content!=null && _content.length()>0) |
| { |
| // flush content directly |
| len = _endp.flush(_content); |
| if (len>0) |
| _content.skip(len); |
| } |
| } |
| else |
| { |
| if (_buffer.length()==0 && _content!=null && _content.length()>0) |
| { |
| // Copy content to buffer |
| _content.skip(_buffer.put(_content)); |
| } |
| |
| int size=_buffer.length(); |
| len =_endp.flush(_buffer); |
| LOG.debug("flushBuffer {} of {}",len,size); |
| if (len>0) |
| _buffer.skip(len); |
| } |
| |
| if (_content!=null && _content.length()==0) |
| _content=null; |
| if (_buffer!=null && _buffer.length()==0 && _content==null) |
| { |
| _buffers.returnBuffer(_buffer); |
| _buffer=null; |
| } |
| |
| if (_state==STATE_FLUSHING && _buffer==null && _content==null) |
| _state=STATE_END; |
| |
| return len; |
| } |
| |
| } |