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 25 package java.net.http; 26 27 import java.io.ByteArrayOutputStream; 28 import java.io.PrintStream; 29 import java.io.UnsupportedEncodingException; 30 import java.net.NetPermission; 31 import java.net.URI; 32 import java.net.URLPermission; 33 import java.nio.ByteBuffer; 34 import java.security.AccessController; 35 import java.security.PrivilegedAction; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.Set; 39 import javax.net.ssl.SSLParameters; 40 import sun.net.NetProperties; 41 42 /** 43 * Miscellaneous utilities 44 */ 45 class Utils { 46 47 /** 48 * Allocated buffer size. Must never be higher than 16K. But can be lower 49 * if smaller allocation units preferred. HTTP/2 mandates that all 50 * implementations support frame payloads of at least 16K. 51 */ 52 public static final int BUFSIZE = 16 * 1024; 53 54 /** Validates a RFC7230 token */ 55 static void validateToken(String token, String errormsg) { 56 int length = token.length(); 57 for (int i = 0; i < length; i++) { 58 int c = token.codePointAt(i); 59 if (c >= 0x30 && c <= 0x39 // 0 - 9 60 || (c >= 0x61 && c <= 0x7a) // a - z 61 || (c >= 0x41 && c <= 0x5a) // A - Z 62 || (c >= 0x21 && c <= 0x2e && c != 0x22 && c != 0x27 && c != 0x2c) 63 || (c >= 0x5e && c <= 0x60) 64 || (c == 0x7c) || (c == 0x7e)) { 65 } else { 66 throw new IllegalArgumentException(errormsg); 67 } 68 } 69 } 70 71 /** 72 * Return sthe security permission required for the given details. 73 * If method is CONNECT, then uri must be of form "scheme://host:port" 74 */ 75 static URLPermission getPermission(URI uri, 76 String method, 77 Map<String, List<String>> headers) { 78 StringBuilder sb = new StringBuilder(); 79 80 String urlstring, actionstring; 81 82 if (method.equals("CONNECT")) { 83 urlstring = uri.toString(); 84 actionstring = "CONNECT"; 85 } else { 86 sb.append(uri.getScheme()) 87 .append("://") 88 .append(uri.getHost()) 89 .append(uri.getPath()); 90 urlstring = sb.toString(); 91 92 sb = new StringBuilder(); 100 sb.append(','); 101 } 102 sb.append(key); 103 first = false; 104 } 105 } 106 actionstring = sb.toString(); 107 } 108 return new URLPermission(urlstring, actionstring); 109 } 110 111 static void checkNetPermission(String target) { 112 SecurityManager sm = System.getSecurityManager(); 113 if (sm == null) 114 return; 115 NetPermission np = new NetPermission(target); 116 sm.checkPermission(np); 117 } 118 119 static int getIntegerNetProperty(String name, int defaultValue) { 120 return AccessController.doPrivileged((PrivilegedAction<Integer>)() -> 121 NetProperties.getInteger(name, defaultValue) ); 122 } 123 124 static String getNetProperty(String name) { 125 return AccessController.doPrivileged((PrivilegedAction<String>)() -> 126 NetProperties.get(name) ); 127 } 128 129 static SSLParameters copySSLParameters(SSLParameters p) { 130 SSLParameters p1 = new SSLParameters(); 131 p1.setAlgorithmConstraints(p.getAlgorithmConstraints()); 132 p1.setCipherSuites(p.getCipherSuites()); 133 p1.setEnableRetransmissions(p.getEnableRetransmissions()); 134 p1.setEndpointIdentificationAlgorithm(p.getEndpointIdentificationAlgorithm()); 135 p1.setMaximumPacketSize(p.getMaximumPacketSize()); 136 p1.setNeedClientAuth(p.getNeedClientAuth()); 137 p1.setProtocols(p.getProtocols().clone()); 138 p1.setSNIMatchers(p.getSNIMatchers()); 139 p1.setServerNames(p.getServerNames()); 140 p1.setUseCipherSuitesOrder(p.getUseCipherSuitesOrder()); 141 p1.setWantClientAuth(p.getWantClientAuth()); 142 return p1; 143 } 144 145 146 /** Resumes reading into the given buffer. */ 147 static void unflip(ByteBuffer buf) { 148 buf.position(buf.limit()); 149 buf.limit(buf.capacity()); 150 } 151 152 /** 153 * Set limit to position, and position to mark. 154 * 155 * 156 * @param buffer 157 * @param mark 158 */ 159 static void flipToMark(ByteBuffer buffer, int mark) { 160 buffer.limit(buffer.position()); 161 buffer.position(mark); 162 } 163 164 /** Compact and leave ready for reading. */ 165 static void compact(List<ByteBuffer> buffers) { 166 for (ByteBuffer b : buffers) { 167 b.compact(); 168 b.flip(); 169 } 170 } 171 172 static String stackTrace(Throwable t) { 173 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 174 String s = null; 175 try { 176 PrintStream p = new PrintStream(bos, true, "US-ASCII"); 177 t.printStackTrace(p); 178 s = bos.toString("US-ASCII"); 179 } catch (UnsupportedEncodingException ex) { 180 // can't happen 181 } 182 return s; 183 } 184 185 /** Copies as much of src to dst as possible. */ 186 static void copy (ByteBuffer src, ByteBuffer dst) { 187 int srcLen = src.remaining(); 188 int dstLen = dst.remaining(); 189 if (srcLen > dstLen) { 190 int diff = srcLen - dstLen; 191 int limit = src.limit(); 192 src.limit(limit - diff); 193 dst.put(src); 194 src.limit(limit); 195 } else { 196 dst.put(src); 197 } 198 } 199 200 static ByteBuffer copy(ByteBuffer src) { 201 ByteBuffer dst = ByteBuffer.allocate(src.remaining()); 202 dst.put(src); 203 dst.flip(); 204 return dst; 205 } 206 207 static String combine(String[] s) { 208 StringBuilder sb = new StringBuilder(); 209 sb.append('['); 210 boolean first = true; 211 for (String s1 : s) { 212 if (!first) { 213 sb.append(", "); 214 first = false; 215 } 216 sb.append(s1); 217 } 218 sb.append(']'); 219 return sb.toString(); 220 } 221 } | 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(); 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 } |