Project import generated by Copybara.
PiperOrigin-RevId: 229942388
Change-Id: Ib5a23c152c95ed4294cece9f902227c21ce531ef
diff --git a/spdy/core/spdy_framer.h b/spdy/core/spdy_framer.h
new file mode 100644
index 0000000..e268994
--- /dev/null
+++ b/spdy/core/spdy_framer.h
@@ -0,0 +1,365 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_SPDY_CORE_SPDY_FRAMER_H_
+#define QUICHE_SPDY_CORE_SPDY_FRAMER_H_
+
+#include <stddef.h>
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <utility>
+
+#include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_headers_handler_interface.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
+#include "net/third_party/quiche/src/spdy/core/zero_copy_output_buffer.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
+
+namespace spdy {
+
+namespace test {
+
+class SpdyFramerPeer;
+class SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
+class SpdyFramerTest_PushPromiseFramesWithIterator_Test;
+
+} // namespace test
+
+class SPDY_EXPORT_PRIVATE SpdyFrameSequence {
+ public:
+ virtual ~SpdyFrameSequence() {}
+
+ // Serializes the next frame in the sequence to |output|. Returns the number
+ // of bytes written to |output|.
+ virtual size_t NextFrame(ZeroCopyOutputBuffer* output) = 0;
+
+ // Returns true iff there is at least one more frame in the sequence.
+ virtual bool HasNextFrame() const = 0;
+
+ // Get SpdyFrameIR of the frame to be serialized.
+ virtual const SpdyFrameIR& GetIR() const = 0;
+};
+
+class SPDY_EXPORT_PRIVATE SpdyFramer {
+ public:
+ enum CompressionOption {
+ ENABLE_COMPRESSION,
+ DISABLE_COMPRESSION,
+ };
+
+ // Create a SpdyFrameSequence to serialize |frame_ir|.
+ static std::unique_ptr<SpdyFrameSequence> CreateIterator(
+ SpdyFramer* framer,
+ std::unique_ptr<const SpdyFrameIR> frame_ir);
+
+ // Gets the serialized flags for the given |frame|.
+ static uint8_t GetSerializedFlags(const SpdyFrameIR& frame);
+
+ // Serialize a data frame.
+ static SpdySerializedFrame SerializeData(const SpdyDataIR& data_ir);
+ // Serializes the data frame header and optionally padding length fields,
+ // excluding actual data payload and padding.
+ static SpdySerializedFrame SerializeDataFrameHeaderWithPaddingLengthField(
+ const SpdyDataIR& data_ir);
+
+ // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE
+ // frame is used to implement per stream flow control.
+ static SpdySerializedFrame SerializeWindowUpdate(
+ const SpdyWindowUpdateIR& window_update);
+
+ explicit SpdyFramer(CompressionOption option);
+
+ virtual ~SpdyFramer();
+
+ // Set debug callbacks to be called from the framer. The debug visitor is
+ // completely optional and need not be set in order for normal operation.
+ // If this is called multiple times, only the last visitor will be used.
+ void set_debug_visitor(SpdyFramerDebugVisitorInterface* debug_visitor);
+
+ SpdySerializedFrame SerializeRstStream(
+ const SpdyRstStreamIR& rst_stream) const;
+
+ // Serializes a SETTINGS frame. The SETTINGS frame is
+ // used to communicate name/value pairs relevant to the communication channel.
+ SpdySerializedFrame SerializeSettings(const SpdySettingsIR& settings) const;
+
+ // Serializes a PING frame. The unique_id is used to
+ // identify the ping request/response.
+ SpdySerializedFrame SerializePing(const SpdyPingIR& ping) const;
+
+ // Serializes a GOAWAY frame. The GOAWAY frame is used
+ // prior to the shutting down of the TCP connection, and includes the
+ // stream_id of the last stream the sender of the frame is willing to process
+ // to completion.
+ SpdySerializedFrame SerializeGoAway(const SpdyGoAwayIR& goaway) const;
+
+ // Serializes a HEADERS frame. The HEADERS frame is used
+ // for sending headers.
+ SpdySerializedFrame SerializeHeaders(const SpdyHeadersIR& headers);
+
+ // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used
+ // to inform the client that it will be receiving an additional stream
+ // in response to the original request. The frame includes synthesized
+ // headers to explain the upcoming data.
+ SpdySerializedFrame SerializePushPromise(
+ const SpdyPushPromiseIR& push_promise);
+
+ // Serializes a CONTINUATION frame. The CONTINUATION frame is used
+ // to continue a sequence of header block fragments.
+ SpdySerializedFrame SerializeContinuation(
+ const SpdyContinuationIR& continuation) const;
+
+ // Serializes an ALTSVC frame. The ALTSVC frame advertises the
+ // availability of an alternative service to the client.
+ SpdySerializedFrame SerializeAltSvc(const SpdyAltSvcIR& altsvc);
+
+ // Serializes a PRIORITY frame. The PRIORITY frame advises a change in
+ // the relative priority of the given stream.
+ SpdySerializedFrame SerializePriority(const SpdyPriorityIR& priority) const;
+
+ // Serializes an unknown frame given a frame header and payload.
+ SpdySerializedFrame SerializeUnknown(const SpdyUnknownIR& unknown) const;
+
+ // Serialize a frame of unknown type.
+ SpdySerializedFrame SerializeFrame(const SpdyFrameIR& frame);
+
+ // Serialize a data frame.
+ bool SerializeData(const SpdyDataIR& data,
+ ZeroCopyOutputBuffer* output) const;
+
+ // Serializes the data frame header and optionally padding length fields,
+ // excluding actual data payload and padding.
+ bool SerializeDataFrameHeaderWithPaddingLengthField(
+ const SpdyDataIR& data,
+ ZeroCopyOutputBuffer* output) const;
+
+ bool SerializeRstStream(const SpdyRstStreamIR& rst_stream,
+ ZeroCopyOutputBuffer* output) const;
+
+ // Serializes a SETTINGS frame. The SETTINGS frame is
+ // used to communicate name/value pairs relevant to the communication channel.
+ bool SerializeSettings(const SpdySettingsIR& settings,
+ ZeroCopyOutputBuffer* output) const;
+
+ // Serializes a PING frame. The unique_id is used to
+ // identify the ping request/response.
+ bool SerializePing(const SpdyPingIR& ping,
+ ZeroCopyOutputBuffer* output) const;
+
+ // Serializes a GOAWAY frame. The GOAWAY frame is used
+ // prior to the shutting down of the TCP connection, and includes the
+ // stream_id of the last stream the sender of the frame is willing to process
+ // to completion.
+ bool SerializeGoAway(const SpdyGoAwayIR& goaway,
+ ZeroCopyOutputBuffer* output) const;
+
+ // Serializes a HEADERS frame. The HEADERS frame is used
+ // for sending headers.
+ bool SerializeHeaders(const SpdyHeadersIR& headers,
+ ZeroCopyOutputBuffer* output);
+
+ // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE
+ // frame is used to implement per stream flow control.
+ bool SerializeWindowUpdate(const SpdyWindowUpdateIR& window_update,
+ ZeroCopyOutputBuffer* output) const;
+
+ // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used
+ // to inform the client that it will be receiving an additional stream
+ // in response to the original request. The frame includes synthesized
+ // headers to explain the upcoming data.
+ bool SerializePushPromise(const SpdyPushPromiseIR& push_promise,
+ ZeroCopyOutputBuffer* output);
+
+ // Serializes a CONTINUATION frame. The CONTINUATION frame is used
+ // to continue a sequence of header block fragments.
+ bool SerializeContinuation(const SpdyContinuationIR& continuation,
+ ZeroCopyOutputBuffer* output) const;
+
+ // Serializes an ALTSVC frame. The ALTSVC frame advertises the
+ // availability of an alternative service to the client.
+ bool SerializeAltSvc(const SpdyAltSvcIR& altsvc,
+ ZeroCopyOutputBuffer* output);
+
+ // Serializes a PRIORITY frame. The PRIORITY frame advises a change in
+ // the relative priority of the given stream.
+ bool SerializePriority(const SpdyPriorityIR& priority,
+ ZeroCopyOutputBuffer* output) const;
+
+ // Serializes an unknown frame given a frame header and payload.
+ bool SerializeUnknown(const SpdyUnknownIR& unknown,
+ ZeroCopyOutputBuffer* output) const;
+
+ // Serialize a frame of unknown type.
+ size_t SerializeFrame(const SpdyFrameIR& frame, ZeroCopyOutputBuffer* output);
+
+ // Returns whether this SpdyFramer will compress header blocks using HPACK.
+ bool compression_enabled() const {
+ return compression_option_ == ENABLE_COMPRESSION;
+ }
+
+ void SetHpackIndexingPolicy(HpackEncoder::IndexingPolicy policy) {
+ GetHpackEncoder()->SetIndexingPolicy(std::move(policy));
+ }
+
+ // Updates the maximum size of the header encoder compression table.
+ void UpdateHeaderEncoderTableSize(uint32_t value);
+
+ // Returns the maximum size of the header encoder compression table.
+ size_t header_encoder_table_size() const;
+
+ void SetEncoderHeaderTableDebugVisitor(
+ std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor);
+
+ // Get (and lazily initialize) the HPACK encoder state.
+ HpackEncoder* GetHpackEncoder();
+
+ // Returns the estimate of dynamically allocated memory in bytes.
+ size_t EstimateMemoryUsage() const;
+
+ protected:
+ friend class test::SpdyFramerPeer;
+ friend class test::SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
+ friend class test::SpdyFramerTest_PushPromiseFramesWithIterator_Test;
+
+ // Iteratively converts a SpdyFrameIR into an appropriate sequence of Spdy
+ // frames.
+ // Example usage:
+ // std::unique_ptr<SpdyFrameSequence> it = CreateIterator(framer, frame_ir);
+ // while (it->HasNextFrame()) {
+ // if(it->NextFrame(output) == 0) {
+ // // Write failed;
+ // }
+ // }
+ class SPDY_EXPORT_PRIVATE SpdyFrameIterator : public SpdyFrameSequence {
+ public:
+ // Creates an iterator with the provided framer.
+ // Does not take ownership of |framer|.
+ // |framer| must outlive this instance.
+ explicit SpdyFrameIterator(SpdyFramer* framer);
+ ~SpdyFrameIterator() override;
+
+ // Serializes the next frame in the sequence to |output|. Returns the number
+ // of bytes written to |output|.
+ size_t NextFrame(ZeroCopyOutputBuffer* output) override;
+
+ // Returns true iff there is at least one more frame in the sequence.
+ bool HasNextFrame() const override;
+
+ // SpdyFrameIterator is neither copyable nor movable.
+ SpdyFrameIterator(const SpdyFrameIterator&) = delete;
+ SpdyFrameIterator& operator=(const SpdyFrameIterator&) = delete;
+
+ protected:
+ virtual size_t GetFrameSizeSansBlock() const = 0;
+ virtual bool SerializeGivenEncoding(const SpdyString& encoding,
+ ZeroCopyOutputBuffer* output) const = 0;
+
+ SpdyFramer* GetFramer() const { return framer_; }
+
+ void SetEncoder(const SpdyFrameWithHeaderBlockIR* ir) {
+ encoder_ =
+ framer_->GetHpackEncoder()->EncodeHeaderSet(ir->header_block());
+ }
+
+ bool has_next_frame() const { return has_next_frame_; }
+
+ private:
+ SpdyFramer* const framer_;
+ std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoder_;
+ bool is_first_frame_;
+ bool has_next_frame_;
+ };
+
+ // Iteratively converts a SpdyHeadersIR (with a possibly huge
+ // SpdyHeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
+ // write to the output.
+ class SPDY_EXPORT_PRIVATE SpdyHeaderFrameIterator : public SpdyFrameIterator {
+ public:
+ // Does not take ownership of |framer|. Take ownership of |headers_ir|.
+ SpdyHeaderFrameIterator(SpdyFramer* framer,
+ std::unique_ptr<const SpdyHeadersIR> headers_ir);
+
+ ~SpdyHeaderFrameIterator() override;
+
+ private:
+ const SpdyFrameIR& GetIR() const override;
+ size_t GetFrameSizeSansBlock() const override;
+ bool SerializeGivenEncoding(const SpdyString& encoding,
+ ZeroCopyOutputBuffer* output) const override;
+
+ const std::unique_ptr<const SpdyHeadersIR> headers_ir_;
+ };
+
+ // Iteratively converts a SpdyPushPromiseIR (with a possibly huge
+ // SpdyHeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
+ // write to the output.
+ class SPDY_EXPORT_PRIVATE SpdyPushPromiseFrameIterator
+ : public SpdyFrameIterator {
+ public:
+ // Does not take ownership of |framer|. Take ownership of |push_promise_ir|.
+ SpdyPushPromiseFrameIterator(
+ SpdyFramer* framer,
+ std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir);
+
+ ~SpdyPushPromiseFrameIterator() override;
+
+ private:
+ const SpdyFrameIR& GetIR() const override;
+ size_t GetFrameSizeSansBlock() const override;
+ bool SerializeGivenEncoding(const SpdyString& encoding,
+ ZeroCopyOutputBuffer* output) const override;
+
+ const std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir_;
+ };
+
+ // Converts a SpdyFrameIR into one Spdy frame (a sequence of length 1), and
+ // write it to the output.
+ class SPDY_EXPORT_PRIVATE SpdyControlFrameIterator
+ : public SpdyFrameSequence {
+ public:
+ SpdyControlFrameIterator(SpdyFramer* framer,
+ std::unique_ptr<const SpdyFrameIR> frame_ir);
+ ~SpdyControlFrameIterator() override;
+
+ size_t NextFrame(ZeroCopyOutputBuffer* output) override;
+
+ bool HasNextFrame() const override;
+
+ const SpdyFrameIR& GetIR() const override;
+
+ private:
+ SpdyFramer* const framer_;
+ std::unique_ptr<const SpdyFrameIR> frame_ir_;
+ bool has_next_frame_ = true;
+ };
+
+ private:
+ void SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers,
+ uint8_t* flags,
+ size_t* size,
+ SpdyString* hpack_encoding,
+ int* weight,
+ size_t* length_field);
+ void SerializePushPromiseBuilderHelper(const SpdyPushPromiseIR& push_promise,
+ uint8_t* flags,
+ SpdyString* hpack_encoding,
+ size_t* size);
+
+ std::unique_ptr<HpackEncoder> hpack_encoder_;
+
+ SpdyFramerDebugVisitorInterface* debug_visitor_;
+
+ // Determines whether HPACK compression is used.
+ const CompressionOption compression_option_;
+};
+
+} // namespace spdy
+
+#endif // QUICHE_SPDY_CORE_SPDY_FRAMER_H_