From 0fd37e1951ae541d873d0f2803ebeb88d9c9f848 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 13 Jul 2017 21:07:29 -0700 Subject: [PATCH] Transport - Fix a bug in decompression path --- .../chttp2/transport/chttp2_transport.c | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 00b0738b20d..1427b8f3302 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -1671,9 +1671,8 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, } if (s->stream_compression_recv_enabled && !s->unprocessed_incoming_frames_decompressed) { - grpc_slice_buffer decompressed_data; + GPR_ASSERT(s->decompressed_data_buffer.length == 0); bool end_of_context; - grpc_slice_buffer_init(&decompressed_data); if (!s->stream_decompression_ctx) { s->stream_decompression_ctx = grpc_stream_compression_context_create( @@ -1681,17 +1680,18 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, } if (!grpc_stream_decompress(s->stream_decompression_ctx, &s->unprocessed_incoming_frames_buffer, - &decompressed_data, NULL, 5, + &s->decompressed_data_buffer, NULL, 5, &end_of_context)) { grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage); grpc_slice_buffer_reset_and_unref_internal( exec_ctx, &s->unprocessed_incoming_frames_buffer); - s->seen_error = true; + error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream decompression error."); } else { error = grpc_deframe_unprocessed_incoming_frames( - exec_ctx, &s->data_parser, s, &decompressed_data, NULL, - s->recv_message); + exec_ctx, &s->data_parser, s, &s->decompressed_data_buffer, + NULL, s->recv_message); if (end_of_context) { grpc_stream_compression_context_destroy( s->stream_decompression_ctx); @@ -1740,7 +1740,38 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx, } bool pending_data = s->pending_byte_stream || s->unprocessed_incoming_frames_buffer.length > 0; - if (s->read_closed && s->frame_storage.length == 0 && + if (s->stream_compression_recv_enabled && s->read_closed && + s->frame_storage.length > 0 && + s->unprocessed_incoming_frames_buffer.length == 0 && !pending_data && + !s->seen_error && s->recv_trailing_metadata_finished != NULL) { + /* Maybe some SYNC_FLUSH data is left in frame_storage. Consume them and + * maybe decompress the next 5 bytes in the stream. */ + bool end_of_context; + if (!s->stream_decompression_ctx) { + s->stream_decompression_ctx = + grpc_stream_compression_context_create( + GRPC_STREAM_COMPRESSION_DECOMPRESS); + } + if (!grpc_stream_decompress(s->stream_decompression_ctx, + &s->frame_storage, + &s->unprocessed_incoming_frames_buffer, + NULL, 5, &end_of_context)) { + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, + &s->frame_storage); + grpc_slice_buffer_reset_and_unref_internal( + exec_ctx, &s->unprocessed_incoming_frames_buffer); + s->seen_error = true; + } else { + if (s->unprocessed_incoming_frames_buffer.length > 0) { + s->unprocessed_incoming_frames_decompressed = true; + } + if (end_of_context) { + grpc_stream_compression_context_destroy(s->stream_decompression_ctx); + s->stream_decompression_ctx = NULL; + } + } + } + if (s->read_closed && s->frame_storage.length == 0 && s->unprocessed_incoming_frames_buffer.length == 0 && (!pending_data || s->seen_error) && s->recv_trailing_metadata_finished != NULL) { grpc_chttp2_incoming_metadata_buffer_publish(