@Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    if (msg instanceof Http2Settings) {
      // Expected
    } else if (msg instanceof FullHttpResponse) {
      FullHttpResponse response = (FullHttpResponse) msg;

      final Invocation invocation = waitsHolder.poll(response);

      if (invocation != null) {
        final ServiceInvocationContext iCtx = invocation.invocationContext();
        final SerializationFormat serializationFormat = iCtx.scheme().serializationFormat();
        try {
          final Promise<FullHttpResponse> resultPromise = invocation.resultPromise();
          if (HttpStatusClass.SUCCESS == response.status().codeClass()
              // No serialization indicates a raw HTTP protocol which should
              // have error responses returned.
              || serializationFormat == SerializationFormat.NONE) {
            iCtx.resolvePromise(resultPromise, response.retain());
          } else {
            iCtx.rejectPromise(
                resultPromise,
                new InvalidResponseException("HTTP Response code: " + response.status()));
          }
        } finally {
          ReferenceCountUtil.release(msg);
        }
      } else {
        // if invocation not found, we just bypass message to next
        ctx.fireChannelRead(msg);
      }

      if (!isMultiplex
          && HttpHeaderValues.CLOSE.contentEqualsIgnoreCase(
              response.headers().get(HttpHeaderNames.CONNECTION))) {
        ctx.close();
      }
    } else {
      try {
        throw new IllegalStateException("unexpected message type: " + msg);
      } finally {
        ReferenceCountUtil.release(msg);
      }
    }
  }