Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jetty-12 ee10 Closure of Response Object #9651

Open
janbartel opened this issue Apr 14, 2023 · 2 comments
Open

jetty-12 ee10 Closure of Response Object #9651

janbartel opened this issue Apr 14, 2023 · 2 comments
Labels
Bug For general bugs on Jetty side TCK For various Specification Test Compatibility Kits (eg: Servlet, WebSocket, HTTP/2, etc)

Comments

@janbartel
Copy link
Contributor

janbartel commented Apr 14, 2023

The Servlet Specification 6.0 says:

5.7. Closure of Response Object
When a response is closed, the container must immediately flush all remaining content in the response
buffer to the client. The following events indicate that the servlet has satisfied the request and that the
response object is to be closed:
• The termination of the service method of the servlet.
• The amount of content specified in the setContentLength or setContentLengthLong method of the
response has been greater than zero and has been written to the response.
• The sendError method is called.
• The sendRedirect method is called.
• The complete method on AsyncContext is called.

The tck has a test which sets the contentLength then writes more bytes than that, and also tries to set a header:

    int size = 40;
    response.setContentLength(size);

    PrintWriter pw = response.getWriter();
    pw.println("Test PASSED");
    StringBuffer tmp = new StringBuffer(2 * size);
    int i = 0;

    while (i < 8) {
      tmp = tmp.append("111111111x");
      i = i + 1;
    }
    pw.println(tmp);
    response.addIntHeader("header1", 12345);

Tck test is com/sun/ts/tests/servlet/spec/httpservletresponse/URLClient.java.flushBufferTest

Jetty fails the tck test because we respond with an 500 error instead of ignoring the extra content:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>
<title>Error 500 java.io.IOException: written 92 &gt; 40 content-length</title>
</head>
<body>
<h2>HTTP ERROR 500 java.io.IOException: written 92 &gt; 40 content-length</h2>
<table>
<tr><th>URI:</th><td>http://localhost:38225/servlet_spec_httpservletresponse_web/HttpTestServlet?testname=flushBufferTest</td></tr>
<tr><th>STATUS:</th><td>500</td></tr>
<tr><th>MESSAGE:</th><td>java.io.IOException: written 92 &gt; 40 content-length</td></tr>
<tr><th>CAUSED BY:</th><td>java.io.IOException: written 92 &gt; 40 content-length</td></tr>
</table>
<h3>Caused by:</h3><pre>java.io.IOException: written 92 &gt; 40 content-length
	at org.eclipse.jetty.server.internal.HttpChannelState$ChannelResponse.write(HttpChannelState.java:1093)
	at org.eclipse.jetty.ee10.servlet.HttpOutput.channelWrite(HttpOutput.java:215)
	at org.eclipse.jetty.ee10.servlet.HttpOutput.channelWrite(HttpOutput.java:200)
	at org.eclipse.jetty.ee10.servlet.HttpOutput.write(HttpOutput.java:804)
	at java.base/java.io.ByteArrayOutputStream.writeTo(ByteArrayOutputStream.java:161)
	at org.eclipse.jetty.ee10.servlet.writer.Iso88591HttpWriter.write(Iso88591HttpWriter.java:62)
	at org.eclipse.jetty.ee10.servlet.writer.HttpWriter.write(HttpWriter.java:69)
	at org.eclipse.jetty.ee10.servlet.writer.ResponseWriter.println(ResponseWriter.java:426)
	at org.eclipse.jetty.ee10.servlet.writer.ResponseWriter.println(ResponseWriter.java:445)
	at com.sun.ts.tests.servlet.spec.httpservletresponse.HttpTestServlet.flushBufferTest(HttpTestServlet.java:59)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at com.sun.ts.tests.servlet.common.servlets.HttpTCKServlet.invokeTest(HttpTCKServlet.java:91)
	at com.sun.ts.tests.servlet.common.servlets.HttpTCKServlet.doGet(HttpTCKServlet.java:116)
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:527)
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)
	at org.eclipse.jetty.ee10.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1383)
	at org.eclipse.jetty.ee10.servlet.ServletHolder.handle(ServletHolder.java:738)
	at org.eclipse.jetty.ee10.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1601)
	at org.eclipse.jetty.ee10.servlet.ServletHandler$MappedServlet.handle(ServletHandler.java:1534)
	at org.eclipse.jetty.ee10.servlet.ServletChannel.lambda$0(ServletChannel.java:425)
	at org.eclipse.jetty.ee10.servlet.ServletChannel.dispatch(ServletChannel.java:659)
	at org.eclipse.jetty.ee10.servlet.ServletChannel.handle(ServletChannel.java:420)
	at org.eclipse.jetty.ee10.servlet.ServletHandler.handle(ServletHandler.java:458)
	at org.eclipse.jetty.ee10.servlet.security.SecurityHandler.handle(SecurityHandler.java:564)
	at org.eclipse.jetty.ee10.servlet.SessionHandler.handle(SessionHandler.java:664)
	at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:819)
	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:149)
	at org.eclipse.jetty.server.Handler$Sequence.handle(Handler.java:665)
	at org.eclipse.jetty.server.Handler$Wrapper.handle(Handler.java:611)
	at org.eclipse.jetty.server.Server.handle(Server.java:175)
	at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:553)
	at org.eclipse.jetty.server.internal.HttpConnection.onFillable(HttpConnection.java:480)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:322)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100)
	at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:969)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1194)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1149)
	at java.base/java.lang.Thread.run(Thread.java:833)
</pre>
<hr/><a href="https://eclipse.org/jetty">Powered by Jetty:// 12.0.0-SNAPSHOT</a><hr/>

</body>
</html>
@janbartel janbartel added Bug For general bugs on Jetty side TCK For various Specification Test Compatibility Kits (eg: Servlet, WebSocket, HTTP/2, etc) labels Apr 14, 2023
@gregw
Copy link
Contributor

gregw commented Apr 14, 2023

I think this test can be challenged. It is OK that we should close the response if exactly the right amount of data is written, but it is a bit strange to truncate data in excess of the set length.
The string written could be multi-byte characters and the truncation could split a character in half.

I think it is reasonable that we throw an exception from such a write rather than truncate.

@janbartel
Copy link
Contributor Author

Still waiting on some action from the servlet spec group, note that this also affects the 6.1 tck and jetty as documented here: #11931

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug For general bugs on Jetty side TCK For various Specification Test Compatibility Kits (eg: Servlet, WebSocket, HTTP/2, etc)
Projects
None yet
Development

No branches or pull requests

2 participants