http-client/src/main/java/io/airlift/http/client/HttpUriBuilder.java
private static String percentDecode(String encoded)
    {
        Preconditions.checkArgument(ascii().matchesAllOf(encoded), "string must be ASCII");

        ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length());
        for (int i = 0; i < encoded.length(); i++) {
            char c = encoded.charAt(i);

            if (c == '%') {
                Preconditions.checkArgument(i + 2 < encoded.length(), "percent encoded value is truncated");

                int high = Character.digit(encoded.charAt(i + 1), 16);
                int low = Character.digit(encoded.charAt(i + 2), 16);

                Preconditions.checkArgument(high != -1 && low != -1, "percent encoded value is not a valid hex string: ", encoded.substring(i, i + 2));

                int value = (high << 4) | (low);
                out.write(value);
                i += 2;
            }
            else {
                out.write((int) c);
            }
        }

        try {
            return UTF_8.newDecoder()
                    .onMalformedInput(CodingErrorAction.REPORT)
                    .decode(ByteBuffer.wrap(out.toByteArray()))
                    .toString();
        }
        catch (CharacterCodingException e) {
            throw new IllegalArgumentException("input does not represent a proper UTF8-encoded string");
        }
    }
private static String percentDecode(String encoded)
    {
        Preconditions.checkArgument(ascii().matchesAllOf(encoded), "string must be ASCII");

        ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length());
        for (int i = 0; i < encoded.length(); i++) {
            char c = encoded.charAt(i);

            if (c == '%') {
                Preconditions.checkArgument(i + 2 < encoded.length(), "percent encoded value is truncated");

                int high = Character.digit(encoded.charAt(i + 1), 16);
                int low = Character.digit(encoded.charAt(i + 2), 16);

                Preconditions.checkArgument(high != -1 && low != -1, "percent encoded value is not a valid hex string: ", encoded.substring(i, i + 2));

                int value = (high << 4) | (low);
                out.write(value);
                i += 2;
            }
            else {
                out.write((int) c);
            }
        }

        try {
            return UTF_8.newDecoder()
                    .onMalformedInput(CodingErrorAction.REPORT)
                    .decode(ByteBuffer.wrap(out.toByteArray()))
                    .toString();
        }
        catch (CharacterCodingException e) {
            throw new IllegalArgumentException("input does not represent a proper UTF8-encoded string");
        }
    }
input must be an ASCII string representing a percent-encoded UTF-8 byte sequence