#String Processing
A Little Pitfall in Erlang String Handling
I stumbled upon echo.opera.com — a service that prints out HTTP request headers — and thought it would be fun to build my own. After implementing echo_rs in…
Sep 26, 2024
A Little Pitfall in Erlang String Handling

A Little Pitfall in Erlang String Handling

September 26, 2024

I stumbled upon echo.opera.com — a service that prints out HTTP request headers — and thought it would be fun to build my own. After implementing echo_rs in Rust, I got the itch to rewrite it in Erlang as a gen_tcp exercise.

Once I had it working, I noticed the layout was broken when displaying raw request data in hexadecimal.

image.png

After some debugging I traced the issue to the string:slice function. The approach was to split the raw request data into chunks of 0x10 bytes, convert each chunk to hexadecimal, then decode it as ASCII. The problem: string:slice doesn't strictly respect the requested length.

-define(ELEMENT_PER_LINE, 16).

image 2.png

Since string:slice couldn't do what I needed, the natural fix was to treat the data as binary — Erlang is natively excellent at binary manipulation. The solution: split on binary boundaries first, then process each chunk.

-spec slice_binary(
    binary(),
    non_neg_integer(),
    non_neg_integer()
) -> {ok, binary()}.
slice_binary(Bin, Start, Len) ->
    case Len > byte_size(Bin) - Start of
        true ->
            <<_:Start/binary, Rest/binary>> = Bin,
            {ok, Rest};
        false ->
            <<_:Start/binary, Rest/binary>> = Bin,
            <<Slice:Len/binary, _/binary>> = Rest,
            {ok, Slice}
    end.

This guarantees we always get exactly the length we asked for.

image 3.png

The full source code is available at echo.