Add methods to WebTransportSession to expose perspective and underlying protocol.

PiperOrigin-RevId: 937515306
diff --git a/quiche/quic/core/http/web_transport_http3.h b/quiche/quic/core/http/web_transport_http3.h
index 80268bf..d0aa95a 100644
--- a/quiche/quic/core/http/web_transport_http3.h
+++ b/quiche/quic/core/http/web_transport_http3.h
@@ -101,6 +101,14 @@
   webtransport::SessionStats GetSessionStats() override {
     return WebTransportStatsForQuicSession(*session_);
   }
+  webtransport::Perspective GetPerspective() const override {
+    return session_->perspective() == quic::Perspective::IS_CLIENT
+               ? webtransport::Perspective::kClient
+               : webtransport::Perspective::kServer;
+  }
+  webtransport::UnderlyingProtocol GetUnderlyingProtocol() const override {
+    return webtransport::UnderlyingProtocol::kHttp3;
+  }
 
   void NotifySessionDraining() override;
   void SetOnDraining(quiche::SingleUseCallback<void()> callback) override {
diff --git a/quiche/quic/core/quic_generic_session.h b/quiche/quic/core/quic_generic_session.h
index 16eba28..eca4c70 100644
--- a/quiche/quic/core/quic_generic_session.h
+++ b/quiche/quic/core/quic_generic_session.h
@@ -102,6 +102,14 @@
   webtransport::SessionStats GetSessionStats() override {
     return WebTransportStatsForQuicSession(*this);
   }
+  webtransport::Perspective GetPerspective() const override {
+    return perspective() == quic::Perspective::IS_CLIENT
+               ? webtransport::Perspective::kClient
+               : webtransport::Perspective::kServer;
+  }
+  webtransport::UnderlyingProtocol GetUnderlyingProtocol() const override {
+    return webtransport::UnderlyingProtocol::kRawQuic;
+  }
   void NotifySessionDraining() override {}
   void SetOnDraining(quiche::SingleUseCallback<void()>) override {}
   std::optional<std::string> GetNegotiatedSubprotocol() const override {
diff --git a/quiche/web_transport/encapsulated/encapsulated_web_transport.cc b/quiche/web_transport/encapsulated/encapsulated_web_transport.cc
index 2ed07ff..b0eb915 100644
--- a/quiche/web_transport/encapsulated/encapsulated_web_transport.cc
+++ b/quiche/web_transport/encapsulated/encapsulated_web_transport.cc
@@ -773,4 +773,10 @@
   return std::nullopt;
 }
 
+Perspective EncapsulatedSession::GetPerspective() const { return perspective_; }
+
+UnderlyingProtocol EncapsulatedSession::GetUnderlyingProtocol() const {
+  return UnderlyingProtocol::kHttp2;
+}
+
 }  // namespace webtransport
diff --git a/quiche/web_transport/encapsulated/encapsulated_web_transport.h b/quiche/web_transport/encapsulated/encapsulated_web_transport.h
index d711ad0..ea1e401 100644
--- a/quiche/web_transport/encapsulated/encapsulated_web_transport.h
+++ b/quiche/web_transport/encapsulated/encapsulated_web_transport.h
@@ -101,6 +101,8 @@
   void NotifySessionDraining() override;
   void SetOnDraining(quiche::SingleUseCallback<void()> callback) override;
   std::optional<std::string> GetNegotiatedSubprotocol() const override;
+  Perspective GetPerspective() const override;
+  UnderlyingProtocol GetUnderlyingProtocol() const override;
 
   // StreamVisitor implementation.
   void OnCanWrite() override;
diff --git a/quiche/web_transport/test_tools/mock_web_transport.h b/quiche/web_transport/test_tools/mock_web_transport.h
index c3aa295..3172bd7 100644
--- a/quiche/web_transport/test_tools/mock_web_transport.h
+++ b/quiche/web_transport/test_tools/mock_web_transport.h
@@ -96,6 +96,8 @@
               (override));
   MOCK_METHOD(std::optional<std::string>, GetNegotiatedSubprotocol, (),
               (const, override));
+  MOCK_METHOD(Perspective, GetPerspective, (), (const, override));
+  MOCK_METHOD(UnderlyingProtocol, GetUnderlyingProtocol, (), (const, override));
 };
 
 }  // namespace test
diff --git a/quiche/web_transport/web_transport.h b/quiche/web_transport/web_transport.h
index 1e84efb..302780c 100644
--- a/quiche/web_transport/web_transport.h
+++ b/quiche/web_transport/web_transport.h
@@ -26,7 +26,28 @@
 
 namespace webtransport {
 
-enum class Perspective { kClient, kServer };
+enum class Perspective : uint8_t { kClient, kServer };
+
+enum class UnderlyingProtocol : uint8_t {
+  // WebTransport over HTTP/3
+  kHttp3,
+  // WebTransport over HTTP/2.  Implementations may not be running over actual
+  // HTTP/2 connection, as the transport can run over any TCP-like connection.
+  kHttp2,
+  // Raw QUIC exposed via WebTransport API.
+  kRawQuic,
+  // A protocol other than those explicitly specified above.
+  kOther,
+
+  // NOTE: this entry should not be used and you should not rely on its value,
+  // which may change.
+  //
+  // The purpose of this enumerated value is to force people who handle status
+  // codes with `switch()` statements to *not* simply enumerate all possible
+  // values, but instead provide a "default:" case. Providing such a default
+  // case ensures that code will compile when new codes are added.
+  kDoNotUseReservedForFutureExpansionUseDefaultInSwitchInstead_ = 0xff
+};
 
 // A numeric ID uniquely identifying a WebTransport stream. Note that by design,
 // those IDs are not available in the Web API, and the IDs do not necessarily
@@ -381,6 +402,9 @@
   // Returns the negotiated subprotocol, or std::nullopt, if none was
   // negotiated.
   virtual std::optional<std::string> GetNegotiatedSubprotocol() const = 0;
+
+  virtual Perspective GetPerspective() const = 0;
+  virtual UnderlyingProtocol GetUnderlyingProtocol() const = 0;
 };
 
 }  // namespace webtransport