@@ -403,11 +403,11 @@ private String canonicalize(boolean coordinatesOnly) {
403403 }
404404 purl .append ("/" );
405405 if (namespace != null ) {
406- purl .append (encodePath (namespace ));
406+ purl .append (encodePath (namespace , ":" ));
407407 purl .append ("/" );
408408 }
409409 if (name != null ) {
410- purl .append (percentEncode (name ));
410+ purl .append (percentEncode (name , ":" ));
411411 }
412412 if (version != null ) {
413413 purl .append ("@" ).append (percentEncode (version ));
@@ -418,36 +418,44 @@ private String canonicalize(boolean coordinatesOnly) {
418418 qualifiers .entrySet ().stream ().forEachOrdered ((entry ) -> {
419419 purl .append (entry .getKey ().toLowerCase ());
420420 purl .append ("=" );
421- purl .append (percentEncode (entry .getValue ()));
421+ purl .append (percentEncode (entry .getValue (), ":/" ));
422422 purl .append ("&" );
423423 });
424424 purl .setLength (purl .length () - 1 );
425425 }
426426 if (subpath != null ) {
427- purl .append ("#" ).append (encodePath (subpath ));
427+ purl .append ("#" ).append (encodePath (subpath , "?#+&=" ));
428428 }
429429 }
430430 return purl .toString ();
431431 }
432432
433+ private String percentEncode (String input , Charset charset , String charsToExclude ) {
434+ return uriEncode (input , charset , charsToExclude );
435+ }
436+
437+ private String percentEncode (String input , String charsToExclude ) {
438+ return percentEncode (input , StandardCharsets .UTF_8 , charsToExclude );
439+ }
440+
433441 /**
434442 * Encodes the input in conformance with RFC 3986.
435443 *
436444 * @param input the String to encode
437445 * @return an encoded String
438446 */
439447 private String percentEncode (final String input ) {
440- return uriEncode (input , StandardCharsets .UTF_8 );
448+ return uriEncode (input , StandardCharsets .UTF_8 , null );
441449 }
442450
443- private static String uriEncode (String source , Charset charset ) {
451+ private static String uriEncode (String source , Charset charset , String chars ) {
444452 if (source == null || source .length () == 0 ) {
445453 return source ;
446454 }
447455
448456 StringBuilder builder = new StringBuilder ();
449457 for (byte b : source .getBytes (charset )) {
450- if (isUnreserved (b )) {
458+ if (isUnreserved (b ) || chars != null && chars . indexOf ( b ) != - 1 ) {
451459 builder .append ((char ) b );
452460 }
453461 else {
@@ -460,7 +468,7 @@ private static String uriEncode(String source, Charset charset) {
460468 }
461469
462470 private static boolean isUnreserved (int c ) {
463- return (isAlpha (c ) || isDigit (c ) || '-' == c || '.' == c || '_' == c || '~' == c || ':' == c || '/' == c );
471+ return (isAlpha (c ) || isDigit (c ) || '-' == c || '.' == c || '_' == c || '~' == c );
464472 }
465473
466474 private static boolean isAlpha (int c ) {
@@ -640,8 +648,8 @@ private String[] parsePath(final String value, final boolean isSubpath) throws M
640648 .toArray (String []::new );
641649 }
642650
643- private String encodePath (final String path ) {
644- return Arrays .stream (path .split ("/" )).map (segment -> percentEncode (segment )).collect (Collectors .joining ("/" ));
651+ private String encodePath (final String path , String chars ) {
652+ return Arrays .stream (path .split ("/" )).map (segment -> percentEncode (segment , chars )).collect (Collectors .joining ("/" ));
645653 }
646654
647655 /**
0 commit comments