Search code examples
javaspringspring-mvcjettyspdy

Exception in web server logs with Jetty, Spring, and SPDY


I am receiving an error below when making a rest call to Spring MVC web application. The browser receives the correct response, but I would like the exception to disappear. Any help would be great.

I am running a web server using Jetty 9.2.0.v20140526, Spring framework 4.0.5.RELEASE and NPN 1.1.6.v20130911 (SPDY)

Error Message

[STDERR] java.lang.IllegalStateException: not lastContent, no content and no responseInfo!
[STDERR]    at org.eclipse.jetty.spdy.server.http.HttpTransportOverSPDY.send(HttpTransportOverSPDY.java:164)
[STDERR]    at org.eclipse.jetty.spdy.server.http.HttpTransportOverSPDY.send(HttpTransportOverSPDY.java:97)
[STDERR]    at org.eclipse.jetty.server.HttpChannel.sendResponse(HttpChannel.java:733)
[STDERR]    at org.eclipse.jetty.server.HttpChannel.write(HttpChannel.java:766)
[STDERR]    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:134)
[STDERR]    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:127)
[STDERR]    at org.eclipse.jetty.server.HttpOutput.flush(HttpOutput.java:229)
[STDERR]    at java.io.FilterOutputStream.flush(FilterOutputStream.java:140)
[STDERR]    at org.eclipse.jetty.servlets.gzip.AbstractCompressedStream.flush(AbstractCompressedStream.java:125)
[STDERR]    at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:209)
[STDERR]    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:143)
[STDERR]    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:89)
[STDERR]    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:193)
[STDERR]    at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:71)
[STDERR]    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:122)
[STDERR]    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
[STDERR]    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
[STDERR]    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
[STDERR]    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
[STDERR]    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
[STDERR]    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
[STDERR]    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
[STDERR]    at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
[STDERR]    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
[STDERR]    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
[STDERR]    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:751)
[STDERR]    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1666)
[STDERR]    at org.eclipse.jetty.servlets.UserAgentFilter.doFilter(UserAgentFilter.java:83)
[STDERR]    at org.eclipse.jetty.servlets.GzipFilter.doFilter(GzipFilter.java:351)
[STDERR]    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1645)
[STDERR]    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:564)
[STDERR]    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
[STDERR]    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:578)
[STDERR]    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:221)
[STDERR]    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1111)
[STDERR]    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:498)
[STDERR]    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:183)
[STDERR]    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1045)
[STDERR]    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
[STDERR]    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:199)
[STDERR]    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:109)
[STDERR]    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:98)
[STDERR]    at org.eclipse.jetty.server.Server.handle(Server.java:461)
[STDERR]    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:284)
[STDERR]    at org.eclipse.jetty.server.HttpChannel.run(HttpChannel.java:241)
[STDERR]    at org.eclipse.jetty.spdy.server.http.HttpChannelOverSPDY.run(HttpChannelOverSPDY.java:87)
[STDERR]    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:607)
[STDERR]    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:536)
[STDERR]    at java.lang.Thread.run(Thread.java:744)

Spring Code from my controller

@Controller
public class TestController {
    @RequestMapping(value="/run/test", method=RequestMethod.GET, produces="text/plain")
    @ResponseBody
    protected String runTest() throws IOException {
        return "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012";
    }
}

If I make the size of the return value smaller it will eventually work without the exception. Not sure why the large size is an issue...

Maven Plugin Config from the pom.xml to start Jetty

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.2.0.v20140526</version>
    <configuration>
        <scanIntervalSeconds>5</scanIntervalSeconds>
        <stopKey>STOP</stopKey>
        <stopPort>9999</stopPort>
        <jettyXml>src/main/etc/jetty.xml, src/main/etc/jetty-spdy.xml</jettyXml>
        <contextXml>src/main/etc/context.xml</contextXml>
        <waitForChild>true</waitForChild>
        <jvmArgs>-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Dspring.profiles.active=dev</jvmArgs>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty.spdy</groupId>
            <artifactId>spdy-http-server</artifactId>
            <version>9.2.0.v20140526</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlets</artifactId>
            <version>9.2.0.v20140526</version>
        </dependency>
        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-rewrite</artifactId>
          <version>9.2.0.v20140526</version>
        </dependency>
        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-jsp</artifactId>
          <version>9.2.0.v20140526</version>
        </dependency>
    </dependencies>
</plugin>

UPDATE: If I remove the servlet filter for gzip it works.

From the web.xml

<filter>
    <filter-name>GzipFilter</filter-name>
    <filter-class>org.eclipse.jetty.servlets.GzipFilter</filter-class>
    <init-param>
        <param-name>mimeTypes</param-name>
        <param-value>text/html,text/plain,text/xml,application/xhtml+xml,text/css,application/javascript,image/svg+xml,application/json</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Solution

  • I have got similar exception when I tried to flush() on an empty stream. It happens only with SPDY, so for this protocol I have special version of flush() which checks if the stream can be flushed.

    In my output stream flush() looks like:

    synchronized public void flush()
            throws IOException
        {
        // out.flush() do not work on an empty SPDY output stream!!!
        // it ends with:
        // java.lang.IllegalStateException: not lastContent, no content and no responseInfo!
        //    at org.eclipse.jetty.spdy.server.http.HttpTransportOverSPDY.send(HttpTransportOverSPDY.java:164)
        // this is a reason for "flushed" variable
        if (flushed)
            return;
        out.flush();
        flushed = true;
        } // flush
    

    In write() method I set flushed = false if I wrote some bytes to output stream.

    My class uses out = response.getOutputStream() which can be SPDY output stream (which raises exception), or HTTP/HTTPS output stream which can flush() empty stream without errors.