Chris,
Christopher Schultz-2 wrote >> I'm running a tomcat 8.5.23 instance on ubuntu 16.04 (spring boot >> application with embedded tomcat) configured with 2 connectors: >> Http11NioProtocol and AjpNioProtocol. The AJP one is accessed >> through an apache2 instance configured with mod_jk.It all works >> well in the normal use case. >> >> The application has code to look for the EOFExceptions during read >> e.g. the client aborts the request which works well with HTTP but >> not AJP. In my test I'm simulating this by closing the connection >> half way through (some headers have been sent but no body) >> >> The problem I'm seeing is an inconsistent behaviour for >> CoyoteInputStream.read() The HTTP connector throws an EOFException >> in this case while the AJP one just returns -1. >> >> The relevant call stack is this at >> org.apache.coyote.ajp.AjpProcessor.refillReadBuffer(AjpProcessor.java: > 684) >> >> > at >> org.apache.coyote.ajp.AjpProcessor$SocketInputBuffer.doRead(AjpProcess > or.java:1433) >> >> > at org.apache.coyote.Request.doRead(Request.java:581) >> at >> org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.ja > va:326) >> >> > at >> org.apache.catalina.connector.InputBuffer.checkByteBufferEof(InputBuff > er.java:642) >> >> > at >> org.apache.catalina.connector.InputBuffer.readByte(InputBuffer.java:33 > 7) >> >> > at >> org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream > .java:93) >> >> Now based on this old and unrelated thread >> https://mail-archives.apache.org/mod_mbox/tomcat-users/201312.mbox/%3C > 15FF6F04-B4C9-4D9B-B1B3-5C10CA955AEE@ > %3E >> >> > I understand that the AJP connector is perfectly capable of raising an >> EOFException but it's just not doing that for me. >> >> The documentation >> https://tomcat.apache.org/tomcat-8.0-doc/config/ajp.html does not >> suggest I need to do anything special. >> >> I guess it's possible that this has something to do with the way >> apache2 talks to the AJP connector. Any help is appreciated. > > Interesting. > > If your servlet simply reads the InputStream like this, you don't get > an EOFException? > > ServletInputStream in = request.getInputStream(); > for(;;) > in.read(); > > What part of the Servlet specification or Servlet API leads you to > believe that EOFException should be thrown when the request has been > completely read (or has been truncated, and no further data is available > )? > > I don't see anything to suggest that such behavior is either required > or expected. > > In fact, I'm surprised that the HTTP connector throws an EOFException > instead of simply returning -1 like the API says it should. > > - -chris Let me first correct something I've said earlier: HTTP Connector will actually throw an IOException when ssl unwrap fails (rather than an EOFException) in at org.apache.tomcat.util.net.SecureNioChannel.read(SecureNioChannel.java:618) at org.apache.tomcat.util.net.NioBlockingSelector.read(NioBlockingSelector.java:173) at org.apache.tomcat.util.net.NioSelectorPool.read(NioSelectorPool.java:235) at org.apache.tomcat.util.net.NioSelectorPool.read(NioSelectorPool.java:216) at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1241) at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1190) at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:717) at org.apache.coyote.http11.Http11InputBuffer.access$300(Http11InputBuffer.java:40) at org.apache.coyote.http11.Http11InputBuffer$SocketInputBuffer.doRead(Http11InputBuffer.java:1072) at org.apache.coyote.http11.filters.IdentityInputFilter.doRead(IdentityInputFilter.java:140) at org.apache.coyote.http11.Http11InputBuffer.doRead(Http11InputBuffer.java:261) at org.apache.coyote.Request.doRead(Request.java:581) at org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:326) at org.apache.catalina.connector.InputBuffer.checkByteBufferEof(InputBuffer.java:642) at org.apache.catalina.connector.InputBuffer.readByte(InputBuffer.java:337) at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:93) while the AJP Connector returns -1. You're right I can't expect an EOFException, the API just mentions generic IOException. I guess my expectation comes from the fact that the HTTP Connector throws an IOException on both read and write while the AJP one only throws a java.io.IOException: Broken pipe exception on write but not on read where it returns -1. I don't know the networking API well enough to say the behaviour is wrong, just hoping I can get the AJP Connector to signal (via some IOException) on read that something is unexpected. Here's the relevant apache log [Wed Jan 17 14:42:41 2018] [23791:140542260176640] [info] ajp_service::jk_ajp_common.c (2773): (directory_service) sending request to tomcat failed (unrecoverable), because of client read error (attempt=1) [Wed Jan 17 14:42:41 2018] [23791:140542260176640] [debug] ajp_reset_endpoint::jk_ajp_common.c (851): (directory_service) resetting endpoint with socket 23 (socket shutdown) [Wed Jan 17 14:42:41 2018] [23791:140542260176640] [debug] ajp_abort_endpoint::jk_ajp_common.c (821): (directory_service) aborting endpoint with socket 23 [Wed Jan 17 14:42:41 2018] [23791:140542260176640] [debug] jk_shutdown_socket::jk_connect.c (932): About to shutdown socket 23 [127.0.0.1:42538 -> 127.0.0.1:15443] [Wed Jan 17 14:42:41 2018] [23791:140542260176640] [debug] jk_is_input_event::jk_connect.c (1383): timeout during poll on socket 23 [127.0.0.1:42538 -> 127.0.0.1:15443] (timeout=100) [Wed Jan 17 14:42:41 2018] [23791:140542260176640] [debug] jk_shutdown_socket::jk_connect.c (1016): Shutdown socket 23 [127.0.0.1:42538 -> 127.0.0.1:15443] and read 0 lingering bytes in 0 sec. [Wed Jan 17 14:42:41 2018] [23791:140542260176640] [debug] ajp_done::jk_ajp_common.c (3282): recycling connection pool for worker directory_service and socket -1 [Wed Jan 17 14:42:41 2018] [23791:140542260176640] [debug] jk_handler::mod_jk.c (2921): Consumed 0 bytes of remaining request data for worker=directory_service [Wed Jan 17 14:42:41 2018] [23791:140542260176640] [info] jk_handler::mod_jk.c (2984): Aborting connection for worker=directory_service And tomcat log [DEBUG] [ajp-nio-127.0.0.1-15443-exec-7] 14:42:41.067 AjpNioProtocol - Processing socket [org.apache.tomcat.util.net.NioChannel@517a280d:java.nio.channels.SocketChannel[connected local=/127.0.0.1:15443 remote=/127.0.0.1:42538]] with status [OPEN_READ] [DEBUG] [ajp-nio-127.0.0.1-15443-exec-7] 14:42:41.068 AjpNioProtocol - Found processor [null] for socket [org.apache.tomcat.util.net.NioChannel@517a280d:java.nio.channels.SocketChannel[connected local=/127.0.0.1:15443 remote=/127.0.0.1:42538]] [DEBUG] [ajp-nio-127.0.0.1-15443-exec-7] 14:42:41.068 AjpNioProtocol - Popped processor [org.apache.coyote.ajp.AjpProcessor@1f4c1d25] from cache [DEBUG] [ajp-nio-127.0.0.1-15443-exec-7] 14:46:38.078 AjpMessage - Received 979 18 [DEBUG] [ajp-nio-127.0.0.1-15443-exec-7] 14:46:39.578 AjpMessage - Received 2 18 // read data is processed here but there's no IOException on read. When I try to write however I get a java.io.IOException: Broken pipe [DEBUG] [ajp-nio-127.0.0.1-15443-exec-7] 14:46:40.717 AjpProcessor - Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@1be2c90:org.apache.tomcat.util.net.NioChannel@517a280d:java.nio.channels.SocketChannel[connected local=/127.0.0.1:15443 remote=/127.0.0.1:42538]], Status in: [OPEN_READ], State out: [CLOSED] [DEBUG] [ajp-nio-127.0.0.1-15443-exec-7] 14:46:40.717 AjpNioProtocol - Pushed Processor [org.apache.coyote.ajp.AjpProcessor@1f4c1d25] -- Sent from: http://tomcat.10.x6.nabble.com/Tomcat-User-f1968778.html --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org