< prev index next >
   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  */
  24 package java.net.http;
  25 
  26 import sun.net.NetProperties;
  27 
  28 import javax.net.ssl.SSLParameters;
  29 import java.io.ByteArrayOutputStream;
  30 import java.io.Closeable;
  31 import java.io.IOException;
  32 import java.io.PrintStream;
  33 import java.io.UnsupportedEncodingException;
  34 import java.net.InetSocketAddress;
  35 import java.net.NetPermission;
  36 import java.net.URI;
  37 import java.net.URLPermission;
  38 import java.nio.Buffer;
  39 import java.nio.ByteBuffer;
  40 import java.nio.charset.StandardCharsets;
  41 import java.security.AccessController;
  42 import java.security.PrivilegedAction;
  43 import java.util.Arrays;
  44 import java.util.List;
  45 import java.util.Map;
  46 import java.util.Set;
  47 import java.util.concurrent.CompletableFuture;
  48 import java.util.function.LongBinaryOperator;
  49 import java.util.function.Predicate;
  50 
  51 /**
  52  * Miscellaneous utilities
  53  */
  54 final class Utils {
  55 
  56     /**
  57      * Allocated buffer size. Must never be higher than 16K. But can be lower
  58      * if smaller allocation units preferred. HTTP/2 mandates that all
  59      * implementations support frame payloads of at least 16K.
  60      */
  61     public static final int BUFSIZE = 16 * 1024;
  62 
  63     private static final Set<String> DISALLOWED_HEADERS_SET = Set.of(
  64             "authorization", "connection", "cookie", "content-length",
  65             "date", "expect", "from", "host", "origin", "proxy-authorization",
  66             "referer", "user-agent", "upgrade", "via", "warning");
  67 
  68     static final Predicate<String>
  69         ALLOWED_HEADERS = header -> !Utils.DISALLOWED_HEADERS_SET.contains(header);
  70 
  71     static final Predicate<String>
  72         ALL_HEADERS = header -> true;
  73 
  74     static InetSocketAddress getAddress(HttpRequestImpl req) {
  75         URI uri = req.uri();
  76         if (uri == null) {
  77             return req.authority();
  78         }
  79         int port = uri.getPort();
  80         if (port == -1) {
  81             if (uri.getScheme().equalsIgnoreCase("https")) {
  82                 port = 443;
  83             } else {
  84                 port = 80;
  85             }
  86         }
  87         String host = uri.getHost();
  88         if (req.proxy() == null) {
  89             return new InetSocketAddress(host, port);
  90         } else {
  91             return InetSocketAddress.createUnresolved(host, port);
  92         }
  93     }
  94 
  95     /**
  96      * Puts position to limit and limit to capacity so we can resume reading
  97      * into this buffer, but if required > 0 then limit may be reduced so that
  98      * no more than required bytes are read next time.
  99      */
 100     static void resumeChannelRead(ByteBuffer buf, int required) {
 101         int limit = buf.limit();
 102         buf.position(limit);
 103         int capacity = buf.capacity() - limit;
 104         if (required > 0 && required < capacity) {
 105             buf.limit(limit + required);
 106         } else {
 107             buf.limit(buf.capacity());
 108         }
 109     }
 110 
 111     private Utils() { }
 112 
 113     /**
 114      * Validates a RFC7230 token
 115      */
 116     static void validateToken(String token, String errormsg) {
 117         int length = token.length();
 118         for (int i = 0; i < length; i++) {
 119             int c = token.codePointAt(i);
 120             if (c >= 0x30 && c <= 0x39 // 0 - 9
 121                     || (c >= 0x61 && c <= 0x7a) // a - z
 122                     || (c >= 0x41 && c <= 0x5a) // A - Z
 123                     || (c >= 0x21 && c <= 0x2e && c != 0x22 && c != 0x27 && c != 0x2c)
 124                     || (c >= 0x5e && c <= 0x60)
 125                     || (c == 0x7c) || (c == 0x7e)) {
 126             } else {
 127                 throw new IllegalArgumentException(errormsg);
 128             }
 129         }
 130     }
 131 
 132     /**
 133      * Returns the security permission required for the given details.
 134      * If method is CONNECT, then uri must be of form "scheme://host:port"
 135      */
 136     static URLPermission getPermission(URI uri,
 137                                        String method,
 138                                        Map<String, List<String>> headers) {
 139         StringBuilder sb = new StringBuilder();
 140 
 141         String urlstring, actionstring;
 142 
 143         if (method.equals("CONNECT")) {
 144             urlstring = uri.toString();
 145             actionstring = "CONNECT";
 146         } else {
 147             sb.append(uri.getScheme())
 148                     .append("://")
 149                     .append(uri.getHost())
 150                     .append(uri.getPath());
 151             urlstring = sb.toString();
 152 
 153             sb = new StringBuilder();
 154             sb.append(method);
 155             if (headers != null && !headers.isEmpty()) {
 156                 sb.append(':');
 157                 Set<String> keys = headers.keySet();
 158                 boolean first = true;
 159                 for (String key : keys) {
 160                     if (!first) {
 161                         sb.append(',');
 162                     }
 163                     sb.append(key);
 164                     first = false;
 165                 }
 166             }
 167             actionstring = sb.toString();
 168         }
 169         return new URLPermission(urlstring, actionstring);
 170     }
 171 
 172     static void checkNetPermission(String target) {
 173         SecurityManager sm = System.getSecurityManager();
 174         if (sm == null)
 175             return;
 176         NetPermission np = new NetPermission(target);
 177         sm.checkPermission(np);
 178     }
 179 
 180     static int getIntegerNetProperty(String name, int defaultValue) {
 181         return AccessController.doPrivileged((PrivilegedAction<Integer>) () ->
 182                 NetProperties.getInteger(name, defaultValue));
 183     }
 184 
 185     static String getNetProperty(String name) {
 186         return AccessController.doPrivileged((PrivilegedAction<String>) () ->
 187                 NetProperties.get(name));
 188     }
 189 
 190     static SSLParameters copySSLParameters(SSLParameters p) {
 191         SSLParameters p1 = new SSLParameters();
 192         p1.setAlgorithmConstraints(p.getAlgorithmConstraints());
 193         p1.setCipherSuites(p.getCipherSuites());
 194         p1.setEnableRetransmissions(p.getEnableRetransmissions());
 195         p1.setEndpointIdentificationAlgorithm(p.getEndpointIdentificationAlgorithm());
 196         p1.setMaximumPacketSize(p.getMaximumPacketSize());
 197         p1.setNeedClientAuth(p.getNeedClientAuth());
 198         String[] protocols = p.getProtocols();
 199         if (protocols != null)
 200             p1.setProtocols(protocols.clone());
 201         p1.setSNIMatchers(p.getSNIMatchers());
 202         p1.setServerNames(p.getServerNames());
 203         p1.setUseCipherSuitesOrder(p.getUseCipherSuitesOrder());
 204         p1.setWantClientAuth(p.getWantClientAuth());
 205         return p1;
 206     }
 207 
 208     /**
 209      * Set limit to position, and position to mark.
 210      */
 211     static void flipToMark(ByteBuffer buffer, int mark) {
 212         buffer.limit(buffer.position());
 213         buffer.position(mark);
 214     }
 215 
 216     static String stackTrace(Throwable t) {
 217         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 218         String s = null;
 219         try {
 220             PrintStream p = new PrintStream(bos, true, "US-ASCII");
 221             t.printStackTrace(p);
 222             s = bos.toString("US-ASCII");
 223         } catch (UnsupportedEncodingException ex) {
 224             // can't happen
 225         }
 226         return s;
 227     }
 228 
 229     /**
 230      * Copies as much of src to dst as possible.
 231      */
 232     static void copy(ByteBuffer src, ByteBuffer dst) {
 233         int srcLen = src.remaining();
 234         int dstLen = dst.remaining();
 235         if (srcLen > dstLen) {
 236             int diff = srcLen - dstLen;
 237             int limit = src.limit();
 238             src.limit(limit - diff);
 239             dst.put(src);
 240             src.limit(limit);
 241         } else {
 242             dst.put(src);
 243         }
 244     }
 245 
 246     static ByteBuffer copy(ByteBuffer src) {
 247         ByteBuffer dst = ByteBuffer.allocate(src.remaining());
 248         dst.put(src);
 249         dst.flip();
 250         return dst;
 251     }
 252 
 253     //
 254     // Helps to trim long names (packages, nested/inner types) in logs/toString
 255     //
 256     static String toStringSimple(Object o) {
 257         return o.getClass().getSimpleName() + "@" +
 258                 Integer.toHexString(System.identityHashCode(o));
 259     }
 260 
 261     //
 262     // 1. It adds a number of remaining bytes;
 263     // 2. Standard Buffer-type toString for CharBuffer (since it adheres to the
 264     // contract of java.lang.CharSequence.toString() which is both not too
 265     // useful and not too private)
 266     //
 267     static String toString(Buffer b) {
 268         return toStringSimple(b)
 269                 + "[pos=" + b.position()
 270                 + " lim=" + b.limit()
 271                 + " cap=" + b.capacity()
 272                 + " rem=" + b.remaining() + "]";
 273     }
 274 
 275     static String toString(CharSequence s) {
 276         return s == null
 277                 ? "null"
 278                 : toStringSimple(s) + "[len=" + s.length() + "]";
 279     }
 280 
 281     static String dump(Object... objects) {
 282         return Arrays.toString(objects);
 283     }
 284 
 285     static final System.Logger logger = System.getLogger("java.net.http.WebSocket");
 286 
 287     static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocate(0);
 288 
 289     static String webSocketSpecViolation(String section, String detail) {
 290         return "RFC 6455 " + section + " " + detail;
 291     }
 292 
 293     static void logResponse(HttpResponseImpl r) {
 294         if (!Log.requests()) {
 295             return;
 296         }
 297         StringBuilder sb = new StringBuilder();
 298         String method = r.request().method();
 299         URI uri = r.uri();
 300         String uristring = uri == null ? "" : uri.toString();
 301         sb.append('(').append(method).append(" ").append(uristring).append(") ").append(Integer.toString(r.statusCode()));
 302         Log.logResponse(sb.toString());
 303     }
 304 
 305     static int remaining(ByteBuffer[] bufs) {
 306         int remain = 0;
 307         for (ByteBuffer buf : bufs)
 308             remain += buf.remaining();
 309         return remain;
 310     }
 311 
 312     // assumes buffer was written into starting at position zero
 313     static void unflip(ByteBuffer buf) {
 314         buf.position(buf.limit());
 315         buf.limit(buf.capacity());
 316     }
 317 
 318     static void close(Closeable... chans) {
 319         for (Closeable chan : chans) {
 320             System.err.println("Closing " + chan);
 321             try {
 322                 chan.close();
 323             } catch (IOException e) {
 324             }
 325         }
 326     }
 327 
 328     static ByteBuffer[] reduce(ByteBuffer[] bufs, int start, int number) {
 329         if (start == 0 && number == bufs.length)
 330             return bufs;
 331         ByteBuffer[] nbufs = new ByteBuffer[number];
 332         int j = 0;
 333         for (int i=start; i<start+number; i++)
 334             nbufs[j++] = bufs[i];
 335         return nbufs;
 336     }
 337 
 338     static String asString(ByteBuffer buf) {
 339         byte[] b = new byte[buf.remaining()];
 340         buf.get(b);
 341         return new String(b, StandardCharsets.US_ASCII);
 342     }
 343 
 344     // Put all these static 'empty' singletons here
 345     @SuppressWarnings("rawtypes")
 346     static CompletableFuture[] EMPTY_CFARRAY = new CompletableFuture[0];
 347 
 348     static ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocate(0);
 349     static ByteBuffer[] EMPTY_BB_ARRAY = new ByteBuffer[0];
 350 }
< prev index next >