11package org .tron .core .services .jsonrpc ;
22
3+ import com .fasterxml .jackson .core .JsonProcessingException ;
34import com .fasterxml .jackson .databind .JsonNode ;
45import com .fasterxml .jackson .databind .ObjectMapper ;
6+ import com .fasterxml .jackson .databind .node .ArrayNode ;
57import com .fasterxml .jackson .databind .node .ObjectNode ;
68import com .googlecode .jsonrpc4j .HttpStatusCodeProvider ;
79import com .googlecode .jsonrpc4j .JsonRpcInterceptor ;
@@ -29,12 +31,13 @@ public class JsonRpcServlet extends RateLimiterServlet {
2931
3032 private static final ObjectMapper MAPPER = new ObjectMapper ();
3133
32- enum JsonRpcError {
34+ private enum JsonRpcError {
3335 PARSE_ERROR (-32700 ),
36+ INTERNAL_ERROR (-32603 ),
3437 EXCEED_LIMIT (-32005 ),
3538 RESPONSE_TOO_LARGE (-32003 );
3639
37- final int code ;
40+ private final int code ;
3841
3942 JsonRpcError (int code ) {
4043 this .code = code ;
@@ -86,19 +89,25 @@ public Integer getJsonRpcCode(int httpStatusCode) {
8689 protected void doPost (HttpServletRequest req , HttpServletResponse resp ) throws IOException {
8790 CommonParameter parameter = CommonParameter .getInstance ();
8891
89- byte [] body ;
92+ // Transport IOException from readBody propagates as HTTP 500 (genuine IO failure).
93+ byte [] body = readBody (req .getInputStream ());
9094 JsonNode rootNode ;
9195 try {
92- body = readBody (req .getInputStream ());
9396 rootNode = MAPPER .readTree (body );
94- } catch (IOException e ) {
95- writeJsonRpcError (resp , JsonRpcError .PARSE_ERROR , "Parse error" , null );
97+ if (rootNode == null || rootNode .isMissingNode ()) {
98+ writeJsonRpcError (resp , JsonRpcError .PARSE_ERROR , "Parse error" , null , false );
99+ return ;
100+ }
101+ } catch (JsonProcessingException e ) {
102+ writeJsonRpcError (resp , JsonRpcError .PARSE_ERROR , "Parse error" , null , false );
96103 return ;
97104 }
105+
106+ boolean isBatch = rootNode .isArray ();
98107 int batchSize = parameter .getJsonRpcMaxBatchSize ();
99- if (rootNode . isArray () && batchSize > 0 && rootNode .size () > batchSize ) {
108+ if (isBatch && batchSize > 0 && rootNode .size () > batchSize ) {
100109 writeJsonRpcError (resp , JsonRpcError .EXCEED_LIMIT ,
101- "Batch size " + rootNode .size () + " exceeds the limit of " + batchSize , null );
110+ "Batch size " + rootNode .size () + " exceeds the limit of " + batchSize , null , true );
102111 return ;
103112 }
104113
@@ -108,15 +117,18 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I
108117
109118 try {
110119 rpcServer .handle (cachedReq , bufferedResp );
111- } catch (Exception e ) {
112- throw new IOException ("RPC execution failed" , e );
120+ } catch (RuntimeException e ) {
121+ logger .error ("RPC execution failed" , e );
122+ JsonNode idNode = isBatch ? null : rootNode .get ("id" );
123+ writeJsonRpcError (resp , JsonRpcError .INTERNAL_ERROR , "Internal error" , idNode , isBatch );
124+ return ;
113125 }
114126
115127 if (bufferedResp .isOverflow ()) {
116- JsonNode idNode = ! rootNode . isArray () ? rootNode .get ("id" ) : null ;
128+ JsonNode idNode = isBatch ? null : rootNode .get ("id" );
117129 writeJsonRpcError (resp , JsonRpcError .RESPONSE_TOO_LARGE ,
118130 "Response exceeds the limit of " + parameter .getJsonRpcMaxResponseSize () + " bytes" ,
119- idNode );
131+ idNode , isBatch );
120132 return ;
121133 }
122134 bufferedResp .commitToResponse ();
@@ -133,18 +145,25 @@ private byte[] readBody(InputStream in) throws IOException {
133145 }
134146
135147 private void writeJsonRpcError (HttpServletResponse resp , JsonRpcError error , String message ,
136- JsonNode id ) throws IOException {
137- ObjectNode root = MAPPER .createObjectNode ();
138- root .put ("jsonrpc" , "2.0" );
139- ObjectNode errNode = root .putObject ("error" );
148+ JsonNode id , boolean isBatch ) throws IOException {
149+ ObjectNode errorObj = MAPPER .createObjectNode ();
150+ errorObj .put ("jsonrpc" , "2.0" );
151+ ObjectNode errNode = errorObj .putObject ("error" );
140152 errNode .put ("code" , error .code );
141153 errNode .put ("message" , message );
142154 if (id != null && !id .isNull () && !id .isMissingNode ()) {
143- root .set ("id" , id );
155+ errorObj .set ("id" , id );
156+ } else {
157+ errorObj .putNull ("id" );
158+ }
159+ byte [] bytes ;
160+ if (isBatch ) {
161+ ArrayNode arr = MAPPER .createArrayNode ();
162+ arr .add (errorObj );
163+ bytes = MAPPER .writeValueAsBytes (arr );
144164 } else {
145- root . putNull ( "id" );
165+ bytes = MAPPER . writeValueAsBytes ( errorObj );
146166 }
147- byte [] bytes = MAPPER .writeValueAsBytes (root );
148167 resp .setContentType ("application/json; charset=utf-8" );
149168 resp .setStatus (HttpServletResponse .SC_OK );
150169 resp .setContentLength (bytes .length );
0 commit comments