Skip to content

Commit 870e835

Browse files
authored
fix:issue-5110 (#5113)
1 parent de42f27 commit 870e835

File tree

2 files changed

+109
-14
lines changed

2 files changed

+109
-14
lines changed

gateway/internal/eventhandler.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package internal
22

33
import (
4+
"fmt"
45
"io"
56
"net/http"
67

@@ -12,6 +13,22 @@ import (
1213
"google.golang.org/grpc/status"
1314
)
1415

16+
// MetadataHeaderPrefix is the http prefix that represents custom metadata
17+
// parameters to or from a gRPC call.
18+
const MetadataHeaderPrefix = "Grpc-Metadata-"
19+
20+
// MetadataTrailerPrefix is prepended to gRPC metadata as it is converted to
21+
// HTTP headers in a response handled by go-zero gateway
22+
const MetadataTrailerPrefix = "Grpc-Trailer-"
23+
24+
func defaultOutgoingHeaderMatcher(key string) (string, bool) {
25+
return fmt.Sprintf("%s%s", MetadataHeaderPrefix, key), true
26+
}
27+
28+
func defaultOutgoingTrailerMatcher(key string) (string, bool) {
29+
return fmt.Sprintf("%s%s", MetadataTrailerPrefix, key), true
30+
}
31+
1532
type EventHandler struct {
1633
Status *status.Status
1734
writer io.Writer
@@ -31,9 +48,11 @@ func NewEventHandler(writer io.Writer, resolver jsonpb.AnyResolver) *EventHandle
3148
func (h *EventHandler) OnReceiveHeaders(md metadata.MD) {
3249
w, ok := h.writer.(http.ResponseWriter)
3350
if ok {
34-
for k, v := range md {
35-
for _, val := range v {
36-
w.Header().Add(k, val)
51+
for k, vs := range md {
52+
if h, ok := defaultOutgoingHeaderMatcher(k); ok {
53+
for _, v := range vs {
54+
w.Header().Add(h, v)
55+
}
3756
}
3857
}
3958
}
@@ -48,9 +67,11 @@ func (h *EventHandler) OnReceiveResponse(message proto.Message) {
4867
func (h *EventHandler) OnReceiveTrailers(status *status.Status, md metadata.MD) {
4968
w, ok := h.writer.(http.ResponseWriter)
5069
if ok {
51-
for k, v := range md {
52-
for _, val := range v {
53-
w.Header().Add(k, val)
70+
for k, vs := range md {
71+
if h, ok := defaultOutgoingTrailerMatcher(k); ok {
72+
for _, v := range vs {
73+
w.Header().Add(h, v)
74+
}
5475
}
5576
}
5677
}

gateway/internal/eventhandler_test.go

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ func TestEventHandler_OnReceiveTrailers(t *testing.T) {
4040
},
4141
expectedStatus: codes.OK,
4242
expectedHeader: map[string][]string{
43-
"X-Custom-Header": {"value1", "value2"},
44-
"X-Another-Header": {"single-value"},
43+
"Grpc-Trailer-X-Custom-Header": {"value1", "value2"},
44+
"Grpc-Trailer-X-Another-Header": {"single-value"},
4545
},
4646
},
4747
{
@@ -100,9 +100,9 @@ func TestEventHandler_OnReceiveHeaders(t *testing.T) {
100100
"x-another-header": []string{"single-value"},
101101
},
102102
expectedHeader: map[string][]string{
103-
"Content-Type": {"application/json"},
104-
"X-Custom-Header": {"value1", "value2"},
105-
"X-Another-Header": {"single-value"},
103+
"Grpc-Metadata-Content-Type": {"application/json"},
104+
"Grpc-Metadata-X-Custom-Header": {"value1", "value2"},
105+
"Grpc-Metadata-X-Another-Header": {"single-value"},
106106
},
107107
},
108108
{
@@ -158,7 +158,81 @@ func TestEventHandler_OnReceiveHeaders_MultipleValues(t *testing.T) {
158158
"x-header-2": []string{"value3"},
159159
})
160160

161-
// Check that headers are accumulated (not overwritten)
162-
assert.Equal(t, []string{"value1", "value2"}, recorder.Header()["X-Header-1"])
163-
assert.Equal(t, []string{"value3"}, recorder.Header()["X-Header-2"])
161+
// Check that headers are accumulated (not overwritten) with proper prefix
162+
assert.Equal(t, []string{"value1", "value2"}, recorder.Header()["Grpc-Metadata-X-Header-1"])
163+
assert.Equal(t, []string{"value3"}, recorder.Header()["Grpc-Metadata-X-Header-2"])
164+
}
165+
166+
func TestEventHandler_OnReceiveHeaders_MetadataPrefix(t *testing.T) {
167+
tests := []struct {
168+
name string
169+
metadata metadata.MD
170+
expectedHeader map[string][]string
171+
}{
172+
{
173+
name: "all metadata headers should be prefixed with Grpc-Metadata-",
174+
metadata: metadata.MD{
175+
"content-type": []string{"application/grpc"},
176+
"x-custom-header": []string{"value1"},
177+
"authorization": []string{"Bearer token"},
178+
},
179+
expectedHeader: map[string][]string{
180+
"Grpc-Metadata-Content-Type": {"application/grpc"},
181+
"Grpc-Metadata-X-Custom-Header": {"value1"},
182+
"Grpc-Metadata-Authorization": {"Bearer token"},
183+
},
184+
},
185+
{
186+
name: "mixed case headers should be prefixed",
187+
metadata: metadata.MD{
188+
"Content-Type": []string{"APPLICATION/JSON"},
189+
"X-Custom-Header": []string{"value1"},
190+
},
191+
expectedHeader: map[string][]string{
192+
"Grpc-Metadata-Content-Type": {"APPLICATION/JSON"},
193+
"Grpc-Metadata-X-Custom-Header": {"value1"},
194+
},
195+
},
196+
{
197+
name: "multiple values for same header",
198+
metadata: metadata.MD{
199+
"x-multi-header": []string{"value1", "value2", "value3"},
200+
},
201+
expectedHeader: map[string][]string{
202+
"Grpc-Metadata-X-Multi-Header": {"value1", "value2", "value3"},
203+
},
204+
},
205+
{
206+
name: "empty metadata",
207+
metadata: metadata.MD{},
208+
expectedHeader: map[string][]string{},
209+
},
210+
}
211+
212+
for _, tt := range tests {
213+
t.Run(tt.name, func(t *testing.T) {
214+
recorder := httptest.NewRecorder()
215+
h := NewEventHandler(recorder, nil)
216+
217+
h.OnReceiveHeaders(tt.metadata)
218+
219+
// Check that headers are set correctly
220+
for key, expectedValues := range tt.expectedHeader {
221+
actualValues := recorder.Header()[key]
222+
assert.Equal(t, expectedValues, actualValues, "Header %s should match", key)
223+
}
224+
225+
// Ensure no unexpected headers are set
226+
for actualKey := range recorder.Header() {
227+
found := false
228+
for expectedKey := range tt.expectedHeader {
229+
if actualKey == expectedKey {
230+
found = true
231+
break
232+
}
233+
}
234+
assert.True(t, found, "Unexpected header found: %s", actualKey)
235+
}
236+
})
237+
}
164238
}

0 commit comments

Comments
 (0)