httprust

How to split a Vec<u8> by a sequence of chars?


I want to extract the payload of a HTTP request as a Vec<u8>. In the request, the payload is separated from the rest by the sequence \r\n\r\n, that's why I want to split my Vec at this position, and take the second element.

My current solution is to use the following function I wrote.

fn find_payload_index(buffer: &Vec<u8>) -> usize {
    for (pos, e) in buffer.iter().enumerate() {
        if pos < 3 {
            continue
        }
        if buffer[pos - 3] == 13 && buffer[pos - 2] == 10 && buffer[pos - 1] == 13 && buffer[pos] == 10 {
            return pos + 1;
        }
    }
    0
}

13 is the ASCII value of \r and 10 the value of \n. I then split by the returned index. While this solution is technically working, it feels very unclean, and I was wondering how to do this in a more elegant way.


Solution

  • First of:

    1. A function should almost never have a &Vec<_> parameter.

      See Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?.

    2. Don't use the magic values 10 and 13, Rust supports byte literals: b'\r' and b'\n'.

    As for your question: I believe you can make it a bit simpler using windows and matches! with a byte string literal pattern:

    fn find_payload_index(buffer: &[u8]) -> Option<usize> {
        buffer
            .windows(4)
            .enumerate()
            .find(|(_, w)| matches!(*w, b"\r\n\r\n"))
            .map(|(i, _)| i)
    }
    

    Permalink to the playground with test cases.