type response = { body: string, status: int, }; let body = response => response.body; let status = response => response.status; let rec getBody = listOfStrings => switch (listOfStrings) { | [] => "" | ["", ...rest] => String.concat("\n", rest) | [_, ...xs] => getBody(xs) }; let getStatus = string => List.nth(String.split_on_char(' ', string), 1) |> int_of_string; exception Unknown_status_code(int, response); exception Not_found(response); exception Internal_server_error(response); let verifyStatus = response => switch (response.status) { | 200 => Lwt.return(response) | x when x / 100 == 4 => Lwt.fail(Not_found(response)) | x when x / 100 == 5 => Lwt.fail(Internal_server_error(response)) | x => Lwt.fail(Unknown_status_code(response.status, response)) }; let rec skipRedirects = (~skipping=false, lines) => switch (skipping, lines) { | (_, []) => failwith("Response is empty") | (true, ["", ...xs]) => skipRedirects(~skipping=false, xs) | (true, [x, ...xs]) => skipRedirects(~skipping=true, xs) | (false, [x, ...xs]) when Str.first_chars(x, 4) == "HTTP" && getStatus(x) / 100 == 3 => skipRedirects(~skipping=true, xs) | (false, xs) => xs }; let parseResponse = lines => { let linesAfterRedirect = skipRedirects(lines); let body = getBody(linesAfterRedirect); let status = getStatus(linesAfterRedirect |> List.hd); {body, status}; }; let makeRequest = url => { let%lwt response = System.unix_exec("curl", ~args=[|url, "-D", "-", "--silent"|]); response |> parseResponse |> verifyStatus; }; let download = (url, ~into) => { let%lwt response = System.unix_exec( "curl", ~args=[|url, "-L", "-D", "-", "--silent", "-o", into|], ); response |> parseResponse |> verifyStatus; };