From 67c57ecc07826153a074268cdee0df613a451015 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Tue, 26 Dec 2023 13:51:55 +0530 Subject: [PATCH 1/3] Use TreeMap to store headers --- .../java/org/jsoup/helper/HttpConnection.java | 58 +++++-------------- 1 file changed, 13 insertions(+), 45 deletions(-) diff --git a/src/main/java/org/jsoup/helper/HttpConnection.java b/src/main/java/org/jsoup/helper/HttpConnection.java index db2877a7bb..05b7540da1 100644 --- a/src/main/java/org/jsoup/helper/HttpConnection.java +++ b/src/main/java/org/jsoup/helper/HttpConnection.java @@ -43,6 +43,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.TreeMap; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; @@ -50,7 +51,6 @@ import static org.jsoup.Connection.Method.HEAD; import static org.jsoup.helper.DataUtil.UTF_8; -import static org.jsoup.internal.Normalizer.lowerCase; import static org.jsoup.internal.SharedConstants.DefaultBufferSize; /** @@ -410,18 +410,18 @@ private static abstract class Base> implements Conn Map cookies; private Base() { - headers = new LinkedHashMap<>(); + headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); cookies = new LinkedHashMap<>(); } private Base(Base copy) { + this(); url = copy.url; // unmodifiable object method = copy.method; - headers = new LinkedHashMap<>(); for (Map.Entry> entry : copy.headers.entrySet()) { headers.put(entry.getKey(), new ArrayList<>(entry.getValue())); } - cookies = new LinkedHashMap<>(); cookies.putAll(copy.cookies); // just holds strings + cookies.putAll(copy.cookies); // just holds strings } @Override @@ -453,8 +453,8 @@ public T method(Method method) { @Override public String header(String name) { Validate.notNullParam(name, "name"); - List vals = getHeadersCaseInsensitive(name); - if (vals.size() > 0) { + List vals = headers.get(name); + if (vals != null) { // https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 return StringUtil.join(vals, ", "); } @@ -465,15 +465,9 @@ public String header(String name) { @Override public T addHeader(String name, @Nullable String value) { Validate.notEmptyParam(name, "name"); - //noinspection ConstantConditions - value = value == null ? "" : value; - List values = headers(name); - if (values.isEmpty()) { - values = new ArrayList<>(); - headers.put(name, values); - } - values.add(value); + headers.computeIfAbsent(name, Functions.listFunction()) + .add(value == null ? "" : value); return (T) this; } @@ -481,7 +475,7 @@ public T addHeader(String name, @Nullable String value) { @Override public List headers(String name) { Validate.notEmptyParam(name, "name"); - return getHeadersCaseInsensitive(name); + return headers.getOrDefault(name, Collections.emptyList()); } @Override @@ -495,7 +489,7 @@ public T header(String name, String value) { @Override public boolean hasHeader(String name) { Validate.notEmptyParam(name, "name"); - return !getHeadersCaseInsensitive(name).isEmpty(); + return headers.containsKey(name); } /** @@ -505,20 +499,14 @@ public boolean hasHeader(String name) { public boolean hasHeaderWithValue(String name, String value) { Validate.notEmpty(name); Validate.notEmpty(value); - List values = headers(name); - for (String candidate : values) { - if (value.equalsIgnoreCase(candidate)) - return true; - } - return false; + return headers.getOrDefault(name, Collections.emptyList()).stream() + .anyMatch(value::equalsIgnoreCase); } @Override public T removeHeader(String name) { Validate.notEmptyParam(name, "name"); - Map.Entry> entry = scanHeaders(name); // remove is case-insensitive too - if (entry != null) - headers.remove(entry.getKey()); // ensures correct case + headers.remove(name); // remove is case-insensitive too return (T) this; } @@ -539,26 +527,6 @@ public Map> multiHeaders() { return headers; } - private List getHeadersCaseInsensitive(String name) { - Validate.notNull(name); - - for (Map.Entry> entry : headers.entrySet()) { - if (name.equalsIgnoreCase(entry.getKey())) - return entry.getValue(); - } - - return Collections.emptyList(); - } - - private Map.@Nullable Entry> scanHeaders(String name) { - String lc = lowerCase(name); - for (Map.Entry> entry : headers.entrySet()) { - if (lowerCase(entry.getKey()).equals(lc)) - return entry; - } - return null; - } - @Override public String cookie(String name) { Validate.notEmptyParam(name, "name"); From 2b4fde2dcf9aec1efc7b454a733c95f26c10d8c1 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Thu, 18 Jul 2024 17:09:10 +0530 Subject: [PATCH 2/3] Cleaned up HttpConnection.Base class a bit --- .../java/org/jsoup/helper/HttpConnection.java | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/jsoup/helper/HttpConnection.java b/src/main/java/org/jsoup/helper/HttpConnection.java index 05b7540da1..c5a89edc35 100644 --- a/src/main/java/org/jsoup/helper/HttpConnection.java +++ b/src/main/java/org/jsoup/helper/HttpConnection.java @@ -394,20 +394,11 @@ public Connection postDataCharset(String charset) { } @SuppressWarnings("unchecked") - private static abstract class Base> implements Connection.Base { - private static final URL UnsetUrl; // only used if you created a new Request() - static { - try { - UnsetUrl = new URL("http://undefined/"); - } catch (MalformedURLException e) { - throw new IllegalStateException(e); - } - } - - URL url = UnsetUrl; - Method method = Method.GET; - Map> headers; - Map cookies; + private abstract static class Base> implements Connection.Base { + protected URL url; + protected Method method = Method.GET; + protected final Map> headers; + protected final Map cookies; private Base() { headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); @@ -426,7 +417,7 @@ private Base(Base copy) { @Override public URL url() { - if (url == UnsetUrl) + if (url == null) throw new IllegalArgumentException("URL not set. Make sure to call #url(...) before executing the request."); return url; } @@ -590,7 +581,6 @@ public static class Request extends HttpConnection.Base impl maxBodySizeBytes = 1024 * 1024 * 2; // 2MB followRedirects = true; data = new ArrayList<>(); - method = Method.GET; addHeader("Accept-Encoding", "gzip"); addHeader(USER_AGENT, DEFAULT_UA); parser = Parser.htmlParser(); From e8b666498c78ff99b67793f7add9651d85ab25bd Mon Sep 17 00:00:00 2001 From: Jonathan Hedley Date: Mon, 29 Jul 2024 15:24:01 +1000 Subject: [PATCH 3/3] Format tweak --- src/main/java/org/jsoup/helper/HttpConnection.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jsoup/helper/HttpConnection.java b/src/main/java/org/jsoup/helper/HttpConnection.java index c5a89edc35..a193789d4e 100644 --- a/src/main/java/org/jsoup/helper/HttpConnection.java +++ b/src/main/java/org/jsoup/helper/HttpConnection.java @@ -458,7 +458,7 @@ public T addHeader(String name, @Nullable String value) { Validate.notEmptyParam(name, "name"); headers.computeIfAbsent(name, Functions.listFunction()) - .add(value == null ? "" : value); + .add(value == null ? "" : value); return (T) this; } @@ -491,7 +491,7 @@ public boolean hasHeaderWithValue(String name, String value) { Validate.notEmpty(name); Validate.notEmpty(value); return headers.getOrDefault(name, Collections.emptyList()).stream() - .anyMatch(value::equalsIgnoreCase); + .anyMatch(value::equalsIgnoreCase); } @Override