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

Alanxtl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/dubbo-go-samples.git


The following commit(s) were added to refs/heads/main by this push:
     new 250e15c0 test(triple_header_trailer): cover SendHeader response-header 
path (#1139)
250e15c0 is described below

commit 250e15c01b3e37d3dc0ba274a68a3f4529bcdc60
Author: Lcos <[email protected]>
AuthorDate: Tue Aug 18 10:51:27 2026 +0800

    test(triple_header_trailer): cover SendHeader response-header path (#1139)
    
    Exercise triple.SendHeader in the unary Greet handler (in addition to the
    existing SetHeader) and assert the flushed header reaches the client.
    
    Before dubbo-go #3668, SendHeader merged user headers into
    conn.RequestHeader() instead of conn.ResponseHeader(), so the headers were
    silently dropped (grpcHandlerConn.Send only flushes responseHeader) and the
    inbound request header map was polluted. The current sample never called
    SendHeader, so the integration test could not catch the bug. Adding a
    SendHeader call plus a requireHeader assertion turns this sample into a
    regression test for #3667.
    
    Verified locally by pointing go.mod at dubbo-go via 'go mod edit -replace':
    - main (buggy): client panics with 'missing header X-Unary-Send-Response'
      and exits 1; the existing X-Unary-Response (SetHeader path) still arrives.
    - pr-3668 (fixed): client receives [unary-send-header] and exits 0; all
      four call types pass.
    
    Refs: apache/dubbo-go#3668, apache/dubbo-go#3667
---
 triple_header_trailer/README.md             |  4 ++--
 triple_header_trailer/README_CN.md          |  4 ++--
 triple_header_trailer/go-client/cmd/main.go | 17 +++++++++++------
 triple_header_trailer/go-server/cmd/main.go | 16 ++++++++++------
 4 files changed, 25 insertions(+), 16 deletions(-)

diff --git a/triple_header_trailer/README.md b/triple_header_trailer/README.md
index df7e6b80..6f44223a 100644
--- a/triple_header_trailer/README.md
+++ b/triple_header_trailer/README.md
@@ -8,14 +8,14 @@ It covers:
 
 - Client request headers with `triple.NewOutgoingContext` and 
`triple.AppendToOutgoingContext`
 - Server request metadata with `triple.FromIncomingContext` and generated 
stream `RequestHeader`
-- Unary response headers and trailers with `triple.SetHeader`, 
`triple.SetTrailer`, `client.WithResponseHeader`, and 
`client.WithResponseTrailer`
+- Unary response headers and trailers with `triple.SetHeader`, 
`triple.SendHeader`, `triple.SetTrailer`, `client.WithResponseHeader`, and 
`client.WithResponseTrailer`
 - Server stream response headers and trailers with `ResponseHeader` / 
`ResponseTrailer`
 - Client-side stream response headers and trailers with generated stream 
methods
 - `http.Header` style key lookup with `Values("X-Sample-Token")`
 
 This is different from the `context` sample. The `context` sample demonstrates 
Dubbo attachments through `constant.AttachmentKey`. This sample demonstrates 
Triple metadata APIs exposed as `http.Header`.
 
-For generated Dubbo-Go unary calls, the server uses `triple.SetHeader` and 
`triple.SetTrailer` to attach response metadata, and the client passes 
`client.WithResponseHeader` and `client.WithResponseTrailer` to capture it for 
that call. For generated bidi-stream and client-stream calls, pass request 
metadata before stream creation with `NewOutgoingContext` / 
`AppendToOutgoingContext`. On the server side, handlers can read the resulting 
metadata from `triple.FromIncomingContext`; generated [...]
+For generated Dubbo-Go unary calls, the server uses `triple.SetHeader`, 
`triple.SendHeader`, and `triple.SetTrailer` to attach response metadata, and 
the client passes `client.WithResponseHeader` and `client.WithResponseTrailer` 
to capture it for that call. `SetHeader` buffers the headers until the response 
is sent; `SendHeader` flushes them immediately (before the first message), 
which is useful when a handler needs to publish response metadata early. For 
generated bidi-stream and clien [...]
 
 ## Run
 
diff --git a/triple_header_trailer/README_CN.md 
b/triple_header_trailer/README_CN.md
index 46cf78b4..891fe19f 100644
--- a/triple_header_trailer/README_CN.md
+++ b/triple_header_trailer/README_CN.md
@@ -8,14 +8,14 @@
 
 - 客户端通过 `triple.NewOutgoingContext` 和 `triple.AppendToOutgoingContext` 发送请求 
header
 - 服务端通过 `triple.FromIncomingContext` 和生成流式接口的 `RequestHeader` 读取请求 metadata
-- Unary 调用通过 
`triple.SetHeader`、`triple.SetTrailer`、`client.WithResponseHeader` 和 
`client.WithResponseTrailer` 读写响应 header / trailer
+- Unary 调用通过 
`triple.SetHeader`、`triple.SendHeader`、`triple.SetTrailer`、`client.WithResponseHeader`
 和 `client.WithResponseTrailer` 读写响应 header / trailer
 - 服务端通过流式接口的 `ResponseHeader` / `ResponseTrailer` 设置响应 header / trailer
 - 客户端通过生成的流式接口读取响应 header / trailer
 - 按 `http.Header` 的方式使用 `Values("X-Sample-Token")` 读取 header
 
 这和 `context` 示例不同。`context` 示例演示的是通过 `constant.AttachmentKey` 传递 Dubbo 
attachments;本示例演示的是 Triple metadata API,并以 `http.Header` 的形式暴露给应用代码。
 
-对于 Dubbo-Go 生成的 Unary 调用,服务端通过 `triple.SetHeader` 和 `triple.SetTrailer` 写入响应 
metadata,客户端通过 `client.WithResponseHeader` 和 `client.WithResponseTrailer` 
捕获本次调用的响应 metadata。对于生成的双向流和客户端流调用,应在创建 stream 前通过 `NewOutgoingContext` / 
`AppendToOutgoingContext` 传入请求 metadata。服务端 handler 可以通过 
`triple.FromIncomingContext` 读取这些 metadata;生成的 stream handler 也可以通过 
`RequestHeader` 查看。
+对于 Dubbo-Go 生成的 Unary 调用,服务端通过 `triple.SetHeader`、`triple.SendHeader` 和 
`triple.SetTrailer` 写入响应 metadata,客户端通过 `client.WithResponseHeader` 和 
`client.WithResponseTrailer` 捕获本次调用的响应 metadata。`SetHeader` 会把 header 
缓冲到响应发送时才发出;`SendHeader` 则立即刷新(在第一条消息之前),适合 handler 需要尽早发布响应 metadata 
的场景。对于生成的双向流和客户端流调用,应在创建 stream 前通过 `NewOutgoingContext` / 
`AppendToOutgoingContext` 传入请求 metadata。服务端 handler 可以通过 
`triple.FromIncomingContext` 读取这些 metadata;生成的 stream handler 也可以通过 
`RequestHeader` 查看。
 
 ## 运行方式
 
diff --git a/triple_header_trailer/go-client/cmd/main.go 
b/triple_header_trailer/go-client/cmd/main.go
index 8f1cb075..1b9a869d 100644
--- a/triple_header_trailer/go-client/cmd/main.go
+++ b/triple_header_trailer/go-client/cmd/main.go
@@ -38,12 +38,13 @@ import (
 )
 
 const (
-       tokenHeader       = "X-Sample-Token"
-       modeHeader        = "X-Sample-Mode"
-       unaryResponseKey  = "X-Unary-Response"
-       unaryTrailerKey   = "X-Unary-Trailer"
-       streamResponseKey = "X-Stream-Response"
-       streamTrailerKey  = "X-Stream-Trailer"
+       tokenHeader        = "X-Sample-Token"
+       modeHeader         = "X-Sample-Mode"
+       unaryResponseKey   = "X-Unary-Response"
+       unarySendHeaderKey = "X-Unary-Send-Response"
+       unaryTrailerKey    = "X-Unary-Trailer"
+       streamResponseKey  = "X-Stream-Response"
+       streamTrailerKey   = "X-Stream-Trailer"
 )
 
 func main() {
@@ -90,10 +91,14 @@ func testUnary(cli greet.GreetService) error {
        }
        logger.Infof("unary response: %s", resp.Greeting)
        logger.Infof("unary response header %s=%v", unaryResponseKey, 
responseHeader.Values(unaryResponseKey))
+       logger.Infof("unary response send header %s=%v", unarySendHeaderKey, 
responseHeader.Values(unarySendHeaderKey))
        logger.Infof("unary response trailer %s=%v", unaryTrailerKey, 
responseTrailer.Values(unaryTrailerKey))
        if err := requireHeader(responseHeader, unaryResponseKey, 
"unary-header"); err != nil {
                return err
        }
+       if err := requireHeader(responseHeader, unarySendHeaderKey, 
"unary-send-header"); err != nil {
+               return err
+       }
        return requireHeader(responseTrailer, unaryTrailerKey, "unary-trailer")
 }
 
diff --git a/triple_header_trailer/go-server/cmd/main.go 
b/triple_header_trailer/go-server/cmd/main.go
index ac0d42c2..23e2e59c 100644
--- a/triple_header_trailer/go-server/cmd/main.go
+++ b/triple_header_trailer/go-server/cmd/main.go
@@ -38,12 +38,13 @@ import (
 )
 
 const (
-       tokenHeader       = "X-Sample-Token"
-       modeHeader        = "X-Sample-Mode"
-       unaryResponseKey  = "X-Unary-Response"
-       unaryTrailerKey   = "X-Unary-Trailer"
-       streamResponseKey = "X-Stream-Response"
-       streamTrailerKey  = "X-Stream-Trailer"
+       tokenHeader        = "X-Sample-Token"
+       modeHeader         = "X-Sample-Mode"
+       unaryResponseKey   = "X-Unary-Response"
+       unarySendHeaderKey = "X-Unary-Send-Response"
+       unaryTrailerKey    = "X-Unary-Trailer"
+       streamResponseKey  = "X-Stream-Response"
+       streamTrailerKey   = "X-Stream-Trailer"
 )
 
 type GreetTripleServer struct{}
@@ -55,6 +56,9 @@ func (srv *GreetTripleServer) Greet(ctx context.Context, req 
*greet.GreetRequest
        if err := triple.SetHeader(ctx, http.Header{unaryResponseKey: 
[]string{"unary-header"}}); err != nil {
                return nil, err
        }
+       if err := triple.SendHeader(ctx, http.Header{unarySendHeaderKey: 
[]string{"unary-send-header"}}); err != nil {
+               return nil, err
+       }
        if err := triple.SetTrailer(ctx, http.Header{unaryTrailerKey: 
[]string{"unary-trailer"}}); err != nil {
                return nil, err
        }

Reply via email to