42 import java.net.InetSocketAddress; |
42 import java.net.InetSocketAddress; |
43 import java.net.URI; |
43 import java.net.URI; |
44 import java.net.URLPermission; |
44 import java.net.URLPermission; |
45 import java.net.http.HttpHeaders; |
45 import java.net.http.HttpHeaders; |
46 import java.nio.ByteBuffer; |
46 import java.nio.ByteBuffer; |
|
47 import java.nio.CharBuffer; |
|
48 import java.nio.charset.CharacterCodingException; |
47 import java.nio.charset.Charset; |
49 import java.nio.charset.Charset; |
|
50 import java.nio.charset.CodingErrorAction; |
48 import java.nio.charset.StandardCharsets; |
51 import java.nio.charset.StandardCharsets; |
49 import java.security.AccessController; |
52 import java.security.AccessController; |
50 import java.security.PrivilegedAction; |
53 import java.security.PrivilegedAction; |
|
54 import java.text.Normalizer; |
51 import java.util.Arrays; |
55 import java.util.Arrays; |
52 import java.util.Collection; |
56 import java.util.Collection; |
53 import java.util.Collections; |
57 import java.util.Collections; |
54 import java.util.List; |
58 import java.util.List; |
55 import java.util.Set; |
59 import java.util.Set; |
579 } |
583 } |
580 } |
584 } |
581 return (int) remain; |
585 return (int) remain; |
582 } |
586 } |
583 |
587 |
584 public static long remaining(ByteBufferReference[] refs) { |
|
585 long remain = 0; |
|
586 for (ByteBufferReference ref : refs) { |
|
587 remain += ref.get().remaining(); |
|
588 } |
|
589 return remain; |
|
590 } |
|
591 |
|
592 public static int remaining(ByteBufferReference[] refs, int max) { |
|
593 long remain = 0; |
|
594 for (ByteBufferReference ref : refs) { |
|
595 remain += ref.get().remaining(); |
|
596 if (remain > max) { |
|
597 throw new IllegalArgumentException("too many bytes"); |
|
598 } |
|
599 } |
|
600 return (int) remain; |
|
601 } |
|
602 |
|
603 public static int remaining(ByteBuffer[] refs, int max) { |
588 public static int remaining(ByteBuffer[] refs, int max) { |
604 long remain = 0; |
589 long remain = 0; |
605 for (ByteBuffer b : refs) { |
590 for (ByteBuffer b : refs) { |
606 remain += b.remaining(); |
591 remain += b.remaining(); |
607 if (remain > max) { |
592 if (remain > max) { |
621 |
606 |
622 // Put all these static 'empty' singletons here |
607 // Put all these static 'empty' singletons here |
623 public static final ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocate(0); |
608 public static final ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocate(0); |
624 public static final ByteBuffer[] EMPTY_BB_ARRAY = new ByteBuffer[0]; |
609 public static final ByteBuffer[] EMPTY_BB_ARRAY = new ByteBuffer[0]; |
625 public static final List<ByteBuffer> EMPTY_BB_LIST = List.of(); |
610 public static final List<ByteBuffer> EMPTY_BB_LIST = List.of(); |
626 public static final ByteBufferReference[] EMPTY_BBR_ARRAY = new ByteBufferReference[0]; |
|
627 |
611 |
628 /** |
612 /** |
629 * Returns a slice of size {@code amount} from the given buffer. If the |
613 * Returns a slice of size {@code amount} from the given buffer. If the |
630 * buffer contains more data than {@code amount}, then the slice's capacity |
614 * buffer contains more data than {@code amount}, then the slice's capacity |
631 * ( and, but not just, its limit ) is set to {@code amount}. If the buffer |
615 * ( and, but not just, its limit ) is set to {@code amount}. If the buffer |
957 return 1 << 30; |
941 return 1 << 30; |
958 } else { |
942 } else { |
959 return 1 << (32 - Integer.numberOfLeadingZeros(n - 1)); |
943 return 1 << (32 - Integer.numberOfLeadingZeros(n - 1)); |
960 } |
944 } |
961 } |
945 } |
|
946 |
|
947 // -- toAsciiString-like support to encode path and query URI segments |
|
948 |
|
949 private static final char[] hexDigits = { |
|
950 '0', '1', '2', '3', '4', '5', '6', '7', |
|
951 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' |
|
952 }; |
|
953 |
|
954 private static void appendEscape(StringBuilder sb, byte b) { |
|
955 sb.append('%'); |
|
956 sb.append(hexDigits[(b >> 4) & 0x0f]); |
|
957 sb.append(hexDigits[(b >> 0) & 0x0f]); |
|
958 } |
|
959 |
|
960 // Encodes all characters >= \u0080 into escaped, normalized UTF-8 octets, |
|
961 // assuming that s is otherwise legal |
|
962 // |
|
963 public static String encode(String s) { |
|
964 int n = s.length(); |
|
965 if (n == 0) |
|
966 return s; |
|
967 |
|
968 // First check whether we actually need to encode |
|
969 for (int i = 0;;) { |
|
970 if (s.charAt(i) >= '\u0080') |
|
971 break; |
|
972 if (++i >= n) |
|
973 return s; |
|
974 } |
|
975 |
|
976 String ns = Normalizer.normalize(s, Normalizer.Form.NFC); |
|
977 ByteBuffer bb = null; |
|
978 try { |
|
979 bb = StandardCharsets.UTF_8.newEncoder() |
|
980 .onMalformedInput(CodingErrorAction.REPORT) |
|
981 .onUnmappableCharacter(CodingErrorAction.REPORT) |
|
982 .encode(CharBuffer.wrap(ns)); |
|
983 } catch (CharacterCodingException x) { |
|
984 assert false : x; |
|
985 } |
|
986 |
|
987 StringBuilder sb = new StringBuilder(); |
|
988 while (bb.hasRemaining()) { |
|
989 int b = bb.get() & 0xff; |
|
990 if (b >= 0x80) |
|
991 appendEscape(sb, (byte)b); |
|
992 else |
|
993 sb.append((char)b); |
|
994 } |
|
995 return sb.toString(); |
|
996 } |
962 } |
997 } |