Branches the nghttp2_adapter interface from //net/http2.

PiperOrigin-RevId: 361667825
Change-Id: I94cab47ce471f23eb872a39173efbc9c159eb76b
diff --git a/http2/adapter/http2_adapter.h b/http2/adapter/http2_adapter.h
new file mode 100644
index 0000000..cccc269
--- /dev/null
+++ b/http2/adapter/http2_adapter.h
@@ -0,0 +1,114 @@
+#ifndef QUICHE_HTTP2_ADAPTER_HTTP2_ADAPTER_H_
+#define QUICHE_HTTP2_ADAPTER_HTTP2_ADAPTER_H_
+
+#include "absl/strings/string_view.h"
+#include "absl/types/span.h"
+#include "http2/adapter/http2_protocol.h"
+#include "http2/adapter/http2_session.h"
+#include "http2/adapter/http2_visitor_interface.h"
+
+namespace http2 {
+namespace adapter {
+
+// Http2Adapter is an HTTP/2-processing class that exposes an interface similar
+// to the nghttp2 library for processing the HTTP/2 wire format. As nghttp2
+// parses HTTP/2 frames and invokes callbacks on Http2Adapter, Http2Adapter then
+// invokes corresponding callbacks on its passed-in Http2VisitorInterface.
+// Http2Adapter is a base class shared between client-side and server-side
+// implementations.
+class Http2Adapter {
+ public:
+  Http2Adapter(const Http2Adapter&) = delete;
+  Http2Adapter& operator=(const Http2Adapter&) = delete;
+
+  // Processes the incoming |bytes| as HTTP/2 and invokes callbacks on the
+  // |visitor_| as appropriate.
+  ssize_t ProcessBytes(absl::string_view bytes);
+
+  // Submits the |settings| to be written to the peer, e.g., as part of the
+  // HTTP/2 connection preface.
+  void SubmitSettings(absl::Span<const Http2Setting> settings);
+
+  // Submits a PRIORITY frame for the given stream.
+  void SubmitPriorityForStream(Http2StreamId stream_id,
+                               Http2StreamId parent_stream_id, int weight,
+                               bool exclusive);
+
+  // Submits a PING on the connection. Note that nghttp2 automatically submits
+  // PING acks upon receiving non-ack PINGs from the peer, so callers only use
+  // this method to originate PINGs. See nghttp2_option_set_no_auto_ping_ack().
+  void SubmitPing(Http2PingId ping_id);
+
+  // Submits a GOAWAY on the connection. Note that |last_accepted_stream_id|
+  // refers to stream IDs initiated by the peer. For client-side, this last
+  // stream ID must be even (or 0); for server-side, this last stream ID must be
+  // odd (or 0). To submit a GOAWAY with |last_accepted_stream_id| with the
+  // maximum stream ID, signaling imminent connection termination, call
+  // SubmitShutdownNotice() instead (though this is only possible server-side).
+  void SubmitGoAway(Http2StreamId last_accepted_stream_id,
+                    Http2ErrorCode error_code, absl::string_view opaque_data);
+
+  // Submits a WINDOW_UPDATE for the given stream (a |stream_id| of 0 indicates
+  // a connection-level WINDOW_UPDATE).
+  void SubmitWindowUpdate(Http2StreamId stream_id, int window_increment);
+
+  // Submits a METADATA frame for the given stream (a |stream_id| of 0 indicates
+  // connection-level METADATA). If |fin|, the frame will also have the
+  // END_METADATA flag set.
+  void SubmitMetadata(Http2StreamId stream_id, bool fin);
+
+  // Returns serialized bytes for writing to the wire.
+  // Writes should be submitted to Http2Adapter first, so that Http2Adapter
+  // has data to serialize and return in this method.
+  std::string GetBytesToWrite();
+
+  // Returns the connection-level flow control window for the peer.
+  int GetPeerConnectionWindow() const;
+
+  // Marks the given amount of data as consumed for the given stream, which
+  // enables the nghttp2 layer to trigger WINDOW_UPDATEs as appropriate.
+  void MarkDataConsumedForStream(Http2StreamId stream_id, size_t num_bytes);
+
+ protected:
+  // Subclasses should expose a public factory method for constructing and
+  // initializing (via Initialize()) adapter instances.
+  explicit Http2Adapter(Http2VisitorInterface& visitor) : visitor_(visitor) {}
+  virtual ~Http2Adapter();
+
+  // Initializes the underlying HTTP/2 session and submits initial SETTINGS.
+  // Users must call Initialize() before doing other work with Http2Adapter.
+  // Because Initialize() calls virtual methods, this method cannot be called in
+  // the constructor. Factory methods may instead construct and initialize
+  // Http2Adapter instances to hide this implementation detail from users.
+  void Initialize();
+
+  // Creates the callbacks that will be used to initialize the |session_|.
+  virtual std::unique_ptr<Http2SessionCallbacks> CreateCallbacks();
+
+  // Creates with the given |callbacks| and |visitor| as context.
+  virtual std::unique_ptr<Http2Session> CreateSession(
+      std::unique_ptr<Http2SessionCallbacks> callbacks,
+      std::unique_ptr<Http2Options> options,
+      std::unique_ptr<Http2VisitorInterface> visitor) = 0;
+
+  // Accessors. Do not transfer ownership.
+  Http2VisitorInterface& visitor() { return visitor_; }
+
+ private:
+  // Creates the connection-level configuration options for the |session_|.
+  std::unique_ptr<Http2Options> CreateOptions();
+
+  // Http2Adapter will invoke callbacks upon the |visitor_| while processing.
+  Http2VisitorInterface& visitor_;
+
+  // Http2Adapter creates a |session_| for use with the underlying library.
+  std::unique_ptr<Http2Session> session_;
+
+  // Http2Adapter creates the |options_| for use with the |session_|.
+  std::unique_ptr<Http2Options> options_;
+};
+
+}  // namespace adapter
+}  // namespace http2
+
+#endif  // QUICHE_HTTP2_ADAPTER_HTTP2_ADAPTER_H_
diff --git a/http2/adapter/http2_protocol.cc b/http2/adapter/http2_protocol.cc
new file mode 100644
index 0000000..18e8985
--- /dev/null
+++ b/http2/adapter/http2_protocol.cc
@@ -0,0 +1,68 @@
+#include "http2/adapter/http2_protocol.h"
+
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+
+namespace http2 {
+namespace adapter {
+
+const char kHttp2MethodPseudoHeader[] = ":method";
+const char kHttp2SchemePseudoHeader[] = ":scheme";
+const char kHttp2AuthorityPseudoHeader[] = ":authority";
+const char kHttp2PathPseudoHeader[] = ":path";
+const char kHttp2StatusPseudoHeader[] = ":status";
+
+absl::string_view Http2SettingsIdToString(uint16_t id) {
+  switch (id) {
+    case Http2KnownSettingsId::HEADER_TABLE_SIZE:
+      return "SETTINGS_HEADER_TABLE_SIZE";
+    case Http2KnownSettingsId::ENABLE_PUSH:
+      return "SETTINGS_ENABLE_PUSH";
+    case Http2KnownSettingsId::MAX_CONCURRENT_STREAMS:
+      return "SETTINGS_MAX_CONCURRENT_STREAMS";
+    case Http2KnownSettingsId::INITIAL_WINDOW_SIZE:
+      return "SETTINGS_INITIAL_WINDOW_SIZE";
+    case Http2KnownSettingsId::MAX_FRAME_SIZE:
+      return "SETTINGS_MAX_FRAME_SIZE";
+    case Http2KnownSettingsId::MAX_HEADER_LIST_SIZE:
+      return "SETTINGS_MAX_HEADER_LIST_SIZE";
+  }
+  return "SETTINGS_UNKNOWN";
+}
+
+absl::string_view Http2ErrorCodeToString(Http2ErrorCode error_code) {
+  switch (error_code) {
+    case Http2ErrorCode::NO_ERROR:
+      return "NO_ERROR";
+    case Http2ErrorCode::PROTOCOL_ERROR:
+      return "PROTOCOL_ERROR";
+    case Http2ErrorCode::INTERNAL_ERROR:
+      return "INTERNAL_ERROR";
+    case Http2ErrorCode::FLOW_CONTROL_ERROR:
+      return "FLOW_CONTROL_ERROR";
+    case Http2ErrorCode::SETTINGS_TIMEOUT:
+      return "SETTINGS_TIMEOUT";
+    case Http2ErrorCode::STREAM_CLOSED:
+      return "STREAM_CLOSED";
+    case Http2ErrorCode::FRAME_SIZE_ERROR:
+      return "FRAME_SIZE_ERROR";
+    case Http2ErrorCode::REFUSED_STREAM:
+      return "REFUSED_STREAM";
+    case Http2ErrorCode::CANCEL:
+      return "CANCEL";
+    case Http2ErrorCode::COMPRESSION_ERROR:
+      return "COMPRESSION_ERROR";
+    case Http2ErrorCode::CONNECT_ERROR:
+      return "CONNECT_ERROR";
+    case Http2ErrorCode::ENHANCE_YOUR_CALM:
+      return "ENHANCE_YOUR_CALM";
+    case Http2ErrorCode::INADEQUATE_SECURITY:
+      return "INADEQUATE_SECURITY";
+    case Http2ErrorCode::HTTP_1_1_REQUIRED:
+      return "HTTP_1_1_REQUIRED";
+  }
+  return "UNKNOWN_ERROR";
+}
+
+}  // namespace adapter
+}  // namespace http2
diff --git a/http2/adapter/http2_protocol.h b/http2/adapter/http2_protocol.h
new file mode 100644
index 0000000..49e5f16
--- /dev/null
+++ b/http2/adapter/http2_protocol.h
@@ -0,0 +1,105 @@
+#ifndef QUICHE_HTTP2_ADAPTER_HTTP2_PROTOCOL_H_
+#define QUICHE_HTTP2_ADAPTER_HTTP2_PROTOCOL_H_
+
+#include <cstdint>
+#include <string>
+#include <utility>
+
+#include "base/integral_types.h"
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+
+namespace http2 {
+namespace adapter {
+
+// Represents an HTTP/2 stream ID, consistent with nghttp2.
+using Http2StreamId = int32_t;
+
+// Represents an HTTP/2 SETTINGS parameter as specified in RFC 7540 Section 6.5.
+using Http2SettingsId = uint16_t;
+
+// Represents the payload of an HTTP/2 PING frame.
+using Http2PingId = uint64_t;
+
+// Represents an HTTP/2 header field. A header field is a key-value pair with
+// lowercase keys (as specified in RFC 7540 Section 8.1.2).
+using Header = std::pair<std::string, std::string>;
+
+// Represents an HTTP/2 SETTINGS key-value parameter.
+struct Http2Setting {
+  Http2SettingsId id;
+  uint32_t value;
+};
+
+// The maximum possible stream ID.
+const Http2StreamId kMaxStreamId = 0x7FFFFFFF;
+
+// The stream ID that represents the connection (e.g., for connection-level flow
+// control updates).
+const Http2StreamId kConnectionStreamId = 0;
+
+// The default value for the size of the largest frame payload, according to RFC
+// 7540 Section 6.5.2 (SETTINGS_MAX_FRAME_SIZE).
+const int kDefaultFramePayloadSizeLimit = 16 * 1024;
+
+// The default value for the initial stream flow control window size, according
+// to RFC 7540 Section 6.9.2.
+const int kDefaultInitialStreamWindowSize = 64 * 1024 - 1;
+
+// The pseudo-header fields as specified in RFC 7540 Section 8.1.2.3 (request)
+// and Section 8.1.2.4 (response).
+ABSL_CONST_INIT extern const char kHttp2MethodPseudoHeader[];
+ABSL_CONST_INIT extern const char kHttp2SchemePseudoHeader[];
+ABSL_CONST_INIT extern const char kHttp2AuthorityPseudoHeader[];
+ABSL_CONST_INIT extern const char kHttp2PathPseudoHeader[];
+ABSL_CONST_INIT extern const char kHttp2StatusPseudoHeader[];
+
+// HTTP/2 error codes as specified in RFC 7540 Section 7.
+enum class Http2ErrorCode {
+  NO_ERROR = 0x0,
+  PROTOCOL_ERROR = 0x1,
+  INTERNAL_ERROR = 0x2,
+  FLOW_CONTROL_ERROR = 0x3,
+  SETTINGS_TIMEOUT = 0x4,
+  STREAM_CLOSED = 0x5,
+  FRAME_SIZE_ERROR = 0x6,
+  REFUSED_STREAM = 0x7,
+  CANCEL = 0x8,
+  COMPRESSION_ERROR = 0x9,
+  CONNECT_ERROR = 0xA,
+  ENHANCE_YOUR_CALM = 0xB,
+  INADEQUATE_SECURITY = 0xC,
+  HTTP_1_1_REQUIRED = 0xD,
+  MAX_ERROR_CODE = HTTP_1_1_REQUIRED,
+};
+
+// The SETTINGS parameters defined in RFC 7540 Section 6.5.2. Endpoints may send
+// SETTINGS parameters outside of these definitions as per RFC 7540 Section 5.5.
+// This is explicitly an enum instead of an enum class for ease of implicit
+// conversion to the underlying Http2SettingsId type and use with non-standard
+// extension SETTINGS parameters.
+enum Http2KnownSettingsId : Http2SettingsId {
+  HEADER_TABLE_SIZE = 0x1,
+  MIN_SETTING = HEADER_TABLE_SIZE,
+  ENABLE_PUSH = 0x2,
+  MAX_CONCURRENT_STREAMS = 0x3,
+  INITIAL_WINDOW_SIZE = 0x4,
+  MAX_FRAME_SIZE = 0x5,
+  MAX_HEADER_LIST_SIZE = 0x6,
+  MAX_SETTING = MAX_HEADER_LIST_SIZE
+};
+
+// Returns a human-readable string representation of the given SETTINGS |id| for
+// logging/debugging. Returns "SETTINGS_UNKNOWN" for IDs outside of the RFC 7540
+// Section 6.5.2 definitions.
+absl::string_view Http2SettingsIdToString(uint16_t id);
+
+// Returns a human-readable string representation of the given |error_code| for
+// logging/debugging. Returns "UNKNOWN_ERROR" for errors outside of RFC 7540
+// Section 7 definitions.
+absl::string_view Http2ErrorCodeToString(Http2ErrorCode error_code);
+
+}  // namespace adapter
+}  // namespace http2
+
+#endif  // QUICHE_HTTP2_ADAPTER_HTTP2_PROTOCOL_H_
diff --git a/http2/adapter/http2_session.h b/http2/adapter/http2_session.h
new file mode 100644
index 0000000..831cf73
--- /dev/null
+++ b/http2/adapter/http2_session.h
@@ -0,0 +1,41 @@
+#ifndef QUICHE_HTTP2_ADAPTER_HTTP2_SESSION_H_
+#define QUICHE_HTTP2_ADAPTER_HTTP2_SESSION_H_
+
+#include <cstdint>
+
+#include "absl/strings/string_view.h"
+#include "http2/adapter/http2_protocol.h"
+
+namespace http2 {
+namespace adapter {
+
+struct Http2SessionCallbacks {};
+
+// A class to represent the state of a single HTTP/2 connection.
+class Http2Session {
+ public:
+  Http2Session() = default;
+  virtual ~Http2Session() {}
+
+  virtual ssize_t ProcessBytes(absl::string_view bytes) = 0;
+
+  virtual int Consume(Http2StreamId stream_id, size_t num_bytes) = 0;
+
+  virtual bool want_read() = 0;
+  virtual bool want_write() = 0;
+  virtual int GetRemoteWindowSize() = 0;
+};
+
+class Http2Options {
+ public:
+  Http2Options() = default;
+  virtual ~Http2Options() {}
+
+  // This method returns an opaque reference to the underlying type.
+  virtual void* GetOptions() = 0;
+};
+
+}  // namespace adapter
+}  // namespace http2
+
+#endif  // QUICHE_HTTP2_ADAPTER_HTTP2_SESSION_H_
diff --git a/http2/adapter/http2_visitor_interface.h b/http2/adapter/http2_visitor_interface.h
new file mode 100644
index 0000000..765e9f4
--- /dev/null
+++ b/http2/adapter/http2_visitor_interface.h
@@ -0,0 +1,178 @@
+#ifndef QUICHE_HTTP2_ADAPTER_HTTP2_VISITOR_INTERFACE_H_
+#define QUICHE_HTTP2_ADAPTER_HTTP2_VISITOR_INTERFACE_H_
+
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "http2/adapter/http2_protocol.h"
+
+namespace http2 {
+namespace adapter {
+
+// Http2VisitorInterface contains callbacks for receiving HTTP/2-level events. A
+// processor like NghttpAdapter parses HTTP/2 frames and invokes the callbacks
+// on an instance of this interface. Prefer a void return type for these
+// callbacks, instead setting output parameters as needed.
+//
+// Example sequences of calls/events:
+//   GET:
+//     - OnBeginHeadersForStream()
+//     - OnHeaderForStream()
+//     - OnEndHeadersForStream()
+//     - OnEndStream()
+//
+//   POST:
+//     - OnBeginHeadersForStream()
+//     - OnHeaderForStream()
+//     - OnEndHeadersForStream()
+//     - OnBeginDataForStream()
+//     - OnDataForStream()
+//     - OnEndStream()
+//
+//   Request canceled mid-stream, e.g, with error code CANCEL:
+//     - OnBeginHeadersForStream()
+//     - OnHeaderForStream()
+//     - OnEndHeadersForStream()
+//     - OnRstStream()
+//     - OnAbortStream()
+//
+//   Request closed mid-stream, e.g., with error code NO_ERROR:
+//     - OnBeginHeadersForStream()
+//     - OnHeaderForStream()
+//     - OnEndHeadersForStream()
+//     - OnRstStream()
+//     - OnCloseStream()
+//
+// More details are at RFC 7540 (go/http2spec), and more examples are at
+// http://google3/net/http2/server/lib/internal/h2/nghttp2/nghttp2_server_adapter_test.cc.
+class Http2VisitorInterface {
+ public:
+  Http2VisitorInterface(const Http2VisitorInterface&) = delete;
+  Http2VisitorInterface& operator=(const Http2VisitorInterface&) = delete;
+  virtual ~Http2VisitorInterface() = default;
+
+  // Called when a connection-level processing error has been encountered.
+  virtual void OnConnectionError() = 0;
+
+  // Called when a non-ack SETTINGS frame is received.
+  virtual void OnSettingsStart() = 0;
+
+  // Called for each SETTINGS id-value pair.
+  virtual void OnSetting(Http2Setting setting) = 0;
+
+  // Called at the end of a non-ack SETTINGS frame.
+  virtual void OnSettingsEnd() = 0;
+
+  // Called when a SETTINGS ack frame is received.
+  virtual void OnSettingsAck() = 0;
+
+  // Called when the connection receives the header block for a HEADERS frame on
+  // a stream but has not yet parsed individual headers.
+  virtual void OnBeginHeadersForStream(Http2StreamId stream_id) = 0;
+
+  // Called when the connection receives the header |key| and |value| for a
+  // stream. The HTTP/2 pseudo-headers defined in RFC 7540 Sections 8.1.2.3 and
+  // 8.1.2.4 are also conveyed in this callback. This method is called after
+  // OnBeginHeadersForStream().
+  virtual void OnHeaderForStream(Http2StreamId stream_id, absl::string_view key,
+                                 absl::string_view value) = 0;
+
+  // Called when the connection has received the complete header block for a
+  // logical HEADERS frame on a stream (which may contain CONTINUATION frames,
+  // transparent to the user).
+  virtual void OnEndHeadersForStream(Http2StreamId stream_id) = 0;
+
+  // Called when the connection receives the beginning of a DATA frame. The data
+  // payload will be provided via subsequent calls to OnDataForStream().
+  virtual void OnBeginDataForStream(Http2StreamId stream_id,
+                                    size_t payload_length) = 0;
+
+  // Called when the connection receives some |data| (as part of a DATA frame
+  // payload) for a stream.
+  virtual void OnDataForStream(Http2StreamId stream_id,
+                               absl::string_view data) = 0;
+
+  // Called when the peer sends the END_STREAM flag on a stream, indicating that
+  // the peer will not send additional headers or data for that stream.
+  virtual void OnEndStream(Http2StreamId stream_id) = 0;
+
+  // Called when the connection receives a RST_STREAM for a stream. This call
+  // will be followed by either OnCloseStream() or OnAbortStream().
+  virtual void OnRstStream(Http2StreamId stream_id,
+                           Http2ErrorCode error_code) = 0;
+
+  // Called when a stream is closed with error code NO_ERROR. Compare with
+  // OnAbortStream().
+  virtual void OnCloseStream(Http2StreamId stream_id) = 0;
+
+  // Called when a stream is aborted, i.e., closed for the reason indicated by
+  // the given |error_code|, where error_code != NO_ERROR. Compare with
+  // OnCloseStream().
+  virtual void OnAbortStream(Http2StreamId stream_id,
+                             Http2ErrorCode error_code) = 0;
+
+  // Called when the connection receives a PRIORITY frame.
+  virtual void OnPriorityForStream(Http2StreamId stream_id,
+                                   Http2StreamId parent_stream_id, int weight,
+                                   bool exclusive) = 0;
+
+  // Called when the connection receives a PING frame.
+  virtual void OnPing(Http2PingId ping_id, bool is_ack) = 0;
+
+  // Called when the connection receives a PUSH_PROMISE frame. The server push
+  // request headers follow in calls to OnHeaderForStream() with |stream_id|.
+  virtual void OnPushPromiseForStream(Http2StreamId stream_id,
+                                      Http2StreamId promised_stream_id) = 0;
+
+  // Called when the connection receives a GOAWAY frame.
+  virtual void OnGoAway(Http2StreamId last_accepted_stream_id,
+                        Http2ErrorCode error_code,
+                        absl::string_view opaque_data) = 0;
+
+  // Called when the connection receives a WINDOW_UPDATE frame. For
+  // connection-level window updates, the |stream_id| will be 0.
+  virtual void OnWindowUpdate(Http2StreamId stream_id,
+                              int window_increment) = 0;
+
+  // Called when the connection is ready to send data for a stream. The
+  // implementation should write at most |length| bytes of the data payload to
+  // the |destination_buffer| and set |end_stream| to true IFF there will be no
+  // more data sent on this stream. Sets |written| to the number of bytes
+  // written to the |destination_buffer| or a negative value if an error occurs.
+  virtual void OnReadyToSendDataForStream(Http2StreamId stream_id,
+                                             char* destination_buffer,
+                                             size_t length,
+                                             ssize_t* written,
+                                             bool* end_stream) = 0;
+
+  // Called when the connection is ready to write metadata for |stream_id| to
+  // the wire. The implementation should write at most |length| bytes of the
+  // serialized metadata payload to the |buffer| and set |written| to the number
+  // of bytes written or a negative value if there was an error.
+  virtual void OnReadyToSendMetadataForStream(Http2StreamId stream_id,
+                                              char* buffer, size_t length,
+                                              ssize_t* written) = 0;
+
+  // Called when the connection receives the beginning of a METADATA frame
+  // (which may itself be the middle of a logical metadata block). The metadata
+  // payload will be provided via subsequent calls to OnMetadataForStream().
+  virtual void OnBeginMetadataForStream(Http2StreamId stream_id,
+                                        size_t payload_length) = 0;
+
+  // Called when the connection receives |metadata| as part of a METADATA frame
+  // payload for a stream.
+  virtual void OnMetadataForStream(Http2StreamId stream_id,
+                                   absl::string_view metadata) = 0;
+
+  // Called when the connection has finished receiving a logical metadata block
+  // for a stream. Note that there may be multiple metadata blocks for a stream.
+  virtual void OnMetadataEndForStream(Http2StreamId stream_id) = 0;
+
+ protected:
+  Http2VisitorInterface() = default;
+};
+
+}  // namespace adapter
+}  // namespace http2
+
+#endif  // QUICHE_HTTP2_ADAPTER_HTTP2_VISITOR_INTERFACE_H_