(tomcat) 02/04: Add a common header parser for headers and trailers
This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git commit a5a7c112505b471e943967fd33c72299cbe6bb9f Author: Mark Thomas AuthorDate: Fri Apr 26 15:47:23 2024 +0100 Add a common header parser for headers and trailers --- .../tomcat/util/http/parser/HttpHeaderParser.java | 409 + .../util/http/parser/LocalStrings.properties | 3 + .../util/http/parser/LocalStrings_fr.properties| 2 + .../util/http/parser/LocalStrings_ja.properties| 2 + 4 files changed, 416 insertions(+) diff --git a/java/org/apache/tomcat/util/http/parser/HttpHeaderParser.java b/java/org/apache/tomcat/util/http/parser/HttpHeaderParser.java new file mode 100644 index 00..7ef3b8b5ee --- /dev/null +++ b/java/org/apache/tomcat/util/http/parser/HttpHeaderParser.java @@ -0,0 +1,409 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.http.parser; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.HeaderUtil; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.res.StringManager; + +public class HttpHeaderParser { + +private static final StringManager sm = StringManager.getManager(HttpHeaderParser.class); + +private static final byte CR = (byte) '\r'; +private static final byte LF = (byte) '\n'; +private static final byte SP = (byte) ' '; +private static final byte HT = (byte) '\t'; +private static final byte COLON = (byte) ':'; +private static final byte A = (byte) 'A'; +private static final byte a = (byte) 'a'; +private static final byte Z = (byte) 'Z'; +private static final byte LC_OFFSET = A - a; + +private final HeaderDataSource source; +private final MimeHeaders headers; +private final boolean tolerantEol; +private final HeaderParseData headerData = new HeaderParseData(); + +private HeaderParsePosition headerParsePos = HeaderParsePosition.HEADER_START; +private byte prevChr = 0; +private byte chr = 0; + + +public HttpHeaderParser(HeaderDataSource source, MimeHeaders headers, boolean tolerantEol) { +this.source = source; +this.headers = headers; +this.tolerantEol = tolerantEol; +} + + +public void recycle() { +chr = 0; +prevChr = 0; +headerParsePos = HeaderParsePosition.HEADER_START; +headerData.recycle(); +} + + +/** + * Parse an HTTP header. + * + * @return One of {@link HeaderParseStatus#NEED_MORE_DATA}, {@link HeaderParseStatus#HAVE_MORE_HEADERS} or + * {@link HeaderParseStatus#DONE}. + * + * @throws IOException If an error occurs during the parsing of the headers + */ +public HeaderParseStatus parseHeader() throws IOException { + +while (headerParsePos == HeaderParsePosition.HEADER_START) { + +// Read new bytes if needed +if (source.getHeaderByteBuffer().position() >= source.getHeaderByteBuffer().limit()) { +if (!source.fillHeaderBuffer()) { +return HeaderParseStatus.NEED_MORE_DATA; +} +} + +prevChr = chr; +chr = source.getHeaderByteBuffer().get(); + +if (chr == CR && prevChr != CR) { +// Possible start of CRLF - process the next byte. +} else if (chr == LF) { +if (!tolerantEol && prevChr != CR) { +throw new IllegalArgumentException(sm.getString("httpHeaderParser.invalidCrlfNoCR")); +} +return HeaderParseStatus.DONE; +} else { +if (prevChr == CR) { +// Must have read two bytes (first was CR, second was not LF) + source.getHeaderByteBuffer().position(source.getHeaderByteBuffer().position() - 2); +} else { +// Must have only read one byte +
(tomcat) 02/04: Add a common header parser for headers and trailers
This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git commit 3443bffb40c22b2c107e277575e02f9f4e688e3d Author: Mark Thomas AuthorDate: Fri Apr 26 15:47:23 2024 +0100 Add a common header parser for headers and trailers --- .../tomcat/util/http/parser/HttpHeaderParser.java | 409 + .../util/http/parser/LocalStrings.properties | 3 + .../util/http/parser/LocalStrings_fr.properties| 2 + .../util/http/parser/LocalStrings_ja.properties| 2 + 4 files changed, 416 insertions(+) diff --git a/java/org/apache/tomcat/util/http/parser/HttpHeaderParser.java b/java/org/apache/tomcat/util/http/parser/HttpHeaderParser.java new file mode 100644 index 00..7ef3b8b5ee --- /dev/null +++ b/java/org/apache/tomcat/util/http/parser/HttpHeaderParser.java @@ -0,0 +1,409 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.http.parser; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.HeaderUtil; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.res.StringManager; + +public class HttpHeaderParser { + +private static final StringManager sm = StringManager.getManager(HttpHeaderParser.class); + +private static final byte CR = (byte) '\r'; +private static final byte LF = (byte) '\n'; +private static final byte SP = (byte) ' '; +private static final byte HT = (byte) '\t'; +private static final byte COLON = (byte) ':'; +private static final byte A = (byte) 'A'; +private static final byte a = (byte) 'a'; +private static final byte Z = (byte) 'Z'; +private static final byte LC_OFFSET = A - a; + +private final HeaderDataSource source; +private final MimeHeaders headers; +private final boolean tolerantEol; +private final HeaderParseData headerData = new HeaderParseData(); + +private HeaderParsePosition headerParsePos = HeaderParsePosition.HEADER_START; +private byte prevChr = 0; +private byte chr = 0; + + +public HttpHeaderParser(HeaderDataSource source, MimeHeaders headers, boolean tolerantEol) { +this.source = source; +this.headers = headers; +this.tolerantEol = tolerantEol; +} + + +public void recycle() { +chr = 0; +prevChr = 0; +headerParsePos = HeaderParsePosition.HEADER_START; +headerData.recycle(); +} + + +/** + * Parse an HTTP header. + * + * @return One of {@link HeaderParseStatus#NEED_MORE_DATA}, {@link HeaderParseStatus#HAVE_MORE_HEADERS} or + * {@link HeaderParseStatus#DONE}. + * + * @throws IOException If an error occurs during the parsing of the headers + */ +public HeaderParseStatus parseHeader() throws IOException { + +while (headerParsePos == HeaderParsePosition.HEADER_START) { + +// Read new bytes if needed +if (source.getHeaderByteBuffer().position() >= source.getHeaderByteBuffer().limit()) { +if (!source.fillHeaderBuffer()) { +return HeaderParseStatus.NEED_MORE_DATA; +} +} + +prevChr = chr; +chr = source.getHeaderByteBuffer().get(); + +if (chr == CR && prevChr != CR) { +// Possible start of CRLF - process the next byte. +} else if (chr == LF) { +if (!tolerantEol && prevChr != CR) { +throw new IllegalArgumentException(sm.getString("httpHeaderParser.invalidCrlfNoCR")); +} +return HeaderParseStatus.DONE; +} else { +if (prevChr == CR) { +// Must have read two bytes (first was CR, second was not LF) + source.getHeaderByteBuffer().position(source.getHeaderByteBuffer().position() - 2); +} else { +// Must have only read one byte +