< prev index next >

src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/internal/common/Utils.java

Print this page


   1 /*
   2  * Copyright (c) 2015, 2016, 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.incubator.http.internal.common;
  27 
  28 import jdk.internal.misc.InnocuousThread;
  29 import sun.net.NetProperties;
  30 import sun.net.util.IPAddressUtil;
  31 
  32 import javax.net.ssl.SSLParameters;
  33 import java.io.ByteArrayOutputStream;
  34 import java.io.Closeable;
  35 import java.io.IOException;
  36 import java.io.UncheckedIOException;
  37 import java.io.PrintStream;

  38 import java.io.UnsupportedEncodingException;


  39 import java.net.InetSocketAddress;
  40 import java.net.NetPermission;
  41 import java.net.URI;
  42 import java.net.URLPermission;
  43 import java.nio.ByteBuffer;
  44 import java.nio.charset.Charset;
  45 import java.nio.charset.StandardCharsets;
  46 import java.security.AccessController;
  47 import java.security.PrivilegedAction;
  48 import java.util.Arrays;
  49 import java.util.Collection;
  50 import java.util.List;
  51 import java.util.Map;
  52 import java.util.Optional;
  53 import java.util.Set;
  54 import java.util.concurrent.BlockingQueue;
  55 import java.util.concurrent.CompletableFuture;
  56 import java.util.concurrent.Executor;
  57 import java.util.concurrent.ExecutorService;
  58 import java.util.concurrent.Executors;
  59 import java.util.concurrent.LinkedBlockingQueue;
  60 import java.util.function.Predicate;
  61 import jdk.incubator.http.HttpHeaders;



  62 
  63 /**
  64  * Miscellaneous utilities
  65  */
  66 public final class Utils {
  67 



















  68     /**
  69      * Allocated buffer size. Must never be higher than 16K. But can be lower
  70      * if smaller allocation units preferred. HTTP/2 mandates that all
  71      * implementations support frame payloads of at least 16K.
  72      */
  73     public static final int DEFAULT_BUFSIZE = 16 * 1024;
  74 
  75     public static final int BUFSIZE = getIntegerNetProperty(
  76             "jdk.httpclient.bufsize", DEFAULT_BUFSIZE
  77     );
  78 
  79     private static final Set<String> DISALLOWED_HEADERS_SET = Set.of(
  80             "authorization", "connection", "cookie", "content-length",
  81             "date", "expect", "from", "host", "origin", "proxy-authorization",
  82             "referer", "user-agent", "upgrade", "via", "warning");
  83 
  84     public static final Predicate<String>
  85         ALLOWED_HEADERS = header -> !Utils.DISALLOWED_HEADERS_SET.contains(header);
  86 
  87     public static final Predicate<String>
  88         ALL_HEADERS = header -> true;
  89 
  90     public static ByteBuffer getBuffer() {
  91         return ByteBuffer.allocate(BUFSIZE);
  92     }
  93 







  94     public static IOException getIOException(Throwable t) {
  95         if (t instanceof IOException) {
  96             return (IOException) t;
  97         }
  98         Throwable cause = t.getCause();
  99         if (cause != null) {
 100             return getIOException(cause);
 101         }
 102         return new IOException(t);
 103     }
 104 


 105     /**
 106      * We use the same buffer for reading all headers and dummy bodies in an Exchange.

 107      */
 108     public static ByteBuffer getExchangeBuffer() {
 109         ByteBuffer buf = getBuffer();
 110         // Force a read the first time it is used
 111         buf.limit(0);
 112         return buf;





 113     }
 114 
 115     /**
 116      * Puts position to limit and limit to capacity so we can resume reading
 117      * into this buffer, but if required > 0 then limit may be reduced so that
 118      * no more than required bytes are read next time.
 119      */
 120     static void resumeChannelRead(ByteBuffer buf, int required) {
 121         int limit = buf.limit();
 122         buf.position(limit);
 123         int capacity = buf.capacity() - limit;
 124         if (required > 0 && required < capacity) {
 125             buf.limit(limit + required);
 126         } else {
 127             buf.limit(buf.capacity());


 128         }

 129     }
 130 
 131     private Utils() { }
 132 
 133     public static ExecutorService innocuousThreadPool() {
 134         return Executors.newCachedThreadPool(
 135                 (r) -> InnocuousThread.newThread("DefaultHttpClient", r));
 136     }
 137 
 138     // ABNF primitives defined in RFC 7230
 139     private static final boolean[] tchar      = new boolean[256];
 140     private static final boolean[] fieldvchar = new boolean[256];
 141 
 142     static {
 143         char[] allowedTokenChars =
 144                 ("!#$%&'*+-.^_`|~0123456789" +
 145                  "abcdefghijklmnopqrstuvwxyz" +
 146                  "ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
 147         for (char c : allowedTokenChars) {
 148             tchar[c] = true;
 149         }
 150         for (char c = 0x21; c < 0xFF; c++) {
 151             fieldvchar[c] = true;
 152         }
 153         fieldvchar[0x7F] = false; // a little hole (DEL) in the range
 154     }
 155 
 156     /*


 200             }
 201             if (accepted) {
 202                 if (c == ' ' || c == '\t') {
 203                     accepted = false;
 204                 } else if (!fieldvchar[c]) {
 205                     return false; // forbidden byte
 206                 }
 207             } else {
 208                 if (c != ' ' && c != '\t') {
 209                     if (fieldvchar[c]) {
 210                         accepted = true;
 211                     } else {
 212                         return false; // forbidden byte
 213                     }
 214                 }
 215             }
 216         }
 217         return accepted;
 218     }
 219 
 220     /**
 221      * Returns the security permission required for the given details.
 222      * If method is CONNECT, then uri must be of form "scheme://host:port"
 223      */
 224     public static URLPermission getPermission(URI uri,
 225                                               String method,
 226                                               Map<String, List<String>> headers) {
 227         StringBuilder sb = new StringBuilder();
 228 
 229         String urlstring, actionstring;
 230 
 231         if (method.equals("CONNECT")) {
 232             urlstring = uri.toString();
 233             actionstring = "CONNECT";
 234         } else {
 235             sb.append(uri.getScheme())
 236                     .append("://")
 237                     .append(uri.getAuthority())
 238                     .append(uri.getPath());
 239             urlstring = sb.toString();
 240 
 241             sb = new StringBuilder();
 242             sb.append(method);
 243             if (headers != null && !headers.isEmpty()) {
 244                 sb.append(':');
 245                 Set<String> keys = headers.keySet();
 246                 boolean first = true;
 247                 for (String key : keys) {
 248                     if (!first) {
 249                         sb.append(',');
 250                     }
 251                     sb.append(key);
 252                     first = false;
 253                 }
 254             }
 255             actionstring = sb.toString();
 256         }
 257         return new URLPermission(urlstring, actionstring);
 258     }
 259 
 260     public static void checkNetPermission(String target) {
 261         SecurityManager sm = System.getSecurityManager();
 262         if (sm == null) {
 263             return;
 264         }
 265         NetPermission np = new NetPermission(target);
 266         sm.checkPermission(np);
 267     }
 268 
 269     public static int getIntegerNetProperty(String name, int defaultValue) {
 270         return AccessController.doPrivileged((PrivilegedAction<Integer>) () ->
 271                 NetProperties.getInteger(name, defaultValue));
 272     }
 273 
 274     static String getNetProperty(String name) {
 275         return AccessController.doPrivileged((PrivilegedAction<String>) () ->
 276                 NetProperties.get(name));
 277     }
 278 





 279     public static SSLParameters copySSLParameters(SSLParameters p) {
 280         SSLParameters p1 = new SSLParameters();
 281         p1.setAlgorithmConstraints(p.getAlgorithmConstraints());
 282         p1.setCipherSuites(p.getCipherSuites());
 283         // JDK 8 EXCL START
 284         p1.setEnableRetransmissions(p.getEnableRetransmissions());
 285         p1.setMaximumPacketSize(p.getMaximumPacketSize());
 286         // JDK 8 EXCL END
 287         p1.setEndpointIdentificationAlgorithm(p.getEndpointIdentificationAlgorithm());
 288         p1.setNeedClientAuth(p.getNeedClientAuth());
 289         String[] protocols = p.getProtocols();
 290         if (protocols != null) {
 291             p1.setProtocols(protocols.clone());
 292         }
 293         p1.setSNIMatchers(p.getSNIMatchers());
 294         p1.setServerNames(p.getServerNames());
 295         p1.setUseCipherSuitesOrder(p.getUseCipherSuitesOrder());
 296         p1.setWantClientAuth(p.getWantClientAuth());
 297         return p1;
 298     }
 299 
 300     /**
 301      * Set limit to position, and position to mark.
 302      */
 303     public static void flipToMark(ByteBuffer buffer, int mark) {
 304         buffer.limit(buffer.position());
 305         buffer.position(mark);
 306     }
 307 
 308     public static String stackTrace(Throwable t) {
 309         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 310         String s = null;
 311         try {
 312             PrintStream p = new PrintStream(bos, true, "US-ASCII");
 313             t.printStackTrace(p);
 314             s = bos.toString("US-ASCII");
 315         } catch (UnsupportedEncodingException ex) {
 316             // can't happen
 317         }
 318         return s;
 319     }
 320 
 321     /**
 322      * Copies as much of src to dst as possible.
 323      * Return number of bytes copied
 324      */
 325     public static int copy(ByteBuffer src, ByteBuffer dst) {
 326         int srcLen = src.remaining();
 327         int dstLen = dst.remaining();
 328         if (srcLen > dstLen) {
 329             int diff = srcLen - dstLen;
 330             int limit = src.limit();
 331             src.limit(limit - diff);
 332             dst.put(src);
 333             src.limit(limit);
 334         } else {
 335             dst.put(src);
 336         }
 337         return srcLen - src.remaining();
 338     }
 339 
 340     // copy up to amount from src to dst, but no more
 341     public static int copyUpTo(ByteBuffer src, ByteBuffer dst, int amount) {
 342         int toCopy = Math.min(src.remaining(), Math.min(dst.remaining(), amount));
 343         copy(src, dst, toCopy);
 344         return toCopy;
 345     }
 346 
 347     /**
 348      * Copy amount bytes from src to dst. at least amount must be
 349      * available in both dst and in src
 350      */
 351     public static void copy(ByteBuffer src, ByteBuffer dst, int amount) {
 352         int excess = src.remaining() - amount;
 353         assert excess >= 0;
 354         if (excess > 0) {
 355             int srclimit = src.limit();
 356             src.limit(srclimit - excess);
 357             dst.put(src);
 358             src.limit(srclimit);



















 359         } else {
 360             dst.put(src);
 361         }



 362     }
 363 
 364     public static ByteBuffer copy(ByteBuffer src) {
 365         ByteBuffer dst = ByteBuffer.allocate(src.remaining());
 366         dst.put(src);
 367         dst.flip();
 368         return dst;
 369     }
 370 
 371     public static String dump(Object... objects) {
 372         return Arrays.toString(objects);
 373     }
 374 
 375     public static String stringOf(Collection<?> source) {
 376         // We don't know anything about toString implementation of this
 377         // collection, so let's create an array
 378         return Arrays.toString(source.toArray());
 379     }
 380 
 381     public static int remaining(ByteBuffer[] bufs) {
 382         int remain = 0;
 383         for (ByteBuffer buf : bufs) {
 384             remain += buf.remaining();
 385         }
 386         return remain;
 387     }
 388 
 389     public static int remaining(List<ByteBuffer> bufs) {
 390         int remain = 0;
 391         for (ByteBuffer buf : bufs) {
 392             remain += buf.remaining();

 393         }
 394         return remain;

 395     }
 396 
 397     public static int remaining(ByteBufferReference[] refs) {
 398         int remain = 0;
 399         for (ByteBufferReference ref : refs) {
 400             remain += ref.get().remaining();

 401         }
 402         return remain;
 403     }
 404 
 405     // assumes buffer was written into starting at position zero
 406     static void unflip(ByteBuffer buf) {
 407         buf.position(buf.limit());
 408         buf.limit(buf.capacity());
 409     }
 410 
 411     public static void close(Closeable... closeables) {
 412         for (Closeable c : closeables) {
 413             try {
 414                 c.close();
 415             } catch (IOException ignored) { }


 416         }
 417     }
 418 
 419     public static void close(Throwable t, Closeable... closeables) {
 420         for (Closeable c : closeables) {
 421             try {
 422                 ExceptionallyCloseable.close(t, c);
 423             } catch (IOException ignored) { }
 424         }

 425     }
 426 
 427     /**
 428      * Returns an array with the same buffers, but starting at position zero
 429      * in the array.
 430      */
 431     public static ByteBuffer[] reduce(ByteBuffer[] bufs, int start, int number) {
 432         if (start == 0 && number == bufs.length) {
 433             return bufs;
 434         }
 435         ByteBuffer[] nbufs = new ByteBuffer[number];
 436         int j = 0;
 437         for (int i=start; i<start+number; i++) {
 438             nbufs[j++] = bufs[i];
 439         }
 440         return nbufs;
 441     }
 442 
 443     static String asString(ByteBuffer buf) {
 444         byte[] b = new byte[buf.remaining()];
 445         buf.get(b);
 446         return new String(b, StandardCharsets.US_ASCII);


 447     }
 448 
 449     /**
 450      * Returns a single threaded executor which uses one invocation
 451      * of the parent executor to execute tasks (in sequence).
 452      *
 453      * Use a null valued Runnable to terminate.
 454      */
 455     // TODO: this is a blocking way of doing this;
 456     public static Executor singleThreadExecutor(Executor parent) {
 457         BlockingQueue<Optional<Runnable>> queue = new LinkedBlockingQueue<>();
 458         parent.execute(() -> {
 459             while (true) {
 460                 try {
 461                     Optional<Runnable> o = queue.take();
 462                     if (!o.isPresent()) {
 463                         return;
 464                     }
 465                     o.get().run();
 466                 } catch (InterruptedException ex) {
 467                     return;
 468                 }







 469             }
 470         });
 471         return new Executor() {
 472             @Override
 473             public void execute(Runnable command) {
 474                 queue.offer(Optional.ofNullable(command));
 475             }
 476         };
 477     }
 478 
 479     private static void executeInline(Runnable r) {
 480         r.run();



 481     }
 482 
 483     static Executor callingThreadExecutor() {
 484         return Utils::executeInline;
 485     }
 486 
 487     // Put all these static 'empty' singletons here
 488     @SuppressWarnings("rawtypes")
 489     public static final CompletableFuture[] EMPTY_CFARRAY = new CompletableFuture[0];
 490 
 491     public static final ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocate(0);
 492     public static final ByteBuffer[] EMPTY_BB_ARRAY = new ByteBuffer[0];


 493 
 494     public static ByteBuffer slice(ByteBuffer buffer, int amount) {
 495         ByteBuffer newb = buffer.slice();
 496         newb.limit(amount);
 497         buffer.position(buffer.position() + amount);
 498         return newb;
 499     }
 500 
 501     /**
 502      * Get the Charset from the Content-encoding header. Defaults to
 503      * UTF_8
 504      */
 505     public static Charset charsetFrom(HttpHeaders headers) {
 506         String encoding = headers.firstValue("Content-encoding")
 507                 .orElse("UTF_8");
 508         try {
 509             return Charset.forName(encoding);
 510         } catch (IllegalArgumentException e) {
 511             return StandardCharsets.UTF_8;
 512         }
 513     }
 514 
 515     public static UncheckedIOException unchecked(IOException e) {
 516         return new UncheckedIOException(e);























































































































































 517     }
 518 }
   1 /*
   2  * Copyright (c) 2015, 2017, 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.incubator.http.internal.common;
  27 
  28 import jdk.incubator.http.HttpHeaders;
  29 import sun.net.NetProperties;
  30 import sun.net.util.IPAddressUtil;
  31 
  32 import javax.net.ssl.SSLParameters;
  33 import java.io.ByteArrayOutputStream;
  34 import java.io.Closeable;
  35 import java.io.IOException;

  36 import java.io.PrintStream;
  37 import java.io.UncheckedIOException;
  38 import java.io.UnsupportedEncodingException;
  39 import java.lang.System.Logger;
  40 import java.lang.System.Logger.Level;
  41 import java.net.InetSocketAddress;

  42 import java.net.URI;
  43 import java.net.URLPermission;
  44 import java.nio.ByteBuffer;
  45 import java.nio.charset.Charset;
  46 import java.nio.charset.StandardCharsets;
  47 import java.security.AccessController;
  48 import java.security.PrivilegedAction;
  49 import java.util.Arrays;
  50 import java.util.Collection;
  51 import java.util.List;


  52 import java.util.Set;
  53 import java.util.concurrent.CompletionException;
  54 import java.util.concurrent.ExecutionException;




  55 import java.util.function.Predicate;
  56 import java.util.function.Supplier;
  57 import java.util.stream.Stream;
  58 
  59 import static java.util.stream.Collectors.joining;
  60 
  61 /**
  62  * Miscellaneous utilities
  63  */
  64 public final class Utils {
  65 
  66     public static final boolean ASSERTIONSENABLED;
  67     static {
  68         boolean enabled = false;
  69         assert enabled = true;
  70         ASSERTIONSENABLED = enabled;
  71     }
  72 //    public static final boolean TESTING;
  73 //    static {
  74 //        if (ASSERTIONSENABLED) {
  75 //            PrivilegedAction<String> action = () -> System.getProperty("test.src");
  76 //            TESTING = AccessController.doPrivileged(action) != null;
  77 //        } else TESTING = false;
  78 //    }
  79     public static final boolean DEBUG = // Revisit: temporary dev flag.
  80             getBooleanProperty(DebugLogger.HTTP_NAME, false);
  81     public static final boolean DEBUG_HPACK = // Revisit: temporary dev flag.
  82             getBooleanProperty(DebugLogger.HPACK_NAME, false);
  83     public static final boolean TESTING = DEBUG;
  84 
  85     /**
  86      * Allocated buffer size. Must never be higher than 16K. But can be lower
  87      * if smaller allocation units preferred. HTTP/2 mandates that all
  88      * implementations support frame payloads of at least 16K.
  89      */
  90     private static final int DEFAULT_BUFSIZE = 16 * 1024;
  91 
  92     public static final int BUFSIZE = getIntegerNetProperty(
  93             "jdk.httpclient.bufsize", DEFAULT_BUFSIZE
  94     );
  95 
  96     private static final Set<String> DISALLOWED_HEADERS_SET = Set.of(
  97             "authorization", "connection", "cookie", "content-length",
  98             "date", "expect", "from", "host", "origin", "proxy-authorization",
  99             "referer", "user-agent", "upgrade", "via", "warning");
 100 
 101     public static final Predicate<String>
 102         ALLOWED_HEADERS = header -> !Utils.DISALLOWED_HEADERS_SET.contains(header);
 103 



 104     public static ByteBuffer getBuffer() {
 105         return ByteBuffer.allocate(BUFSIZE);
 106     }
 107 
 108     public static Throwable getCompletionCause(Throwable x) {
 109         if (!(x instanceof CompletionException)
 110                 && !(x instanceof ExecutionException)) return x;
 111         final Throwable cause = x.getCause();
 112         return cause == null ? x : cause;
 113     }
 114 
 115     public static IOException getIOException(Throwable t) {
 116         if (t instanceof IOException) {
 117             return (IOException) t;
 118         }
 119         Throwable cause = t.getCause();
 120         if (cause != null) {
 121             return getIOException(cause);
 122         }
 123         return new IOException(t);
 124     }
 125 
 126     private Utils() { }
 127 
 128     /**
 129      * Returns the security permissions required to connect to the proxy, or
 130      * {@code null} if none is required or applicable.
 131      */
 132     public static URLPermission permissionForProxy(InetSocketAddress proxyAddress) {
 133         if (proxyAddress == null)
 134             return null;
 135 
 136         StringBuilder sb = new StringBuilder();
 137         sb.append("socket://")
 138           .append(proxyAddress.getHostString()).append(":")
 139           .append(proxyAddress.getPort());
 140         String urlString = sb.toString();
 141         return new URLPermission(urlString, "CONNECT");
 142     }
 143 
 144     /**
 145      * Returns the security permission required for the given details.
 146      */
 147     public static URLPermission permissionForServer(URI uri,
 148                                                     String method,
 149                                                     Stream<String> headers) {
 150         String urlString = new StringBuilder()
 151                 .append(uri.getScheme()).append("://")
 152                 .append(uri.getAuthority())
 153                 .append(uri.getPath()).toString();
 154 
 155         StringBuilder actionStringBuilder = new StringBuilder(method);
 156         String collected = headers.collect(joining(","));
 157         if (!collected.isEmpty()) {
 158             actionStringBuilder.append(":").append(collected);
 159         }
 160         return new URLPermission(urlString, actionStringBuilder.toString());
 161     }
 162 






 163 
 164     // ABNF primitives defined in RFC 7230
 165     private static final boolean[] tchar      = new boolean[256];
 166     private static final boolean[] fieldvchar = new boolean[256];
 167 
 168     static {
 169         char[] allowedTokenChars =
 170                 ("!#$%&'*+-.^_`|~0123456789" +
 171                  "abcdefghijklmnopqrstuvwxyz" +
 172                  "ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
 173         for (char c : allowedTokenChars) {
 174             tchar[c] = true;
 175         }
 176         for (char c = 0x21; c < 0xFF; c++) {
 177             fieldvchar[c] = true;
 178         }
 179         fieldvchar[0x7F] = false; // a little hole (DEL) in the range
 180     }
 181 
 182     /*


 226             }
 227             if (accepted) {
 228                 if (c == ' ' || c == '\t') {
 229                     accepted = false;
 230                 } else if (!fieldvchar[c]) {
 231                     return false; // forbidden byte
 232                 }
 233             } else {
 234                 if (c != ' ' && c != '\t') {
 235                     if (fieldvchar[c]) {
 236                         accepted = true;
 237                     } else {
 238                         return false; // forbidden byte
 239                     }
 240                 }
 241             }
 242         }
 243         return accepted;
 244     }
 245 

















































 246     public static int getIntegerNetProperty(String name, int defaultValue) {
 247         return AccessController.doPrivileged((PrivilegedAction<Integer>) () ->
 248                 NetProperties.getInteger(name, defaultValue));
 249     }
 250 
 251     static String getNetProperty(String name) {
 252         return AccessController.doPrivileged((PrivilegedAction<String>) () ->
 253                 NetProperties.get(name));
 254     }
 255 
 256     static boolean getBooleanProperty(String name, boolean def) {
 257         return AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
 258                 Boolean.parseBoolean(System.getProperty(name, String.valueOf(def))));
 259     }
 260 
 261     public static SSLParameters copySSLParameters(SSLParameters p) {
 262         SSLParameters p1 = new SSLParameters();
 263         p1.setAlgorithmConstraints(p.getAlgorithmConstraints());
 264         p1.setCipherSuites(p.getCipherSuites());
 265         // JDK 8 EXCL START
 266         p1.setEnableRetransmissions(p.getEnableRetransmissions());
 267         p1.setMaximumPacketSize(p.getMaximumPacketSize());
 268         // JDK 8 EXCL END
 269         p1.setEndpointIdentificationAlgorithm(p.getEndpointIdentificationAlgorithm());
 270         p1.setNeedClientAuth(p.getNeedClientAuth());
 271         String[] protocols = p.getProtocols();
 272         if (protocols != null) {
 273             p1.setProtocols(protocols.clone());
 274         }
 275         p1.setSNIMatchers(p.getSNIMatchers());
 276         p1.setServerNames(p.getServerNames());
 277         p1.setUseCipherSuitesOrder(p.getUseCipherSuitesOrder());
 278         p1.setWantClientAuth(p.getWantClientAuth());
 279         return p1;
 280     }
 281 
 282     /**
 283      * Set limit to position, and position to mark.
 284      */
 285     public static void flipToMark(ByteBuffer buffer, int mark) {
 286         buffer.limit(buffer.position());
 287         buffer.position(mark);
 288     }
 289 
 290     public static String stackTrace(Throwable t) {
 291         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 292         String s = null;
 293         try {
 294             PrintStream p = new PrintStream(bos, true, "US-ASCII");
 295             t.printStackTrace(p);
 296             s = bos.toString("US-ASCII");
 297         } catch (UnsupportedEncodingException ex) {
 298             throw new InternalError(ex); // Can't happen
 299         }
 300         return s;
 301     }
 302 
 303     /**
 304      * Copies as much of src to dst as possible.
 305      * Return number of bytes copied
 306      */
 307     public static int copy(ByteBuffer src, ByteBuffer dst) {
 308         int srcLen = src.remaining();
 309         int dstLen = dst.remaining();
 310         if (srcLen > dstLen) {
 311             int diff = srcLen - dstLen;
 312             int limit = src.limit();
 313             src.limit(limit - diff);
 314             dst.put(src);
 315             src.limit(limit);
 316         } else {
 317             dst.put(src);
 318         }
 319         return srcLen - src.remaining();
 320     }
 321 
 322     /** Threshold beyond which data is no longer copied into the current
 323      * buffer, if that buffer has enough unused space. */
 324     private static final int COPY_THRESHOLD = 8192;



 325 
 326     /**
 327      * Adds the data from buffersToAdd to currentList. Either 1) appends the
 328      * data from a particular buffer to the last buffer in the list ( if
 329      * there is enough unused space ), or 2) adds it to the list.
 330      *
 331      * @return the number of bytes added
 332      */
 333     public static long accumulateBuffers(List<ByteBuffer> currentList,
 334                                          List<ByteBuffer> buffersToAdd) {
 335         long accumulatedBytes = 0;
 336         for (ByteBuffer bufferToAdd : buffersToAdd) {
 337             int remaining = bufferToAdd.remaining();
 338             if (remaining <= 0)
 339                 continue;
 340             int listSize = currentList.size();
 341             if (listSize == 0) {
 342                 currentList.add(bufferToAdd);
 343                 accumulatedBytes = remaining;
 344                 continue;
 345             }
 346 
 347             ByteBuffer lastBuffer = currentList.get(currentList.size() - 1);
 348             int freeSpace = lastBuffer.capacity() - lastBuffer.limit();
 349             if (remaining <= COPY_THRESHOLD && freeSpace >= remaining) {
 350                 // append the new data to the unused space in the last buffer
 351                 int position = lastBuffer.position();
 352                 int limit = lastBuffer.limit();
 353                 lastBuffer.position(limit);
 354                 lastBuffer.limit(limit + bufferToAdd.limit());
 355                 lastBuffer.put(bufferToAdd);
 356                 lastBuffer.position(position);
 357             } else {
 358                 currentList.add(bufferToAdd);
 359             }
 360             accumulatedBytes += remaining;
 361         }
 362         return accumulatedBytes;
 363     }
 364 
 365     public static ByteBuffer copy(ByteBuffer src) {
 366         ByteBuffer dst = ByteBuffer.allocate(src.remaining());
 367         dst.put(src);
 368         dst.flip();
 369         return dst;
 370     }
 371 
 372     public static String dump(Object... objects) {
 373         return Arrays.toString(objects);
 374     }
 375 
 376     public static String stringOf(Collection<?> source) {
 377         // We don't know anything about toString implementation of this
 378         // collection, so let's create an array
 379         return Arrays.toString(source.toArray());
 380     }
 381 
 382     public static long remaining(ByteBuffer[] bufs) {
 383         long remain = 0;
 384         for (ByteBuffer buf : bufs) {
 385             remain += buf.remaining();
 386         }
 387         return remain;
 388     }
 389 
 390     public static boolean hasRemaining(List<ByteBuffer> bufs) {
 391         synchronized (bufs) {
 392             for (ByteBuffer buf : bufs) {
 393                 if (buf.hasRemaining())
 394                     return true;
 395             }
 396         }
 397         return false;
 398     }
 399 
 400     public static long remaining(List<ByteBuffer> bufs) {
 401         long remain = 0;
 402         synchronized (bufs) {
 403             for (ByteBuffer buf : bufs) {
 404                 remain += buf.remaining();
 405             }

 406         }
 407         return remain;




 408     }
 409 
 410     public static int remaining(List<ByteBuffer> bufs, int max) {
 411         long remain = 0;
 412         synchronized (bufs) {
 413             for (ByteBuffer buf : bufs) {
 414                 remain += buf.remaining();
 415                 if (remain > max) {
 416                     throw new IllegalArgumentException("too many bytes");
 417                 }
 418             }






 419         }
 420         return (int) remain;
 421     }
 422 
 423     public static long remaining(ByteBufferReference[] refs) {
 424         long remain = 0;
 425         for (ByteBufferReference ref : refs) {
 426             remain += ref.get().remaining();








 427         }
 428         return remain;
 429     }
 430 
 431     public static int remaining(ByteBufferReference[] refs, int max) {
 432         long remain = 0;
 433         for (ByteBufferReference ref : refs) {
 434             remain += ref.get().remaining();
 435             if (remain > max) {
 436                 throw new IllegalArgumentException("too many bytes");
 437             }
















 438         }
 439         return (int) remain;


 440     }
 441 
 442     public static int remaining(ByteBuffer[] refs, int max) {
 443         long remain = 0;
 444         for (ByteBuffer b : refs) {
 445             remain += b.remaining();
 446             if (remain > max) {
 447                 throw new IllegalArgumentException("too many bytes");
 448             }





 449         }
 450         return (int) remain;
 451     }
 452 
 453     public static void close(Closeable... closeables) {
 454         for (Closeable c : closeables) {
 455             try {
 456                 c.close();
 457             } catch (IOException ignored) { }
 458         }



 459     }
 460 
 461     // Put all these static 'empty' singletons here



 462     public static final ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocate(0);
 463     public static final ByteBuffer[] EMPTY_BB_ARRAY = new ByteBuffer[0];
 464     public static final List<ByteBuffer> EMPTY_BB_LIST = List.of();
 465     public static final ByteBufferReference[] EMPTY_BBR_ARRAY = new ByteBufferReference[0];
 466 
 467     public static ByteBuffer slice(ByteBuffer buffer, int amount) {
 468         ByteBuffer newb = buffer.slice();
 469         newb.limit(amount);
 470         buffer.position(buffer.position() + amount);
 471         return newb;
 472     }
 473 
 474     /**
 475      * Get the Charset from the Content-encoding header. Defaults to
 476      * UTF_8
 477      */
 478     public static Charset charsetFrom(HttpHeaders headers) {
 479         String encoding = headers.firstValue("Content-encoding")
 480                 .orElse("UTF_8");
 481         try {
 482             return Charset.forName(encoding);
 483         } catch (IllegalArgumentException e) {
 484             return StandardCharsets.UTF_8;
 485         }
 486     }
 487 
 488     public static UncheckedIOException unchecked(IOException e) {
 489         return new UncheckedIOException(e);
 490     }
 491 
 492     /**
 493      * Get a logger for debug HTTP traces.
 494      *
 495      * The logger should only be used with levels whose severity is
 496      * {@code <= DEBUG}. By default, this logger will forward all messages
 497      * logged to an internal logger named "jdk.internal.httpclient.debug".
 498      * In addition, if the property -Djdk.internal.httpclient.debug=true is set,
 499      * it will print the messages on stderr.
 500      * The logger will add some decoration to the printed message, in the form of
 501      * {@code <Level>:[<thread-name>] [<elapsed-time>] <dbgTag>: <formatted message>}
 502      *
 503      * @param dbgTag A lambda that returns a string that identifies the caller
 504      *               (e.g: "SocketTube(3)", or "Http2Connection(SocketTube(3))")
 505      *
 506      * @return A logger for HTTP internal debug traces
 507      */
 508     public static Logger getDebugLogger(Supplier<String> dbgTag) {
 509         return getDebugLogger(dbgTag, DEBUG);
 510     }
 511 
 512     /**
 513      * Get a logger for debug HTTP traces.The logger should only be used
 514      * with levels whose severity is {@code <= DEBUG}.
 515      *
 516      * By default, this logger will forward all messages logged to an internal
 517      * logger named "jdk.internal.httpclient.debug".
 518      * In addition, if the message severity level is >= to
 519      * the provided {@code errLevel} it will print the messages on stderr.
 520      * The logger will add some decoration to the printed message, in the form of
 521      * {@code <Level>:[<thread-name>] [<elapsed-time>] <dbgTag>: <formatted message>}
 522      *
 523      * @apiNote To obtain a logger that will always print things on stderr in
 524      *          addition to forwarding to the internal logger, use
 525      *          {@code getDebugLogger(this::dbgTag, Level.ALL);}.
 526      *          This is also equivalent to calling
 527      *          {@code getDebugLogger(this::dbgTag, true);}.
 528      *          To obtain a logger that will only forward to the internal logger,
 529      *          use {@code getDebugLogger(this::dbgTag, Level.OFF);}.
 530      *          This is also equivalent to calling
 531      *          {@code getDebugLogger(this::dbgTag, false);}.
 532      *
 533      * @param dbgTag A lambda that returns a string that identifies the caller
 534      *               (e.g: "SocketTube(3)", or "Http2Connection(SocketTube(3))")
 535      * @param errLevel The level above which messages will be also printed on
 536      *               stderr (in addition to be forwarded to the internal logger).
 537      *
 538      * @return A logger for HTTP internal debug traces
 539      */
 540     static Logger getDebugLogger(Supplier<String> dbgTag, Level errLevel) {
 541         return DebugLogger.createHttpLogger(dbgTag, Level.OFF, errLevel);
 542     }
 543 
 544     /**
 545      * Get a logger for debug HTTP traces.The logger should only be used
 546      * with levels whose severity is {@code <= DEBUG}.
 547      *
 548      * By default, this logger will forward all messages logged to an internal
 549      * logger named "jdk.internal.httpclient.debug".
 550      * In addition, the provided boolean {@code on==true}, it will print the
 551      * messages on stderr.
 552      * The logger will add some decoration to the printed message, in the form of
 553      * {@code <Level>:[<thread-name>] [<elapsed-time>] <dbgTag>: <formatted message>}
 554      *
 555      * @apiNote To obtain a logger that will always print things on stderr in
 556      *          addition to forwarding to the internal logger, use
 557      *          {@code getDebugLogger(this::dbgTag, true);}.
 558      *          This is also equivalent to calling
 559      *          {@code getDebugLogger(this::dbgTag, Level.ALL);}.
 560      *          To obtain a logger that will only forward to the internal logger,
 561      *          use {@code getDebugLogger(this::dbgTag, false);}.
 562      *          This is also equivalent to calling
 563      *          {@code getDebugLogger(this::dbgTag, Level.OFF);}.
 564      *
 565      * @param dbgTag A lambda that returns a string that identifies the caller
 566      *               (e.g: "SocketTube(3)", or "Http2Connection(SocketTube(3))")
 567      * @param on  Whether messages should also be printed on
 568      *               stderr (in addition to be forwarded to the internal logger).
 569      *
 570      * @return A logger for HTTP internal debug traces
 571      */
 572     public static Logger getDebugLogger(Supplier<String> dbgTag, boolean on) {
 573         Level errLevel = on ? Level.ALL : Level.OFF;
 574         return getDebugLogger(dbgTag, errLevel);
 575     }
 576 
 577     /**
 578      * Get a logger for debug HPACK traces.The logger should only be used
 579      * with levels whose severity is {@code <= DEBUG}.
 580      *
 581      * By default, this logger will forward all messages logged to an internal
 582      * logger named "jdk.internal.httpclient.hpack.debug".
 583      * In addition, if the message severity level is >= to
 584      * the provided {@code outLevel} it will print the messages on stdout.
 585      * The logger will add some decoration to the printed message, in the form of
 586      * {@code <Level>:[<thread-name>] [<elapsed-time>] <dbgTag>: <formatted message>}
 587      *
 588      * @apiNote To obtain a logger that will always print things on stdout in
 589      *          addition to forwarding to the internal logger, use
 590      *          {@code getHpackLogger(this::dbgTag, Level.ALL);}.
 591      *          This is also equivalent to calling
 592      *          {@code getHpackLogger(this::dbgTag, true);}.
 593      *          To obtain a logger that will only forward to the internal logger,
 594      *          use {@code getHpackLogger(this::dbgTag, Level.OFF);}.
 595      *          This is also equivalent to calling
 596      *          {@code getHpackLogger(this::dbgTag, false);}.
 597      *
 598      * @param dbgTag A lambda that returns a string that identifies the caller
 599      *               (e.g: "Http2Connection(SocketTube(3))/hpack.Decoder(3)")
 600      * @param outLevel The level above which messages will be also printed on
 601      *               stdout (in addition to be forwarded to the internal logger).
 602      *
 603      * @return A logger for HPACK internal debug traces
 604      */
 605     public static Logger getHpackLogger(Supplier<String> dbgTag, Level outLevel) {
 606         Level errLevel = Level.OFF;
 607         return DebugLogger.createHpackLogger(dbgTag, outLevel, errLevel);
 608     }
 609 
 610     /**
 611      * Get a logger for debug HPACK traces.The logger should only be used
 612      * with levels whose severity is {@code <= DEBUG}.
 613      *
 614      * By default, this logger will forward all messages logged to an internal
 615      * logger named "jdk.internal.httpclient.hpack.debug".
 616      * In addition, the provided boolean {@code on==true}, it will print the
 617      * messages on stdout.
 618      * The logger will add some decoration to the printed message, in the form of
 619      * {@code <Level>:[<thread-name>] [<elapsed-time>] <dbgTag>: <formatted message>}
 620      *
 621      * @apiNote To obtain a logger that will always print things on stdout in
 622      *          addition to forwarding to the internal logger, use
 623      *          {@code getHpackLogger(this::dbgTag, true);}.
 624      *          This is also equivalent to calling
 625      *          {@code getHpackLogger(this::dbgTag, Level.ALL);}.
 626      *          To obtain a logger that will only forward to the internal logger,
 627      *          use {@code getHpackLogger(this::dbgTag, false);}.
 628      *          This is also equivalent to calling
 629      *          {@code getHpackLogger(this::dbgTag, Level.OFF);}.
 630      *
 631      * @param dbgTag A lambda that returns a string that identifies the caller
 632      *               (e.g: "Http2Connection(SocketTube(3))/hpack.Decoder(3)")
 633      * @param on  Whether messages should also be printed on
 634      *            stdout (in addition to be forwarded to the internal logger).
 635      *
 636      * @return A logger for HPACK internal debug traces
 637      */
 638     public static Logger getHpackLogger(Supplier<String> dbgTag, boolean on) {
 639         Level outLevel = on ? Level.ALL : Level.OFF;
 640         return getHpackLogger(dbgTag, outLevel);
 641     }
 642 }
< prev index next >