From bb453f3f7c8506c37fc6f97012060c2c7ae21ebb Mon Sep 17 00:00:00 2001 From: klzgrad Date: Sat, 13 Jun 2020 17:59:48 +0800 Subject: [PATCH] h2: Pad RST_STREAM frames Clients sending too many RST_STREAM is an irregular behavior. Hack in a preceding END_STREAM DATA frame padded towards [48, 72] before RST_STREAM so that the TLS record looks like a HEADERS frame. The server often replies to this with a WINDOW_UPDATE because padding is accounted in flow control. Whether this constitudes a new irregular behavior is still unclear. --- src/net/spdy/spdy_session.cc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/net/spdy/spdy_session.cc b/src/net/spdy/spdy_session.cc index 1a010d686e..cb44d26131 100644 --- a/src/net/spdy/spdy_session.cc +++ b/src/net/spdy/spdy_session.cc @@ -15,6 +15,7 @@ #include "base/logging.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" +#include "base/rand_util.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/abseil_string_conversions.h" @@ -2222,6 +2223,25 @@ void SpdySession::EnqueueResetStreamFrame(spdy::SpdyStreamId stream_id, DCHECK(buffered_spdy_framer_.get()); std::unique_ptr rst_frame( buffered_spdy_framer_->CreateRstStream(stream_id, error_code)); + // Can't send padding if the send window is very tight. + if (session_send_window_size_ >= 72) { + constexpr int kNonPaddingSize = + spdy::kDataFrameMinimumSize + spdy::kRstStreamFrameSize; + uint8_t padding_length = base::RandInt(48, 72) - kNonPaddingSize; + size_t expected_length = kNonPaddingSize + padding_length; + spdy::SpdyFrameBuilder builder(expected_length); + builder.BeginNewFrame(spdy::SpdyFrameType::DATA, + spdy::DATA_FLAG_FIN | spdy::DATA_FLAG_PADDED, + stream_id, padding_length); + builder.WriteUInt8(padding_length - 1); + std::string padding(padding_length - 1, 0); + builder.WriteBytes(padding.data(), padding.size()); + builder.BeginNewFrame(spdy::SpdyFrameType::RST_STREAM, 0, stream_id, 4); + builder.WriteUInt32(error_code); + DCHECK_EQ(expected_length, builder.length()); + rst_frame = std::make_unique(builder.take()); + DecreaseSendWindowSize(padding_length); + } EnqueueSessionWrite(priority, spdy::SpdyFrameType::RST_STREAM, std::move(rst_frame));