-----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

Reply via email to