mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-02-18 17:37:33 +00:00
Fix HTTP/REST clients HTTP Content-Type header parsers. (#4139)
* Fix client HTTP content-type parsers. * Fix tests. * Address review comment and apply wildcard checks for generic decodeBytes.
This commit is contained in:
parent
9999362b11
commit
ca871a5435
@ -70,6 +70,7 @@ const
|
|||||||
|
|
||||||
ApplicationJsonMediaType* = MediaType.init("application/json")
|
ApplicationJsonMediaType* = MediaType.init("application/json")
|
||||||
TextPlainMediaType* = MediaType.init("text/plain")
|
TextPlainMediaType* = MediaType.init("text/plain")
|
||||||
|
OctetStreamMediaType* = MediaType.init("application/octet-stream")
|
||||||
UrlEncodedMediaType* = MediaType.init("application/x-www-form-urlencoded")
|
UrlEncodedMediaType* = MediaType.init("application/x-www-form-urlencoded")
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -2376,10 +2377,21 @@ proc encodeBytes*[T: EncodeArrays](value: T,
|
|||||||
else:
|
else:
|
||||||
err("Content-Type not supported")
|
err("Content-Type not supported")
|
||||||
|
|
||||||
proc decodeBytes*[T: DecodeTypes](t: typedesc[T], value: openArray[byte],
|
proc decodeBytes*[T: DecodeTypes](
|
||||||
contentType: string): RestResult[T] =
|
t: typedesc[T],
|
||||||
case contentType
|
value: openArray[byte],
|
||||||
of "application/json":
|
contentType: Opt[ContentTypeData]
|
||||||
|
): RestResult[T] =
|
||||||
|
|
||||||
|
let mediaType =
|
||||||
|
if contentType.isNone():
|
||||||
|
ApplicationJsonMediaType
|
||||||
|
else:
|
||||||
|
if isWildCard(contentType.get().mediaType):
|
||||||
|
return err("Incorrect Content-Type")
|
||||||
|
contentType.get().mediaType
|
||||||
|
|
||||||
|
if mediaType == ApplicationJsonMediaType:
|
||||||
try:
|
try:
|
||||||
ok RestJson.decode(value, T,
|
ok RestJson.decode(value, T,
|
||||||
requireAllFields = true,
|
requireAllFields = true,
|
||||||
@ -2392,10 +2404,19 @@ proc decodeBytes*[T: DecodeTypes](t: typedesc[T], value: openArray[byte],
|
|||||||
else:
|
else:
|
||||||
err("Content-Type not supported")
|
err("Content-Type not supported")
|
||||||
|
|
||||||
proc decodeBytes*[T: SszDecodeTypes](t: typedesc[T], value: openArray[byte],
|
proc decodeBytes*[T: SszDecodeTypes](
|
||||||
contentType: string, updateRoot = true): RestResult[T] =
|
t: typedesc[T],
|
||||||
case contentType
|
value: openArray[byte],
|
||||||
of "application/octet-stream":
|
contentType: Opt[ContentTypeData],
|
||||||
|
updateRoot = true
|
||||||
|
): RestResult[T] =
|
||||||
|
|
||||||
|
if contentType.isNone() or
|
||||||
|
isWildCard(contentType.get().mediaType):
|
||||||
|
return err("Missing or incorrect Content-Type")
|
||||||
|
|
||||||
|
let mediaType = contentType.get().mediaType
|
||||||
|
if mediaType == OctetStreamMediaType:
|
||||||
try:
|
try:
|
||||||
var v: RestResult[T]
|
var v: RestResult[T]
|
||||||
v.ok(T()) # This optimistically avoids an expensive genericAssign
|
v.ok(T()) # This optimistically avoids an expensive genericAssign
|
||||||
|
@ -132,27 +132,23 @@ proc getBlock*(client: RestClientRef, block_id: BlockIdent,
|
|||||||
let data =
|
let data =
|
||||||
case resp.status
|
case resp.status
|
||||||
of 200:
|
of 200:
|
||||||
case resp.contentType
|
if resp.contentType.isNone() or
|
||||||
of "application/json":
|
isWildCard(resp.contentType.get().mediaType):
|
||||||
let blck =
|
raise newException(RestError, "Missing or incorrect Content-Type")
|
||||||
block:
|
else:
|
||||||
let res = decodeBytes(GetBlockResponse, resp.data,
|
let mediaType = resp.contentType.get().mediaType
|
||||||
resp.contentType)
|
if mediaType == ApplicationJsonMediaType:
|
||||||
if res.isErr():
|
let blck = decodeBytes(GetBlockResponse, resp.data,
|
||||||
raise newException(RestError, $res.error())
|
resp.contentType).valueOr:
|
||||||
res.get()
|
raise newException(RestError, $error)
|
||||||
ForkedSignedBeaconBlock.init(blck.data)
|
ForkedSignedBeaconBlock.init(blck.data)
|
||||||
of "application/octet-stream":
|
elif mediaType == OctetStreamMediaType:
|
||||||
let blck =
|
let blck = decodeBytes(GetPhase0BlockSszResponse, resp.data,
|
||||||
block:
|
resp.contentType).valueOr:
|
||||||
let res = decodeBytes(GetPhase0BlockSszResponse, resp.data,
|
raise newException(RestError, $error)
|
||||||
resp.contentType)
|
|
||||||
if res.isErr():
|
|
||||||
raise newException(RestError, $res.error())
|
|
||||||
res.get()
|
|
||||||
ForkedSignedBeaconBlock.init(blck)
|
ForkedSignedBeaconBlock.init(blck)
|
||||||
else:
|
else:
|
||||||
raise newException(RestError, "Unsupported content-type")
|
raise newException(RestError, "Unsupported Content-Type")
|
||||||
of 400, 404, 500:
|
of 400, 404, 500:
|
||||||
raiseGenericError(resp)
|
raiseGenericError(resp)
|
||||||
else:
|
else:
|
||||||
@ -180,35 +176,31 @@ proc getBlockV2*(client: RestClientRef, block_id: BlockIdent,
|
|||||||
return
|
return
|
||||||
case resp.status
|
case resp.status
|
||||||
of 200:
|
of 200:
|
||||||
case resp.contentType
|
if resp.contentType.isNone() or
|
||||||
of "application/json":
|
isWildCard(resp.contentType.get().mediaType):
|
||||||
let blck =
|
raise newException(RestError, "Missing or incorrect Content-Type")
|
||||||
block:
|
else:
|
||||||
let res = decodeBytes(GetBlockV2Response, resp.data,
|
let mediaType = resp.contentType.get().mediaType
|
||||||
resp.contentType)
|
if mediaType == ApplicationJsonMediaType:
|
||||||
if res.isErr():
|
let blck = decodeBytes(GetBlockV2Response, resp.data,
|
||||||
raise newException(RestError, $res.error())
|
resp.contentType).valueOr:
|
||||||
newClone(res.get())
|
raise newException(RestError, $error)
|
||||||
some blck
|
some(newClone(blck))
|
||||||
of "application/octet-stream":
|
elif mediaType == OctetStreamMediaType:
|
||||||
try:
|
try:
|
||||||
some newClone(readSszForkedSignedBeaconBlock(cfg, resp.data))
|
some newClone(readSszForkedSignedBeaconBlock(cfg, resp.data))
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
raise newException(RestError, exc.msg)
|
raise newException(RestError, exc.msg)
|
||||||
else:
|
else:
|
||||||
raise newException(RestError, "Unsupported content-type")
|
raise newException(RestError, "Unsupported Content-Type")
|
||||||
of 404:
|
of 404:
|
||||||
none(ref ForkedSignedBeaconBlock)
|
none(ref ForkedSignedBeaconBlock)
|
||||||
|
|
||||||
of 400, 500:
|
of 400, 500:
|
||||||
let error =
|
let error = decodeBytes(RestGenericError, resp.data,
|
||||||
block:
|
resp.contentType).valueOr:
|
||||||
let res = decodeBytes(RestGenericError, resp.data, resp.contentType)
|
|
||||||
if res.isErr():
|
|
||||||
let msg = "Incorrect response error format (" & $resp.status &
|
let msg = "Incorrect response error format (" & $resp.status &
|
||||||
") [" & $res.error() & "]"
|
") [" & $error & "]"
|
||||||
raise newException(RestError, msg)
|
raise newException(RestError, msg)
|
||||||
res.get()
|
|
||||||
let msg = "Error response (" & $resp.status & ") [" & error.message & "]"
|
let msg = "Error response (" & $resp.status & ") [" & error.message & "]"
|
||||||
raise newException(RestError, msg)
|
raise newException(RestError, msg)
|
||||||
else:
|
else:
|
||||||
|
@ -32,24 +32,20 @@ proc getState*(client: RestClientRef, state_id: StateIdent,
|
|||||||
let data =
|
let data =
|
||||||
case resp.status
|
case resp.status
|
||||||
of 200:
|
of 200:
|
||||||
case resp.contentType
|
if resp.contentType.isNone() or
|
||||||
of "application/json":
|
isWildCard(resp.contentType.get().mediaType):
|
||||||
let state =
|
raise newException(RestError, "Missing or incorrect Content-Type")
|
||||||
block:
|
else:
|
||||||
let res = decodeBytes(GetStateResponse, resp.data,
|
let mediaType = resp.contentType.get().mediaType
|
||||||
resp.contentType)
|
if mediaType == ApplicationJsonMediaType:
|
||||||
if res.isErr():
|
let state = decodeBytes(GetStateResponse, resp.data,
|
||||||
raise newException(RestError, $res.error())
|
resp.contentType).valueOr:
|
||||||
res.get()
|
raise newException(RestError, $error)
|
||||||
state.data
|
state.data
|
||||||
of "application/octet-stream":
|
elif mediaType == OctetStreamMediaType:
|
||||||
let state =
|
let state = decodeBytes(GetPhase0StateSszResponse, resp.data,
|
||||||
block:
|
resp.contentType).valueOr:
|
||||||
let res = decodeBytes(GetPhase0StateSszResponse, resp.data,
|
raise newException(RestError, $error)
|
||||||
resp.contentType)
|
|
||||||
if res.isErr():
|
|
||||||
raise newException(RestError, $res.error())
|
|
||||||
res.get()
|
|
||||||
state
|
state
|
||||||
else:
|
else:
|
||||||
raise newException(RestError, "Unsupported content-type")
|
raise newException(RestError, "Unsupported content-type")
|
||||||
@ -93,8 +89,12 @@ proc getStateV2*(client: RestClientRef, state_id: StateIdent,
|
|||||||
let data =
|
let data =
|
||||||
case resp.status
|
case resp.status
|
||||||
of 200:
|
of 200:
|
||||||
case resp.contentType
|
if resp.contentType.isNone() or
|
||||||
of "application/json":
|
isWildCard(resp.contentType.get().mediaType):
|
||||||
|
raise newException(RestError, "Missing or incorrect Content-Type")
|
||||||
|
else:
|
||||||
|
let mediaType = resp.contentType.get().mediaType
|
||||||
|
if mediaType == ApplicationJsonMediaType:
|
||||||
let state =
|
let state =
|
||||||
block:
|
block:
|
||||||
let res = newClone(decodeBytes(GetStateV2Response, resp.data,
|
let res = newClone(decodeBytes(GetStateV2Response, resp.data,
|
||||||
@ -103,7 +103,7 @@ proc getStateV2*(client: RestClientRef, state_id: StateIdent,
|
|||||||
raise newException(RestError, $res[].error())
|
raise newException(RestError, $res[].error())
|
||||||
newClone(res[].get())
|
newClone(res[].get())
|
||||||
state
|
state
|
||||||
of "application/octet-stream":
|
elif mediaType == OctetStreamMediaType:
|
||||||
try:
|
try:
|
||||||
newClone(readSszForkedHashedBeaconState(cfg, resp.data))
|
newClone(readSszForkedHashedBeaconState(cfg, resp.data))
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
|
@ -105,17 +105,26 @@ proc signData*(client: RestClientRef, identifier: ValidatorPubKey,
|
|||||||
case response.status
|
case response.status
|
||||||
of 200:
|
of 200:
|
||||||
inc(nbc_remote_signer_200_responses)
|
inc(nbc_remote_signer_200_responses)
|
||||||
let sig = if response.contentType.contains("text/plain"):
|
let sig =
|
||||||
|
if response.contentType.isNone() or
|
||||||
|
isWildCard(response.contentType.get().mediaType):
|
||||||
|
return Web3SignerDataResponse.err(
|
||||||
|
"Unable to decode signature from missing or incorrect content")
|
||||||
|
else:
|
||||||
|
let mediaType = response.contentType.get().mediaType
|
||||||
|
if mediaType == TextPlainMediaType:
|
||||||
let asStr = fromBytes(string, response.data)
|
let asStr = fromBytes(string, response.data)
|
||||||
let sigFromText = fromHex(ValidatorSig, asStr)
|
let sigFromText = fromHex(ValidatorSig, asStr)
|
||||||
if sigFromText.isErr:
|
if sigFromText.isErr:
|
||||||
return Web3SignerDataResponse.err("Unable to decode signature from plain text")
|
return Web3SignerDataResponse.err(
|
||||||
|
"Unable to decode signature from plain text")
|
||||||
sigFromText.get.load
|
sigFromText.get.load
|
||||||
else:
|
else:
|
||||||
let res = decodeBytes(Web3SignerSignatureResponse, response.data,
|
let res = decodeBytes(Web3SignerSignatureResponse, response.data,
|
||||||
response.contentType)
|
response.contentType)
|
||||||
if res.isErr:
|
if res.isErr:
|
||||||
let msg = "Unable to decode remote signer response [" & $res.error() & "]"
|
let msg = "Unable to decode remote signer response [" &
|
||||||
|
$res.error() & "]"
|
||||||
inc(nbc_remote_signer_failures)
|
inc(nbc_remote_signer_failures)
|
||||||
return Web3SignerDataResponse.err(msg)
|
return Web3SignerDataResponse.err(msg)
|
||||||
res.get.signature.load
|
res.get.signature.load
|
||||||
|
@ -650,19 +650,19 @@ proc runTests(keymanager: KeymanagerToTest) {.async.} =
|
|||||||
let
|
let
|
||||||
r1 = decodeBytes(KeystoresAndSlashingProtection,
|
r1 = decodeBytes(KeystoresAndSlashingProtection,
|
||||||
Vector1.toOpenArrayByte(0, len(Vector1) - 1),
|
Vector1.toOpenArrayByte(0, len(Vector1) - 1),
|
||||||
"application/json")
|
Opt.some(getContentType("application/json").get()))
|
||||||
r2 = decodeBytes(KeystoresAndSlashingProtection,
|
r2 = decodeBytes(KeystoresAndSlashingProtection,
|
||||||
Vector2.toOpenArrayByte(0, len(Vector2) - 1),
|
Vector2.toOpenArrayByte(0, len(Vector2) - 1),
|
||||||
"application/json")
|
Opt.some(getContentType("application/json").get()))
|
||||||
r3 = decodeBytes(KeystoresAndSlashingProtection,
|
r3 = decodeBytes(KeystoresAndSlashingProtection,
|
||||||
Vector3.toOpenArrayByte(0, len(Vector3) - 1),
|
Vector3.toOpenArrayByte(0, len(Vector3) - 1),
|
||||||
"application/json")
|
Opt.some(getContentType("application/json").get()))
|
||||||
r4 = decodeBytes(KeystoresAndSlashingProtection,
|
r4 = decodeBytes(KeystoresAndSlashingProtection,
|
||||||
Vector4.toOpenArrayByte(0, len(Vector4) - 1),
|
Vector4.toOpenArrayByte(0, len(Vector4) - 1),
|
||||||
"application/json")
|
Opt.some(getContentType("application/json").get()))
|
||||||
r5 = decodeBytes(KeystoresAndSlashingProtection,
|
r5 = decodeBytes(KeystoresAndSlashingProtection,
|
||||||
Vector5.toOpenArrayByte(0, len(Vector5) - 1),
|
Vector5.toOpenArrayByte(0, len(Vector5) - 1),
|
||||||
"application/json")
|
Opt.some(getContentType("application/json").get()))
|
||||||
|
|
||||||
check:
|
check:
|
||||||
r1.isOk() == true
|
r1.isOk() == true
|
||||||
|
2
vendor/nim-presto
vendored
2
vendor/nim-presto
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 3984431dc0fc829eb668e12e57e90542b041d298
|
Subproject commit 8d5a2512f0fbbb44d265f179c5c5769f4bc351ea
|
Loading…
x
Reference in New Issue
Block a user