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
Change the API of ShallowEtagHeaderFilter to avoid all copying

Change the signatures of the isEligibleForEtag generateETagHeaderValue and
methods to take an InputStream instead of a byte[]. This change allows
ShallowEtagHeaderFilter to avoid creating a byte[] completely,
eliminating all data copying.

Issue: SPR-12081