1 /*
   2  * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.internal.net.http.common;
  27 
  28 import sun.net.NetProperties;
  29 import sun.net.util.IPAddressUtil;
  30 import sun.net.www.HeaderParser;
  31 
  32 import javax.net.ssl.ExtendedSSLSession;
  33 import javax.net.ssl.SSLException;
  34 import javax.net.ssl.SSLHandshakeException;
  35 import javax.net.ssl.SSLParameters;
  36 import javax.net.ssl.SSLSession;
  37 import java.io.ByteArrayOutputStream;
  38 import java.io.Closeable;
  39 import java.io.IOException;
  40 import java.io.PrintStream;
  41 import java.io.UncheckedIOException;
  42 import java.io.UnsupportedEncodingException;
  43 import java.lang.System.Logger.Level;
  44 import java.net.ConnectException;
  45 import java.net.InetSocketAddress;
  46 import java.net.URI;
  47 import java.net.URLPermission;
  48 import java.net.http.HttpClient;
  49 import java.net.http.HttpHeaders;
  50 import java.net.http.HttpTimeoutException;
  51 import java.nio.ByteBuffer;
  52 import java.nio.CharBuffer;
  53 import java.nio.charset.CharacterCodingException;
  54 import java.nio.charset.Charset;
  55 import java.nio.charset.CodingErrorAction;
  56 import java.nio.charset.StandardCharsets;
  57 import java.security.AccessController;
  58 import java.security.PrivilegedAction;
  59 import java.text.Normalizer;
  60 import java.util.Arrays;
  61 import java.util.Collection;
  62 import java.util.Collections;
  63 import java.util.List;
  64 import java.util.Set;
  65 import java.util.TreeSet;
  66 import java.util.concurrent.CompletableFuture;
  67 import java.util.concurrent.CompletionException;
  68 import java.util.concurrent.ExecutionException;
  69 import java.util.function.BiPredicate;
  70 import java.util.function.Function;
  71 import java.util.function.Predicate;
  72 import java.util.function.Supplier;
  73 import java.util.stream.Collectors;
  74 import java.util.stream.Stream;
  75 
  76 import static java.lang.String.format;
  77 import static java.util.stream.Collectors.joining;
  78 import jdk.internal.net.http.HttpRequestImpl;
  79 
  80 /**
  81  * Miscellaneous utilities
  82  */
  83 public final class Utils {
  84 
  85     public static final boolean ASSERTIONSENABLED;
  86 
  87     static {
  88         boolean enabled = false;
  89         assert enabled = true;
  90         ASSERTIONSENABLED = enabled;
  91     }
  92 
  93 //    public static final boolean TESTING;
  94 //    static {
  95 //        if (ASSERTIONSENABLED) {
  96 //            PrivilegedAction<String> action = () -> System.getProperty("test.src");
  97 //            TESTING = AccessController.doPrivileged(action) != null;
  98 //        } else TESTING = false;
  99 //    }
 100     public static final boolean DEBUG = // Revisit: temporary dev flag.
 101             getBooleanProperty(DebugLogger.HTTP_NAME, false);
 102     public static final boolean DEBUG_WS = // Revisit: temporary dev flag.
 103             getBooleanProperty(DebugLogger.WS_NAME, false);
 104     public static final boolean DEBUG_HPACK = // Revisit: temporary dev flag.
 105             getBooleanProperty(DebugLogger.HPACK_NAME, false);
 106     public static final boolean TESTING = DEBUG;
 107 
 108     public static final boolean isHostnameVerificationDisabled = // enabled by default
 109             hostnameVerificationDisabledValue();
 110 
 111     private static boolean hostnameVerificationDisabledValue() {
 112         String prop = getProperty("jdk.internal.httpclient.disableHostnameVerification");
 113         if (prop == null)
 114             return false;
 115         return prop.isEmpty() ? true : Boolean.parseBoolean(prop);
 116     }
 117 
 118     /**
 119      * Allocated buffer size. Must never be higher than 16K. But can be lower
 120      * if smaller allocation units preferred. HTTP/2 mandates that all
 121      * implementations support frame payloads of at least 16K.
 122      */
 123     private static final int DEFAULT_BUFSIZE = 16 * 1024;
 124 
 125     public static final int BUFSIZE = getIntegerNetProperty(
 126             "jdk.httpclient.bufsize", DEFAULT_BUFSIZE
 127     );
 128 
 129     public static final BiPredicate<String,String> ACCEPT_ALL = (x,y) -> true;
 130 
 131     private static final Set<String> DISALLOWED_HEADERS_SET = getDisallowedHeaders();
 132 
 133     private static Set<String> getDisallowedHeaders() {
 134         Set<String> headers = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
 135         headers.addAll(Set.of("connection", "content-length", "expect", "host", "upgrade"));
 136 
 137         String v = getNetProperty("jdk.httpclient.allowRestrictedHeaders");
 138         if (v != null) {
 139             // any headers found are removed from set.
 140             String[] tokens = v.trim().split(",");
 141             for (String token : tokens) {
 142                 headers.remove(token);
 143             }
 144             return Collections.unmodifiableSet(headers);
 145         } else {
 146             return Collections.unmodifiableSet(headers);
 147         }
 148     }
 149 
 150     public static final BiPredicate<String, String>
 151             ALLOWED_HEADERS = (header, unused) -> !DISALLOWED_HEADERS_SET.contains(header);
 152 
 153     public static final BiPredicate<String, String> VALIDATE_USER_HEADER =
 154             (name, value) -> {
 155                 assert name != null : "null header name";
 156                 assert value != null : "null header value";
 157                 if (!isValidName(name)) {
 158                     throw newIAE("invalid header name: \"%s\"", name);
 159                 }
 160                 if (!Utils.ALLOWED_HEADERS.test(name, null)) {
 161                     throw newIAE("restricted header name: \"%s\"", name);
 162                 }
 163                 if (!isValidValue(value)) {
 164                     throw newIAE("invalid header value for %s: \"%s\"", name, value);
 165                 }
 166                 return true;
 167             };
 168 
 169     // Headers that are not generally restricted, and can therefore be set by users,
 170     // but can in some contexts be overridden by the implementation.
 171     // Currently, only contains "Authorization" which will
 172     // be overridden, when an Authenticator is set on the HttpClient.
 173     // Needs to be BiPred<String,String> to fit with general form of predicates
 174     // used by caller.
 175 
 176     public static final BiPredicate<String, String> CONTEXT_RESTRICTED(HttpClient client) {
 177         return (k, v) -> client.authenticator() == null ||
 178                 ! (k.equalsIgnoreCase("Authorization")
 179                         && k.equalsIgnoreCase("Proxy-Authorization"));
 180     }
 181 
 182     private static final Predicate<String> IS_PROXY_HEADER = (k) ->
 183             k != null && k.length() > 6 && "proxy-".equalsIgnoreCase(k.substring(0,6));
 184     private static final Predicate<String> NO_PROXY_HEADER =
 185             IS_PROXY_HEADER.negate();
 186     private static final Predicate<String> ALL_HEADERS = (s) -> true;
 187 
 188     private static final Set<String> PROXY_AUTH_DISABLED_SCHEMES;
 189     private static final Set<String> PROXY_AUTH_TUNNEL_DISABLED_SCHEMES;
 190     static {
 191         String proxyAuthDisabled =
 192                 getNetProperty("jdk.http.auth.proxying.disabledSchemes");
 193         String proxyAuthTunnelDisabled =
 194                 getNetProperty("jdk.http.auth.tunneling.disabledSchemes");
 195         PROXY_AUTH_DISABLED_SCHEMES =
 196                 proxyAuthDisabled == null ? Set.of() :
 197                         Stream.of(proxyAuthDisabled.split(","))
 198                                 .map(String::trim)
 199                                 .filter((s) -> !s.isEmpty())
 200                                 .collect(Collectors.toUnmodifiableSet());
 201         PROXY_AUTH_TUNNEL_DISABLED_SCHEMES =
 202                 proxyAuthTunnelDisabled == null ? Set.of() :
 203                         Stream.of(proxyAuthTunnelDisabled.split(","))
 204                                 .map(String::trim)
 205                                 .filter((s) -> !s.isEmpty())
 206                                 .collect(Collectors.toUnmodifiableSet());
 207     }
 208 
 209     public static <T> CompletableFuture<T> wrapForDebug(Logger logger, String name, CompletableFuture<T> cf) {
 210         if (logger.on()) {
 211             return cf.handle((r,t) -> {
 212                 logger.log("%s completed %s", name, t == null ? "successfully" : t );
 213                 return cf;
 214             }).thenCompose(Function.identity());
 215         } else {
 216             return cf;
 217         }
 218     }
 219 
 220     private static final String WSPACES = " \t\r\n";
 221     private static final boolean isAllowedForProxy(String name,
 222                                                    String value,
 223                                                    Set<String> disabledSchemes,
 224                                                    Predicate<String> allowedKeys) {
 225         if (!allowedKeys.test(name)) return false;
 226         if (disabledSchemes.isEmpty()) return true;
 227         if (name.equalsIgnoreCase("proxy-authorization")) {
 228             if (value.isEmpty()) return false;
 229             for (String scheme : disabledSchemes) {
 230                 int slen = scheme.length();
 231                 int vlen = value.length();
 232                 if (vlen == slen) {
 233                     if (value.equalsIgnoreCase(scheme)) {
 234                         return false;
 235                     }
 236                 } else if (vlen > slen) {
 237                     if (value.substring(0,slen).equalsIgnoreCase(scheme)) {
 238                         int c = value.codePointAt(slen);
 239                         if (WSPACES.indexOf(c) > -1
 240                                 || Character.isSpaceChar(c)
 241                                 || Character.isWhitespace(c)) {
 242                             return false;
 243                         }
 244                     }
 245                 }
 246             }
 247         }
 248         return true;
 249     }
 250 
 251     public static final BiPredicate<String, String> PROXY_TUNNEL_FILTER =
 252             (s,v) -> isAllowedForProxy(s, v, PROXY_AUTH_TUNNEL_DISABLED_SCHEMES,
 253                     IS_PROXY_HEADER);
 254     public static final BiPredicate<String, String> PROXY_FILTER =
 255             (s,v) -> isAllowedForProxy(s, v, PROXY_AUTH_DISABLED_SCHEMES,
 256                     ALL_HEADERS);
 257     public static final BiPredicate<String, String> NO_PROXY_HEADERS_FILTER =
 258             (n,v) -> Utils.NO_PROXY_HEADER.test(n);
 259 
 260 
 261     public static boolean proxyHasDisabledSchemes(boolean tunnel) {
 262         return tunnel ? ! PROXY_AUTH_TUNNEL_DISABLED_SCHEMES.isEmpty()
 263                       : ! PROXY_AUTH_DISABLED_SCHEMES.isEmpty();
 264     }
 265 
 266     // WebSocket connection Upgrade headers
 267     private static final String HEADER_CONNECTION = "Connection";
 268     private static final String HEADER_UPGRADE    = "Upgrade";
 269 
 270     public static final void setWebSocketUpgradeHeaders(HttpRequestImpl request) {
 271         request.setSystemHeader(HEADER_UPGRADE, "websocket");
 272         request.setSystemHeader(HEADER_CONNECTION, "Upgrade");
 273     }
 274 
 275     public static IllegalArgumentException newIAE(String message, Object... args) {
 276         return new IllegalArgumentException(format(message, args));
 277     }
 278     public static ByteBuffer getBuffer() {
 279         return ByteBuffer.allocate(BUFSIZE);
 280     }
 281 
 282     public static Throwable getCompletionCause(Throwable x) {
 283         if (!(x instanceof CompletionException)
 284                 && !(x instanceof ExecutionException)) return x;
 285         final Throwable cause = x.getCause();
 286         if (cause == null) {
 287             throw new InternalError("Unexpected null cause", x);
 288         }
 289         return cause;
 290     }
 291 
 292     public static IOException getIOException(Throwable t) {
 293         if (t instanceof IOException) {
 294             return (IOException) t;
 295         }
 296         Throwable cause = t.getCause();
 297         if (cause != null) {
 298             return getIOException(cause);
 299         }
 300         return new IOException(t);
 301     }
 302 
 303     /**
 304      * Adds a more specific exception detail message, based on the given
 305      * exception type and the message supplier. This is primarily to present
 306      * more descriptive messages in IOExceptions that may be visible to calling
 307      * code.
 308      *
 309      * @return a possibly new exception that has as its detail message, the
 310      *         message from the messageSupplier, and the given throwable as its
 311      *         cause. Otherwise returns the given throwable
 312      */
 313     public static Throwable wrapWithExtraDetail(Throwable t,
 314                                                 Supplier<String> messageSupplier) {
 315         if (!(t instanceof IOException))
 316             return t;
 317 
 318         if (t instanceof SSLHandshakeException)
 319             return t;  // no need to decorate
 320 
 321         String msg = messageSupplier.get();
 322         if (msg == null)
 323             return t;
 324 
 325         if (t instanceof ConnectionExpiredException) {
 326             if (t.getCause() instanceof SSLHandshakeException)
 327                 return t;  // no need to decorate
 328             IOException ioe = new IOException(msg, t.getCause());
 329             t = new ConnectionExpiredException(ioe);
 330         } else {
 331             IOException ioe = new IOException(msg, t);
 332             t = ioe;
 333         }
 334         return t;
 335     }
 336 
 337     private Utils() { }
 338 
 339     /**
 340      * Returns the security permissions required to connect to the proxy, or
 341      * {@code null} if none is required or applicable.
 342      */
 343     public static URLPermission permissionForProxy(InetSocketAddress proxyAddress) {
 344         if (proxyAddress == null)
 345             return null;
 346 
 347         StringBuilder sb = new StringBuilder();
 348         sb.append("socket://")
 349           .append(proxyAddress.getHostString()).append(":")
 350           .append(proxyAddress.getPort());
 351         String urlString = sb.toString();
 352         return new URLPermission(urlString, "CONNECT");
 353     }
 354 
 355     /**
 356      * Returns the security permission required for the given details.
 357      */
 358     public static URLPermission permissionForServer(URI uri,
 359                                                     String method,
 360                                                     Stream<String> headers) {
 361         String urlString = new StringBuilder()
 362                 .append(uri.getScheme()).append("://")
 363                 .append(uri.getRawAuthority())
 364                 .append(uri.getRawPath()).toString();
 365 
 366         StringBuilder actionStringBuilder = new StringBuilder(method);
 367         String collected = headers.collect(joining(","));
 368         if (!collected.isEmpty()) {
 369             actionStringBuilder.append(":").append(collected);
 370         }
 371         return new URLPermission(urlString, actionStringBuilder.toString());
 372     }
 373 
 374 
 375     // ABNF primitives defined in RFC 7230
 376     private static final boolean[] tchar      = new boolean[256];
 377     private static final boolean[] fieldvchar = new boolean[256];
 378 
 379     static {
 380         char[] allowedTokenChars =
 381                 ("!#$%&'*+-.^_`|~0123456789" +
 382                  "abcdefghijklmnopqrstuvwxyz" +
 383                  "ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
 384         for (char c : allowedTokenChars) {
 385             tchar[c] = true;
 386         }
 387         for (char c = 0x21; c < 0xFF; c++) {
 388             fieldvchar[c] = true;
 389         }
 390         fieldvchar[0x7F] = false; // a little hole (DEL) in the range
 391     }
 392 
 393     /*
 394      * Validates a RFC 7230 field-name.
 395      */
 396     public static boolean isValidName(String token) {
 397         for (int i = 0; i < token.length(); i++) {
 398             char c = token.charAt(i);
 399             if (c > 255 || !tchar[c]) {
 400                 return false;
 401             }
 402         }
 403         return !token.isEmpty();
 404     }
 405 
 406     public static class ServerName {
 407         ServerName(String name, boolean isLiteral) {
 408             this.name = name;
 409             this.isLiteral = isLiteral;
 410         }
 411 
 412         final String name;
 413         final boolean isLiteral;
 414 
 415         public String getName() {
 416             return name;
 417         }
 418 
 419         public boolean isLiteral() {
 420             return isLiteral;
 421         }
 422     }
 423 
 424     /**
 425      * Analyse the given address and determine if it is literal or not,
 426      * returning the address in String form.
 427      */
 428     public static ServerName getServerName(InetSocketAddress addr) {
 429         String host = addr.getHostString();
 430         byte[] literal = IPAddressUtil.textToNumericFormatV4(host);
 431         if (literal == null) {
 432             // not IPv4 literal. Check IPv6
 433             literal = IPAddressUtil.textToNumericFormatV6(host);
 434             return new ServerName(host, literal != null);
 435         } else {
 436             return new ServerName(host, true);
 437         }
 438     }
 439 
 440     private static boolean isLoopbackLiteral(byte[] bytes) {
 441         if (bytes.length == 4) {
 442             return bytes[0] == 127;
 443         } else if (bytes.length == 16) {
 444             for (int i=0; i<14; i++)
 445                 if (bytes[i] != 0)
 446                     return false;
 447             if (bytes[15] != 1)
 448                 return false;
 449             return true;
 450         } else
 451             throw new InternalError();
 452     }
 453 
 454     /*
 455      * Validates a RFC 7230 field-value.
 456      *
 457      * "Obsolete line folding" rule
 458      *
 459      *     obs-fold = CRLF 1*( SP / HTAB )
 460      *
 461      * is not permitted!
 462      */
 463     public static boolean isValidValue(String token) {
 464         for (int i = 0; i < token.length(); i++) {
 465             char c = token.charAt(i);
 466             if (c > 255) {
 467                 return false;
 468             }
 469             if (c == ' ' || c == '\t') {
 470                 continue;
 471             } else if (!fieldvchar[c]) {
 472                 return false; // forbidden byte
 473             }
 474         }
 475         return true;
 476     }
 477 
 478 
 479     public static int getIntegerNetProperty(String name, int defaultValue) {
 480         return AccessController.doPrivileged((PrivilegedAction<Integer>) () ->
 481                 NetProperties.getInteger(name, defaultValue));
 482     }
 483 
 484     public static String getNetProperty(String name) {
 485         return AccessController.doPrivileged((PrivilegedAction<String>) () ->
 486                 NetProperties.get(name));
 487     }
 488 
 489     public static boolean getBooleanProperty(String name, boolean def) {
 490         return AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
 491                 Boolean.parseBoolean(System.getProperty(name, String.valueOf(def))));
 492     }
 493 
 494     public static String getProperty(String name) {
 495         return AccessController.doPrivileged((PrivilegedAction<String>) () ->
 496                 System.getProperty(name));
 497     }
 498 
 499     public static int getIntegerProperty(String name, int defaultValue) {
 500         return AccessController.doPrivileged((PrivilegedAction<Integer>) () ->
 501                 Integer.parseInt(System.getProperty(name, String.valueOf(defaultValue))));
 502     }
 503 
 504     public static SSLParameters copySSLParameters(SSLParameters p) {
 505         SSLParameters p1 = new SSLParameters();
 506         p1.setAlgorithmConstraints(p.getAlgorithmConstraints());
 507         p1.setCipherSuites(p.getCipherSuites());
 508         // JDK 8 EXCL START
 509         p1.setEnableRetransmissions(p.getEnableRetransmissions());
 510         p1.setMaximumPacketSize(p.getMaximumPacketSize());
 511         // JDK 8 EXCL END
 512         p1.setEndpointIdentificationAlgorithm(p.getEndpointIdentificationAlgorithm());
 513         p1.setNeedClientAuth(p.getNeedClientAuth());
 514         String[] protocols = p.getProtocols();
 515         if (protocols != null) {
 516             p1.setProtocols(protocols.clone());
 517         }
 518         p1.setSNIMatchers(p.getSNIMatchers());
 519         p1.setServerNames(p.getServerNames());
 520         p1.setUseCipherSuitesOrder(p.getUseCipherSuitesOrder());
 521         p1.setWantClientAuth(p.getWantClientAuth());
 522         return p1;
 523     }
 524 
 525     /**
 526      * Set limit to position, and position to mark.
 527      */
 528     public static void flipToMark(ByteBuffer buffer, int mark) {
 529         buffer.limit(buffer.position());
 530         buffer.position(mark);
 531     }
 532 
 533     public static String stackTrace(Throwable t) {
 534         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 535         String s = null;
 536         try {
 537             PrintStream p = new PrintStream(bos, true, "US-ASCII");
 538             t.printStackTrace(p);
 539             s = bos.toString("US-ASCII");
 540         } catch (UnsupportedEncodingException ex) {
 541             throw new InternalError(ex); // Can't happen
 542         }
 543         return s;
 544     }
 545 
 546     /**
 547      * Copies as much of src to dst as possible.
 548      * Return number of bytes copied
 549      */
 550     public static int copy(ByteBuffer src, ByteBuffer dst) {
 551         int srcLen = src.remaining();
 552         int dstLen = dst.remaining();
 553         if (srcLen > dstLen) {
 554             int diff = srcLen - dstLen;
 555             int limit = src.limit();
 556             src.limit(limit - diff);
 557             dst.put(src);
 558             src.limit(limit);
 559         } else {
 560             dst.put(src);
 561         }
 562         return srcLen - src.remaining();
 563     }
 564 
 565     /** Threshold beyond which data is no longer copied into the current
 566      * buffer, if that buffer has enough unused space. */
 567     private static final int COPY_THRESHOLD = 8192;
 568 
 569     /**
 570      * Adds the data from buffersToAdd to currentList. Either 1) appends the
 571      * data from a particular buffer to the last buffer in the list ( if
 572      * there is enough unused space ), or 2) adds it to the list.
 573      *
 574      * @return the number of bytes added
 575      */
 576     public static long accumulateBuffers(List<ByteBuffer> currentList,
 577                                          List<ByteBuffer> buffersToAdd) {
 578         long accumulatedBytes = 0;
 579         for (ByteBuffer bufferToAdd : buffersToAdd) {
 580             int remaining = bufferToAdd.remaining();
 581             if (remaining <= 0)
 582                 continue;
 583             int listSize = currentList.size();
 584             if (listSize == 0) {
 585                 currentList.add(bufferToAdd);
 586                 accumulatedBytes = remaining;
 587                 continue;
 588             }
 589 
 590             ByteBuffer lastBuffer = currentList.get(listSize - 1);
 591             int freeSpace = lastBuffer.capacity() - lastBuffer.limit();
 592             if (remaining <= COPY_THRESHOLD && freeSpace >= remaining) {
 593                 // append the new data to the unused space in the last buffer
 594                 int position = lastBuffer.position();
 595                 int limit = lastBuffer.limit();
 596                 lastBuffer.position(limit);
 597                 lastBuffer.limit(limit + remaining);
 598                 lastBuffer.put(bufferToAdd);
 599                 lastBuffer.position(position);
 600             } else {
 601                 currentList.add(bufferToAdd);
 602             }
 603             accumulatedBytes += remaining;
 604         }
 605         return accumulatedBytes;
 606     }
 607 
 608     public static ByteBuffer copy(ByteBuffer src) {
 609         ByteBuffer dst = ByteBuffer.allocate(src.remaining());
 610         dst.put(src);
 611         dst.flip();
 612         return dst;
 613     }
 614 
 615     public static ByteBuffer copyAligned(ByteBuffer src) {
 616         int len = src.remaining();
 617         int size = ((len + 7) >> 3) << 3;
 618         assert size >= len;
 619         ByteBuffer dst = ByteBuffer.allocate(size);
 620         dst.put(src);
 621         dst.flip();
 622         return dst;
 623     }
 624 
 625     public static String dump(Object... objects) {
 626         return Arrays.toString(objects);
 627     }
 628 
 629     public static String stringOf(Collection<?> source) {
 630         // We don't know anything about toString implementation of this
 631         // collection, so let's create an array
 632         return Arrays.toString(source.toArray());
 633     }
 634 
 635     public static long remaining(ByteBuffer[] bufs) {
 636         long remain = 0;
 637         for (ByteBuffer buf : bufs) {
 638             remain += buf.remaining();
 639         }
 640         return remain;
 641     }
 642 
 643     public static boolean hasRemaining(List<ByteBuffer> bufs) {
 644         synchronized (bufs) {
 645             for (ByteBuffer buf : bufs) {
 646                 if (buf.hasRemaining())
 647                     return true;
 648             }
 649         }
 650         return false;
 651     }
 652 
 653     public static long remaining(List<ByteBuffer> bufs) {
 654         long remain = 0;
 655         synchronized (bufs) {
 656             for (ByteBuffer buf : bufs) {
 657                 remain += buf.remaining();
 658             }
 659         }
 660         return remain;
 661     }
 662 
 663     public static int remaining(List<ByteBuffer> bufs, int max) {
 664         long remain = 0;
 665         synchronized (bufs) {
 666             for (ByteBuffer buf : bufs) {
 667                 remain += buf.remaining();
 668                 if (remain > max) {
 669                     throw new IllegalArgumentException("too many bytes");
 670                 }
 671             }
 672         }
 673         return (int) remain;
 674     }
 675 
 676     public static int remaining(ByteBuffer[] refs, int max) {
 677         long remain = 0;
 678         for (ByteBuffer b : refs) {
 679             remain += b.remaining();
 680             if (remain > max) {
 681                 throw new IllegalArgumentException("too many bytes");
 682             }
 683         }
 684         return (int) remain;
 685     }
 686 
 687     public static void close(Closeable... closeables) {
 688         for (Closeable c : closeables) {
 689             try {
 690                 c.close();
 691             } catch (IOException ignored) { }
 692         }
 693     }
 694 
 695     // Put all these static 'empty' singletons here
 696     public static final ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocate(0);
 697     public static final ByteBuffer[] EMPTY_BB_ARRAY = new ByteBuffer[0];
 698     public static final List<ByteBuffer> EMPTY_BB_LIST = List.of();
 699 
 700     /**
 701      * Returns a slice of size {@code amount} from the given buffer. If the
 702      * buffer contains more data than {@code amount}, then the slice's capacity
 703      * ( and, but not just, its limit ) is set to {@code amount}. If the buffer
 704      * does not contain more data than {@code amount}, then the slice's capacity
 705      * will be the same as the given buffer's capacity.
 706      */
 707     public static ByteBuffer sliceWithLimitedCapacity(ByteBuffer buffer, int amount) {
 708         final int index = buffer.position() + amount;
 709         final int limit = buffer.limit();
 710         if (index != limit) {
 711             // additional data in the buffer
 712             buffer.limit(index);  // ensures that the slice does not go beyond
 713         } else {
 714             // no additional data in the buffer
 715             buffer.limit(buffer.capacity());  // allows the slice full capacity
 716         }
 717 
 718         ByteBuffer newb = buffer.slice();
 719         buffer.position(index);
 720         buffer.limit(limit);    // restore the original buffer's limit
 721         newb.limit(amount);     // slices limit to amount (capacity may be greater)
 722         return newb;
 723     }
 724 
 725     /**
 726      * Get the Charset from the Content-encoding header. Defaults to
 727      * UTF_8
 728      */
 729     public static Charset charsetFrom(HttpHeaders headers) {
 730         String type = headers.firstValue("Content-type")
 731                 .orElse("text/html; charset=utf-8");
 732         int i = type.indexOf(";");
 733         if (i >= 0) type = type.substring(i+1);
 734         try {
 735             HeaderParser parser = new HeaderParser(type);
 736             String value = parser.findValue("charset");
 737             if (value == null) return StandardCharsets.UTF_8;
 738             return Charset.forName(value);
 739         } catch (Throwable x) {
 740             Log.logTrace("Can't find charset in \"{0}\" ({1})", type, x);
 741             return StandardCharsets.UTF_8;
 742         }
 743     }
 744 
 745     public static UncheckedIOException unchecked(IOException e) {
 746         return new UncheckedIOException(e);
 747     }
 748 
 749     /**
 750      * Get a logger for debug HTTP traces.
 751      *
 752      * The logger should only be used with levels whose severity is
 753      * {@code <= DEBUG}. By default, this logger will forward all messages
 754      * logged to an internal logger named "jdk.internal.httpclient.debug".
 755      * In addition, if the property -Djdk.internal.httpclient.debug=true is set,
 756      * it will print the messages on stderr.
 757      * The logger will add some decoration to the printed message, in the form of
 758      * {@code <Level>:[<thread-name>] [<elapsed-time>] <dbgTag>: <formatted message>}
 759      *
 760      * @param dbgTag A lambda that returns a string that identifies the caller
 761      *               (e.g: "SocketTube(3)", or "Http2Connection(SocketTube(3))")
 762      *
 763      * @return A logger for HTTP internal debug traces
 764      */
 765     public static Logger getDebugLogger(Supplier<String> dbgTag) {
 766         return getDebugLogger(dbgTag, DEBUG);
 767     }
 768 
 769     /**
 770      * Get a logger for debug HTTP traces.The logger should only be used
 771      * with levels whose severity is {@code <= DEBUG}.
 772      *
 773      * By default, this logger will forward all messages logged to an internal
 774      * logger named "jdk.internal.httpclient.debug".
 775      * In addition, if the message severity level is >= to
 776      * the provided {@code errLevel} it will print the messages on stderr.
 777      * The logger will add some decoration to the printed message, in the form of
 778      * {@code <Level>:[<thread-name>] [<elapsed-time>] <dbgTag>: <formatted message>}
 779      *
 780      * @apiNote To obtain a logger that will always print things on stderr in
 781      *          addition to forwarding to the internal logger, use
 782      *          {@code getDebugLogger(this::dbgTag, Level.ALL);}.
 783      *          This is also equivalent to calling
 784      *          {@code getDebugLogger(this::dbgTag, true);}.
 785      *          To obtain a logger that will only forward to the internal logger,
 786      *          use {@code getDebugLogger(this::dbgTag, Level.OFF);}.
 787      *          This is also equivalent to calling
 788      *          {@code getDebugLogger(this::dbgTag, false);}.
 789      *
 790      * @param dbgTag A lambda that returns a string that identifies the caller
 791      *               (e.g: "SocketTube(3)", or "Http2Connection(SocketTube(3))")
 792      * @param errLevel The level above which messages will be also printed on
 793      *               stderr (in addition to be forwarded to the internal logger).
 794      *
 795      * @return A logger for HTTP internal debug traces
 796      */
 797     static Logger getDebugLogger(Supplier<String> dbgTag, Level errLevel) {
 798         return DebugLogger.createHttpLogger(dbgTag, Level.OFF, errLevel);
 799     }
 800 
 801     /**
 802      * Get a logger for debug HTTP traces.The logger should only be used
 803      * with levels whose severity is {@code <= DEBUG}.
 804      *
 805      * By default, this logger will forward all messages logged to an internal
 806      * logger named "jdk.internal.httpclient.debug".
 807      * In addition, the provided boolean {@code on==true}, it will print the
 808      * messages on stderr.
 809      * The logger will add some decoration to the printed message, in the form of
 810      * {@code <Level>:[<thread-name>] [<elapsed-time>] <dbgTag>: <formatted message>}
 811      *
 812      * @apiNote To obtain a logger that will always print things on stderr in
 813      *          addition to forwarding to the internal logger, use
 814      *          {@code getDebugLogger(this::dbgTag, true);}.
 815      *          This is also equivalent to calling
 816      *          {@code getDebugLogger(this::dbgTag, Level.ALL);}.
 817      *          To obtain a logger that will only forward to the internal logger,
 818      *          use {@code getDebugLogger(this::dbgTag, false);}.
 819      *          This is also equivalent to calling
 820      *          {@code getDebugLogger(this::dbgTag, Level.OFF);}.
 821      *
 822      * @param dbgTag A lambda that returns a string that identifies the caller
 823      *               (e.g: "SocketTube(3)", or "Http2Connection(SocketTube(3))")
 824      * @param on  Whether messages should also be printed on
 825      *               stderr (in addition to be forwarded to the internal logger).
 826      *
 827      * @return A logger for HTTP internal debug traces
 828      */
 829     public static Logger getDebugLogger(Supplier<String> dbgTag, boolean on) {
 830         Level errLevel = on ? Level.ALL : Level.OFF;
 831         return getDebugLogger(dbgTag, errLevel);
 832     }
 833 
 834     /**
 835      * Return the host string from a HttpRequestImpl
 836      *
 837      * @param request
 838      * @return
 839      */
 840     public static String hostString(HttpRequestImpl request) {
 841         URI uri = request.uri();
 842         int port = uri.getPort();
 843         String host = uri.getHost();
 844 
 845         boolean defaultPort;
 846         if (port == -1) {
 847             defaultPort = true;
 848         } else if (uri.getScheme().equalsIgnoreCase("https")) {
 849             defaultPort = port == 443;
 850         } else {
 851             defaultPort = port == 80;
 852         }
 853 
 854         if (defaultPort) {
 855             return host;
 856         } else {
 857             return host + ":" + Integer.toString(port);
 858         }
 859     }
 860 
 861     /**
 862      * Get a logger for debug HPACK traces.The logger should only be used
 863      * with levels whose severity is {@code <= DEBUG}.
 864      *
 865      * By default, this logger will forward all messages logged to an internal
 866      * logger named "jdk.internal.httpclient.hpack.debug".
 867      * In addition, if the message severity level is >= to
 868      * the provided {@code errLevel} it will print the messages on stderr.
 869      * The logger will add some decoration to the printed message, in the form of
 870      * {@code <Level>:[<thread-name>] [<elapsed-time>] <dbgTag>: <formatted message>}
 871      *
 872      * @apiNote To obtain a logger that will always print things on stderr in
 873      *          addition to forwarding to the internal logger, use
 874      *          {@code getHpackLogger(this::dbgTag, Level.ALL);}.
 875      *          This is also equivalent to calling
 876      *          {@code getHpackLogger(this::dbgTag, true);}.
 877      *          To obtain a logger that will only forward to the internal logger,
 878      *          use {@code getHpackLogger(this::dbgTag, Level.OFF);}.
 879      *          This is also equivalent to calling
 880      *          {@code getHpackLogger(this::dbgTag, false);}.
 881      *
 882      * @param dbgTag A lambda that returns a string that identifies the caller
 883      *               (e.g: "Http2Connection(SocketTube(3))/hpack.Decoder(3)")
 884      * @param errLevel The level above which messages will be also printed on
 885      *               stderr (in addition to be forwarded to the internal logger).
 886      *
 887      * @return A logger for HPACK internal debug traces
 888      */
 889     public static Logger getHpackLogger(Supplier<String> dbgTag, Level errLevel) {
 890         Level outLevel = Level.OFF;
 891         return DebugLogger.createHpackLogger(dbgTag, outLevel, errLevel);
 892     }
 893 
 894     /**
 895      * Get a logger for debug HPACK traces.The logger should only be used
 896      * with levels whose severity is {@code <= DEBUG}.
 897      *
 898      * By default, this logger will forward all messages logged to an internal
 899      * logger named "jdk.internal.httpclient.hpack.debug".
 900      * In addition, the provided boolean {@code on==true}, it will print the
 901      * messages on stderr.
 902      * The logger will add some decoration to the printed message, in the form of
 903      * {@code <Level>:[<thread-name>] [<elapsed-time>] <dbgTag>: <formatted message>}
 904      *
 905      * @apiNote To obtain a logger that will always print things on stderr in
 906      *          addition to forwarding to the internal logger, use
 907      *          {@code getHpackLogger(this::dbgTag, true);}.
 908      *          This is also equivalent to calling
 909      *          {@code getHpackLogger(this::dbgTag, Level.ALL);}.
 910      *          To obtain a logger that will only forward to the internal logger,
 911      *          use {@code getHpackLogger(this::dbgTag, false);}.
 912      *          This is also equivalent to calling
 913      *          {@code getHpackLogger(this::dbgTag, Level.OFF);}.
 914      *
 915      * @param dbgTag A lambda that returns a string that identifies the caller
 916      *               (e.g: "Http2Connection(SocketTube(3))/hpack.Decoder(3)")
 917      * @param on  Whether messages should also be printed on
 918      *            stderr (in addition to be forwarded to the internal logger).
 919      *
 920      * @return A logger for HPACK internal debug traces
 921      */
 922     public static Logger getHpackLogger(Supplier<String> dbgTag, boolean on) {
 923         Level errLevel = on ? Level.ALL : Level.OFF;
 924         return getHpackLogger(dbgTag, errLevel);
 925     }
 926 
 927     /**
 928      * Get a logger for debug WebSocket traces.The logger should only be used
 929      * with levels whose severity is {@code <= DEBUG}.
 930      *
 931      * By default, this logger will forward all messages logged to an internal
 932      * logger named "jdk.internal.httpclient.websocket.debug".
 933      * In addition, if the message severity level is >= to
 934      * the provided {@code errLevel} it will print the messages on stderr.
 935      * The logger will add some decoration to the printed message, in the form of
 936      * {@code <Level>:[<thread-name>] [<elapsed-time>] <dbgTag>: <formatted message>}
 937      *
 938      * @apiNote To obtain a logger that will always print things on stderr in
 939      *          addition to forwarding to the internal logger, use
 940      *          {@code getWebSocketLogger(this::dbgTag, Level.ALL);}.
 941      *          This is also equivalent to calling
 942      *          {@code getWSLogger(this::dbgTag, true);}.
 943      *          To obtain a logger that will only forward to the internal logger,
 944      *          use {@code getWebSocketLogger(this::dbgTag, Level.OFF);}.
 945      *          This is also equivalent to calling
 946      *          {@code getWSLogger(this::dbgTag, false);}.
 947      *
 948      * @param dbgTag A lambda that returns a string that identifies the caller
 949      *               (e.g: "WebSocket(3)")
 950      * @param errLevel The level above which messages will be also printed on
 951      *               stderr (in addition to be forwarded to the internal logger).
 952      *
 953      * @return A logger for HPACK internal debug traces
 954      */
 955     public static Logger getWebSocketLogger(Supplier<String> dbgTag, Level errLevel) {
 956         Level outLevel = Level.OFF;
 957         return DebugLogger.createWebSocketLogger(dbgTag, outLevel, errLevel);
 958     }
 959 
 960     /**
 961      * Get a logger for debug WebSocket traces.The logger should only be used
 962      * with levels whose severity is {@code <= DEBUG}.
 963      *
 964      * By default, this logger will forward all messages logged to an internal
 965      * logger named "jdk.internal.httpclient.websocket.debug".
 966      * In addition, the provided boolean {@code on==true}, it will print the
 967      * messages on stderr.
 968      * The logger will add some decoration to the printed message, in the form of
 969      * {@code <Level>:[<thread-name>] [<elapsed-time>] <dbgTag>: <formatted message>}
 970      *
 971      * @apiNote To obtain a logger that will always print things on stderr in
 972      *          addition to forwarding to the internal logger, use
 973      *          {@code getWebSocketLogger(this::dbgTag, true);}.
 974      *          This is also equivalent to calling
 975      *          {@code getWebSocketLogger(this::dbgTag, Level.ALL);}.
 976      *          To obtain a logger that will only forward to the internal logger,
 977      *          use {@code getWebSocketLogger(this::dbgTag, false);}.
 978      *          This is also equivalent to calling
 979      *          {@code getHpackLogger(this::dbgTag, Level.OFF);}.
 980      *
 981      * @param dbgTag A lambda that returns a string that identifies the caller
 982      *               (e.g: "WebSocket(3)")
 983      * @param on  Whether messages should also be printed on
 984      *            stderr (in addition to be forwarded to the internal logger).
 985      *
 986      * @return A logger for WebSocket internal debug traces
 987      */
 988     public static Logger getWebSocketLogger(Supplier<String> dbgTag, boolean on) {
 989         Level errLevel = on ? Level.ALL : Level.OFF;
 990         return getWebSocketLogger(dbgTag, errLevel);
 991     }
 992 
 993     /**
 994      * SSLSessions returned to user are wrapped in an immutable object
 995      */
 996     public static SSLSession immutableSession(SSLSession session) {
 997         if (session instanceof ExtendedSSLSession)
 998             return new ImmutableExtendedSSLSession((ExtendedSSLSession)session);
 999         else
1000             return new ImmutableSSLSession(session);
1001     }
1002 
1003     /**
1004      * Enabled by default. May be disabled for testing. Use with care
1005      */
1006     public static boolean isHostnameVerificationDisabled() {
1007         return isHostnameVerificationDisabled;
1008     }
1009 
1010     public static InetSocketAddress resolveAddress(InetSocketAddress address) {
1011         if (address != null && address.isUnresolved()) {
1012             // The default proxy selector may select a proxy whose  address is
1013             // unresolved. We must resolve the address before connecting to it.
1014             address = new InetSocketAddress(address.getHostString(), address.getPort());
1015         }
1016         return address;
1017     }
1018 
1019     public static Throwable toConnectException(Throwable e) {
1020         if (e == null) return null;
1021         e = getCompletionCause(e);
1022         if (e instanceof ConnectException) return e;
1023         if (e instanceof SecurityException) return e;
1024         if (e instanceof SSLException) return e;
1025         if (e instanceof Error) return e;
1026         if (e instanceof HttpTimeoutException) return e;
1027         Throwable cause = e;
1028         e = new ConnectException(e.getMessage());
1029         e.initCause(cause);
1030         return e;
1031     }
1032 
1033     /**
1034      * Returns the smallest (closest to zero) positive number {@code m} (which
1035      * is also a power of 2) such that {@code n <= m}.
1036      * <pre>{@code
1037      *          n  pow2Size(n)
1038      * -----------------------
1039      *          0           1
1040      *          1           1
1041      *          2           2
1042      *          3           4
1043      *          4           4
1044      *          5           8
1045      *          6           8
1046      *          7           8
1047      *          8           8
1048      *          9          16
1049      *         10          16
1050      *        ...         ...
1051      * 2147483647  1073741824
1052      * } </pre>
1053      *
1054      * The result is capped at {@code 1 << 30} as beyond that int wraps.
1055      *
1056      * @param n
1057      *         capacity
1058      *
1059      * @return the size of the array
1060      * @apiNote Used to size arrays in circular buffers (rings), usually in
1061      * order to squeeze extra performance substituting {@code %} operation for
1062      * {@code &}, which is up to 2 times faster.
1063      */
1064     public static int pow2Size(int n) {
1065         if (n < 0) {
1066             throw new IllegalArgumentException();
1067         } else if (n == 0) {
1068             return 1;
1069         } else if (n >= (1 << 30)) { // 2^31 is a negative int
1070             return 1 << 30;
1071         } else {
1072             return 1 << (32 - Integer.numberOfLeadingZeros(n - 1));
1073         }
1074     }
1075 
1076     // -- toAsciiString-like support to encode path and query URI segments
1077 
1078     private static final char[] hexDigits = {
1079             '0', '1', '2', '3', '4', '5', '6', '7',
1080             '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
1081     };
1082 
1083     private static void appendEscape(StringBuilder sb, byte b) {
1084         sb.append('%');
1085         sb.append(hexDigits[(b >> 4) & 0x0f]);
1086         sb.append(hexDigits[(b >> 0) & 0x0f]);
1087     }
1088 
1089     // Encodes all characters >= \u0080 into escaped, normalized UTF-8 octets,
1090     // assuming that s is otherwise legal
1091     //
1092     public static String encode(String s) {
1093         int n = s.length();
1094         if (n == 0)
1095             return s;
1096 
1097         // First check whether we actually need to encode
1098         for (int i = 0;;) {
1099             if (s.charAt(i) >= '\u0080')
1100                 break;
1101             if (++i >= n)
1102                 return s;
1103         }
1104 
1105         String ns = Normalizer.normalize(s, Normalizer.Form.NFC);
1106         ByteBuffer bb = null;
1107         try {
1108             bb = StandardCharsets.UTF_8.newEncoder()
1109                     .onMalformedInput(CodingErrorAction.REPORT)
1110                     .onUnmappableCharacter(CodingErrorAction.REPORT)
1111                     .encode(CharBuffer.wrap(ns));
1112         } catch (CharacterCodingException x) {
1113             assert false : x;
1114         }
1115 
1116         StringBuilder sb = new StringBuilder();
1117         while (bb.hasRemaining()) {
1118             int b = bb.get() & 0xff;
1119             if (b >= 0x80)
1120                 appendEscape(sb, (byte)b);
1121             else
1122                 sb.append((char)b);
1123         }
1124         return sb.toString();
1125     }
1126 }