Fix connection corruption from double-LastHttpContent in streaming pipeline Server: Guard sendLastHttpContent with state check so it is skipped when writeError() in makeChunk() already terminated the response. Without this, a serialization error mid-stream sends two LastHttpContent messages, corrupting HTTP framing on keep-alive connections. Client: Null out queueInputStream after signalEndOfStream on LastHttpContent so spurious content between responses is dropped rather than offered to the closed stream.
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpStreamingResponseHandler.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpStreamingResponseHandler.java index 6177887..3db50fd 100644 --- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpStreamingResponseHandler.java +++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpStreamingResponseHandler.java
@@ -150,6 +150,9 @@ if (isGraphBinaryResponse()) { if (queueInputStream != null) { queueInputStream.signalEndOfStream(); + // Null out so any spurious content arriving between responses is dropped + // rather than offered to the already-closed stream. + queueInputStream = null; } // Reader thread handles completion directly via markComplete/markError } else {
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java index fa34d4d..e113aaf 100644 --- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java +++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
@@ -242,7 +242,11 @@ // failures that follow this will show up in the response body instead. sendHttpResponse(ctx, OK, createResponseHeaders(ctx, serializer, requestCtx).toArray(CharSequence[]::new)); sendHttpContents(ctx, requestCtx); - sendLastHttpContent(ctx, HttpResponseStatus.OK, ""); + // Skip if writeError() already terminated the response (e.g., serialization error in makeChunk). + // Sending a second LastHttpContent would corrupt the HTTP framing on keep-alive connections. + if (requestCtx.getRequestState() != RequestState.ERROR) { + sendLastHttpContent(ctx, HttpResponseStatus.OK, ""); + } } catch (Throwable t) { writeError(requestCtx, formErrorResponseMessage(t, requestMessage), serializer.getValue1()); } finally {