Skip to content

feat(grpc): add server-side stream validators#2602

Open
sauravzg wants to merge 1 commit intomasterfrom
sauravz/server-stream-validators
Open

feat(grpc): add server-side stream validators#2602
sauravzg wants to merge 1 commit intomasterfrom
sauravz/server-stream-validators

Conversation

@sauravzg
Copy link
Copy Markdown
Collaborator

Introduces ServerSendStreamValidator and ServerRecvStreamValidator to enforce strict gRPC semantics on server streams. These are intended to wrap raw transport streams before passing them to application-level handlers, ensuring that user-provided service logic cannot violate protocol rules.

  • ServerSendStreamValidator ensures proper response sequencing (Headers -> Messages -> Trailers) and prevents invalid state transitions, while fully supporting trailers-only responses.
  • ServerRecvStreamValidator safely manages terminal states, ensuring that any subsequent polls after stream completion consistently return an error to prevent undefined behavior.
  • Adds comprehensive unit tests to verify state machine correctness and protocol compliance.

This is recreation of #2595 to allow using a stacked PR workflow

@sauravzg sauravzg requested a review from dfawley April 23, 2026 18:21
@sauravzg sauravzg force-pushed the sauravz/handle-trailers branch from 507787e to e2f4bd0 Compare April 23, 2026 18:29
@sauravzg sauravzg force-pushed the sauravz/server-stream-validators branch 2 times, most recently from c5c0e67 to 038f365 Compare April 23, 2026 18:52
@sauravzg sauravzg force-pushed the sauravz/handle-trailers branch from e2f4bd0 to 90ae261 Compare April 27, 2026 15:40
@sauravzg sauravzg force-pushed the sauravz/server-stream-validators branch from 038f365 to 89b8525 Compare April 27, 2026 15:40
Base automatically changed from sauravz/handle-trailers to master April 29, 2026 12:02
@sauravzg sauravzg force-pushed the sauravz/server-stream-validators branch from 89b8525 to 355c9cd Compare April 29, 2026 12:04
Copy link
Copy Markdown
Collaborator

@dfawley dfawley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to figure out how exactly this is going to be used.

Most likely it will be a server-side interceptor? In which case, when an error occurs, I would think we'd want to terminate the RPC with a status that indicates the cause of the problem.

Comment thread grpc/src/server/stream_util.rs
Introduces `ServerSendStreamValidator` and `ServerRecvStreamValidator`
to enforce strict gRPC semantics on server streams. These are intended
to wrap raw transport streams before passing them to application-level
handlers, ensuring that user-provided service logic cannot violate
protocol rules.

- `ServerSendStreamValidator` ensures proper response sequencing
  (Headers -> Messages -> Trailers) and prevents invalid state
  transitions, while fully supporting trailers-only responses.
- `ServerRecvStreamValidator` safely manages terminal states, ensuring
  that any subsequent polls after stream completion consistently return
  an error to prevent undefined behavior.
- Adds comprehensive unit tests to verify state machine correctness and
  protocol compliance.
@sauravzg sauravzg force-pushed the sauravz/server-stream-validators branch from 355c9cd to de7ee29 Compare April 30, 2026 18:34
@sauravzg
Copy link
Copy Markdown
Collaborator Author

I'm trying to figure out how exactly this is going to be used.

Most likely it will be a server-side interceptor? In which case, when an error occurs, I would think we'd want to terminate the RPC with a status that indicates the cause of the problem.

Yes on the server side interceptor.

RecvStreamVal.. is somewhat straight forward. This'll be used closer to the protobuf API to ensure that we transition our generic stream request receiver to the protobuf API stream object.

SendStreamVal.. is closer to the transport to validate the outgoing data after all other interceptors.

I somewhat agree with the need for status. We need to update the SendStream API on the server side to return status. This wasn't a problem previously because Trailers were a part of the SendStream and would be used to send trailers and terminate the API.

Now that we are returning trailers instead of sending them, we need more details from SendStream to propagate to trailers . Does it sound okay to add Status to the SendStream API itself, because we initially had some reservations on it , but I guess the situation has changed.

@sauravzg sauravzg removed their assignment Apr 30, 2026
@sauravzg sauravzg requested a review from dfawley April 30, 2026 18:55
@dfawley
Copy link
Copy Markdown
Collaborator

dfawley commented Apr 30, 2026

I somewhat agree with the need for status. We need to update the SendStream API on the server side to return status. This wasn't a problem previously because Trailers were a part of the SendStream and would be used to send trailers and terminate the API.

I was expecting we'd just need an interceptor that can terminate the RPC underneath the handler when either the SendStream or RecvStream has any problem. I.e. we can't do stream validation via something that simply wraps each stream independently.

@sauravzg
Copy link
Copy Markdown
Collaborator Author

sauravzg commented May 4, 2026

I somewhat agree with the need for status. We need to update the SendStream API on the server side to return status. This wasn't a problem previously because Trailers were a part of the SendStream and would be used to send trailers and terminate the API.

I was expecting we'd just need an interceptor that can terminate the RPC underneath the handler when either the SendStream or RecvStream has any problem. I.e. we can't do stream validation via something that simply wraps each stream independently.

I mean we are definitely gonna need an interceptor for this. But I was planning to separate it into two responsibilities , one for lifecycle for stream and another for lifecycle of handler.

Something along the lines of RecvStreamValidator and moving the logic of stream termination closer to the protobuf API.
and then
SendStreamValidator and moving the logic of handling errors from the SendStream closer to the transport to handle error from interceptors.

But we might need some status on the SendStream now, because if sendstream terminates, we'll need to return Trailers. I could either terminate the stream with some arbitrary Internal stream broken error, or we could try and "safely" propagate the error to trailers?

@dfawley
Copy link
Copy Markdown
Collaborator

dfawley commented May 7, 2026

But I was planning to separate it into two responsibilities , one for lifecycle for stream and another for lifecycle of handler.

Sure but they will need to be linked, so it would make more sense to me to make them all together.

Something along the lines of RecvStreamValidator and moving the logic of stream termination closer to the protobuf API.
and then SendStreamValidator and moving the logic of handling errors from the SendStream closer to the transport to handle error from interceptors.

So you're thinking two different interceptors might be needed?

or we could try and "safely" propagate the error to trailers?

Yes we should make sure the RPC error includes an explanation of the protocol violation. I expect the interceptor would basically select on the handler future and a receive from a oneshot channel that the validator writes to, and then terminates with whichever status comes first, dropping the other future.

@sauravzg
Copy link
Copy Markdown
Collaborator Author

sauravzg commented May 7, 2026

So, we discussed offline. It'd make sense for both stream and handler validation to be a part of the same PR.

I initially thought we'd need different handlers, but based on my progress so far, I believe a single one suffices.

Yes we should make sure the RPC error includes an explanation of the protocol violation. I expect the interceptor would basically select on the handler future and a receive from a oneshot channel that the validator writes to, and then terminates with whichever status comes first, dropping the other future.

Since , we don't expose error status from sendstream or recvstream right now, we cannot propagate anything beyond an arbitrary "internal error: stream broken" . Would you want to tweak our stream APIs to be able to propagate errors Err(Status) or Err(String) instead of Err()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants