Use a more efficient buffer implementation in ShallowEtagHeaderFilter

FastByteArrayOutputStream uses a LinkedList<Byte[]> to store the
content as opposed to ResizableByteArrayOutputStream that uses a
byte[].This difference means that when add bytes,
FastByteArrayOutputStream will add them to the current byte[], then
when that's full, simply create a new one and add it to the list.
ResizableByteArrayOutputStream will create a new byte[], copy the old
byte[]'s data to the new byte[], then discard the old byte[].
FastByteArrayOutputStream therefore does fewer memory allocations and
doesn't do any copying.

Issue: SPR-12081