From 335f292a5816910aebf215e3a88db8a665133e0e Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 10 Apr 2022 21:48:46 +0300 Subject: [PATCH] Fix connection leaks in the HTTP client --- json_rpc/clients/httpclient.nim | 43 ++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/json_rpc/clients/httpclient.nim b/json_rpc/clients/httpclient.nim index 2fe916c..34fd882 100644 --- a/json_rpc/clients/httpclient.nim +++ b/json_rpc/clients/httpclient.nim @@ -65,17 +65,38 @@ method call*(client: RpcHttpClient, name: string, let id = client.getNextId() reqBody = $rpcCallNode(name, params, id) - req = HttpClientRequestRef.post(client.httpSession, - client.httpAddress.get, - body = reqBody.toOpenArrayByte(0, reqBody.len - 1), - headers = headers) - res = - try: - await req.send() - except CancelledError as e: - raise e - except CatchableError as e: - raise (ref RpcPostError)(msg: "Failed to send POST Request with JSON-RPC.", parent: e) + + var req: HttpClientRequestRef + var res: HttpClientResponseRef + + defer: + # BEWARE! + # Using multiple defer statements in this function or multiple + # try/except blocks within a single defer statement doesn't + # produce the desired run-time code, so we use slightly bizzare + # code to ensure the exceptions safety of this function: + try: + var closeFutures = newSeq[Future[void]]() + if req != nil: closeFutures.add req.closeWait() + if res != nil: closeFutures.add res.closeWait() + if closeFutures.len > 0: await allFutures(closeFutures) + except CatchableError as err: + # TODO + # `close` functions shouldn't raise in general, but we first + # need to ensure this through exception tracking in Chronos + debug "Error closing JSON-RPC HTTP resuest/response", err = err.msg + + req = HttpClientRequestRef.post(client.httpSession, + client.httpAddress.get, + body = reqBody.toOpenArrayByte(0, reqBody.len - 1), + headers = headers) + res = + try: + await req.send() + except CancelledError as e: + raise e + except CatchableError as e: + raise (ref RpcPostError)(msg: "Failed to send POST Request with JSON-RPC.", parent: e) if res.status < 200 or res.status >= 300: # res.status is not 2xx (success) raise newException(ErrorResponse, "POST Response: " & $res.status)