@@ -434,11 +434,11 @@ private String canonicalize(boolean coordinatesOnly) {
434434 }
435435 purl .append ("/" );
436436 if (namespace != null ) {
437- purl .append (encodePath (namespace ));
437+ purl .append (encodePath (namespace , ":" ));
438438 purl .append ("/" );
439439 }
440440 if (name != null ) {
441- purl .append (percentEncode (name ));
441+ purl .append (percentEncode (name , ":" ));
442442 }
443443 if (version != null ) {
444444 purl .append ("@" ).append (percentEncode (version ));
@@ -449,36 +449,44 @@ private String canonicalize(boolean coordinatesOnly) {
449449 qualifiers .entrySet ().stream ().forEachOrdered ((entry ) -> {
450450 purl .append (entry .getKey ().toLowerCase ());
451451 purl .append ("=" );
452- purl .append (percentEncode (entry .getValue ()));
452+ purl .append (percentEncode (entry .getValue (), ":/" ));
453453 purl .append ("&" );
454454 });
455455 purl .setLength (purl .length () - 1 );
456456 }
457457 if (subpath != null ) {
458- purl .append ("#" ).append (encodePath (subpath ));
458+ purl .append ("#" ).append (encodePath (subpath , "?#+&=" ));
459459 }
460460 }
461461 return purl .toString ();
462462 }
463463
464+ private String percentEncode (final String input , final Charset charset , final String charsToExclude ) {
465+ return uriEncode (input , charset , charsToExclude );
466+ }
467+
468+ private String percentEncode (final String input , final String charsToExclude ) {
469+ return percentEncode (input , StandardCharsets .UTF_8 , charsToExclude );
470+ }
471+
464472 /**
465473 * Encodes the input in conformance with RFC 3986.
466474 *
467475 * @param input the String to encode
468476 * @return an encoded String
469477 */
470478 private String percentEncode (final String input ) {
471- return uriEncode (input , StandardCharsets .UTF_8 );
479+ return percentEncode (input , StandardCharsets .UTF_8 , null );
472480 }
473481
474- private static String uriEncode (String source , Charset charset ) {
482+ private static String uriEncode (String source , Charset charset , String chars ) {
475483 if (source == null || source .length () == 0 ) {
476484 return source ;
477485 }
478486
479487 StringBuilder builder = new StringBuilder ();
480488 for (byte b : source .getBytes (charset )) {
481- if (isUnreserved (b )) {
489+ if (isUnreserved (b ) || chars != null && chars . indexOf ( b ) != - 1 ) {
482490 builder .append ((char ) b );
483491 }
484492 else {
@@ -491,7 +499,7 @@ private static String uriEncode(String source, Charset charset) {
491499 }
492500
493501 private static boolean isUnreserved (int c ) {
494- return (isAlpha (c ) || isDigit (c ) || '-' == c || '.' == c || '_' == c || '~' == c || ':' == c || '/' == c );
502+ return (isAlpha (c ) || isDigit (c ) || '-' == c || '.' == c || '_' == c || '~' == c );
495503 }
496504
497505 private static boolean isAlpha (int c ) {
@@ -718,8 +726,8 @@ private String[] parsePath(final String value, final boolean isSubpath) throws M
718726 .toArray (String []::new );
719727 }
720728
721- private String encodePath (final String path ) {
722- return Arrays .stream (path .split ("/" )).map (segment -> percentEncode (segment )).collect (Collectors .joining ("/" ));
729+ private String encodePath (final String path , String chars ) {
730+ return Arrays .stream (path .split ("/" )).map (segment -> percentEncode (segment , chars )).collect (Collectors .joining ("/" ));
723731 }
724732
725733 /**
0 commit comments