You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2026/05/25 16:08:01 UTC
(httpcomponents-client) branch master updated (599eb0920 -> 0d5d05fc7)
This is an automated email from the ASF dual-hosted git repository.
ok2c pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git
from 599eb0920 Migated Jakarta REST client tests to Assert4J
new 96897cdbf Parsing code optimization in ETag
new 0d5d05fc7 Parsing code optimization in DateUtils
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../apache/hc/client5/http/utils/DateUtils.java | 66 ++++++++++++++++++++--
.../org/apache/hc/client5/http/validator/ETag.java | 34 ++++++++---
.../hc/client5/http/utils/TestDateUtils.java | 27 +++++++++
3 files changed, 116 insertions(+), 11 deletions(-)
(httpcomponents-client) 02/02: Parsing code optimization in DateUtils
Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ok2c pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git
commit 0d5d05fc7a55afb6c69dc360a0ac216bab3ad26f
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Mon May 25 16:37:47 2026 +0200
Parsing code optimization in DateUtils
---
.../apache/hc/client5/http/utils/DateUtils.java | 66 ++++++++++++++++++++--
.../hc/client5/http/utils/TestDateUtils.java | 27 +++++++++
2 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/utils/DateUtils.java b/httpclient5/src/main/java/org/apache/hc/client5/http/utils/DateUtils.java
index bb1f00adf..54e468d57 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/utils/DateUtils.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/utils/DateUtils.java
@@ -37,10 +37,15 @@
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
+import java.util.function.BiFunction;
+import org.apache.hc.core5.http.FormattedHeader;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.MessageHeaders;
+import org.apache.hc.core5.http.message.ParserCursor;
import org.apache.hc.core5.util.Args;
+import org.apache.hc.core5.util.CharArrayBuffer;
+import org.apache.hc.core5.util.Tokenizer;
/**
* A utility class for parsing and formatting HTTP dates as used in cookies and
@@ -156,12 +161,28 @@ public static LocalDateTime toUTC(final Date date) {
* @since 5.2
*/
public static Instant parseDate(final String dateValue, final DateTimeFormatter... dateFormatters) {
+ return parseDate((CharSequence) dateValue, dateFormatters);
+ }
+
+ /**
+ * Parses the date value using the given date/time formats.
+ * <p>This method can handle strings without time-zone information by failing gracefully, in which case
+ * it returns {@code null}.</p>
+ *
+ * @param dateValue the instant value to parse
+ * @param dateFormatters the date/time formats to use
+ *
+ * @return the parsed instant or null if input could not be parsed
+ *
+ * @since 5.7
+ */
+ public static Instant parseDate(final CharSequence dateValue, final DateTimeFormatter... dateFormatters) {
Args.notNull(dateValue, "Date value");
- String v = dateValue;
+ CharSequence v = dateValue;
// trim single quotes around date if present
// see issue #5279
- if (v.length() > 1 && v.startsWith("'") && v.endsWith("'")) {
- v = v.substring (1, v.length() - 1);
+ if (v.length() > 1 && v.charAt(0) == '\'' && v.charAt(v.length() - 1) == '\'') {
+ v = v.subSequence(1, v.length() - 1);
}
for (final DateTimeFormatter dateFormatter : dateFormatters) {
@@ -187,6 +208,43 @@ public static Instant parseStandardDate(final String dateValue) {
return parseDate(dateValue, STANDARD_PATTERNS);
}
+ /**
+ * TODO to be replaced by method from core MessageSupport
+ */
+ private static <T> T parserHeaderValue(final Header header, final BiFunction<CharSequence, ParserCursor, T> transformation) {
+ Args.notNull(header, "Header");
+ if (header instanceof FormattedHeader) {
+ final CharArrayBuffer buf = ((FormattedHeader) header).getBuffer();
+ final ParserCursor cursor = new ParserCursor(0, buf.length());
+ cursor.updatePos(((FormattedHeader) header).getValuePos());
+ return transformation.apply(buf, cursor);
+ } else {
+ final String value = header.getValue();
+ final ParserCursor cursor = new ParserCursor(0, value.length());
+ return transformation.apply(value, cursor);
+ }
+ }
+
+ /**
+ * Parses the date value using the given date/time formats.
+ * <p>This method can handle strings without time-zone information by failing gracefully, in which case
+ * it returns {@code null}.</p>
+ *
+ * @param header the header with an instant value to parse
+ * @param dateFormatters the date/time formats to use
+ *
+ * @return the parsed instant or null if input could not be parsed
+ *
+ * @since 5.7
+ */
+ public static Instant parseDate(final Header header, final DateTimeFormatter... dateFormatters) {
+ Args.notNull(header, "Header");
+ return parserHeaderValue(header, (cs, cursor) -> {
+ Tokenizer.INSTANCE.skipWhiteSpace(cs, cursor);
+ return parseDate(cs.subSequence(cursor.getPos(), cursor.getUpperBound()), dateFormatters);
+ });
+ }
+
/**
* Parses an instant value from a header with the given name.
*
@@ -205,7 +263,7 @@ public static Instant parseStandardDate(final MessageHeaders headers, final Stri
if (header == null) {
return null;
}
- return parseStandardDate(header.getValue());
+ return parseDate(header, STANDARD_PATTERNS);
}
/**
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/utils/TestDateUtils.java b/httpclient5/src/test/java/org/apache/hc/client5/http/utils/TestDateUtils.java
index 531febeef..ad5e40f48 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/utils/TestDateUtils.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/utils/TestDateUtils.java
@@ -34,9 +34,13 @@
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
+import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpHeaders;
+import org.apache.hc.core5.http.ParseException;
import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.message.BufferedHeader;
import org.apache.hc.core5.http.message.HeaderGroup;
+import org.apache.hc.core5.util.CharArrayBuffer;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -63,6 +67,29 @@ void testBasicDateParse() {
Assertions.assertEquals(instant, DateUtils.parseStandardDate("Fri, 14 Oct 2005 00:00:00 GMT"));
}
+ static Header createHeader(final String headerValue) throws ParseException {
+ final CharArrayBuffer buf = new CharArrayBuffer(100);
+ buf.append(HttpHeaders.DATE);
+ buf.append(": ");
+ buf.append(headerValue);
+ return new BufferedHeader(buf);
+ }
+
+ @Test
+ void testBasicDateHeaderParse() throws Exception {
+ final Instant instant = createInstant(2005, Month.OCTOBER, 14);
+ Assertions.assertEquals(instant, DateUtils.parseDate(createHeader("Fri, 14 Oct 2005 00:00:00 GMT"), DateUtils.FORMATTER_RFC1123));
+ Assertions.assertEquals(instant, DateUtils.parseDate(createHeader("Friday, 14 Oct 2005 00:00:00 GMT"), DateUtils.FORMATTER_RFC1123));
+ Assertions.assertEquals(instant, DateUtils.parseDate(createHeader("Fri, 14-Oct-2005 00:00:00 GMT"), DateUtils.FORMATTER_RFC1036));
+ Assertions.assertEquals(instant, DateUtils.parseDate(createHeader("Friday, 14-Oct-2005 00:00:00 GMT"), DateUtils.FORMATTER_RFC1036));
+ Assertions.assertEquals(instant, DateUtils.parseDate(createHeader(" Friday, 14-Oct-2005 00:00:00 GMT"), DateUtils.FORMATTER_RFC1036));
+ Assertions.assertEquals(instant.minus(2, ChronoUnit.HOURS),
+ DateUtils.parseDate(createHeader("Fri, 14 Oct 2005 00:00:00 CET"), DateUtils.FORMATTER_RFC1123));
+ Assertions.assertEquals(instant.minus(2, ChronoUnit.HOURS),
+ DateUtils.parseDate(createHeader("Fri, 14-Oct-05 00:00:00 CET"), DateUtils.FORMATTER_RFC1036));
+ Assertions.assertEquals(instant, DateUtils.parseStandardDate("Fri, 14 Oct 2005 00:00:00 GMT"));
+ }
+
@Test
void testDateParseMessage() {
final HeaderGroup message1 = new HeaderGroup();
(httpcomponents-client) 01/02: Parsing code optimization in ETag
Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ok2c pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git
commit 96897cdbf2d3cc8b8cfa80e3b59d150a51e123f3
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Mon May 25 15:11:01 2026 +0200
Parsing code optimization in ETag
---
.../org/apache/hc/client5/http/validator/ETag.java | 34 +++++++++++++++++-----
1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/validator/ETag.java b/httpclient5/src/main/java/org/apache/hc/client5/http/validator/ETag.java
index 100d3ba4c..87984f452 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/validator/ETag.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/validator/ETag.java
@@ -27,12 +27,16 @@
package org.apache.hc.client5.http.validator;
+import java.util.function.BiFunction;
+
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.Internal;
import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.http.FormattedHeader;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.MessageHeaders;
+import org.apache.hc.core5.http.message.ParserCursor;
import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.CharArrayBuffer;
import org.apache.hc.core5.util.LangUtils;
@@ -80,7 +84,10 @@ public static boolean weakCompare(final ETag t1, final ETag t2) {
return t1.value.equals(t2.value);
}
- static ETag parse(final CharSequence buf, final Tokenizer.Cursor cursor) {
+ /**
+ * @since 5.7
+ */
+ public static ETag parse(final CharSequence buf, final ParserCursor cursor) {
final Tokenizer tokenizer = Tokenizer.INSTANCE;
tokenizer.skipWhiteSpace(buf, cursor);
@@ -126,19 +133,32 @@ public static ETag parse(final String s) {
if (s == null) {
return null;
}
- final Tokenizer.Cursor cursor = new Tokenizer.Cursor(0, s.length());
+ final ParserCursor cursor = new ParserCursor(0, s.length());
return parse(s, cursor);
}
+ /**
+ * TODO to be replaced by method from core MessageSupport
+ */
+ private static <T> T parserHeaderValue(final Header header, final BiFunction<CharSequence, ParserCursor, T> transformation) {
+ Args.notNull(header, "Header");
+ if (header instanceof FormattedHeader) {
+ final CharArrayBuffer buf = ((FormattedHeader) header).getBuffer();
+ final ParserCursor cursor = new ParserCursor(0, buf.length());
+ cursor.updatePos(((FormattedHeader) header).getValuePos());
+ return transformation.apply(buf, cursor);
+ } else {
+ final String value = header.getValue();
+ final ParserCursor cursor = new ParserCursor(0, value.length());
+ return transformation.apply(value, cursor);
+ }
+ }
+
public static ETag parse(final Header h) {
if (h == null) {
return null;
}
- final String value = h.getValue();
- if (value == null) {
- return null;
- }
- return parse(value);
+ return parserHeaderValue(h, ETag::parse);
}
public static ETag get(final MessageHeaders message) {