Repository: netty/netty
File: codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java (Java)

Code before:
    }

    private static int findNonWhitespace(byte[] sb, int offset, int end) {
        for (int result = offset; result < end; ++result) {
            byte c = sb[result];
            if (!isWhitespace(c)) {
                return result;
            } else if (!isOWS(c)) {
                // Only OWS is supported for whitespace
                throw new IllegalArgumentException("Invalid separator, only a single space or horizontal tab allowed," +
                        " but received a '" + c + "' (0x" + Integer.toHexString(c) + ")");
            }
        }
        return end;
    }

    private static int findEndOfString(byte[] sb, int start, int end) {
        for (int result = end - 1; result > start; --result) {
            byte c = sb[result];
            if (!isWhitespace(c)) {
                return result + 1;
            } else if (!isOWS(c)) {
                // Only OWS is supported for whitespace
                // See https://datatracker.ietf.org/doc/html/rfc9110#section-5.5
                throw new IllegalArgumentException("Invalid end of value, only a space or horizontal tab allowed," +
                        " but received a '" + c + "' (0x" + Integer.toHexString(c) + ")");
            }
        }
        return 0;
    }

    private static boolean isOWS(byte ch) {
        return ch == ' ' || ch == 0x09;
    }

    private static class HeaderParser {
        protected final ByteBuf seq;
        protected final int maxLength;
        int size;

        HeaderParser(ByteBuf seq, int maxLength) {
            this.seq = seq;
            this.maxLength = maxLength;
        }

        public ByteBuf parse(ByteBuf buffer) {
            final int readableBytes = buffer.readableBytes();
            final int readerIndex = buffer.readerIndex();
            final int maxBodySize = maxLength - size;
            assert maxBodySize >= 0;
            // adding 2 to account for both CR (if present) and LF

Review comment (suggestion):
A thought: the default header validator will already reject these chars if they're allowed to get there (along with NULL which falls into the same class of rejected chars but wont be caught here) and if someone wants to accept anything they can override the validator. However, this may open the door to other problems such as request smuggling so I think your suggestion might be the safest way forward.

```suggestion
            if (!isOWS(sb[result])) {
                return result + 1;
            }
```

Code after:
    }

    private static int findNonWhitespace(byte[] sb, int offset, int end) {
        for (int result = offset; result < end; ++result) {
            byte c = sb[result];
            if (!isWhitespace(c)) {
                return result;
            } else if (!isOWS(c)) {
                // Only OWS is supported for whitespace
                throw new IllegalArgumentException("Invalid separator, only a single space or horizontal tab allowed," +
                        " but received a '" + c + "' (0x" + Integer.toHexString(c) + ")");
            }
        }
        return end;
    }

    private static int findEndOfString(byte[] sb, int start, int end) {
        for (int result = end - 1; result > start; --result) {
            if (!isOWS(sb[result])) {
                return result + 1;
            }
        }
        return 0;
    }

    private static boolean isOWS(byte ch) {
        return ch == ' ' || ch == 0x09;
    }

    private static class HeaderParser {
        protected final ByteBuf seq;
        protected final int maxLength;
        int size;

        HeaderParser(ByteBuf seq, int maxLength) {
            this.seq = seq;
            this.maxLength = maxLength;
        }

        public ByteBuf parse(ByteBuf buffer) {
            final int readableBytes = buffer.readableBytes();
            final int readerIndex = buffer.readerIndex();
            final int maxBodySize = maxLength - size;
            assert maxBodySize >= 0;
            // adding 2 to account for both CR (if present) and LF
            // don't remove 2L: it's key to cover maxLength = Integer.MAX_VALUE
            final long maxBodySizeWithCRLF = maxBodySize + 2L;
            final int toProcess = (int) Math.min(maxBodySizeWithCRLF, readableBytes);
            final int toIndexExclusive = readerIndex + toProcess;
            assert toIndexExclusive >= readerIndex;
            final int indexOfLf = buffer.indexOf(readerIndex, toIndexExclusive, HttpConstants.LF);