Skip to content

Commit e818f5a

Browse files
authored
Include the request ID in all error responses when available. This prevents any clients from getting stuck awaiting for a specific response. The ID will not be available if the request is somehow malformed. (#10740)
1 parent 0e309e3 commit e818f5a

File tree

2 files changed

+24
-14
lines changed

2 files changed

+24
-14
lines changed

webserver/jsonrpc/src/main/java/io/helidon/webserver/jsonrpc/JsonRpcRouting.java

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public void routing(HttpRules httpRules) {
110110
if (errorHandler != null) {
111111
Optional<JsonRpcError> userError = errorHandler.handle(req, jsonObject);
112112
if (userError.isPresent()) {
113-
res.status(Status.OK_200).send(jsonRpcError(userError.get(), res, jsonObject));
113+
res.status(Status.OK_200).send(jsonRpcError(userError.get(), res, jsonObject.get("id")));
114114
} else {
115115
res.status(Status.OK_200).send();
116116
}
@@ -143,14 +143,14 @@ public void routing(HttpRules httpRules) {
143143

144144
// use error if returned, otherwise internal error
145145
if (mappedError.isPresent()) {
146-
JsonObject jsonRpcError = jsonRpcError(mappedError.get(), res, null);
146+
JsonObject jsonRpcError = jsonRpcError(mappedError.get(), res, jsonObject.get("id"));
147147
res.status(Status.OK_200).send(jsonRpcError);
148148
return;
149149
}
150150
} catch (Throwable throwable2) {
151151
// falls through
152152
}
153-
sendInternalError(res);
153+
sendInternalError(res, jsonObject.get("id"));
154154
}
155155
} else if (jsonRequest instanceof JsonArray jsonArray) {
156156
// we must receive at least one request
@@ -178,9 +178,10 @@ public void routing(HttpRules httpRules) {
178178
// Use error if returned by error handler
179179
if (errorHandler != null) {
180180
Optional<JsonRpcError> userError = errorHandler.handle(req, jsonObject);
181-
userError.ifPresent(e -> arrayBuilder.add(jsonRpcError(e, res, jsonObject)));
181+
userError.ifPresent(
182+
e -> arrayBuilder.add(jsonRpcError(e, res, jsonObject.get("id"))));
182183
} else {
183-
JsonObject verifyError = jsonRpcError(error, res, jsonObject);
184+
JsonObject verifyError = jsonRpcError(error, res, jsonObject.get("id"));
184185
arrayBuilder.add(verifyError);
185186
}
186187
continue;
@@ -202,14 +203,14 @@ public void routing(HttpRules httpRules) {
202203

203204
// use error if returned, otherwise internal error
204205
if (mappedError.isPresent()) {
205-
JsonObject jsonRpcError = jsonRpcError(mappedError.get(), res, null);
206+
JsonObject jsonRpcError = jsonRpcError(mappedError.get(), res, jsonObject.get("id"));
206207
arrayBuilder.add(jsonRpcError);
207208
continue;
208209
}
209210
} catch (Throwable throwable2) {
210211
// falls through
211212
}
212-
JsonObject internalError = jsonRpcError(INTERNAL_ERROR_ERROR, res, null);
213+
JsonObject internalError = jsonRpcError(INTERNAL_ERROR_ERROR, res, jsonObject.get("id"));
213214
arrayBuilder.add(internalError);
214215
}
215216
}
@@ -260,10 +261,10 @@ private JsonRpcError verifyJsonRpc(JsonObject object, Map<String, JsonRpcHandler
260261
}
261262
}
262263

263-
private JsonObject jsonRpcError(JsonRpcError error, ServerResponse res, JsonObject jsonObject) {
264+
private JsonObject jsonRpcError(JsonRpcError error, ServerResponse res, JsonValue id) {
264265
JsonRpcResponse rpcRes = new JsonRpcResponseImpl(JsonValue.NULL, res);
265-
if (jsonObject != null && jsonObject.containsKey("id")) {
266-
rpcRes.rpcId(jsonObject.get("id"));
266+
if (id != null) {
267+
rpcRes.rpcId(id);
267268
}
268269
if (error.data().isEmpty()) {
269270
rpcRes.error(error.code(), error.message());
@@ -273,8 +274,8 @@ private JsonObject jsonRpcError(JsonRpcError error, ServerResponse res, JsonObje
273274
return rpcRes.asJsonObject();
274275
}
275276

276-
private void sendInternalError(ServerResponse res) {
277-
JsonObject internalError = jsonRpcError(INTERNAL_ERROR_ERROR, res, null);
277+
private void sendInternalError(ServerResponse res, JsonValue id) {
278+
JsonObject internalError = jsonRpcError(INTERNAL_ERROR_ERROR, res, id);
278279
res.status(Status.OK_200).send(internalError);
279280
}
280281

@@ -369,7 +370,7 @@ public void send() {
369370
}
370371
sendCalled.set(true);
371372
} catch (Exception e) {
372-
sendInternalError(res);
373+
sendInternalError(res, rpcId().orElse(null));
373374
}
374375
}
375376

@@ -398,7 +399,7 @@ public void send() {
398399
arrayBuilder.add(asJsonObject());
399400
}
400401
} catch (Exception e) {
401-
sendInternalError(res);
402+
sendInternalError(res, rpcId().orElse(null));
402403
}
403404
}
404405
}

webserver/tests/jsonrpc/src/test/java/io/helidon/webserver/tests/jsonrpc/JsonRpcExceptionTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,11 @@ void beforeEach() {
9898
@Test
9999
void testPing1() throws InterruptedException {
100100
try (JsonRpcClientResponse res = client.rpcMethod("ping1")
101+
.rpcId(1)
101102
.path("/rpc")
102103
.submit()) {
104+
assertThat(res.rpcId().isPresent(), is(true));
105+
assertThat(res.rpcId().get().toString(), is("1"));
103106
assertThat(res.error().isPresent(), is(true));
104107
assertThat(res.error().get().code(), is(-10001));
105108
assertThat(res.error().get().message(), is(MESSAGE1));
@@ -110,8 +113,11 @@ void testPing1() throws InterruptedException {
110113
@Test
111114
void testPing2() throws InterruptedException {
112115
try (JsonRpcClientResponse res = client.rpcMethod("ping2")
116+
.rpcId(1)
113117
.path("/rpc")
114118
.submit()) {
119+
assertThat(res.rpcId().isPresent(), is(true));
120+
assertThat(res.rpcId().get().toString(), is("1"));
115121
assertThat(res.error().isPresent(), is(true));
116122
assertThat(res.error().get().code(), is(-10002));
117123
assertThat(res.error().get().message(), is(MESSAGE2));
@@ -122,8 +128,11 @@ void testPing2() throws InterruptedException {
122128
@Test
123129
void testPing3() throws InterruptedException {
124130
try (JsonRpcClientResponse res = client.rpcMethod("ping3")
131+
.rpcId(1)
125132
.path("/rpc")
126133
.submit()) {
134+
assertThat(res.rpcId().isPresent(), is(true));
135+
assertThat(res.rpcId().get().toString(), is("1"));
127136
assertThat(res.error().isPresent(), is(true));
128137
assertThat(res.error().get().code(), is(JsonRpcError.INTERNAL_ERROR));
129138
}

0 commit comments

Comments
 (0)