Merge remote-tracking branch 'origin/jetty-9.3.x' into jetty-9.4.x
This commit is contained in:
commit
a90e197633
|
@ -718,6 +718,13 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
|||
_written+=BufferUtil.length(content);
|
||||
sendResponse(null,content,complete,callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetBuffer()
|
||||
{
|
||||
if(isCommitted())
|
||||
throw new IllegalStateException("Committed");
|
||||
}
|
||||
|
||||
public HttpOutput.Interceptor getNextInterceptor()
|
||||
{
|
||||
|
|
|
@ -54,12 +54,66 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* close the stream, to be reopened after the inclusion ends.</p>
|
||||
*/
|
||||
public class HttpOutput extends ServletOutputStream implements Runnable
|
||||
{
|
||||
{
|
||||
|
||||
/**
|
||||
* The HttpOutput.Inteceptor is a single intercept point for all
|
||||
* output written to the HttpOutput: via writer; via output stream;
|
||||
* asynchronously; or blocking.
|
||||
* <p>
|
||||
* The Interceptor can be used to implement translations (eg Gzip) or
|
||||
* additional buffering that acts on all output. Interceptors are
|
||||
* created in a chain, so that multiple concerns may intercept.
|
||||
* <p>
|
||||
* The {@link HttpChannel} is an {@link Interceptor} and is always the
|
||||
* last link in any Interceptor chain.
|
||||
* <p>
|
||||
* Responses are committed by the first call to
|
||||
* {@link #write(ByteBuffer, boolean, Callback)}
|
||||
* and closed by a call to {@link #write(ByteBuffer, boolean, Callback)}
|
||||
* with the last boolean set true. If no content is available to commit
|
||||
* or close, then a null buffer is passed.
|
||||
*/
|
||||
public interface Interceptor
|
||||
{
|
||||
void write(ByteBuffer content, boolean complete, Callback callback);
|
||||
/**
|
||||
* Write content.
|
||||
* The response is committed by the first call to write and is closed by
|
||||
* a call with last == true. Empty content buffers may be passed to
|
||||
* force a commit or close.
|
||||
* @param content The content to be written or an empty buffer.
|
||||
* @param last True if this is the last call to write
|
||||
* @param callback The callback to use to indicate {@link Callback#succeeded()}
|
||||
* or {@link Callback#failed(Throwable)}.
|
||||
*/
|
||||
void write(ByteBuffer content, boolean last, Callback callback);
|
||||
|
||||
/**
|
||||
* @return The next Interceptor in the chain or null if this is the
|
||||
* last Interceptor in the chain.
|
||||
*/
|
||||
Interceptor getNextInterceptor();
|
||||
|
||||
/**
|
||||
* @return True if the Interceptor is optimized to receive direct
|
||||
* {@link ByteBuffer}s in the {@link #write(ByteBuffer, boolean, Callback)}
|
||||
* method. If false is returned, then passing direct buffers may cause
|
||||
* inefficiencies.
|
||||
*/
|
||||
boolean isOptimizedForDirectBuffers();
|
||||
|
||||
/**
|
||||
* Reset the buffers.
|
||||
* <p>If the Interceptor contains buffers then reset them.
|
||||
* @throws IllegalStateException Thrown if the response has been
|
||||
* committed and buffers and/or headers cannot be reset.
|
||||
*/
|
||||
default void resetBuffer() throws IllegalStateException
|
||||
{
|
||||
Interceptor next = getNextInterceptor();
|
||||
if (next!=null)
|
||||
next.resetBuffer();
|
||||
};
|
||||
}
|
||||
|
||||
private static Logger LOG = Log.getLogger(HttpOutput.class);
|
||||
|
@ -863,15 +917,19 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
|
||||
public void recycle()
|
||||
{
|
||||
resetBuffer();
|
||||
_interceptor=_channel;
|
||||
if (BufferUtil.hasContent(_aggregate))
|
||||
BufferUtil.clear(_aggregate);
|
||||
_written = 0;
|
||||
reopen();
|
||||
}
|
||||
|
||||
public void resetBuffer()
|
||||
{
|
||||
_written = 0;
|
||||
_interceptor.resetBuffer();
|
||||
if (BufferUtil.hasContent(_aggregate))
|
||||
BufferUtil.clear(_aggregate);
|
||||
_written = 0;
|
||||
reopen();
|
||||
}
|
||||
|
||||
|
|
|
@ -531,6 +531,9 @@ public class Response implements HttpServletResponse
|
|||
LOG.debug("Aborting on sendError on committed response {} {}",code,message);
|
||||
code=-1;
|
||||
}
|
||||
else
|
||||
resetBuffer();
|
||||
|
||||
|
||||
switch(code)
|
||||
{
|
||||
|
@ -544,7 +547,7 @@ public class Response implements HttpServletResponse
|
|||
break;
|
||||
}
|
||||
|
||||
resetBuffer();
|
||||
|
||||
_mimeType=null;
|
||||
_characterEncoding=null;
|
||||
_outputType = OutputType.NONE;
|
||||
|
@ -1213,9 +1216,6 @@ public class Response implements HttpServletResponse
|
|||
@Override
|
||||
public void resetBuffer()
|
||||
{
|
||||
if (isCommitted())
|
||||
throw new IllegalStateException("cannot reset buffer on committed response");
|
||||
|
||||
_out.resetBuffer();
|
||||
}
|
||||
|
||||
|
|
|
@ -201,6 +201,14 @@ public class BufferedResponseHandler extends HandlerWrapper
|
|||
_next=interceptor;
|
||||
_channel=httpChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetBuffer()
|
||||
{
|
||||
_buffers.clear();
|
||||
_aggregating=null;
|
||||
_aggregate=null;
|
||||
};
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer content, boolean last, Callback callback)
|
||||
|
|
|
@ -41,8 +41,6 @@ import org.junit.Test;
|
|||
|
||||
/**
|
||||
* Resource Handler test
|
||||
*
|
||||
* TODO: increase the testing going on here
|
||||
*/
|
||||
public class BufferedResponseHandlerTest
|
||||
{
|
||||
|
@ -95,6 +93,7 @@ public class BufferedResponseHandlerTest
|
|||
_test._writes=10;
|
||||
_test._flush=false;
|
||||
_test._close=false;
|
||||
_test._reset=false;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -218,6 +217,18 @@ public class BufferedResponseHandlerTest
|
|||
assertThat(response,not(containsString("Write: 1")));
|
||||
assertThat(response,containsString("Written: true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReset() throws Exception
|
||||
{
|
||||
_test._reset=true;
|
||||
String response = _local.getResponse("GET /ctx/include/path HTTP/1.1\r\nHost: localhost\r\n\r\n");
|
||||
assertThat(response,containsString(" 200 OK"));
|
||||
assertThat(response,containsString("Write: 0"));
|
||||
assertThat(response,containsString("Write: 9"));
|
||||
assertThat(response,containsString("Written: true"));
|
||||
assertThat(response,not(containsString("RESET")));
|
||||
}
|
||||
|
||||
public static class TestHandler extends AbstractHandler
|
||||
{
|
||||
|
@ -227,16 +238,25 @@ public class BufferedResponseHandlerTest
|
|||
int _writes;
|
||||
boolean _flush;
|
||||
boolean _close;
|
||||
boolean _reset;
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
|
||||
if (_bufferSize>0)
|
||||
response.setBufferSize(_bufferSize);
|
||||
if (_mimeType!=null)
|
||||
response.setContentType(_mimeType);
|
||||
|
||||
|
||||
if (_reset)
|
||||
{
|
||||
response.getOutputStream().print("THIS WILL BE RESET");
|
||||
response.getOutputStream().flush();
|
||||
response.getOutputStream().print("THIS WILL BE RESET");
|
||||
response.resetBuffer();
|
||||
}
|
||||
for (int i=0;i<_writes;i++)
|
||||
{
|
||||
response.addHeader("Write",Integer.toString(i));
|
||||
|
@ -248,7 +268,6 @@ public class BufferedResponseHandlerTest
|
|||
if (_close)
|
||||
response.getOutputStream().close();
|
||||
response.addHeader("Written","true");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue