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.
}