392237 Implemented HttpOutput.sendContent for large content
This commit is contained in:
parent
11fb3fa91e
commit
f420f5016d
|
@ -41,7 +41,7 @@ public class LikeJettyXml
|
|||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
String jetty_home = System.getProperty("jetty.home","../jetty-distribution/target/distribution");
|
||||
String jetty_home = System.getProperty("jetty.home","../../jetty-distribution/target/distribution");
|
||||
System.setProperty("jetty.home",jetty_home);
|
||||
|
||||
// Setup Threadpool
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.http;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
|
@ -38,6 +39,7 @@ public interface HttpContent
|
|||
Resource getResource();
|
||||
long getContentLength();
|
||||
InputStream getInputStream() throws IOException;
|
||||
ReadableByteChannel getReadableByteChannel() throws IOException;
|
||||
void release();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -130,6 +132,13 @@ public interface HttpContent
|
|||
{
|
||||
return _resource.getInputStream();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ReadableByteChannel getReadableByteChannel() throws IOException
|
||||
{
|
||||
return _resource.getReadableByteChannel();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
|
|
|
@ -120,6 +120,11 @@ public class ChannelEndPoint extends AbstractEndPoint implements SocketBased
|
|||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_ishut=true;
|
||||
_oshut=true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -179,7 +184,7 @@ public class ChannelEndPoint extends AbstractEndPoint implements SocketBased
|
|||
}
|
||||
LOG.debug("flushed {} {}", flushed, this);
|
||||
}
|
||||
catch (ClosedChannelException | EOFException | SocketException e)
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new EofException(e);
|
||||
}
|
||||
|
|
|
@ -330,20 +330,16 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
if (!committed)
|
||||
LOG.warn("Could not send response error 500: "+x);
|
||||
}
|
||||
else if (isCommitted())
|
||||
{
|
||||
if (!(x instanceof EofException))
|
||||
LOG.warn("Could not send response error 500: "+x);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: this error handling here must be atomic as above.
|
||||
// TODO: response.sendError() should call back the HttpChannel in order to perform the atomic commit
|
||||
if (!isCommitted())
|
||||
{
|
||||
_request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,x);
|
||||
_request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,x.getClass());
|
||||
_response.sendError(500, x.getMessage());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.warn("Could not send response error 500: "+x);
|
||||
}
|
||||
_request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,x);
|
||||
_request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,x.getClass());
|
||||
_response.sendError(500, x.getMessage());
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.io.EOFException;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
|
@ -32,6 +33,8 @@ import org.eclipse.jetty.http.HttpContent;
|
|||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
/**
|
||||
|
@ -46,6 +49,7 @@ import org.eclipse.jetty.util.resource.Resource;
|
|||
*/
|
||||
public class HttpOutput extends ServletOutputStream
|
||||
{
|
||||
private static Logger LOG = Log.getLogger(HttpOutput.class);
|
||||
private final HttpChannel<?> _channel;
|
||||
private boolean _closed;
|
||||
private long _written;
|
||||
|
@ -80,14 +84,22 @@ public class HttpOutput extends ServletOutputStream
|
|||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
public void close()
|
||||
{
|
||||
if (!_closed)
|
||||
{
|
||||
if (BufferUtil.hasContent(_aggregate))
|
||||
_channel.write(_aggregate, !_channel.getResponse().isIncluding());
|
||||
else
|
||||
_channel.write(BufferUtil.EMPTY_BUFFER, !_channel.getResponse().isIncluding());
|
||||
try
|
||||
{
|
||||
if (BufferUtil.hasContent(_aggregate))
|
||||
_channel.write(_aggregate, !_channel.getResponse().isIncluding());
|
||||
else
|
||||
_channel.write(BufferUtil.EMPTY_BUFFER, !_channel.getResponse().isIncluding());
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
_channel.getEndPoint().shutdownOutput();
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
_closed = true;
|
||||
if (_aggregate != null)
|
||||
|
@ -228,6 +240,8 @@ public class HttpOutput extends ServletOutputStream
|
|||
content = httpContent.getDirectBuffer();
|
||||
if (content == null)
|
||||
content = httpContent.getIndirectBuffer();
|
||||
if (content == null)
|
||||
content = httpContent.getReadableByteChannel();
|
||||
if (content == null)
|
||||
content = httpContent.getInputStream();
|
||||
}
|
||||
|
@ -243,12 +257,56 @@ public class HttpOutput extends ServletOutputStream
|
|||
{
|
||||
_channel.write((ByteBuffer)content, true); // TODO: we have written all content ?
|
||||
}
|
||||
else if (content instanceof ReadableByteChannel)
|
||||
{
|
||||
ReadableByteChannel channel = (ReadableByteChannel)content;
|
||||
ByteBuffer buffer = _channel.getByteBufferPool().acquire(getBufferSize(), true);
|
||||
try
|
||||
{
|
||||
while(channel.isOpen())
|
||||
{
|
||||
int pos = BufferUtil.flipToFill(buffer);
|
||||
int len=channel.read(buffer);
|
||||
if (len<0)
|
||||
break;
|
||||
BufferUtil.flipToFlush(buffer,pos);
|
||||
_channel.write(buffer,false);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
close();
|
||||
_channel.getByteBufferPool().release(buffer);
|
||||
}
|
||||
}
|
||||
else if (content instanceof InputStream)
|
||||
{
|
||||
throw new IllegalArgumentException("not implemented!");
|
||||
InputStream in = (InputStream)content;
|
||||
ByteBuffer buffer = _channel.getByteBufferPool().acquire(getBufferSize(), false);
|
||||
byte[] array = buffer.array();
|
||||
int offset=buffer.arrayOffset();
|
||||
int size=array.length-offset;
|
||||
try
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
int len=in.read(array,offset,size);
|
||||
if (len<0)
|
||||
break;
|
||||
buffer.position(0);
|
||||
buffer.limit(len);
|
||||
_channel.write(buffer,false);
|
||||
}
|
||||
_channel.write(BufferUtil.EMPTY_BUFFER,true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
close();
|
||||
_channel.getByteBufferPool().release(buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new IllegalArgumentException("unknown content type?");
|
||||
throw new IllegalArgumentException("unknown content type "+content.getClass());
|
||||
}
|
||||
|
||||
public int getBufferSize()
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.Comparator;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
@ -526,6 +527,14 @@ public class ResourceCache
|
|||
|
||||
return _resource.getInputStream();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ReadableByteChannel getReadableByteChannel() throws IOException
|
||||
{
|
||||
return _resource.getReadableByteChannel();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
|
|
|
@ -272,18 +272,6 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected Map<String,Object> getAttributeMap ()
|
||||
{
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void addAttributes(Map<String,Object> map)
|
||||
{
|
||||
_attributes.putAll(map);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected boolean access(long time)
|
||||
{
|
||||
|
@ -474,6 +462,12 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void addAttributes(Map<String,Object> map)
|
||||
{
|
||||
_attributes.putAll(map);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
public void setIdChanged(boolean changed)
|
||||
{
|
||||
|
|
|
@ -29,6 +29,10 @@ import java.net.URI;
|
|||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.security.Permission;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
|
@ -281,7 +285,14 @@ public class FileResource extends URLResource
|
|||
{
|
||||
return new FileInputStream(_file);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ReadableByteChannel getReadableByteChannel() throws IOException
|
||||
{
|
||||
return FileChannel.open(_file.toPath(),StandardOpenOption.READ);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Returns an output stream to the resource
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.net.MalformedURLException;
|
|||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
@ -408,6 +409,13 @@ public abstract class Resource implements ResourceFactory
|
|||
*/
|
||||
public abstract InputStream getInputStream()
|
||||
throws java.io.IOException;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns an readable bytechannel to the resource or null if one is not available.
|
||||
*/
|
||||
public abstract ReadableByteChannel getReadableByteChannel()
|
||||
throws java.io.IOException;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
@ -328,6 +329,22 @@ public class ResourceCollection extends Resource
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ReadableByteChannel getReadableByteChannel() throws IOException
|
||||
{
|
||||
if(_resources==null)
|
||||
throw new IllegalStateException("*resources* not set.");
|
||||
|
||||
for(Resource r : _resources)
|
||||
{
|
||||
ReadableByteChannel channel = r.getReadableByteChannel();
|
||||
if(channel!=null)
|
||||
return channel;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.io.OutputStream;
|
|||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.security.Permission;
|
||||
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
@ -224,6 +225,12 @@ public class URLResource extends Resource
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ReadableByteChannel getReadableByteChannel() throws IOException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -96,6 +97,12 @@ public class OrderingTest
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadableByteChannel getReadableByteChannel() throws IOException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.resource.Resource#getName()
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue