Skip to content

Commit fcbd5ec

Browse files
committed
Avoid NPEs in DefaultServerRequestObservationConvention
In some cases, the default response status of a `ServerWebExchange` can be `null`, especially when the response is not available or the server implementation does not set a default response status. This commit ensures that the status code is available when deriving `KeyValue` information from it, or uses a fallback value for the key value. Fixes gh-29359
1 parent e749cd1 commit fcbd5ec

File tree

2 files changed

+14
-3
lines changed

2 files changed

+14
-3
lines changed

spring-web/src/main/java/org/springframework/http/observation/reactive/DefaultServerRequestObservationConvention.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ protected KeyValue status(ServerRequestObservationContext context) {
100100
if (context.isConnectionAborted()) {
101101
return STATUS_UNKNOWN;
102102
}
103-
return (context.getResponse() != null) ? KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, Integer.toString(context.getResponse().getStatusCode().value())) : STATUS_UNKNOWN;
103+
return (context.getResponse() != null && context.getResponse().getStatusCode() != null) ?
104+
KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, Integer.toString(context.getResponse().getStatusCode().value())) : STATUS_UNKNOWN;
104105
}
105106

106107
protected KeyValue uri(ServerRequestObservationContext context) {
@@ -112,7 +113,7 @@ protected KeyValue uri(ServerRequestObservationContext context) {
112113
}
113114
return KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.URI, pattern.toString());
114115
}
115-
if (context.getResponse() != null) {
116+
if (context.getResponse() != null && context.getResponse().getStatusCode() != null) {
116117
HttpStatus status = HttpStatus.resolve(context.getResponse().getStatusCode().value());
117118
if (status != null) {
118119
if (status.is3xxRedirection()) {
@@ -141,7 +142,7 @@ protected KeyValue outcome(ServerRequestObservationContext context) {
141142
if (context.isConnectionAborted()) {
142143
return HTTP_OUTCOME_UNKNOWN;
143144
}
144-
if (context.getResponse() != null) {
145+
if (context.getResponse() != null && context.getResponse().getStatusCode() != null) {
145146
return HttpOutcome.forStatus(context.getResponse().getStatusCode());
146147
}
147148
return HTTP_OUTCOME_UNKNOWN;

spring-web/src/test/java/org/springframework/http/observation/reactive/DefaultServerRequestObservationConventionTests.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ void addsKeyValuesForCancelledExchange() {
141141
.contains(KeyValue.of("http.url", "/test/resource"));
142142
}
143143

144+
@Test
145+
void supportsNullStatusCode() {
146+
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test/resource"));
147+
ServerRequestObservationContext context = new ServerRequestObservationContext(exchange);
148+
149+
assertThat(this.convention.getLowCardinalityKeyValues(context))
150+
.contains(KeyValue.of("status", "UNKNOWN"),
151+
KeyValue.of("exception", "none"), KeyValue.of("outcome", "UNKNOWN"));
152+
}
153+
144154
private static PathPattern getPathPattern(String pattern) {
145155
PathPatternParser pathPatternParser = new PathPatternParser();
146156
return pathPatternParser.parse(pattern);

0 commit comments

Comments
 (0)