This is an automated email from the ASF dual-hosted git repository.

raboof pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko-grpc.git


The following commit(s) were added to refs/heads/main by this push:
     new 5ca512a3 Use the pekko-http Trailer header instead of a private copy. 
(#910)
5ca512a3 is described below

commit 5ca512a3f890ae3c8eb4c4a1aba806b2f2318936
Author: PJ Fanning <[email protected]>
AuthorDate: Wed Oct 7 10:19:07 2026 +0100

    Use the pekko-http Trailer header instead of a private copy. (#910)
    
    Motivation:
    pekko-grpc kept its own private `Trailer` custom header to pre-announce
    the `grpc-status` trailer. That header was moved upstream into
    pekko-http (apache/pekko-http#684, since 1.3.0), and pekko-grpc main
    already requires pekko-http 2.0.0-M1, so the private copy is redundant.
    pekko-http also parses incoming `trailer` headers into its modeled
    type, so two classes existed for the same header name.
    
    Modification:
    Remove the private `Trailer` header from `scaladsl.headers` and use
    `pekko.http.scaladsl.model.headers.Trailer` in `GrpcResponseHelpers`.
    Drop the now-unused `scala.collection.compat.immutable.ArraySeq`
    import, which was never needed for the 2.13/3-only runtime module.
    
    Result:
    Server streaming responses pre-announce trailers with pekko-http's
    modeled and validated `Trailer` header.
    
    Tests:
    - sbt "runtime/testOnly 
org.apache.pekko.grpc.internal.GrpcResponseHelpersSpec" - passed
    - sbt "runtime/mimaReportBinaryIssues" - passed
    - sbt "runtime/scalafmtAll" "runtime/Test/scalafmtAll" - no changes
    
    References:
    Fixes #470
---
 .../pekko/grpc/internal/GrpcResponseHelpers.scala  |  3 ++-
 .../pekko/grpc/scaladsl/headers/headers.scala      | 28 ----------------------
 .../grpc/internal/GrpcResponseHelpersSpec.scala    |  3 ++-
 3 files changed, 4 insertions(+), 30 deletions(-)

diff --git 
a/runtime/src/main/scala/org/apache/pekko/grpc/internal/GrpcResponseHelpers.scala
 
b/runtime/src/main/scala/org/apache/pekko/grpc/internal/GrpcResponseHelpers.scala
index da31ff5b..0c5bfd4e 100644
--- 
a/runtime/src/main/scala/org/apache/pekko/grpc/internal/GrpcResponseHelpers.scala
+++ 
b/runtime/src/main/scala/org/apache/pekko/grpc/internal/GrpcResponseHelpers.scala
@@ -20,6 +20,7 @@ import pekko.annotation.InternalApi
 import pekko.grpc.GrpcProtocol.{ GrpcProtocolWriter, TrailerFrame }
 import pekko.grpc.scaladsl.{ headers, GrpcExceptionHandler }
 import pekko.grpc.{ ProtobufFrameSerializer, ProtobufSerializer, Trailers }
+import pekko.http.scaladsl.model.headers.{ Trailer => TrailerHeader }
 import pekko.http.scaladsl.model.HttpEntity.ChunkStreamPart
 import pekko.http.scaladsl.model.{
   AttributeKey,
@@ -138,7 +139,7 @@ object GrpcResponseHelpers {
       headers = Seq(
         headers.`Message-Encoding`(writer.messageEncoding.name),
         // Pre-announcing trailers: See https://www.rfc-editor.org/rfc/rfc7230 
#Section 4.4
-        headers.`Trailer`(headers.`Status`.name)
+        TrailerHeader(List(headers.`Status`.name))
       ),
       entity = HttpEntity.Chunked(writer.contentType, entity))
   }
diff --git 
a/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/headers/headers.scala 
b/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/headers/headers.scala
index 544e15f4..8de1885e 100644
--- 
a/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/headers/headers.scala
+++ 
b/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/headers/headers.scala
@@ -19,7 +19,6 @@ import pekko.http.scaladsl.model.HttpHeader
 import pekko.http.scaladsl.model.headers.{ ModeledCustomHeader, 
ModeledCustomHeaderCompanion }
 import pekko.http.javadsl.{ model => jm }
 
-import scala.collection.compat.immutable.ArraySeq
 import scala.annotation.nowarn
 import scala.util.Try
 
@@ -126,30 +125,3 @@ object `Status-Message` extends 
ModeledCustomHeaderCompanion[`Status-Message`] {
   def findIn(headers: Seq[HttpHeader]): Option[String] =
     headers.collectFirst { case h if h.is(name) => h.value() }
 }
-
-private[grpc] final class `Trailer` private (values: Seq[String]) extends 
ModeledCustomHeader[`Trailer`] {
-
-  override def companion: ModeledCustomHeaderCompanion[`Trailer`] = `Trailer`
-
-  override def value(): String = values.mkString(", ")
-
-  override def renderInRequests(): Boolean = true
-
-  override def renderInResponses(): Boolean = true
-}
-
-private[grpc] object `Trailer` extends ModeledCustomHeaderCompanion[`Trailer`] 
{
-  def apply(values: Seq[String]): `Trailer` = new `Trailer`(values.map(_.trim))
-
-  override val name = "trailer"
-
-  override val lowercaseName: String = super.lowercaseName
-
-  override def parse(value: String): Try[`Trailer`] =
-    Try(`Trailer`(ArraySeq.unsafeWrapArray(SimpleCSVParser.parse(value))))
-
-  def findIn(headers: Seq[HttpHeader]): Option[Seq[String]] =
-    headers.collectFirst {
-      case header if header.is(name) => 
ArraySeq.unsafeWrapArray(SimpleCSVParser.parse(header.value()))
-    }
-}
diff --git 
a/runtime/src/test/scala/org/apache/pekko/grpc/internal/GrpcResponseHelpersSpec.scala
 
b/runtime/src/test/scala/org/apache/pekko/grpc/internal/GrpcResponseHelpersSpec.scala
index 15629f9c..d465606f 100644
--- 
a/runtime/src/test/scala/org/apache/pekko/grpc/internal/GrpcResponseHelpersSpec.scala
+++ 
b/runtime/src/test/scala/org/apache/pekko/grpc/internal/GrpcResponseHelpersSpec.scala
@@ -22,6 +22,7 @@ import io.grpc.Status
 import org.apache.pekko.actor.ActorSystem
 import org.apache.pekko.grpc.GrpcProtocol
 import org.apache.pekko.grpc.scaladsl.{ headers, ScalapbProtobufSerializer }
+import org.apache.pekko.http.scaladsl.model.headers.Trailer
 import org.apache.pekko.stream.scaladsl.Source
 import org.apache.pekko.testkit.TestKit
 import org.scalatest.matchers.should.Matchers._
@@ -45,7 +46,7 @@ final class GrpcResponseHelpersSpec extends 
TestKit(ActorSystem("GrpcResponseHel
           trail = Source.single(GrpcEntityHelpers.trailer(Status.OK))
         )
 
-      val preAnnouncedTrailers = headers.`Trailer`.findIn(response.headers)
+      val preAnnouncedTrailers = response.header[Trailer].map(_.values)
 
       preAnnouncedTrailers shouldBe Some(Seq(headers.`Status`.name))
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to