[JERSEY-2865] BufferOverflowException in SSE Created: 15/May/15  Updated: 30/Jul/15  Resolved: 24/Jun/15

Status: Resolved
Project: jersey
Component/s: media
Affects Version/s: 2.17
Fix Version/s: 2.19

Type: Bug Priority: Major
Reporter: panghy Assignee: Michal Gajdos
Resolution: Fixed Votes: 0
Labels: 1221, pull-request
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
is duplicated by JERSEY-2885 Chunked responses can be corrupt and ... Resolved

 Description   

Emitting large data with SSE can cause a BufferOverflowException.

! java.nio.BufferOverflowException: null
! at java.nio.Buffer.nextPutIndex(Buffer.java:513) ~[na:1.7.0_65]
! at java.nio.HeapByteBuffer.put(HeapByteBuffer.java:163) ~[na:1.7.0_65]
! at org.eclipse.jetty.util.BufferUtil.append(BufferUtil.java:377) ~[queryserver.jar:na]! at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:231) ~[queryserver.jar:na]
! at org.glassfish.jersey.servlet.internal.ResponseWriter$NonCloseableOutputStreamWrapper.write(ResponseWriter.java:289) ~[queryserver.jar:na]! at org.glassfish.jersey.message.internal.CommittingOutputStream.write(CommittingOutputStream.java:244) ~[queryserver.jar:na]
! at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$UnCloseableOutputStream.write(WriterInterceptorExecutor.java:289) ~[queryserver.jar:na]
! at org.glassfish.jersey.media.sse.OutboundEventWriter$1.write(OutboundEventWriter.java:152) ~[queryserver.jar:na]
! at java.io.OutputStream.write(OutputStream.java:116) ~[na:1.7.0_65]
! at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221) ~[na:1.7.0_65]
! at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291) ~[na:1.7.0_65]
! at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:295) ~[na:1.7.0_65]
! at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141) ~[na:1.7.0_65]
! at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229) ~[na:1.7.0_65]
! at org.glassfish.jersey.message.internal.ReaderWriter.writeToAsString(ReaderWriter.java:190) ~[queryserver.jar:na]
! at org.glassfish.jersey.message.internal.AbstractMessageReaderWriterProvider.writeToAsString(AbstractMessageReaderWriterProvider.java:130) ~[queryserver.jar:n
a]
! at org.glassfish.jersey.message.internal.StringMessageProvider.writeTo(StringMessageProvider.java:99) ~[queryserver.jar:na]
! at org.glassfish.jersey.message.internal.StringMessageProvider.writeTo(StringMessageProvider.java:59) ~[queryserver.jar:na]
! at org.glassfish.jersey.media.sse.OutboundEventWriter.writeTo(OutboundEventWriter.java:135) ~[queryserver.jar:na]
! at org.glassfish.jersey.media.sse.OutboundEventWriter.writeTo(OutboundEventWriter.java:65) ~[queryserver.jar:na]
! at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:265) ~[queryserver.jar:na]
! at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:250) ~[queryserver.jar:na]
! at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162) ~[queryserver.jar:na]
! at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1128) ~[queryserver.jar:na]
! at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:219) ~[queryserver.jar:na]
! at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:190) ~[queryserver.jar:na]
! at org.glassfish.jersey.internal.Errors.process(Errors.java:315) ~[queryserver.jar:na]
! at org.glassfish.jersey.internal.Errors.process(Errors.java:242) ~[queryserver.jar:na]
! at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:367) ~[queryserver.jar:na]
! at org.glassfish.jersey.server.ChunkedOutput.flushQueue(ChunkedOutput.java:190) ~[queryserver.jar:na]
! at org.glassfish.jersey.server.ChunkedOutput.write(ChunkedOutput.java:180) ~[queryserver.jar:na]


 Comments   
Comment by panghy [ 15/May/15 ]

I am pretty sure there's a synchronization bug in ChunkedOutput.java line 196

    private void flushQueue() throws IOException {
...
            requestScope.runInScope(requestScopeInstance, new Callable<Void>() {
                @Override
                public Void call() throws IOException {
                     ...
                     synchronized (this) {
                        if (flushing) {
                            // if another thread is already flushing the queue, we don't have to do anything
                            return null;
                        }
...

The synchronized should be on "ChunkedOutput.this" instead of "this" since it's just referring to the Callable (hence there is no thread safety contrary to what the comment would suggest).

Comment by panghy [ 15/May/15 ]

The original code was right in the first place:

Fixed issue JERSEY-1256
ChunkedResponse.flushQueue now returns immediately if other thread is already
flushing the queue instead of blocking on synchronized.
Only small pieces of the method are synchronized now.

Change-Id: I7625d9d68f4da9e719333a198332b37261e08b15
commit 898f408108ed9f888c3d30c85222e95d86853c44 1 parent 0606c34
@mmatula mmatula authored on Jul 1, 2012

It was "broken" when it got wrapped in a Callable in this check-in

Fixed: ChunkedOutput not writing data in request scope.
Change-Id: I262d48aad3308133de415c12a44e8b3ab92d20b8
Signed-off-by: Marek Potociar <marek.potociar@oracle.com>
commit 1e428d7b82baefea401ed3cd92f3d1a727abd2c3 1 parent a71fe9e
@mpotociar mpotociar authored on Sep 23, 2013
Comment by panghy [ 15/May/15 ]

Pull request created: https://github.com/jersey/jersey/pull/165

Comment by panghy [ 15/May/15 ]

The title and description of this bug should probably be changed to reflect the actual issue and scope (it's not really limited to SSE, all ChunkedOutput that's called by multiple threads is affected by this bug).

Comment by Adam Lindenthal [ 15/May/15 ]

Hi panghy,

thanks for reporting and for the pull request. I'll move the issue to backlog, as we are waiting for review/merge your pull request.

Thanks,
Adam





[JERSEY-2885] Chunked responses can be corrupt and truncated: broken synchronization Created: 10/Jun/15  Updated: 30/Jul/15  Resolved: 30/Jul/15

Status: Resolved
Project: jersey
Component/s: core
Affects Version/s: 2.6
Fix Version/s: 2.19

Type: Bug Priority: Major
Reporter: vladimir.eatwell Assignee: Michal Gajdos
Resolution: Duplicate Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
duplicates JERSEY-2865 BufferOverflowException in SSE Resolved

 Description   

We have services streaming responses using ChunkedOutput. These responses are sometimes corrupt causing the client to reset the connection.

Inspecting the packets show bad response chunks - e.g. chunk length is 8192 but following chunk is longer and contain corrupt data (looks like one chunk scribbled on top of another).

Found a synchronization problem in ChunkedOutput - fixing has stopped the problem (so far).

ChunkedOutput line 196: synchronized(this) should be synchronized(ChunkedOutput.this)

See: https://gist.github.com/anonymous/cd4fe0076a39d10caeb2



 Comments   
Comment by Michal Gajdos [ 30/Jul/15 ]

Duplicate of JERSEY-2865. Fixed in 2.19.





[JERSEY-2862] File upload is broken in Jersey 2.17 Created: 13/May/15  Updated: 30/Jul/15  Resolved: 30/Jul/15

Status: Resolved
Project: jersey
Component/s: media
Affects Version/s: 2.17
Fix Version/s: 2.20

Type: Bug Priority: Major
Reporter: Scott Palmer Assignee: Michal Gajdos
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows 7 64-bit
Java 8u40


Tags: regression, upload

 Description   

This is the commit that did it:

https://github.com/jersey/jersey/commit/d90369ca0e872df280979f04669894871f5c8189#diff-71e5b60df38390f13c313b6cc9847efd

The problem is that the temp file can't be renamed because an empty file with the destination name is created and left there, blocking the moveTo from succeeding.

https://github.com/jersey/jersey/blob/master/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/FormDataParamValueFactoryProvider.java#L253

The problem is hidden because the ultimate renameTo call in WeakDataFile simply logs the failure without letting the caller know that the rename failed.

May 12, 2015 11:40:50 AM org.jvnet.mimepull.WeakDataFile renameTo
INFO: File C:\Users\SCOTT~1.PAL\AppData\Local\Temp\MIME9174014175637264696.tmp was not moved to C:\Users\SCOTT~1.PAL\AppData\Local\Temp\rep818068880122345050tmp

The result is that the web service, with a parameter declared as: @FormDataParam("file") File file, is always given a reference to an empty temp file.

Reverting to Jersey 2.16 fixes the issue.



 Comments   
Comment by Adam Lindenthal [ 15/May/15 ]

Hi, thanks for opening the issue.
I am moving it to backlog, so that we can plan the work on it.

Regards,
Adam





[JERSEY-2920] NPE From LoggingFilter on 404 Errors Created: 22/Jul/15  Updated: 29/Jul/15  Resolved: 29/Jul/15

Status: Resolved
Project: jersey
Component/s: None
Affects Version/s: 2.19
Fix Version/s: 2.20

Type: Bug Priority: Major
Reporter: gilbode Assignee: Michal Gajdos
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Dropwizard 0.8.2



 Description   

Since upgrading to Jersey 2.19 we started getting NPE from the Jersey LoggingFilter on 404 requests. Downgrading to 2.18 makes the NPE go away. This looks like it could be a regression introduced by JERSEY-2871.

Partial stack trace below.

:0:0:0:0:0:0:1 - - [22/Jul/2015:20:58:46 +0000] "GET /a/b/c/ HTTP/1.1" 500 302 "-" "curl/7.37.1" 51
WARN [2015-07-22 20:58:46,069] org.eclipse.jetty.server.HttpChannel: /a/b/c/
! java.lang.NullPointerException: null
! at org.glassfish.jersey.filter.LoggingFilter.filter(LoggingFilter.java:285) ~[x-0.1.0-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.ContainerFilteringStage$ResponseFilterStage.apply(ContainerFilteringStage.java:196) ~[x-0.1.0-SNAPSHOT.jar:na]
! ... 48 common frames omitted
! Causing: org.glassfish.jersey.server.internal.process.MappableException: java.lang.NullPointerException
! at org.glassfish.jersey.server.ContainerFilteringStage$ResponseFilterStage.apply(ContainerFilteringStage.java:198) ~[x-0.1.0-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.ContainerFilteringStage$ResponseFilterStage.apply(ContainerFilteringStage.java:163) ~[x-0.1.0-SNAPSHOT.jar:na]
! at org.glassfish.jersey.process.internal.Stages.process(Stages.java:171) ~[x-0.1.0-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:422) ~[x-0.1.0-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:467) ~[x-0.1.0-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:316) ~[x-0.1.0-SNAPSHOT.jar:na]
! at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) ~[x-0.1.0-SNAPSHOT.jar:na]



 Comments   
Comment by gilbode [ 23/Jul/15 ]

Turns out that we're registering a subclass of LoggingFilter something like this in our Dropwizard:

environment.jersey().register(
new LoggingFilter(java.util.logging.Logger.getAnonymousLogger(), true) {});

The subclass seems to be the cause of the issue.





[JERSEY-2775] Server-Sent Events - write to broken connection does not throw exception Created: 06/Feb/15  Updated: 29/Jul/15  Resolved: 27/Jul/15

Status: Resolved
Project: jersey
Component/s: media
Affects Version/s: 2.15
Fix Version/s: None

Type: Bug Priority: Major
Reporter: ricb Assignee: Libor Kramolis
Resolution: Invalid Votes: 0
Labels: sse
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Tomcat 7.0.53, RHEL 6.


Tags: sse

 Description   

We are using Server-Sent Events to allow our client application to listen to events raised by our Jersey server. This works great.

We have a requirement for our server to have an accurate list of currently-connected SSE callers (instances of our client application). To this end, our server sends a tiny message to each client (via eventOutput.write) once every five seconds. If our client is shut down while SSE-connected, or if the remote computer is powered off while SSE-connected, our server's eventOutput.write call correctly throws the ClientAbortException/SocketException exception shown below. That's perfect: we catch the exception, and mark that client as no longer connected.

The problem: there are two cases where calling eventOutput.write to a no-longer-connected computer does NOT throw an exception: 1) if the Ethernet cable of the remote computer is disconnected while the client is SSE-connected, and 2) if the network adapter in the remote computer is turned off (e.g., by an administrator) while the client is SSE-connected. In these two cases, eventOutput.write does not throw an exception. We can call eventOutput.write to the remote computer every five seconds for hours and no exception is thrown. This makes it impossible to detect that the remote computer is no longer connected.

To sum up, there are four cases:

1) Client software is shut down: eventOutput.write() correctly throws an exception.
2) Computer running client software is powered down: eventOutput.write() correctly throws an exception.
3) Etherhet cable is disconnected from computer running client software: eventOutput.write does not detect broken connection.
4) Network adapter on computer running client software is turned off: eventOutput.write does not detect broken connection.

Here is the (good/useful) exception we get in cases where eventOutput.write DOES throw the exception we want:

org.apache.catalina.connector.ClientAbortException: null
    at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:371) ~[catalina.jar:7.0.53]
    at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:333) ~[catalina.jar:7.0.53]
    at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:101) ~[catalina.jar:7.0.53]
    at org.glassfish.jersey.servlet.internal.ResponseWriter$NonCloseableOutputStreamWrapper.flush(ResponseWriter.java:303) ~[jaxrs-ri-2.13.jar:2.13.]
    at org.glassfish.jersey.message.internal.CommittingOutputStream.flush(CommittingOutputStream.java:292) ~[jaxrs-ri-2.13.jar:2.13.]
    at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:240) ~[jaxrs-ri-2.13.jar:2.13.]
    at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:190) ~[jaxrs-ri-2.13.jar:2.13.]
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315) ~[jaxrs-ri-2.13.jar:2.13.]
    at org.glassfish.jersey.internal.Errors.process(Errors.java:242) ~[jaxrs-ri-2.13.jar:2.13.]
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:347) ~[jaxrs-ri-2.13.jar:2.13.]
    at org.glassfish.jersey.server.ChunkedOutput.flushQueue(ChunkedOutput.java:190) ~[jaxrs-ri-2.13.jar:2.13.]
    at org.glassfish.jersey.server.ChunkedOutput.write(ChunkedOutput.java:180) ~[jaxrs-ri-2.13.jar:2.13.]
    at com.appserver.webservice.AgentSsePollingManager$ConnectionChecker.run(AgentSsePollingManager.java:174) ~[AgentSsePollingManager$ConnectionChecker.class:na]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) [na:1.7.0_71]
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304) [na:1.7.0_71]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178) [na:1.7.0_71]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.7.0_71]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_71]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_71]
    at java.lang.Thread.run(Thread.java:745) [na:1.7.0_71]
Caused by: java.net.SocketException: Broken pipe
    at java.net.SocketOutputStream.socketWrite0(Native Method) ~[na:1.7.0_71]
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113) ~[na:1.7.0_71]
    at java.net.SocketOutputStream.write(SocketOutputStream.java:159) ~[na:1.7.0_71]
    at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:215) ~[tomcat-coyote.jar:7.0.53]
    at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480) ~[tomcat-coyote.jar:7.0.53]
    at org.apache.coyote.http11.InternalOutputBuffer.flush(InternalOutputBuffer.java:119) ~[tomcat-coyote.jar:7.0.53]
    at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:799) ~[tomcat-coyote.jar:7.0.53]
    at org.apache.coyote.Response.action(Response.java:174) ~[tomcat-coyote.jar:7.0.53]
    at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:366) ~[catalina.jar:7.0.53]
    ... 19 common frames omitted


 Comments   
Comment by Libor Kramolis [ 24/Jul/15 ]

Hi @ricb. I'm sorry I can hardly reproduce it. Please try to prepare reproducible test case.

I've tried to reproduce it using Jersey sse-item-store-webapp example and Virtual Boxed Ubuntu Linux to enable/disable network. And no matter if I've used local curl or virtual boxed one it always logs following exception:

org.eclipse.jetty.io.EofException
        at org.eclipse.jetty.io.ChannelEndPoint.flush(ChannelEndPoint.java:188)
        at org.eclipse.jetty.io.WriteFlusher.write(WriteFlusher.java:335)
        at org.eclipse.jetty.io.AbstractEndPoint.write(AbstractEndPoint.java:125)
        at org.eclipse.jetty.server.HttpConnection$ContentCallback.process(HttpConnection.java:680)
        at org.eclipse.jetty.util.IteratingCallback.processIterations(IteratingCallback.java:166)
        at org.eclipse.jetty.util.IteratingCallback.iterate(IteratingCallback.java:126)
        at org.eclipse.jetty.server.HttpConnection.send(HttpConnection.java:303)
        at org.eclipse.jetty.server.HttpChannel.sendResponse(HttpChannel.java:720)
        at org.eclipse.jetty.server.HttpChannel.write(HttpChannel.java:751)
        at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:128)
        at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:122)
        at org.eclipse.jetty.server.HttpOutput.flush(HttpOutput.java:201)
        at org.glassfish.jersey.servlet.internal.ResponseWriter$NonCloseableOutputStreamWrapper.flush(ResponseWriter.java:308)
        at org.glassfish.jersey.message.internal.CommittingOutputStream.flush(CommittingOutputStream.java:292)
        at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:240)
        at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:190)
        at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
        at org.glassfish.jersey.internal.Errors.process(Errors.java:242)
        at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:367)
        at org.glassfish.jersey.server.ChunkedOutput.flushQueue(ChunkedOutput.java:190)
        at org.glassfish.jersey.server.ChunkedOutput.write(ChunkedOutput.java:180)
        at org.glassfish.jersey.server.Broadcaster$1.run(Broadcaster.java:154)
        at org.glassfish.jersey.server.Broadcaster$1.run(Broadcaster.java:151)
        at org.glassfish.jersey.server.Broadcaster.forEachOutput(Broadcaster.java:204)
        at org.glassfish.jersey.server.Broadcaster.broadcast(Broadcaster.java:151)
        at org.glassfish.jersey.examples.sseitemstore.ItemStoreResource.addItem(ItemStoreResource.java:237)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
        at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)
        at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:160)
        at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$VoidOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:142)
        at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
        at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
        at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
        at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
        at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:309)
        at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
        at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
        at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
        at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
        at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
        at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
        at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:292)
        at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1139)
        at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:403)
        at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:386)
        at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:334)
        at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:221)
        at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:717)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1644)
        at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:164)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1615)
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:550)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:568)
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:221)
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1110)
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:479)
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:183)
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1044)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
        at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:199)
        at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:109)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
        at org.eclipse.jetty.server.Server.handle(Server.java:459)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:281)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:232)
        at org.eclipse.jetty.io.AbstractConnection$1.run(AbstractConnection.java:505)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:607)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:536)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: Broken pipe
        at sun.nio.ch.FileDispatcherImpl.writev0(Native Method)
        at sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:51)
        at sun.nio.ch.IOUtil.write(IOUtil.java:148)
        at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:504)
        at org.eclipse.jetty.io.ChannelEndPoint.flush(ChannelEndPoint.java:169)
        ... 73 more

It means it is Jetty and the latest Jersey 2.20-SNAPSHOT version.

Maybe it really depends on environment. My suggestion is to "call clients" (eventOutput.write) setting up timeout. (You can wrap it by Netflix Hystrix Command for example.)

Comment by ricb [ 24/Jul/15 ]

Thanks for working on this, Libor! Sure, I can easily reproduce the problem. It occurs dozens of times per day on our production server, so finding/recreating it is not tricky. I have not tested with VirtualBox in particular. Also, 100% of our client machines run Windows. Two suggestions: 1) can you run this test with a Windows caller? 2) Can you try putting the client (even you Ubuntu client) in hibernate mode and writing to it?

I can provide the code for simple client and server to reproduce the problem if you like. Also, I can set up a VirtualBox running Ubuntu to verify that I can reproduce your result (exception is created), or let you know if I get a different result.

We would be thrilled to get this issue resolved. Please let me know what would be the most useful way to proceed from here.

Ric

Comment by ricb [ 25/Jul/15 ]

Hi, Libor. Today I created simple sse-server and sse-client java projects to demonstrate the bug. The sse-client project merely opens an sse connection to an sse server, listens for messages, and logs all of the messages it receives. The sse-server project runs under Jersey (and Tomcat in my case). It accepts any sse-connection requests (each caller is identified by an id value that is the last segment of the query string) and writes (eventOutput.write) a trivial message ("EOM") to each caller every five seconds. If any write throws an exception, that caller is removed from the collection of callers. Everything is logged.

I ran two tests with these projects:

1) I ran sseclient.jar on a desktop system with a hard-wired Ethernet connection. Once sseclient had established an sse connection to the sseserver project running on a different computer, and had received several sse messages at five-second intervals, I pulled the Ethernet cable from the desktop running the sseclient project. The sseserver Jersey application continued to write "EOM" messages to the no-longer-connected client indefinitely. (Note that sseserver correctly threw an exception if I either stopped the sseclient program or powered down the computer.)

2) I created an Ubuntu 14 system using VirtualBox on my development laptop. On the Ubuntu system, I ran sseclient.jar. Once it had established an sse connection to the sseserver project running on the host computer, and had received several sse message at five-second intervals, I used the Ubuntu system settings "network" utility to turn off the "Wired" connection (this is the only network adapter – there is no wireless configured in this Ubuntu instance). Here too, the sseserver Jerson application continued to write "EOM" messages to the no-longer-connected sse client indefinitely.

So, I am quite confident that you will be able to reproduce the problem if you run my sseserver and sseclient projects. I put the source code for them on github here:

https://github.com/ricpdx/jerseysse.git

The client project is a console application. It expects three parameters: hostname, id, duration. The hostname is simply the ip address or dns name of the system running sseserver. The "id" is any string you care to use to identify the caller uniquely (e.g., "abc", "xyz", whatever). The "duration" is an integer. It serves two purposes. If you set duration to zero, the client reads sse events using Jersey's EventInput class (https://jersey.java.net/documentation/latest/sse.html#d0e11802). If you set duration to > 0, the client reads sse events using Jersey's EventSource class (https://jersey.java.net/documentation/latest/sse.html#d0e11876). Further, in the second case, duration is used as the number of seconds the client should listen for sse events.

Comment by Libor Kramolis [ 27/Jul/15 ]

Hi Ric.

Thanks for testing application. Unfortunately I'm not able to reproduce your infinite waiting problem. This is operation system issue and depends on socket connection time setup.

I've taken your sseserver application, deployed it into Apache Tomcat. For me it was easier to use Chrome or Curl on server side. I've used 2 machines: Windows 7 and MacOSX Yosemite. With following results:
1) Win: Client; Mac: Server : about 70 seconds timeout
2) Win: Server; Mac: Client : about 30 seconds timeout

It really depends on OS setup. There is no way how to influence socket timeouts and retries on Java/Jersey side. It seams your environment setup causes "infinite timeout".

Check your server side network setup on OS level, e.g. http://superuser.com/questions/339959/how-to-set-tcp-ip-abort-interval-or-timeout-in-windows-xp in case of Windows on server side.

Comment by Libor Kramolis [ 27/Jul/15 ]

Closing as Invalid because there is no way how to change "socket timeout behaviour" on Jersey side.

Comment by ricb [ 27/Jul/15 ]

Hi, Libor. Thanks again for your work on this.

I can certainly look up how to configure our server socket parameters. We use linux (RHEL) on all of our servers, btw.

However, I have one question for you first. You say that your mac-server test timed out after 70 seconds. Where are you catching this exception, and what API is throwing the exception? Are you catching the exception on a subsequent call of eventOutput.write? Or do you perhaps register a callback method to catch the exception from some other source?

Comment by Libor Kramolis [ 28/Jul/15 ]

Yes, it was from eventOutput.write call:

org.apache.catalina.connector.ClientAbortException: java.io.IOException: Host is down
	at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:389) ~[catalina.jar:8.0.11]
	at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:426) ~[tomcat-util.jar:8.0.11]
	at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:338) ~[catalina.jar:8.0.11]
	at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:313) ~[catalina.jar:8.0.11]
	at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:110) ~[catalina.jar:8.0.11]
	at org.glassfish.jersey.servlet.internal.ResponseWriter$NonCloseableOutputStreamWrapper.flush(ResponseWriter.java:308) ~[ResponseWriter$NonCloseableOutputStreamWrapper.class:2.19.]
	at org.glassfish.jersey.message.internal.CommittingOutputStream.flush(CommittingOutputStream.java:292) ~[CommittingOutputStream.class:2.19.]
	at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:240) ~[ChunkedOutput$1.class:2.19.]
	at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:190) ~[ChunkedOutput$1.class:2.19.]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:315) ~[Errors.class:2.19.]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:242) ~[Errors.class:2.19.]
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:367) ~[RequestScope.class:2.19.]
	at org.glassfish.jersey.server.ChunkedOutput.flushQueue(ChunkedOutput.java:190) ~[ChunkedOutput.class:2.19.]
	at org.glassfish.jersey.server.ChunkedOutput.write(ChunkedOutput.java:180) ~[ChunkedOutput.class:2.19.]
	at sseserver.SseWriteManager$messageProcessor.run(SseWriteManager.java:48) ~[SseWriteManager$messageProcessor.class:na]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_45]
	at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [na:1.8.0_45]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_45]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [na:1.8.0_45]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_45]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_45]
	at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45]
Caused by: java.io.IOException: Host is down
	at sun.nio.ch.FileDispatcherImpl.write0(Native Method) ~[na:1.8.0_45]
	at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47) ~[na:1.8.0_45]
	at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93) ~[na:1.8.0_45]
	at sun.nio.ch.IOUtil.write(IOUtil.java:65) ~[na:1.8.0_45]
	at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471) ~[na:1.8.0_45]
	at org.apache.tomcat.util.net.NioChannel.write(NioChannel.java:127) ~[tomcat-coyote.jar:8.0.11]
	at org.apache.tomcat.util.net.NioBlockingSelector.write(NioBlockingSelector.java:101) ~[tomcat-coyote.jar:8.0.11]
	at org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:173) ~[tomcat-coyote.jar:8.0.11]
	at org.apache.coyote.http11.InternalNioOutputBuffer.writeToSocket(InternalNioOutputBuffer.java:139) ~[tomcat-coyote.jar:8.0.11]
	at org.apache.coyote.http11.InternalNioOutputBuffer.addToBB(InternalNioOutputBuffer.java:197) ~[tomcat-coyote.jar:8.0.11]
	at org.apache.coyote.http11.InternalNioOutputBuffer.access$000(InternalNioOutputBuffer.java:41) ~[tomcat-coyote.jar:8.0.11]
	at org.apache.coyote.http11.InternalNioOutputBuffer$SocketOutputBuffer.doWrite(InternalNioOutputBuffer.java:320) ~[tomcat-coyote.jar:8.0.11]
	at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:116) ~[tomcat-coyote.jar:8.0.11]
	at org.apache.coyote.http11.AbstractOutputBuffer.doWrite(AbstractOutputBuffer.java:257) ~[tomcat-coyote.jar:8.0.11]
	at org.apache.coyote.Response.doWrite(Response.java:492) ~[tomcat-coyote.jar:8.0.11]
	at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:384) ~[catalina.jar:8.0.11]
	... 21 common frames omitted
Comment by ricb [ 28/Jul/15 ]

Thanks, Libor. Let me understand more clearly.

1. Is the write performed by eventOutput.write synchronous or asynchronous? In other words, does it return to Jersey immediately?

2. If the write is asynchronous, is the exception thrown on the first write after the connection times out, or the second write after the connection times out. For example, let's say the application is calling eventOutput.write every five seconds. If the connection times out at 1:00:58 and the application calls eventOutput at 1:01:00 and 1:01:05, which of these two calls with throw the exception?

3. What Tomcat connector are you using: BIO, NIO, or APR? (We started with BIO then switched to NIO. We are now in the process of changing to APR, which is also blocking.)

Comment by Libor Kramolis [ 29/Jul/15 ]

I did not tune any Tomcat connector so some Tomcat default one was used. And I guess from Java/Jersey perspective it is synchronous but an application was not blocked - it returned immediately from eventOutput.write call. So it is asynchronous on OS level.





[JERSEY-2848] Time Window Statistics don't reset correctly after period of inactivity. Created: 23/Apr/15  Updated: 29/Jul/15  Resolved: 29/Jul/15

Status: Resolved
Project: jersey
Component/s: core
Affects Version/s: 2.17
Fix Version/s: 2.20

Type: Bug Priority: Major
Reporter: RayB Assignee: Stepan Vavra
Resolution: Fixed Votes: 0
Labels: 1221
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

In class org.glassfish.jersey.server.internal.monitoring.TimeWindowStatisticsImpl$Builder

totalCount and totalDuration are not being zero'd out when resetQueue() is called.

Lets say for example we are interested in the 15-second stats.
Then this can be observed by:
1. send 5 requests to some resource
2. immediately check the 15-second time-window stats for that resource. it will say 5
3. wait more than 15-seconds
4. send one more request to the same resource
5. check the 15-second time-window stats for that resource again. it will incorrectly say 6, instead of 1

The stats work correctly if you continuously send in requests, but if there is a gap of time greater than the time-window, then it breaks. What happens is the last count before the gap, becomes the new baseline, and future stats are added to that value, it never goes back to zero. this can happen over and over again, with the stats becoming very large and never resetting to zero.

FIXED CODE:

private void resetQueue(final long requestTime) {
this.unitQueue.clear();
lastUnitEnd = requestTime + unit;
resetLastUnit();

// RayB: suggested BUGFIX next 2-lines
totalCount = 0;
totalDuration = 0;

// fill with empty unit to keep result consistent
for (int i = 0; i < unitsPerInterval; i++)

{ unitQueue.add(Unit.EMPTY_UNIT); }

}



 Comments   
Comment by Stepan Vavra [ 29/Jul/15 ]

Thanks,
it should be ok in release 2.20!





[JERSEY-2700] LoggingFilter trying to process empty entity when receives transfer-encoding:chunked in headers Created: 05/Nov/14  Updated: 29/Jul/15  Resolved: 27/Jul/15

Status: Resolved
Project: jersey
Component/s: core
Affects Version/s: 2.13
Fix Version/s: backlog

Type: Bug Priority: Minor
Reporter: RedYou_3 Assignee: Stepan Vavra
Resolution: Cannot Reproduce Votes: 0
Labels: 1221
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows 7, Java 1.8.0_20, 'org.glassfish.jersey.core:jersey-common:2.13'



 Description   

When client sends DELETE request to jersey endpoint with transfer-encoding:chunked in header, class LoggingFilter tries to process body anyway and it produces the following exception:

java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.checkBounds(String.java:369)
at java.lang.String.<init>(String.java:450)
at org.glassfish.jersey.filter.LoggingFilter.logInboundEntity(LoggingFilter.java:217)
at org.glassfish.jersey.filter.LoggingFilter.filter(LoggingFilter.java:269)
at org.glassfish.jersey.server.ContainerFilteringStage.apply(ContainerFilteringStage.java:131)
at org.glassfish.jersey.server.ContainerFilteringStage.apply(ContainerFilteringStage.java:67)
at org.glassfish.jersey.process.internal.Stages.process(Stages.java:197)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:263)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:297)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:254)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1030)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:373)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:221)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at uk.org.***.AuthenticationTokenProcessingFilter.doFilter(AuthenticationTokenProcessingFilter.java:101)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:683)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1721)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1679)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)


 Comments   
Comment by Adam Lindenthal [ 13/Jan/15 ]

HI RedYou_3,

thanks for submitting this.
I just moved the issue to backlog, which is where we take the issues for further planning and work from.

Regards,
Adam

Comment by Stepan Vavra [ 27/Jul/15 ]

Hi RedYou,
it has been a while since you reported this issue. We're sorry we weren't able to look at it till now. Anyway, I wasn't able to reproduce your issue. May I kindly ask you to provide us with a reproducible example?
LoggingFilter never tries to log an entity if the stream has been previously read as it calls EntityInputStream.isEmpty().
I wonder what exactly is your Jersey configuration/set up that makes the EntityInputStream.isEmpty() return false and also LoggingFilter read the entity from the stream (with a result -1 that denotes a size of the entity).
I suppose, you didn't configure the LoggingFilter with maxEntitySize equal to -1 which was the only way how I reproduced your issue.

Thanks,
Stepan





[JERSEY-2779] ServerSent Events not working when LoggingFilter is enabled with printEntity Created: 09/Feb/15  Updated: 28/Jul/15  Resolved: 28/Jul/15

Status: Resolved
Project: jersey
Component/s: core, media
Affects Version/s: 2.15
Fix Version/s: 2.16

Type: Bug Priority: Major
Reporter: quixote_arg Assignee: Stepan Vavra
Resolution: Fixed Votes: 0
Labels: 1221, sse
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

tomcat 7.0.53



 Description   

Some time ago I added a LoggingFilter to my application, like this on the "extends ResourceConfig" class:

register(new LoggingFilter(Logger.getLogger(LoggingFilter.class.getName()), true));

After some time I noticed that the server sent events stopped working.

I reproduced it with the sample from https://jersey.java.net/documentation/latest/sse.html (adding Thread.sleep(1000) to make it more asynchronous); when the LoggingFilter was enabled (with printEntity set to true) then it will wait the whole 30 seconds and output the entire response at once (instead of one per second, 30 times)

If I comment out the LoggingFilter registration or change it to:

register(LoggingFilter.class);

then the chunks arrive once per second, as expected.

Another side effect of the this bug is that when I close the client connection, no exception is thrown on the server, hence the server keeps sending events to the client, even if the connection was closed a long time ago.



 Comments   
Comment by quixote_arg [ 09/Feb/15 ]

I think that the problem is on LoggingFilter.filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) which tries to log the entire entity which the server responded, which in the case of SSE may never finish

LoggingFilter.java
        if (printEntity && responseContext.hasEntity()) {
            OutputStream stream = new LoggingStream(b, responseContext.getEntityStream());
            responseContext.setEntityStream(stream);
            requestContext.setProperty(ENTITY_LOGGER_PROPERTY, stream);
            // not calling log(b) here - it will be called by the interceptor
        } else {
            log(b);
        }
Comment by Stepan Vavra [ 28/Jul/15 ]

Hi Quixote,

based on my tests, this problem was fixed in 2.16. If the problem still remains, please don't hesitate to reopen this ticket. Additionally, in such case, please provide us with an example that reproduces the problem.

Thanks!
Stepan





[JERSEY-2590] SSE events queued when LoggingFilter with printEntity=true is present Created: 21/Jul/14  Updated: 28/Jul/15  Resolved: 28/Jul/15

Status: Resolved
Project: jersey
Component/s: core
Affects Version/s: 2.10.1
Fix Version/s: 2.15

Type: Bug Priority: Major
Reporter: rossj2 Assignee: Stepan Vavra
Resolution: Fixed Votes: 0
Labels: 1221
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Win7/32, Java 8u5, Java SE (Grizzly HTTP)

Maven:
org.glassfish.jersey.containers:jersey-container-grizzly2-http:2.10.1
org.glassfish.jersey.media:jersey-media-sse:2.10.1

Problem exists at least back to 2.4, and probably earlier.



 Description   

I have a simple Jersey SSE server application with a resource which writes a series of OutboundEvents periodically. I am using a telnet session to open the connection and send the HTTP GET request. The HTTP response headers are received (last header being the Transfer-Encoding: chunked header).

The problem is that several OutboundEvents must accumulate before a single 'chunk' is written to the socket. Exactly 8192 (8K) bytes of chunk data is sent plus the additional 8 bytes of chunk overhead (i.e. the length of '2000' and 2 lots of CRLF surrounding the data), for a total of 8200 bytes on the line (according to Wireshark).

The problem only occurs when the LoggingFilter is enabled with printEntity set to true (or maxEntitySize is supplied which implicitly enables printEntity).

I'm not sure where this 8192 is coming from. I've tried altering maxEntitySize (which has a default of 8192), with no impact on the problem. I've also tried changing the OUTBOUND_CONTENT_LENGTH_BUFFER server property which also has a default of 8192 with no impact either.



 Comments   
Comment by Michal Gajdos [ 21/Jul/14 ]

Thanks for filing this issue, moving to backlog.

Comment by Stepan Vavra [ 28/Jul/15 ]

Hi,
based on my tests, this problem was fixed in 2.15. If the problem still remains, please don't hesitate to reopen this ticket. In such case, please provide us with a simple reproducible example.

Thanks,
Stepan





[JERSEY-2673] 400 errors generated by a ValidationException are returning default error page instead of the Bean Validation's response entity Created: 01/Oct/14  Updated: 27/Jul/15  Resolved: 27/Jul/15

Status: Resolved
Project: jersey
Component/s: containers
Affects Version/s: 2.13
Fix Version/s: 2.20

Type: Bug Priority: Major
Reporter: mwnorman Assignee: Michal Gajdos
Resolution: Fixed Votes: 1
Labels: 1221
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

GrizzlyHttpServerFactory + Jersey + Bean Validation (jersey-container-grizzly2-servlet/jersey-bean-validation ver 2.12, grizzly-http-server ver 2.3.16, hibernate-validator ver 5.0.0.Final)


Attachments: Zip Archive grizzly-error-page-master.zip    

 Description   

400 errors generated by a javax.validation.ValidationException are returning
(Grizzly's) default error page (html) instead of the Bean Validation's
response entity (json). I've tried a ClientResponseFilter and its entityStream
also contains the html error page.
I have put a test project up on github. I asked on Stackoverflow (http://tinyurl.com/o7oou85) and one of
the Grizzly guys says that this is Jersey's behaviour -
org.glassfish.jersey.message.internal.CommittingOutputStream#flushBuffer(boolean) - writes JSON error message to the Servlet OutputStream
and
org.glassfish.jersey.servlet.internal.ResponseWriter#commit() - if data has been written to the response buffer, but not returned to the client (i.e. the response is not committed), the data in the response buffer must be cleared and replaced with the data set by these methods ...

I would like some configuration setting that would allow choice between
the default error page or the Bean Validation's response entity.



 Comments   
Comment by Adam Lindenthal [ 13/Oct/14 ]

Hi mwnorman,

Thanks for submitting the issue. I've just attached your github example to it. And I also edited your description a bit (so that links work etc.), hope you don't mind.

The issue will be now moved to backlog and we will take a look at it in one of the future sprints.

Regards,
Adam

Comment by jendib [ 31/Jan/15 ]

This issue seems to also affect custom WebApplicationException (https://jersey.java.net/documentation/2.15/representations.html#d0e6501).
I tried all the latest Jersey releases, and this bug was introducted in 2.11 (2.10.1 is OK), if this can help.

Comment by Michal Gajdos [ 03/Jul/15 ]

Do you still see this issue? I am somehow not able to reproduce it.





Generated at Thu Jul 30 22:59:43 UTC 2015 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.