-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Emah,
On 1/17/18 10:17 AM, emah wrote: > 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.jav a: >> >>> >>> 684) >>> >>> >> at >>> org.apache.coyote.ajp.AjpProcessor$SocketInputBuffer.doRead(AjpProce ss >> >>> >>> 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(InputBu ff >> >>> >>> er.java:642) >>> >>> >> at >>> org.apache.catalina.connector.InputBuffer.readByte(InputBuffer.java: 33 >> >>> >>> 7) >>> >>> >> at >>> org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStre am >> >>> >>> .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(NioBlockingSelecto r.java:173) > > > at > org.apache.tomcat.util.net.NioSelectorPool.read(NioSelectorPool.java:2 35) > > > at > org.apache.tomcat.util.net.NioSelectorPool.read(NioSelectorPool.java:2 16) > > > at > org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer (NioEndpoint.java:1241) > > > at > org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoi nt.java:1190) > > > at > org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java :717) > > > at > org.apache.coyote.http11.Http11InputBuffer.access$300(Http11InputBuffe r.java:40) > > > at > org.apache.coyote.http11.Http11InputBuffer$SocketInputBuffer.doRead(Ht tp11InputBuffer.java:1072) > > > at > org.apache.coyote.http11.filters.IdentityInputFilter.doRead(IdentityIn putFilter.java:140) > > > at > org.apache.coyote.http11.Http11InputBuffer.doRead(Http11InputBuffer.ja va:261) > > > 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) > > > 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. I'd actually say that Tomcat is being inconsistent, here, and that the EOFException should be "fixed" so that it returns -1 from a read instead . It would be best for you to handle the read=-1 situation in the same way that you handle EOFException. You could even perform a read and throw an EOFExceptin yourself if you get a -1 unexpectedly. > 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.Sock etChannel[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.Sock etChannel[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.a pache.tomcat.util.net.NioChannel@517a280d:java.nio.channels.SocketChanne l[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] The "IOException: Broken pipe" is exactly what you'd expect when writing to a closed stream, so it's not surprising to me that's happenin g. But you are more concerned about the reads than the writes, right? - -chris -----BEGIN PGP SIGNATURE----- Comment: GPGTools - http://gpgtools.org Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQJRBAEBCAA7FiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAlpfhJcdHGNocmlzQGNo cmlzdG9waGVyc2NodWx0ei5uZXQACgkQHPApP6U8pFjXIA//W0HQzD0jdy7Nk2jF E8JLLKyhwGeVjyXHw1D1KtA9DhloeVWxIsv79xLNPPIiJ6Cd12a+MsIXDhYDubtl TwjVSbhq0wRAnG2Fd1I9r1e4K7g88xspq3zsrHaj1n/jHQ/exq5AfQ4bun76LXOi PcUphqxqtpCEdat0Wnj4IVjoYcAiquwv6MNCFs3lP5WvTMIfbZgnCl0q5X3KJCAK Ap/kkLvbzVgfym8kuWurivlDEa0zKTBdN4+s5jQSgkp9hp6f3CnUE1hlDCZvomId 3wyUIsYNFyLUG4NVItsYajQF0XaSQ7nvNfXP3rWgkjzfJoHlofucXR8eDxxutkhq Y0pldpcQxu/JvNq0hLMHCsrHHIygq05xSJRoihKibR36iGkY/tlizMT5Nh30azzO 0TZydjSapjno5Bq405gNL1nag9wJsft5XG8I3S5MaYvlTdRZaw42TeRyaSR1qzXS JSRUFwhlt03F2HSUGDqK1NpUleLQ/m21jwsSMJqTyjTbZVkw6NLanVLdSAbe4Rnl kwamxedUxZA5YXQVnmwxt2Qnh4g71wJuNkXszDsbxaBinFF2ULoIzXSkNKxs6DF1 a3LO+YDK7AxbB8lNsJiUaiGe2zaaOIE0IfYzMmLyk7P0hU3DZOR1lrniXWydbAte pL6hrcSn1JPb9J5WZbhD4r2goeU= =AFgk -----END PGP SIGNATURE----- --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org