(tomcat) 02/04: Add a common header parser for headers and trailers

2024-04-26 Thread markt
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

2024-04-26 Thread markt
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
+