Aias00 opened a new issue, #3511:
URL: https://github.com/apache/dubbo-go/issues/3511
### Problem
The server-side unary handler calls `appendTripleOutgoingAttachments(ctx,
res.Attachments())` to propagate provider-set response attachments to the
client. However, `tri.AppendToOutgoingContext` follows gRPC metadata semantics:
it **returns a new `context.Context`** (it does `ctx = context.WithValue(ctx,
extraDataKey{}, extraData)` when the context has no pre-existing outgoing
data). `appendTripleOutgoingAttachments` discards that return value, and the
function does not reassign `ctx`.
The server handler context is never initialized with an outgoing context
(`handler.go` only sets `handlerOutgoingKey`, not `extraDataKey`). Therefore
the first `AppendToOutgoingContext` call takes the `!ok` branch, creates the
outgoing header map on a *new* context that is immediately thrown away, and the
subsequent `ExtractFromOutgoingContext(ctx)` in `handler.go` reads the
*original* context → returns `nil` → `mergeHeaders(conn.ResponseTrailer(),
nil)` writes nothing.
Result: provider response attachments returned via `res.Attachments()` are
silently dropped and never reach the client trailer. No error is raised.
This mechanism was introduced by #2928 (which switched the server path from
`triResp.Trailer().Set` to `AppendToOutgoingContext`). The discard appears to
have been latent since then. It is distinct from #3445, which is about the
consumer-side generic API for *reading* response trailers.
### Current behavior
`protocol/triple/server.go:557-560` (call site)
```go
res := invoker.Invoke(ctx, invo)
triResp := wrapTripleResponse(res.Result())
appendTripleOutgoingAttachments(ctx, res.Attachments()) // return value
not captured
return triResp, res.Error()
```
`protocol/triple/server.go:638-649` (helper discards the returned context)
```go
func appendTripleOutgoingAttachments(ctx context.Context, attachments
map[string]any) {
for k, v := range attachments {
switch val := v.(type) {
case string:
tri.AppendToOutgoingContext(ctx, k, val) // returned ctx
discarded
case []string:
for _, item := range val {
tri.AppendToOutgoingContext(ctx, k, item) // returned ctx
discarded
}
}
}
}
```
`protocol/triple/triple_protocol/header.go:176-194` (immutable return)
```go
func AppendToOutgoingContext(ctx context.Context, kv ...string)
context.Context {
extraData, ok := ctx.Value(extraDataKey{}).(map[string]http.Header)
if !ok {
extraData = map[string]http.Header{}
ctx = context.WithValue(ctx, extraDataKey{}, extraData) // new
context
}
...
return ctx
}
```
`protocol/triple/triple_protocol/handler.go:117` (server reads the original
context → always nil)
```go
if data := ExtractFromOutgoingContext(ctx); data != nil {
mergeHeaders(conn.ResponseTrailer(), data)
}
```
### Expected behavior
1. Provider attachments set via `res.Attachments()` (string / `[]string`)
must reach the response trailer and be readable by the client.
2. Non-string attachment values should not be silently ignored (current
`switch` has no `default`).
3. Either `appendTripleOutgoingAttachments` returns the updated context and
the caller uses it, or the server uses the working `tri.SetHeader`/`SetTrailer`
(`handlerOutgoingKey → conn`) path consistently.
### Suggested approach
- Change `appendTripleOutgoingAttachments` to return `context.Context` (`ctx
= tri.AppendToOutgoingContext(ctx, k, v)` in the loop) and update the call
site: `ctx = appendTripleOutgoingAttachments(ctx, res.Attachments())`, then
ensure the framework serializes `ExtractFromOutgoingContext(ctx)` into the
response trailer (it already does at `handler.go:117`).
- Or bypass the outgoing-context mechanism entirely and write response
attachments via `triResp.Trailer().Set(...)` (the pre-#2928 path), which does
not depend on context immutability.
- Handle non-string attachment types explicitly (convert or warn).
- Add an end-to-end test: provider returns `res.Attachments()` → client
reads trailer (`tri.FromIncomingContext` / `WithResponseTrailer`) and asserts
the values.
### Acceptance criteria
- [ ] Provider `res.Attachments()` string/`[]string` values are received by
the client response trailer.
- [ ] Non-string attachment types are no longer silently dropped (converted
or warned).
- [ ] End-to-end test covers server→client attachment propagation for unary
calls.
- [ ] Existing triple header/trailer tests remain green.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]