src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java
changeset 49944 4690a2871b44
parent 49765 ee6f7a61f3a5
child 50681 4254bed3c09d
child 56507 2294c51eae30
--- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java	Wed May 02 10:47:16 2018 +0200
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java	Wed May 02 02:36:17 2018 -0700
@@ -44,10 +44,14 @@
 import java.net.URLPermission;
 import java.net.http.HttpHeaders;
 import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
 import java.nio.charset.Charset;
+import java.nio.charset.CodingErrorAction;
 import java.nio.charset.StandardCharsets;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.text.Normalizer;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -581,25 +585,6 @@
         return (int) remain;
     }
 
-    public static long remaining(ByteBufferReference[] refs) {
-        long remain = 0;
-        for (ByteBufferReference ref : refs) {
-            remain += ref.get().remaining();
-        }
-        return remain;
-    }
-
-    public static int remaining(ByteBufferReference[] refs, int max) {
-        long remain = 0;
-        for (ByteBufferReference ref : refs) {
-            remain += ref.get().remaining();
-            if (remain > max) {
-                throw new IllegalArgumentException("too many bytes");
-            }
-        }
-        return (int) remain;
-    }
-
     public static int remaining(ByteBuffer[] refs, int max) {
         long remain = 0;
         for (ByteBuffer b : refs) {
@@ -623,7 +608,6 @@
     public static final ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocate(0);
     public static final ByteBuffer[] EMPTY_BB_ARRAY = new ByteBuffer[0];
     public static final List<ByteBuffer> EMPTY_BB_LIST = List.of();
-    public static final ByteBufferReference[] EMPTY_BBR_ARRAY = new ByteBufferReference[0];
 
     /**
      * Returns a slice of size {@code amount} from the given buffer. If the
@@ -959,4 +943,55 @@
             return 1 << (32 - Integer.numberOfLeadingZeros(n - 1));
         }
     }
+
+    // -- toAsciiString-like support to encode path and query URI segments
+
+    private static final char[] hexDigits = {
+            '0', '1', '2', '3', '4', '5', '6', '7',
+            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+    };
+
+    private static void appendEscape(StringBuilder sb, byte b) {
+        sb.append('%');
+        sb.append(hexDigits[(b >> 4) & 0x0f]);
+        sb.append(hexDigits[(b >> 0) & 0x0f]);
+    }
+
+    // Encodes all characters >= \u0080 into escaped, normalized UTF-8 octets,
+    // assuming that s is otherwise legal
+    //
+    public static String encode(String s) {
+        int n = s.length();
+        if (n == 0)
+            return s;
+
+        // First check whether we actually need to encode
+        for (int i = 0;;) {
+            if (s.charAt(i) >= '\u0080')
+                break;
+            if (++i >= n)
+                return s;
+        }
+
+        String ns = Normalizer.normalize(s, Normalizer.Form.NFC);
+        ByteBuffer bb = null;
+        try {
+            bb = StandardCharsets.UTF_8.newEncoder()
+                    .onMalformedInput(CodingErrorAction.REPORT)
+                    .onUnmappableCharacter(CodingErrorAction.REPORT)
+                    .encode(CharBuffer.wrap(ns));
+        } catch (CharacterCodingException x) {
+            assert false : x;
+        }
+
+        StringBuilder sb = new StringBuilder();
+        while (bb.hasRemaining()) {
+            int b = bb.get() & 0xff;
+            if (b >= 0x80)
+                appendEscape(sb, (byte)b);
+            else
+                sb.append((char)b);
+        }
+        return sb.toString();
+    }
 }