Add PRIORITY_UPDATE frame and implement serialization. PiperOrigin-RevId: 347611775 Change-Id: I8856aba25403f133b2c8e089506daa8d13484e10
diff --git a/spdy/core/spdy_framer.cc b/spdy/core/spdy_framer.cc index d425bdd..44bea4c 100644 --- a/spdy/core/spdy_framer.cc +++ b/spdy/core/spdy_framer.cc
@@ -765,6 +765,21 @@ return builder.take(); } +SpdySerializedFrame SpdyFramer::SerializePriorityUpdate( + const SpdyPriorityUpdateIR& priority_update) const { + const size_t total_size = kPriorityUpdateFrameMinimumSize + + priority_update.priority_field_value().size(); + SpdyFrameBuilder builder(total_size); + builder.BeginNewFrame(SpdyFrameType::PRIORITY_UPDATE, kNoFlags, + priority_update.stream_id()); + + builder.WriteUInt32(priority_update.prioritized_stream_id()); + builder.WriteBytes(priority_update.priority_field_value().data(), + priority_update.priority_field_value().size()); + DCHECK_EQ(total_size, builder.length()); + return builder.take(); +} + SpdySerializedFrame SpdyFramer::SerializeUnknown( const SpdyUnknownIR& unknown) const { const size_t total_size = kFrameHeaderSize + unknown.payload().size(); @@ -818,6 +833,10 @@ void VisitPriority(const SpdyPriorityIR& priority) override { frame_ = framer_->SerializePriority(priority); } + void VisitPriorityUpdate( + const SpdyPriorityUpdateIR& priority_update) override { + frame_ = framer_->SerializePriorityUpdate(priority_update); + } void VisitUnknown(const SpdyUnknownIR& unknown) override { frame_ = framer_->SerializeUnknown(unknown); } @@ -904,6 +923,11 @@ flags_ = kNoFlags; } + void VisitPriorityUpdate( + const SpdyPriorityUpdateIR& /*priority_update*/) override { + flags_ = kNoFlags; + } + uint8_t flags() const { return flags_; } private: @@ -1191,6 +1215,22 @@ return ok; } +bool SpdyFramer::SerializePriorityUpdate( + const SpdyPriorityUpdateIR& priority_update, + ZeroCopyOutputBuffer* output) const { + const size_t total_size = kPriorityUpdateFrameMinimumSize + + priority_update.priority_field_value().size(); + SpdyFrameBuilder builder(total_size, output); + bool ok = builder.BeginNewFrame(SpdyFrameType::PRIORITY_UPDATE, kNoFlags, + priority_update.stream_id()); + + ok = ok && builder.WriteUInt32(priority_update.prioritized_stream_id()); + ok = ok && builder.WriteBytes(priority_update.priority_field_value().data(), + priority_update.priority_field_value().size()); + DCHECK_EQ(total_size, builder.length()); + return ok; +} + bool SpdyFramer::SerializeUnknown(const SpdyUnknownIR& unknown, ZeroCopyOutputBuffer* output) const { const size_t total_size = kFrameHeaderSize + unknown.payload().size(); @@ -1246,6 +1286,10 @@ void VisitPriority(const SpdyPriorityIR& priority) override { result_ = framer_->SerializePriority(priority, output_); } + void VisitPriorityUpdate( + const SpdyPriorityUpdateIR& priority_update) override { + result_ = framer_->SerializePriorityUpdate(priority_update, output_); + } void VisitUnknown(const SpdyUnknownIR& unknown) override { result_ = framer_->SerializeUnknown(unknown, output_); }
diff --git a/spdy/core/spdy_framer.h b/spdy/core/spdy_framer.h index 99c2037..d2ba757 100644 --- a/spdy/core/spdy_framer.h +++ b/spdy/core/spdy_framer.h
@@ -124,6 +124,11 @@ // the relative priority of the given stream. SpdySerializedFrame SerializePriority(const SpdyPriorityIR& priority) const; + // Serializes a PRIORITY_UPDATE frame. + // See https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html. + SpdySerializedFrame SerializePriorityUpdate( + const SpdyPriorityUpdateIR& priority_update) const; + // Serializes an unknown frame given a frame header and payload. SpdySerializedFrame SerializeUnknown(const SpdyUnknownIR& unknown) const; @@ -192,6 +197,11 @@ bool SerializePriority(const SpdyPriorityIR& priority, ZeroCopyOutputBuffer* output) const; + // Serializes a PRIORITY_UPDATE frame. + // See https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html. + bool SerializePriorityUpdate(const SpdyPriorityUpdateIR& priority_update, + ZeroCopyOutputBuffer* output) const; + // Serializes an unknown frame given a frame header and payload. bool SerializeUnknown(const SpdyUnknownIR& unknown, ZeroCopyOutputBuffer* output) const;
diff --git a/spdy/core/spdy_framer_test.cc b/spdy/core/spdy_framer_test.cc index 6a14d0c..a1d7a79 100644 --- a/spdy/core/spdy_framer_test.cc +++ b/spdy/core/spdy_framer_test.cc
@@ -2515,6 +2515,29 @@ CompareFrame(kDescription, frame, kFrameData, ABSL_ARRAYSIZE(kFrameData)); } +TEST_P(SpdyFramerTest, CreatePriorityUpdate) { + const char kDescription[] = "PRIORITY_UPDATE frame"; + const unsigned char kType = + SerializeFrameType(SpdyFrameType::PRIORITY_UPDATE); + const unsigned char kFrameData[] = { + 0x00, 0x00, 0x07, // frame length + kType, // frame type + 0x00, // flags + 0x00, 0x00, 0x00, 0x00, // stream ID, must be 0 for PRIORITY_UPDATE + 0x00, 0x00, 0x00, 0x03, // prioritized stream ID + 'u', '=', '0'}; // priority field value + SpdyPriorityUpdateIR priority_update_ir(/* stream_id = */ 0, + /* prioritized_stream_id = */ 3, + /* priority_field_value = */ "u=0"); + SpdySerializedFrame frame(framer_.SerializeFrame(priority_update_ir)); + if (use_output_) { + EXPECT_EQ(framer_.SerializeFrame(priority_update_ir, &output_), + frame.size()); + frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); + } + CompareFrame(kDescription, frame, kFrameData, ABSL_ARRAYSIZE(kFrameData)); +} + TEST_P(SpdyFramerTest, CreateUnknown) { const char kDescription[] = "Unknown frame"; const uint8_t kType = 0xaf;
diff --git a/spdy/core/spdy_protocol.cc b/spdy/core/spdy_protocol.cc index b1d9f56..dfe3485 100644 --- a/spdy/core/spdy_protocol.cc +++ b/spdy/core/spdy_protocol.cc
@@ -83,6 +83,8 @@ return true; case SpdyFrameType::ALTSVC: return true; + case SpdyFrameType::PRIORITY_UPDATE: + return true; } return false; } @@ -149,6 +151,8 @@ return "PRIORITY"; case SpdyFrameType::ALTSVC: return "ALTSVC"; + case SpdyFrameType::PRIORITY_UPDATE: + return "PRIORITY_UPDATE"; } return "UNKNOWN_FRAME_TYPE"; } @@ -559,6 +563,18 @@ return kPriorityFrameSize; } +void SpdyPriorityUpdateIR::Visit(SpdyFrameVisitor* visitor) const { + return visitor->VisitPriorityUpdate(*this); +} + +SpdyFrameType SpdyPriorityUpdateIR::frame_type() const { + return SpdyFrameType::PRIORITY_UPDATE; +} + +size_t SpdyPriorityUpdateIR::size() const { + return kPriorityUpdateFrameMinimumSize + priority_field_value_.size(); +} + void SpdyUnknownIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitUnknown(*this); }
diff --git a/spdy/core/spdy_protocol.h b/spdy/core/spdy_protocol.h index 39b3daa..c05d7f6 100644 --- a/spdy/core/spdy_protocol.h +++ b/spdy/core/spdy_protocol.h
@@ -99,6 +99,7 @@ CONTINUATION = 0x09, // ALTSVC is a public extension. ALTSVC = 0x0a, + PRIORITY_UPDATE = 0x10, }; // Flags on data packets. @@ -307,6 +308,8 @@ const size_t kContinuationFrameMinimumSize = kFrameHeaderSize; // ALTSVC frame has origin_len (2 octets) field. const size_t kGetAltSvcFrameMinimumSize = kFrameHeaderSize + 2; +// PRIORITY_UPDATE frame has prioritized_stream_id (4 octets) field. +const size_t kPriorityUpdateFrameMinimumSize = kFrameHeaderSize + 4; // Maximum possible configurable size of a frame in octets. const size_t kMaxFrameSizeLimit = kSpdyMaxFrameSizeLimit + kFrameHeaderSize; @@ -883,6 +886,32 @@ bool exclusive_; }; +class QUICHE_EXPORT_PRIVATE SpdyPriorityUpdateIR : public SpdyFrameIR { + public: + SpdyPriorityUpdateIR(SpdyStreamId stream_id, + SpdyStreamId prioritized_stream_id, + std::string priority_field_value) + : SpdyFrameIR(stream_id), + prioritized_stream_id_(prioritized_stream_id), + priority_field_value_(std::move(priority_field_value)) {} + SpdyPriorityUpdateIR(const SpdyPriorityUpdateIR&) = delete; + SpdyPriorityUpdateIR& operator=(const SpdyPriorityUpdateIR&) = delete; + SpdyStreamId prioritized_stream_id() const { return prioritized_stream_id_; } + const std::string& priority_field_value() const { + return priority_field_value_; + } + + void Visit(SpdyFrameVisitor* visitor) const override; + + SpdyFrameType frame_type() const override; + + size_t size() const override; + + private: + SpdyStreamId prioritized_stream_id_; + std::string priority_field_value_; +}; + // Represents a frame of unrecognized type. class QUICHE_EXPORT_PRIVATE SpdyUnknownIR : public SpdyFrameIR { public: @@ -1022,6 +1051,8 @@ virtual void VisitAltSvc(const SpdyAltSvcIR& altsvc) = 0; virtual void VisitPriority(const SpdyPriorityIR& priority) = 0; virtual void VisitData(const SpdyDataIR& data) = 0; + virtual void VisitPriorityUpdate( + const SpdyPriorityUpdateIR& priority_update) = 0; virtual void VisitUnknown(const SpdyUnknownIR& /*unknown*/) { // TODO(birenroy): make abstract. }