sendError(-1) is an abort (#12206)
restore behaviour from jetty <= 11 where a sendError(-1) is a true abort, without an attempt to send an error response.
This commit is contained in:
parent
edbd21bdf0
commit
aa07995f37
|
@ -47,6 +47,7 @@ import org.eclipse.jetty.http.MultiPartCompliance;
|
||||||
import org.eclipse.jetty.http.MultiPartConfig;
|
import org.eclipse.jetty.http.MultiPartConfig;
|
||||||
import org.eclipse.jetty.http.Trailers;
|
import org.eclipse.jetty.http.Trailers;
|
||||||
import org.eclipse.jetty.io.Content;
|
import org.eclipse.jetty.io.Content;
|
||||||
|
import org.eclipse.jetty.io.EndPoint;
|
||||||
import org.eclipse.jetty.server.internal.CompletionStreamWrapper;
|
import org.eclipse.jetty.server.internal.CompletionStreamWrapper;
|
||||||
import org.eclipse.jetty.server.internal.HttpChannelState;
|
import org.eclipse.jetty.server.internal.HttpChannelState;
|
||||||
import org.eclipse.jetty.util.Attributes;
|
import org.eclipse.jetty.util.Attributes;
|
||||||
|
@ -716,6 +717,7 @@ public interface Request extends Attributes, Content.Source
|
||||||
* is returned, then this method must not generate a response, nor complete the callback.
|
* is returned, then this method must not generate a response, nor complete the callback.
|
||||||
* @throws Exception if there is a failure during the handling. Catchers cannot assume that the callback will be
|
* @throws Exception if there is a failure during the handling. Catchers cannot assume that the callback will be
|
||||||
* called and thus should attempt to complete the request as if a false had been returned.
|
* called and thus should attempt to complete the request as if a false had been returned.
|
||||||
|
* @see AbortException
|
||||||
*/
|
*/
|
||||||
boolean handle(Request request, Response response, Callback callback) throws Exception;
|
boolean handle(Request request, Response response, Callback callback) throws Exception;
|
||||||
|
|
||||||
|
@ -725,6 +727,34 @@ public interface Request extends Attributes, Content.Source
|
||||||
{
|
{
|
||||||
return InvocationType.BLOCKING;
|
return InvocationType.BLOCKING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A marker {@link Exception} that can be passed the {@link Callback#failed(Throwable)} of the {@link Callback}
|
||||||
|
* passed in {@link #handle(Request, Response, Callback)}, to cause request handling to be aborted. For HTTP/1
|
||||||
|
* an abort is handled with a {@link EndPoint#close()}, for later versions of HTTP, a reset message will be sent.
|
||||||
|
*/
|
||||||
|
class AbortException extends Exception
|
||||||
|
{
|
||||||
|
public AbortException()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbortException(String message)
|
||||||
|
{
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbortException(String message, Throwable cause)
|
||||||
|
{
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbortException(Throwable cause)
|
||||||
|
{
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1590,18 +1590,18 @@ public class HttpChannelState implements HttpChannel, Components
|
||||||
|
|
||||||
httpChannelState._callbackFailure = failure;
|
httpChannelState._callbackFailure = failure;
|
||||||
|
|
||||||
// Consume any input.
|
if (!stream.isCommitted() && !(failure instanceof Request.Handler.AbortException))
|
||||||
Throwable unconsumed = stream.consumeAvailable();
|
{
|
||||||
ExceptionUtil.addSuppressedIfNotAssociated(failure, unconsumed);
|
// Consume any input.
|
||||||
|
Throwable unconsumed = stream.consumeAvailable();
|
||||||
|
ExceptionUtil.addSuppressedIfNotAssociated(failure, unconsumed);
|
||||||
|
|
||||||
ChannelResponse response = httpChannelState._response;
|
ChannelResponse response = httpChannelState._response;
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("failed stream.isCommitted={}, response.isCommitted={} {}", stream.isCommitted(), response.isCommitted(), this);
|
LOG.debug("failed stream.isCommitted={}, response.isCommitted={} {}", stream.isCommitted(), response.isCommitted(), this);
|
||||||
|
|
||||||
// There may have been an attempt to write an error response that failed.
|
|
||||||
// Do not try to write again an error response if already committed.
|
|
||||||
if (!stream.isCommitted())
|
|
||||||
errorResponse = new ErrorResponse(request);
|
errorResponse = new ErrorResponse(request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorResponse != null)
|
if (errorResponse != null)
|
||||||
|
|
|
@ -138,7 +138,7 @@ public class ServletApiResponse implements HttpServletResponse
|
||||||
{
|
{
|
||||||
switch (sc)
|
switch (sc)
|
||||||
{
|
{
|
||||||
case -1 -> getServletChannel().abort(new IOException(msg));
|
case -1 -> getServletChannel().abort(new Request.Handler.AbortException(msg));
|
||||||
case HttpStatus.PROCESSING_102, HttpStatus.EARLY_HINTS_103 ->
|
case HttpStatus.PROCESSING_102, HttpStatus.EARLY_HINTS_103 ->
|
||||||
{
|
{
|
||||||
if (!isCommitted())
|
if (!isCommitted())
|
||||||
|
|
|
@ -13,8 +13,12 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.ee10.servlet;
|
package org.eclipse.jetty.ee10.servlet;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.net.Socket;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -50,6 +54,7 @@ import org.eclipse.jetty.server.LocalConnector;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.Response;
|
import org.eclipse.jetty.server.Response;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||||
import org.eclipse.jetty.util.Callback;
|
import org.eclipse.jetty.util.Callback;
|
||||||
|
@ -70,6 +75,7 @@ import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
@ -780,6 +786,220 @@ public class ErrorPageTest
|
||||||
assertThat(responseBody, Matchers.containsString("ERROR_REQUEST_URI: /fail/599"));
|
assertThat(responseBody, Matchers.containsString("ERROR_REQUEST_URI: /fail/599"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAbortWithSendError() throws Exception
|
||||||
|
{
|
||||||
|
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS);
|
||||||
|
contextHandler.setContextPath("/");
|
||||||
|
|
||||||
|
HttpServlet failServlet = new HttpServlet()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
|
||||||
|
{
|
||||||
|
response.sendError(-1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
contextHandler.addServlet(failServlet, "/abort");
|
||||||
|
startServer(contextHandler);
|
||||||
|
|
||||||
|
ServerConnector connector = new ServerConnector(_server);
|
||||||
|
connector.setPort(0);
|
||||||
|
_server.addConnector(connector);
|
||||||
|
connector.start();
|
||||||
|
try (Socket socket = new Socket("localhost", connector.getLocalPort()))
|
||||||
|
{
|
||||||
|
OutputStream output = socket.getOutputStream();
|
||||||
|
|
||||||
|
String request = """
|
||||||
|
GET /abort HTTP/1.1\r
|
||||||
|
Host: test\r
|
||||||
|
\r
|
||||||
|
""";
|
||||||
|
output.write(request.getBytes(StandardCharsets.UTF_8));
|
||||||
|
output.flush();
|
||||||
|
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
String line = in.readLine();
|
||||||
|
assertNull(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAbortWithSendErrorChunked() throws Exception
|
||||||
|
{
|
||||||
|
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS);
|
||||||
|
contextHandler.setContextPath("/");
|
||||||
|
|
||||||
|
HttpServlet failServlet = new HttpServlet()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
|
||||||
|
{
|
||||||
|
response.getOutputStream().write("test".getBytes(StandardCharsets.UTF_8));
|
||||||
|
response.flushBuffer();
|
||||||
|
response.sendError(-1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
contextHandler.addServlet(failServlet, "/abort");
|
||||||
|
startServer(contextHandler);
|
||||||
|
|
||||||
|
ServerConnector connector = new ServerConnector(_server);
|
||||||
|
connector.setPort(0);
|
||||||
|
_server.addConnector(connector);
|
||||||
|
connector.start();
|
||||||
|
try (Socket socket = new Socket("localhost", connector.getLocalPort()))
|
||||||
|
{
|
||||||
|
OutputStream output = socket.getOutputStream();
|
||||||
|
|
||||||
|
String request = """
|
||||||
|
GET /abort HTTP/1.1\r
|
||||||
|
Host: test\r
|
||||||
|
\r
|
||||||
|
""";
|
||||||
|
output.write(request.getBytes(StandardCharsets.UTF_8));
|
||||||
|
output.flush();
|
||||||
|
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
String line = in.readLine();
|
||||||
|
assertThat(line, is("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
|
boolean chunked = false;
|
||||||
|
while (!line.isEmpty())
|
||||||
|
{
|
||||||
|
line = in.readLine();
|
||||||
|
assertNotNull(line);
|
||||||
|
chunked |= line.equals("Transfer-Encoding: chunked");
|
||||||
|
}
|
||||||
|
assertTrue(chunked);
|
||||||
|
|
||||||
|
line = in.readLine();
|
||||||
|
assertThat(line, is("4"));
|
||||||
|
line = in.readLine();
|
||||||
|
assertThat(line, is("test"));
|
||||||
|
|
||||||
|
line = in.readLine();
|
||||||
|
assertNull(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAbortWithSendErrorContent() throws Exception
|
||||||
|
{
|
||||||
|
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS);
|
||||||
|
contextHandler.setContextPath("/");
|
||||||
|
|
||||||
|
HttpServlet failServlet = new HttpServlet()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
|
||||||
|
{
|
||||||
|
response.setContentLength(10);
|
||||||
|
response.getOutputStream().write("test\r\n".getBytes(StandardCharsets.UTF_8));
|
||||||
|
response.flushBuffer();
|
||||||
|
response.sendError(-1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
contextHandler.addServlet(failServlet, "/abort");
|
||||||
|
startServer(contextHandler);
|
||||||
|
|
||||||
|
ServerConnector connector = new ServerConnector(_server);
|
||||||
|
connector.setPort(0);
|
||||||
|
_server.addConnector(connector);
|
||||||
|
connector.start();
|
||||||
|
try (Socket socket = new Socket("localhost", connector.getLocalPort()))
|
||||||
|
{
|
||||||
|
OutputStream output = socket.getOutputStream();
|
||||||
|
|
||||||
|
String request = """
|
||||||
|
GET /abort HTTP/1.1\r
|
||||||
|
Host: test\r
|
||||||
|
\r
|
||||||
|
""";
|
||||||
|
output.write(request.getBytes(StandardCharsets.UTF_8));
|
||||||
|
output.flush();
|
||||||
|
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
String line = in.readLine();
|
||||||
|
assertThat(line, is("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
|
boolean chunked = false;
|
||||||
|
while (!line.isEmpty())
|
||||||
|
{
|
||||||
|
line = in.readLine();
|
||||||
|
assertNotNull(line);
|
||||||
|
chunked |= line.equals("Transfer-Encoding: chunked");
|
||||||
|
}
|
||||||
|
assertFalse(chunked);
|
||||||
|
|
||||||
|
line = in.readLine();
|
||||||
|
assertThat(line, is("test"));
|
||||||
|
|
||||||
|
line = in.readLine();
|
||||||
|
assertNull(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAbortWithSendErrorComplete() throws Exception
|
||||||
|
{
|
||||||
|
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS);
|
||||||
|
contextHandler.setContextPath("/");
|
||||||
|
|
||||||
|
HttpServlet failServlet = new HttpServlet()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
|
||||||
|
{
|
||||||
|
response.setContentLength(6);
|
||||||
|
response.getOutputStream().write("test\r\n".getBytes(StandardCharsets.UTF_8));
|
||||||
|
response.sendError(-1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
contextHandler.addServlet(failServlet, "/abort");
|
||||||
|
startServer(contextHandler);
|
||||||
|
|
||||||
|
ServerConnector connector = new ServerConnector(_server);
|
||||||
|
connector.setPort(0);
|
||||||
|
_server.addConnector(connector);
|
||||||
|
connector.start();
|
||||||
|
try (Socket socket = new Socket("localhost", connector.getLocalPort()))
|
||||||
|
{
|
||||||
|
OutputStream output = socket.getOutputStream();
|
||||||
|
|
||||||
|
String request = """
|
||||||
|
GET /abort HTTP/1.1\r
|
||||||
|
Host: test\r
|
||||||
|
\r
|
||||||
|
""";
|
||||||
|
output.write(request.getBytes(StandardCharsets.UTF_8));
|
||||||
|
output.flush();
|
||||||
|
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
String line = in.readLine();
|
||||||
|
assertThat(line, is("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
|
boolean chunked = false;
|
||||||
|
while (!line.isEmpty())
|
||||||
|
{
|
||||||
|
line = in.readLine();
|
||||||
|
assertNotNull(line);
|
||||||
|
chunked |= line.equals("Transfer-Encoding: chunked");
|
||||||
|
}
|
||||||
|
assertFalse(chunked);
|
||||||
|
|
||||||
|
line = in.readLine();
|
||||||
|
assertThat(line, is("test"));
|
||||||
|
|
||||||
|
line = in.readLine();
|
||||||
|
assertNull(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testErrorCodeNoDefaultServletNonExistentErrorLocation() throws Exception
|
public void testErrorCodeNoDefaultServletNonExistentErrorLocation() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -488,7 +488,7 @@ public class Response implements HttpServletResponse
|
||||||
|
|
||||||
switch (code)
|
switch (code)
|
||||||
{
|
{
|
||||||
case -1 -> _channel.abort(new IOException(message));
|
case -1 -> _channel.abort(new org.eclipse.jetty.server.Request.Handler.AbortException(message));
|
||||||
case HttpStatus.PROCESSING_102 -> sendProcessing();
|
case HttpStatus.PROCESSING_102 -> sendProcessing();
|
||||||
case HttpStatus.EARLY_HINTS_103 -> sendEarlyHint();
|
case HttpStatus.EARLY_HINTS_103 -> sendEarlyHint();
|
||||||
default -> _channel.getState().sendError(code, message);
|
default -> _channel.getState().sendError(code, message);
|
||||||
|
|
|
@ -13,8 +13,12 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.ee9.servlet;
|
package org.eclipse.jetty.ee9.servlet;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.net.Socket;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
@ -29,7 +33,6 @@ import jakarta.servlet.DispatcherType;
|
||||||
import jakarta.servlet.Filter;
|
import jakarta.servlet.Filter;
|
||||||
import jakarta.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import jakarta.servlet.FilterConfig;
|
import jakarta.servlet.FilterConfig;
|
||||||
import jakarta.servlet.RequestDispatcher;
|
|
||||||
import jakarta.servlet.Servlet;
|
import jakarta.servlet.Servlet;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.ServletRequest;
|
import jakarta.servlet.ServletRequest;
|
||||||
|
@ -49,10 +52,10 @@ import org.eclipse.jetty.http.HttpTester;
|
||||||
import org.eclipse.jetty.logging.StacklessLogging;
|
import org.eclipse.jetty.logging.StacklessLogging;
|
||||||
import org.eclipse.jetty.server.LocalConnector;
|
import org.eclipse.jetty.server.LocalConnector;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Disabled;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -62,6 +65,7 @@ import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
//@Disabled // TODO
|
//@Disabled // TODO
|
||||||
|
@ -105,6 +109,7 @@ public class ErrorPageTest
|
||||||
_context.addServlet(ErrorAndStatusServlet.class, "/error-and-status/*");
|
_context.addServlet(ErrorAndStatusServlet.class, "/error-and-status/*");
|
||||||
_context.addServlet(ErrorContentTypeCharsetWriterInitializedServlet.class, "/error-mime-charset-writer/*");
|
_context.addServlet(ErrorContentTypeCharsetWriterInitializedServlet.class, "/error-mime-charset-writer/*");
|
||||||
_context.addServlet(ExceptionServlet.class, "/exception-servlet");
|
_context.addServlet(ExceptionServlet.class, "/exception-servlet");
|
||||||
|
_context.addServlet(AbortServlet.class, "/abort");
|
||||||
|
|
||||||
HandlerWrapper noopHandler = new HandlerWrapper()
|
HandlerWrapper noopHandler = new HandlerWrapper()
|
||||||
{
|
{
|
||||||
|
@ -300,6 +305,34 @@ public class ErrorPageTest
|
||||||
assertThat(response, Matchers.containsString("ERROR_REQUEST_URI: /fail/code"));
|
assertThat(response, Matchers.containsString("ERROR_REQUEST_URI: /fail/code"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAbortWithSendError() throws Exception
|
||||||
|
{
|
||||||
|
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS);
|
||||||
|
contextHandler.setContextPath("/");
|
||||||
|
|
||||||
|
ServerConnector connector = new ServerConnector(_server);
|
||||||
|
connector.setPort(0);
|
||||||
|
_server.addConnector(connector);
|
||||||
|
connector.start();
|
||||||
|
try (Socket socket = new Socket("localhost", connector.getLocalPort()))
|
||||||
|
{
|
||||||
|
OutputStream output = socket.getOutputStream();
|
||||||
|
|
||||||
|
String request = """
|
||||||
|
GET /abort HTTP/1.1\r
|
||||||
|
Host: test\r
|
||||||
|
\r
|
||||||
|
""";
|
||||||
|
output.write(request.getBytes(StandardCharsets.UTF_8));
|
||||||
|
output.flush();
|
||||||
|
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
String line = in.readLine();
|
||||||
|
assertNull(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testErrorException() throws Exception
|
public void testErrorException() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -871,4 +904,13 @@ public class ErrorPageTest
|
||||||
super(rootCause);
|
super(rootCause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class AbortServlet extends HttpServlet
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
|
||||||
|
{
|
||||||
|
response.sendError(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue