I am trying (in my journey to learn ocaml) to use eio for sending an http request. I am using piaf and for a simple request I am successful.
Now I want to load an api key from a file before sending then request:
open Piaf
let get ~sw env =
let ( / ) = Eio.Path.( / ) in
let path = Eio.Stdenv.cwd env / "key" in
let key = Eio.Path.load path in
print_endline key;
let headers = [ ("Authorization", Format.sprintf "Bearer %s" key) ] in
Client.Oneshot.get ~sw env (Uri.of_string "https://example.com") ~headers
let () =
Eio_main.run @@ fun env ->
Eio.Switch.run (fun sw ->
let _ = get env ~sw in
print_endline "done")
If I do this, I get this output:
<content-of-./key>
and than the application just hangs. Doing printf debugging I found out, that it seems to hang in Client.Oneshot.get. But if I remove the file system access again, it works.
I can’t fully reproduce this particular example (for me it prints done as well and only then it hangs), and I don’t know why reading a file would change the behavior, but one thing to know about piaf is that the switch won’t exit unless you read (or drain) the response body.
Ergo, you should handle the response instead of ignoring it, like in this example.
That seems really strange! I modified the example:
open Piaf
let get ~sw env =
let ( / ) = Eio.Path.( / ) in
let path = Eio.Stdenv.cwd env / "key" in
let key = Eio.Path.load path in
print_endline key;
let headers = [ ("Authorization", Format.sprintf "Bearer %s" key) ] in
Client.Oneshot.get ~sw env (Uri.of_string "https://example.com") ~headers
let () =
Eio_main.run @@ fun env ->
Eio.Switch.run (fun sw ->
let resp = get env ~sw in
print_endline "done";
let body =
resp |> Result.get_ok
|> (fun r -> Body.to_string r.body)
|> Result.get_ok
in
print_endline body)
But when I run it, it still hangs (after printing the contents of key).
Could you do me a favor and test again if this now works in your machine?
The example you linked to works. but that does not include any file reading. And my example continues to work for me if I remove the file reading…
This is indeed a bit odd. I’ve tried your reproduction, and it fails on macOS (M2) but works on Linux. Could you reproduce the bad behavior on Linux?
I’ve confirmed that this is a bug in h2 / hpack.
The bug I’ve uncovered is related to sending a header value that ends in a newline character. If that’s what you’re also facing, I suspect you want to trim your bearer token string after reading it.
open Piaf
let get ~sw env =
let ( / ) = Eio.Path.( / ) in
let path = Eio.Stdenv.cwd env / "key" in
let key = String.trim @@ Eio.Path.load path in
print_endline key;
let headers = [ ("Authorization", Format.sprintf "Bearer %s" key) ] in
Client.Oneshot.get ~sw env (Uri.of_string "https://example.com") ~headers
let () =
Eio_main.run @@ fun env ->
Eio.Switch.run (fun sw ->
let resp = get env ~sw in
print_endline "done";
let body =
resp |> Result.get_ok
|> (fun r -> Body.to_string r.body)
|> Result.get_ok
in
print_endline body)