Skip to content

Commit 6639be4

Browse files
Fix grpc status headers
1 parent 3c627f3 commit 6639be4

File tree

1 file changed

+46
-26
lines changed

1 file changed

+46
-26
lines changed

spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/GRPCResponseHeadersFilter.java

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.cloud.gateway.filter.headers;
1818

19+
import reactor.netty.http.client.HttpClientResponse;
1920
import reactor.netty.http.server.HttpServerResponse;
2021

2122
import org.springframework.core.Ordered;
@@ -26,6 +27,8 @@
2627
import org.springframework.util.StringUtils;
2728
import org.springframework.web.server.ServerWebExchange;
2829

30+
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR;
31+
2932
/**
3033
* @author Alberto C. Ríos
3134
*/
@@ -37,45 +40,62 @@ public class GRPCResponseHeadersFilter implements HttpHeadersFilter, Ordered {
3740

3841
@Override
3942
public HttpHeaders filter(HttpHeaders headers, ServerWebExchange exchange) {
40-
ServerHttpResponse response = exchange.getResponse();
41-
HttpHeaders responseHeaders = response.getHeaders();
4243
if (isGRPC(exchange)) {
43-
String trailerHeaderValue = GRPC_STATUS_HEADER + "," + GRPC_MESSAGE_HEADER;
44-
String originalTrailerHeaderValue = responseHeaders.getFirst(HttpHeaders.TRAILER);
45-
if (originalTrailerHeaderValue != null) {
46-
trailerHeaderValue += "," + originalTrailerHeaderValue;
47-
}
48-
responseHeaders.set(HttpHeaders.TRAILER, trailerHeaderValue);
44+
ServerHttpResponse response = exchange.getResponse();
45+
HttpHeaders responseHeaders = response.getHeaders();
4946

50-
while (response instanceof ServerHttpResponseDecorator) {
51-
response = ((ServerHttpResponseDecorator) response).getDelegate();
47+
if (headers.containsKey(GRPC_STATUS_HEADER)) {
48+
if (!"0".equals(headers.getFirst(GRPC_STATUS_HEADER))) {
49+
response.setComplete(); // avoid empty DATA frame
50+
}
5251
}
53-
if (response instanceof AbstractServerHttpResponse) {
54-
String grpcStatus = getGrpcStatus(headers);
55-
String grpcMessage = getGrpcMessage(headers);
56-
((HttpServerResponse) ((AbstractServerHttpResponse) response).getNativeResponse()).trailerHeaders(h -> {
57-
h.set(GRPC_STATUS_HEADER, grpcStatus);
58-
h.set(GRPC_MESSAGE_HEADER, grpcMessage);
52+
53+
HttpClientResponse nettyInResponse = exchange.getAttribute(CLIENT_RESPONSE_ATTR);
54+
if (nettyInResponse != null) {
55+
nettyInResponse.trailerHeaders().subscribe(entries -> {
56+
if (entries.contains(GRPC_STATUS_HEADER)) {
57+
addTrailingHeader(entries, response, responseHeaders);
58+
}
5959
});
6060
}
61-
6261
}
62+
6363
return headers;
6464
}
6565

66-
private boolean isGRPC(ServerWebExchange exchange) {
67-
String contentTypeValue = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
68-
return StringUtils.startsWithIgnoreCase(contentTypeValue, "application/grpc");
66+
private void addTrailingHeader(io.netty.handler.codec.http.HttpHeaders sourceHeaders, ServerHttpResponse response,
67+
HttpHeaders responseHeaders) {
68+
String trailerHeaderValue = GRPC_STATUS_HEADER + "," + GRPC_MESSAGE_HEADER;
69+
String originalTrailerHeaderValue = responseHeaders.getFirst(HttpHeaders.TRAILER);
70+
if (originalTrailerHeaderValue != null) {
71+
trailerHeaderValue += "," + originalTrailerHeaderValue;
72+
}
73+
responseHeaders.set(HttpHeaders.TRAILER, trailerHeaderValue);
74+
75+
HttpServerResponse nettyOutResponse = getNettyResponse(response);
76+
if (nettyOutResponse != null) {
77+
String grpcStatus = sourceHeaders.get(GRPC_STATUS_HEADER, "0");
78+
String grpcMessage = sourceHeaders.get(GRPC_MESSAGE_HEADER, "");
79+
nettyOutResponse.trailerHeaders(h -> {
80+
h.set(GRPC_STATUS_HEADER, grpcStatus);
81+
h.set(GRPC_MESSAGE_HEADER, grpcMessage);
82+
});
83+
}
6984
}
7085

71-
private String getGrpcStatus(HttpHeaders headers) {
72-
final String grpcStatusValue = headers.getFirst(GRPC_STATUS_HEADER);
73-
return StringUtils.hasText(grpcStatusValue) ? grpcStatusValue : "0";
86+
private HttpServerResponse getNettyResponse(ServerHttpResponse response) {
87+
while (response instanceof ServerHttpResponseDecorator) {
88+
response = ((ServerHttpResponseDecorator) response).getDelegate();
89+
}
90+
if (response instanceof AbstractServerHttpResponse) {
91+
return ((AbstractServerHttpResponse) response).getNativeResponse();
92+
}
93+
return null;
7494
}
7595

76-
private String getGrpcMessage(HttpHeaders headers) {
77-
final String grpcStatusValue = headers.getFirst(GRPC_MESSAGE_HEADER);
78-
return StringUtils.hasText(grpcStatusValue) ? grpcStatusValue : "";
96+
private boolean isGRPC(ServerWebExchange exchange) {
97+
String contentTypeValue = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
98+
return StringUtils.startsWithIgnoreCase(contentTypeValue, "application/grpc");
7999
}
80100

81101
@Override

0 commit comments

Comments
 (0)