blob: 47d74c3d1eea5d7bf5a1731c61c27f0bf35b0170 [file] [log] [blame]
// ========================================================================
// 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;
}
}