problem: in some cases WS may produce empty or broken messages that breaks the connection
solution: better handling for invalid JSON (cherry picked from commit 1b6a995c4e746f0704643426fc20f7496fc09cef)
This commit is contained in:
@@ -21,6 +21,7 @@ import com.fasterxml.jackson.core.JsonParser
|
|||||||
import com.fasterxml.jackson.core.JsonToken
|
import com.fasterxml.jackson.core.JsonToken
|
||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
import io.emeraldpay.etherjar.rpc.RpcResponseError
|
import io.emeraldpay.etherjar.rpc.RpcResponseError
|
||||||
|
import org.apache.commons.lang3.StringUtils
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
@@ -58,15 +59,18 @@ abstract class ResponseParser<T> {
|
|||||||
} catch (e: JsonParseException) {
|
} catch (e: JsonParseException) {
|
||||||
log.warn("Failed to parse JSON from upstream: ${e.message}")
|
log.warn("Failed to parse JSON from upstream: ${e.message}")
|
||||||
}
|
}
|
||||||
if (state.isReady) {
|
return if (state.isReady) {
|
||||||
return state
|
state
|
||||||
}
|
} else {
|
||||||
return Preparsed(
|
log.debug("Failed to parse `${StringUtils.abbreviateMiddle(String(json), "...", 200)}` JSON")
|
||||||
error = JsonRpcError(
|
state.copy(
|
||||||
RpcResponseError.CODE_UPSTREAM_INVALID_RESPONSE,
|
result = null,
|
||||||
"Invalid JSON structure: never finalized"
|
error = JsonRpcError(
|
||||||
|
RpcResponseError.CODE_UPSTREAM_INVALID_RESPONSE,
|
||||||
|
"Invalid JSON structure: never finalized"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun process(parser: JsonParser, json: ByteArray, field: String, state: Preparsed): Preparsed {
|
open fun process(parser: JsonParser, json: ByteArray, field: String, state: Preparsed): Preparsed {
|
||||||
|
|||||||
@@ -44,6 +44,16 @@ class ResponseWSParser : ResponseParser<ResponseWSParser.WsResponse>() {
|
|||||||
state.error
|
state.error
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (state.error != null) {
|
||||||
|
return WsResponse(
|
||||||
|
// we don't have any real option because it's just an invalid value and can be anything,
|
||||||
|
// so let's suppose its Type as RPC as a most likely scenario
|
||||||
|
Type.RPC,
|
||||||
|
state.id ?: JsonRpcResponse.Id.from(0),
|
||||||
|
null,
|
||||||
|
state.error
|
||||||
|
)
|
||||||
|
}
|
||||||
throw IllegalStateException("State is not ready")
|
throw IllegalStateException("State is not ready")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -223,4 +223,27 @@ class ResponseRpcParserSpec extends Specification {
|
|||||||
!act.hasResult()
|
!act.hasResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "Keep provided ID even if JSON is not full"() {
|
||||||
|
setup:
|
||||||
|
def json = '{"jsonrpc": "2.0", "id": 1}'
|
||||||
|
when:
|
||||||
|
def act = parser.parse(json.getBytes())
|
||||||
|
then:
|
||||||
|
act.id.asNumber() == 1
|
||||||
|
act.error != null
|
||||||
|
act.hasError()
|
||||||
|
!act.hasResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
def "Keep provided ID even if JSON is broken"() {
|
||||||
|
setup:
|
||||||
|
def json = '{"jsonrpc": "2.0", "id": 101, "resu'
|
||||||
|
when:
|
||||||
|
def act = parser.parse(json.getBytes())
|
||||||
|
then:
|
||||||
|
act.id.asNumber() == 101
|
||||||
|
act.error != null
|
||||||
|
act.hasError()
|
||||||
|
!act.hasResult()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,4 +103,24 @@ class ResponseWSParserSpec extends Specification {
|
|||||||
act.error == null
|
act.error == null
|
||||||
new String(act.value) == "null"
|
new String(act.value) == "null"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "Keep provided ID even if JSON is not full"() {
|
||||||
|
setup:
|
||||||
|
def json = '{"jsonrpc": "2.0", "id": 1}'
|
||||||
|
when:
|
||||||
|
def act = parser.parse(json.getBytes())
|
||||||
|
then:
|
||||||
|
act.id.asNumber() == 1
|
||||||
|
act.error != null
|
||||||
|
}
|
||||||
|
|
||||||
|
def "Keep provided ID even if JSON is broken"() {
|
||||||
|
setup:
|
||||||
|
def json = '{"jsonrpc": "2.0", "id": 101, "resu'
|
||||||
|
when:
|
||||||
|
def act = parser.parse(json.getBytes())
|
||||||
|
then:
|
||||||
|
act.id.asNumber() == 101
|
||||||
|
act.error != null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user