Skip to content

Fix deferred TLS output handling on inbound close#3324

Open
He-Pin wants to merge 1 commit into
apache:mainfrom
He-Pin:fix/tls-deferred-close-state
Open

Fix deferred TLS output handling on inbound close#3324
He-Pin wants to merge 1 commit into
apache:mainfrom
He-Pin:fix/tls-deferred-close-state

Conversation

@He-Pin

@He-Pin He-Pin commented Jul 11, 2026

Copy link
Copy Markdown
Member

Motivation

TlsGraphStage migrated the TLS pump phases from TlsActor but also added deferred plaintext batching and deferred transport flushing. When transport input completes before either timer runs, the copied close transition can enter a non-executable FlushingOutboundPhase or complete before buffered ciphertext is emitted.

Modification

Flush buffered transport output before selecting the close phase, and use the SSLEngine's NEED_WRAP state to decide whether protocol output still has to be generated. Add deterministic tests that hold zero-delay timers and cover pending plaintext, buffered ciphertext, and engine wrap output.

Result

Inbound close no longer strands the stage, already-wrapped ciphertext is delivered before completion, and pending engine output is wrapped before shutdown.

Tests

  • stream-tests / Test / testOnly org.apache.pekko.stream.io.TlsGraphStageDeferredCloseSpec (3 passed)
  • stream-tests / Test / testOnly org.apache.pekko.stream.io.TlsGraphStageIsolatedSpec (7 passed)
  • scalafmt --list --mode diff-ref=origin/main
  • headerCreateAll and +headerCheckAll
  • git diff --check
  • Full test suite not run; focused validation only as requested.

References

Refs #2860

Motivation:
The GraphStage TLS engine can receive inbound completion while plaintext batching or ciphertext flushing is deferred. Its close state can then stall or complete before pending protocol output is emitted.

Modification:
Flush buffered ciphertext before choosing the close phase and base completion on whether the SSLEngine still requires a wrap. Add deterministic tests that hold zero-delay timers and exercise pending plaintext, buffered ciphertext, and engine wrap output.

Result:
Inbound close no longer strands the stage in FlushingOutbound, buffered ciphertext is emitted before completion, and pending engine output is wrapped before shutdown.

Tests:
- rtk sbt "stream-tests / Test / testOnly org.apache.pekko.stream.io.TlsGraphStageDeferredCloseSpec" (3 passed)
- rtk sbt "stream-tests / Test / testOnly org.apache.pekko.stream.io.TlsGraphStageIsolatedSpec" (7 passed)
- rtk scalafmt --list --mode diff-ref=origin/main
- rtk sbt "headerCreateAll" "+headerCheckAll"
- rtk git diff --check

References:
Refs apache#2860
@He-Pin He-Pin added this to the 2.0.0-M4 milestone Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant