fn try_parse_response()

in key/aziot-key-client/src/lib.rs [504:566]


fn try_parse_response(
    buf: &[u8],
    new_read: usize,
) -> std::io::Result<Option<(Option<u16>, &[u8])>> {
    let mut headers = [httparse::EMPTY_HEADER; 16];

    let mut res = httparse::Response::new(&mut headers);

    let body_start_pos = match res.parse(buf) {
        Ok(httparse::Status::Complete(body_start_pos)) => body_start_pos,
        Ok(httparse::Status::Partial) if new_read == 0 => return Ok(None),
        Ok(httparse::Status::Partial) => return Err(std::io::ErrorKind::UnexpectedEof.into()),
        Err(err) => return Err(std::io::Error::new(std::io::ErrorKind::Other, err)),
    };

    let res_status_code = res.code;

    let mut content_length = None;
    let mut is_json = false;
    for header in &headers {
        if header.name.eq_ignore_ascii_case("content-length") {
            let value = std::str::from_utf8(header.value)
                .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?;
            let value: usize = value
                .parse()
                .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?;
            content_length = Some(value);
        } else if header.name.eq_ignore_ascii_case("content-type") {
            let value = std::str::from_utf8(header.value)
                .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?;
            if value == "application/json" {
                is_json = true;
            }
        }
    }

    if (res_status_code == Some(204) && content_length.unwrap_or_default() != 0)
        || (res_status_code != Some(204) && !is_json)
    {
        return Err(std::io::Error::new(
            std::io::ErrorKind::Other,
            "malformed HTTP response",
        ));
    }

    let body = &buf[body_start_pos..];
    let body = if let Some(content_length) = content_length {
        if body.len() < content_length {
            return Ok(None);
        }

        &body[..content_length]
    } else {
        // Without a content-length, read until there's no more to read.
        if new_read == 0 {
            body
        } else {
            return Ok(None);
        }
    };

    Ok(Some((res_status_code, body)))
}