Thanks for this.

While I haven't had a chance to look into this, there is enough
information here to justify opening a bug report. That has the added
advantage that it won't get forogtten.

Mark


On 18/10/2016 09:55, Thomas Boniface wrote:
> Just a small correction, the callback was a bit weird. The correct one is
> below (but that doesn't impact the behavior of the scenario)
> 
> @Override
> public void completed(HttpResponse result) {
>     try {
>         try {
>             Thread.sleep(200);
>         } catch (InterruptedException e) {
>             e.printStackTrace();
>         }
> 
>         ServletOutputStream out = res.getOutputStream();
>         out.print("Hello world");
>         out.flush();
>         out.close();
>     } catch (IOException e) {
>     } finally {
>         req.getAsyncContext().complete();
>     }
> }
> 
> 
> 2016-10-18 10:38 GMT+02:00 Thomas Boniface <tho...@stickyads.tv>:
>>
>> I think I managed to narrow things down a bit.
>>
>>
>> I managed to reproduced locally the issue (it's not occuring 100% of the
> time but it appears after a very few attempt for me). I created a really
> basic webapps :
>>
>> package stickyads.tv;
>>
>> import org.apache.http.HttpResponse;
>> import org.apache.http.client.methods.HttpGet;
>> import org.apache.http.concurrent.FutureCallback;
>> import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
>> import org.apache.http.impl.nio.client.HttpAsyncClients;
>>
>> import javax.servlet.*;
>> import javax.servlet.annotation.WebServlet;
>> import java.io.IOException;
>>
>> @WebServlet(value="/hello", name="helloServlet", asyncSupported = true)
>> public class HelloServlet extends GenericServlet {
>>
>>     private static final CloseableHttpAsyncClient httpclient =
> HttpAsyncClients.createDefault();
>>     static {
>>         httpclient.start();
>>     }
>>
>>     @Override
>>     public void service(final ServletRequest req, final ServletResponse
> res) throws ServletException, IOException {
>>         req.startAsync();
>>
>>         HttpGet request = new HttpGet("http://www.apache.org/";);
>>         httpclient.execute(request, new FutureCallback<HttpResponse>() {
>>             @Override
>>             public void completed(HttpResponse result) {
>>                 try {
>>                     try {
>>                         Thread.sleep(200);
>>                     } catch (InterruptedException e) {
>>                         e.printStackTrace();
>>                     }
>>
>>                     ServletOutputStream out = res.getOutputStream();
>>                     out.print("Hello world");
>>                     out.flush();
>>                     out.close();
>>                 } catch (IOException e) {
>>                     // this will generate an NPE
>>                     req.getAsyncContext().complete();
>>                 }
>>             }
>>
>>             @Override
>>             public void failed(Exception ex) {
>>
>>             }
>>
>>             @Override
>>             public void cancelled() {
>>
>>             }
>>         });
>>     }
>> }
>>
>> I deploy the war on tomcat 7.0.72 and then call it using a simple python
> program that sends a request and closes the requests without waiting for a
> response:
>>
>> import socket
>>
>> # create an INET, STREAMing socket
>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>> # now connect to the web server on port 80 - the normal http port
>> s.connect(("127.0.0.1", 8080))
>> s.send("GET /broken-pipe-1.0-SNAPSHOT/hello
> HTTP/1.1\nHost:127.0.0.1\nX-Forwarded-For: 127.0.0.1\nX-Forwarded-Protocol:
> http\n\n")
>>
>> This result in a broken pipe exception, a recycling of the async context
> but no complete:
>>
>> INFO: An error occurred in processing while on a non-container thread.
> The connection will be closed immediately
>> java.net.SocketException: Broken pipe
>>     at java.net.SocketOutputStream.$$YJP$$socketWrite0(Native Method)
>>     at java.net.SocketOutputStream.socketWrite0(SocketOutputStream.java)
>>     at
> java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
>>     at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
>>     at
> org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:215)
>>     at
> org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480)
>>     at
> org.apache.coyote.http11.InternalOutputBuffer.endRequest(InternalOutputBuffer.java:159)
>>     at
> org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:761)
>>     at org.apache.coyote.Response.action(Response.java:174)
>>     at org.apache.coyote.Response.finish(Response.java:274)
>>     at
> org.apache.catalina.connector.OutputBuffer.close(OutputBuffer.java:322)
>>     at
> org.apache.catalina.connector.CoyoteOutputStream.close(CoyoteOutputStream.java:108)
>>     at stickyads.tv.HelloServlet$1.completed(HelloServlet.java:33)
>>     at stickyads.tv.HelloServlet$1.completed(HelloServlet.java:26)
>>     at
> org.apache.http.concurrent.BasicFuture.completed(BasicFuture.java:119)
>>     at
> org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseCompleted(DefaultClientExchangeHandlerImpl.java:177)
>>     at
> org.apache.http.nio.protocol.HttpAsyncRequestExecutor.processResponse(HttpAsyncRequestExecutor.java:412)
>>     at
> org.apache.http.nio.protocol.HttpAsyncRequestExecutor.inputReady(HttpAsyncRequestExecutor.java:305)
>>     at
> org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:267)
>>     at
> org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
>>     at
> org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
>>     at
> org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:116)
>>     at
> org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:164)
>>     at
> org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:339)
>>     at
> org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:317)
>>     at
> org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:278)
>>     at
> org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106)
>>     at
> org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:590)
>>     at java.lang.Thread.run(Thread.java:745)
>>
>> Oct 18, 2016 9:47:24 AM org.apache.catalina.core.AsyncContextImpl logDebug
>> FINE: Req: 1f68c4e1  CReq: 3a716fa9  RP: 4c7aa6ad  Stage: 7  Thread:
> http-bio-8080-exec-5  State:                  N/A  Method: recycle
>  URI: /broken-pipe-1.0-SNAPSHOT/hello
>>
>> Here is also a tcpdump corresponding to this scenario:
>>
>> 09:47:43.916628 IP (tos 0x0, ttl 64, id 63341, offset 0, flags [DF],
> proto TCP (6), length 60)
>>     127.0.0.1.44078 > 127.0.0.1.8080: Flags [S], cksum 0xfe30 (incorrect
> -> 0x0bcc), seq 3052296773, win 43690, options [mss 65495,sackOK,TS val
> 273198376 ecr 0,nop,wscale 7], length 0
>> E..<.m@.@.EL..............ZE.........0.........
>> .H.(........
>> 09:47:43.916642 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto
> TCP (6), length 60)
>>     127.0.0.1.8080 > 127.0.0.1.44078: Flags [S.], cksum 0xfe30 (incorrect
> -> 0x44d5), seq 705486696, ack 3052296774, win 43690, options [mss
> 65495,sackOK,TS val 273198376 ecr 273198376,nop,wscale 7], length 0
>> E..<..@.@.<.............*..h..ZF.....0.........
>> .H.(.H.(....
>> 09:47:43.916653 IP (tos 0x0, ttl 64, id 63342, offset 0, flags [DF],
> proto TCP (6), length 52)
>>     127.0.0.1.44078 > 127.0.0.1.8080: Flags [.], cksum 0xfe28 (incorrect
> -> 0x171a), seq 1, ack 1, win 342, options [nop,nop,TS val 273198376 ecr
> 273198376], length 0
>> E..4.n@.@.ES..............ZF*..i...V.(.....
>> .H.(.H.(
>> 09:47:43.916917 IP (tos 0x0, ttl 64, id 63343, offset 0, flags [DF],
> proto TCP (6), length 172)
>>     127.0.0.1.44078 > 127.0.0.1.8080: Flags [P.], cksum 0xfea0 (incorrect
> -> 0xbf79), seq 1:121, ack 1, win 342, options [nop,nop,TS val 273198376
> ecr 273198376], length 120
>> E....o@.@.D...............ZF*..i...V.......
>> .H.(.H.(GET /broken-pipe-1.0-SNAPSHOT/hello HTTP/1.1
>> Host:127.0.0.1
>> X-Forwarded-For: 127.0.0.1
>> X-Forwarded-Protocol: http
>>
>>
>> 09:47:43.916923 IP (tos 0x0, ttl 64, id 29249, offset 0, flags [DF],
> proto TCP (6), length 52)
>>     127.0.0.1.8080 > 127.0.0.1.44078: Flags [.], cksum 0xfe28 (incorrect
> -> 0x16a2), seq 1, ack 121, win 342, options [nop,nop,TS val 273198376 ecr
> 273198376], length 0
>> E..4rA@.@...............*..i..Z....V.(.....
>> .H.(.H.(
>> 09:47:43.923131 IP (tos 0x0, ttl 64, id 63344, offset 0, flags [DF],
> proto TCP (6), length 52)
>>     127.0.0.1.44078 > 127.0.0.1.8080: Flags [F.], cksum 0xfe28 (incorrect
> -> 0x16a0), seq 121, ack 1, win 342, options [nop,nop,TS val 273198377 ecr
> 273198376], length 0
>> E..4.p@.@.EQ..............Z.*..i...V.(.....
>> .H.).H.(
>> 09:47:43.960144 IP (tos 0x0, ttl 64, id 29250, offset 0, flags [DF],
> proto TCP (6), length 52)
>>     127.0.0.1.8080 > 127.0.0.1.44078: Flags [.], cksum 0xfe28 (incorrect
> -> 0x1695), seq 1, ack 122, win 342, options [nop,nop,TS val 273198387 ecr
> 273198377], length 0
>> E..4rB@.@...............*..i..Z....V.(.....
>> .H.3.H.)
>> 09:47:44.380384 IP (tos 0x0, ttl 64, id 29251, offset 0, flags [DF],
> proto TCP (6), length 179)
>>     127.0.0.1.8080 > 127.0.0.1.44078: Flags [P.], cksum 0xfea7 (incorrect
> -> 0xe005), seq 1:128, ack 122, win 342, options [nop,nop,TS val 273198492
> ecr 273198377], length 127
>> E...rC@.@...............*..i..Z....V.......
>> .H...H.)HTTP/1.1 200 OK
>> Server: Apache-Coyote/1.1
>> Transfer-Encoding: chunked
>> Date: Tue, 18 Oct 2016 07:47:44 GMT
>>
>> b
>> Hello world
>>
>> 09:47:44.380398 IP (tos 0x0, ttl 64, id 52626, offset 0, flags [DF],
> proto TCP (6), length 40)
>>     127.0.0.1.44078 > 127.0.0.1.8080: Flags [R], cksum 0xd571 (correct),
> seq 3052296895, win 0, length 0
>> E..(..@.@.o;..............Z.....P....q..
>>
>> This shows the python "client", sends a FIN to tomcat, tomcat PUSH anyway
> and then the "client" RESETs.
>>
>> Thomas
>>
>> 2016-10-10 19:10 GMT+02:00 Mark Thomas <ma...@apache.org>:
>>>
>>> On 10/10/2016 15:47, Thomas Boniface wrote:
>>>> Hello,
>>>>
>>>> I have managed to test this use case on the server revealing the issue
> with
>>>> the latest tomcat release (7.0.72). I still can observe the issue on
>>>> catalina.out side: a broken pipe exception pops up and a recycle is
> shown
>>>> for the async context but no complete.
>>>
>>> Steps to reproduce?
>>>
>>> Better still, a test case that demonstrates the issue?
>>>
>>> Mark
>>>
>>>
>>>>
>>>> Oct 10, 2016 4:41:07 PM org.apache.coyote.AbstractProcessor
> setErrorState
>>>> INFO: An error occurred in processing while on a non-container thread.
> The
>>>> connection will be closed immediately
>>>> java.net.SocketException: Broken pipe
>>>>     at java.net.SocketOutputStream.$$YJP$$socketWrite0(Native Method)
>>>>     at
> java.net.SocketOutputStream.socketWrite0(SocketOutputStream.java)
>>>>     at
> java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
>>>>     at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
>>>>     at
>>>>
> org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:215)
>>>>     at
> org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480)
>>>>     at
>>>>
> org.apache.coyote.http11.InternalOutputBuffer.endRequest(InternalOutputBuffer.java:159)
>>>>     at
>>>>
> org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:761)
>>>>     at org.apache.coyote.Response.action(Response.java:174)
>>>>     at org.apache.coyote.Response.finish(Response.java:274)
>>>>     at
>>>> org.apache.catalina.connector.OutputBuffer.close(OutputBuffer.java:322)
>>>>     at
>>>>
> org.apache.catalina.connector.CoyoteOutputStream.close(CoyoteOutputStream.java:108)
>>>> ...
>>>> Oct 10, 2016 4:41:07 PM org.apache.catalina.core.AsyncContextImpl
> logDebug
>>>> FINE: Req: 2de85b25  CReq: 70e2c044  RP: 1dff11c5  Stage: 7  Thread:
>>>> http-bio-8080-exec-8  State:                  N/A  Method: recycle
>>>> URI:
>>>>
> /www/delivery/swfIndex.php?reqType=AdsSetup&protocolVersion=2.0&zoneId=5335
>>>>
>>>> On application logs side the behavior changed a bit as I now have a
>>>> IllegalStateException:
>>>>
>>>> java.lang.IllegalStateException: It is illegal to call this method if
> the
>>>> current request is not in asynchronous mode (i.e. isAsyncStarted()
> returns
>>>> false)
>>>>     at
>>>>
> org.apache.catalina.connector.Request.getAsyncContext(Request.java:1740)
>>>> ~[catalina.jar:7.0.72]
>>>>
>>>> In the end, the situation seems pretty similar. The container appears
> to
>>>> recycle the request without completing the async context and I can't
>>>> complete on application side as the request I have is now recycled.
>>>>
>>>> Thanks,
>>>> Thomas
>>>>
>>>>
>>>> 2016-10-03 17:06 GMT+02:00 Thomas Boniface <tho...@stickyads.tv>:
>>>>
>>>>> Hi,
>>>>>
>>>>> Thanks for your feedbacks. I noticed the issue I described do not
> occur on
>>>>> my local or integration environment. I still try to figure out how to
>>>>> reproduce this in an environment I can easely update to the latest
> tomcat
>>>>> version.
>>>>>
>>>>> Although it may not occur in latest release. Could you give me an
> input on
>>>>> what are the consequences of the behaviour I described ?
>>>>>
>>>>> Thanks,
>>>>> Thomas
>>>>>
>>>>> 2016-09-29 9:41 GMT+02:00 Violeta Georgieva <violet...@apache.org>:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> 2016-09-29 10:14 GMT+03:00 Thomas Boniface <tho...@stickyads.tv>:
>>>>>>>
>>>>>>> The tomcat version is 7.0.64.
>>>>>>
>>>>>> I would recommend you to verify the behaviour against the latest
> Tomcat 7
>>>>>> (7.0.72).
>>>>>> We have changes in the async processing since 7.0.64.
>>>>>> http://tomcat.apache.org/tomcat-7.0-doc/changelog.html
>>>>>>
>>>>>> Regards,
>>>>>> Violeta
>>>>>>
>>>>>>> Thomas
>>>>>>>
>>>>>>> 2016-09-28 22:43 GMT+02:00 Christopher Schultz <
>>>>>> ch...@christopherschultz.net
>>>>>>>> :
>>>>>>>
>>>> Thomas,
>>>>
>>>> On 9/28/16 11:55 AM, Thomas Boniface wrote:
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> When a client calls an asynchronous servlet and closes the
>>>>>>>>>> connection a java.io.IOException: Broken pipe is catched by
> Tomcat
>>>>>>>>>> level when the webapp tries to write to the socket.
>>>>>>>>>>
>>>>>>>>>> This exception is not transmited to the webapp level but it seems
>>>>>>>>>> the request has been recycled (all content is reinitialised), in
>>>>>>>>>> such a case it impossible for the webapp to retrieve the
>>>>>>>>>> AsyncContext from the HttpServletRequest making the AsyncContext
>>>>>>>>>> complete call impossible.
>>>>>>>>>>
>>>>>>>>>> Activating the tomcat logging for AsyncContext
>>>>>>>>>> (org.apache.catalina.core.AsyncContextImpl.level = FINE) shows
> the
>>>>>>>>>> recycle method is called but not the complete method, what seems
> to
>>>>>>>>>> confirm my assumption. In a use case were the client waits for
> the
>>>>>>>>>> response, I can see both complete and recycle are called.
>>>>>>>>>>
>>>>>>>>>> My question is, what is the impact of the complete not being
> called
>>>>>>>>>> on the AsyncContext, is the socket cleaned up properly ?
>>>>
>>>> Tomcat version?
>>>>
>>>> -chris
>>>>>>>>
>>>>>>>>
> ---------------------------------------------------------------------
>>>>>>>> To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
>>>>>>>> For additional commands, e-mail: users-h...@tomcat.apache.org
>>>>>>>>
>>>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
>>> For additional commands, e-mail: users-h...@tomcat.apache.org
>>>
>>
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to