Uploaded image for project: 'Undertow'
  1. Undertow
  2. UNDERTOW-707

NPE in io.undertow.server.Connectors.terminateResponse

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Major Major
    • 1.3.22.Final
    • 1.3.19.Final
    • Core
    • None

      Under load I'm sometime getting the following NPE in Undertow:

      2016-04-23 21:31:52,647 ERROR [io.undertow.request] (default task-96) UT005071: Undertow request failed HttpServerExchange{ POST /XXX request {Accept=[*/*], X-Requested-With=[XMLHttpRequest], Accept-Language=[en-us], Cache-Control=[no-cache],  User-Agent=[Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko], Connection=[Keep-Alive], X-Forwarded-Proto=[https], X-Forwarded-Port=[443], X-Forwarded-For=[XXX], Content-Type=[application/x-www-form-urlencoded; charset=UTF-8], Content-Length=[2014], Cookie=[JSESSIONID=Z6_twcAUmbh5EbU_cVzOr3Wj2LPj77tHJbJSs_0Z.XXX], Referer=[XXX], Host=[XXX]} response {Connection=[close], Content-Length=[0], Date=[Sun, 24 Apr 2016 01:31:52 GMT]}}: java.lang.NullPointerException
      	at io.undertow.server.Connectors.terminateResponse(Connectors.java:99)
      	at io.undertow.server.protocol.http.ServerFixedLengthStreamSinkConduit.channelFinished(ServerFixedLengthStreamSinkConduit.java:55)
      	at io.undertow.conduits.AbstractFixedLengthStreamSinkConduit.exitFlush(AbstractFixedLengthStreamSinkConduit.java:309)
      	at io.undertow.conduits.AbstractFixedLengthStreamSinkConduit.flush(AbstractFixedLengthStreamSinkConduit.java:234)
      	at org.xnio.conduits.ConduitStreamSinkChannel.flush(ConduitStreamSinkChannel.java:162)
      	at io.undertow.channels.DetachableStreamSinkChannel.flush(DetachableStreamSinkChannel.java:119)
      	at org.xnio.channels.Channels.flushBlocking(Channels.java:63)
      	at io.undertow.servlet.spec.ServletOutputStreamImpl.close(ServletOutputStreamImpl.java:609)
      	at io.undertow.servlet.spec.HttpServletResponseImpl.closeStreamAndWriter(HttpServletResponseImpl.java:478)
      	at io.undertow.servlet.spec.HttpServletResponseImpl.responseDone(HttpServletResponseImpl.java:561)
      	at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:332)
      	at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:264)
      	at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
      	at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:175)
      	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202)
      	at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:792)
      	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)
      

      When looking at the code:
      https://github.com/undertow-io/undertow/blob/master/core/src/main/java/io/undertow/conduits/AbstractFixedLengthStreamSinkConduit.java

          public boolean flush() throws IOException {
              long val = state;
              if (anyAreSet(val, FLAG_CLOSE_COMPLETE)) {
                  return true;
              }
              boolean flushed = false;
              try {
                  return flushed = next.flush();
              } catch (IOException e) {
                  broken = true;
                  throw e;
              } finally {
                  exitFlush(val, flushed);
              }
          }
      
      private void exitFlush(long oldVal, boolean flushed) {
              long newVal = oldVal;
              boolean callFinish = false;
              if ((anyAreSet(oldVal, FLAG_CLOSE_REQUESTED) || (newVal & MASK_COUNT) == 0L) && flushed) {
                  newVal |= FLAG_CLOSE_COMPLETE;
      
                  if (!anyAreSet(oldVal, FLAG_FINISHED_CALLED) && (newVal & MASK_COUNT) == 0L) {
                      newVal |= FLAG_FINISHED_CALLED;
                      callFinish = true;
                  }
                  state = newVal;
                  if (callFinish) {
                      channelFinished();
                  }
              }
          }
      

      https://github.com/undertow-io/undertow/blob/master/core/src/main/java/io/undertow/server/protocol/http/ServerFixedLengthStreamSinkConduit.java

          @Override
          protected void channelFinished() {
              Connectors.terminateResponse(exchange);
          }
      

      https://github.com/undertow-io/undertow/blob/master/core/src/main/java/io/undertow/server/Connectors.java

          public static void terminateResponse(final HttpServerExchange exchange) {
              exchange.terminateResponse();
          }
      

      I fear that maybe there's a way that exchange is null for some reason. Also, with the try/catch/finally pattern used, could it be possible that we loose some stack trace information if something goes wrong in the exitFlush method?

      Like I mentioned previously this only happen sometime and while under load and I haven't found yet a way to reproduce the issue. Is there anything I could do to help/investigate further?

      Thanks,

              sdouglas1@redhat.com Stuart Douglas (Inactive)
              mathieu@mathieulachance.com Mathieu Lachance (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

                Created:
                Updated:
                Resolved: