diff --git a/src/main/java/org/jsoup/helper/HttpConnection.java b/src/main/java/org/jsoup/helper/HttpConnection.java index 712019108b..ce5a42406f 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; /** @@ -394,39 +394,30 @@ 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 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 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; } @@ -453,8 +444,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,14 +456,9 @@ public String header(String name) { @Override public T addHeader(String name, @Nullable String value) { Validate.notEmptyParam(name, "name"); - 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; } @@ -480,7 +466,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 @@ -494,7 +480,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); } /** @@ -504,20 +490,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; } @@ -538,26 +518,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"); @@ -621,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();