@@ -82,10 +82,11 @@ public SolidContainer(final URI identifier, final Dataset dataset, final Metadat
8282 * @return the contained resources
8383 */
8484 public Set <SolidResource > getResources () {
85- final String container = normalize (getIdentifier ());
8685 // As defined by the Solid Protocol, containers always end with a slash.
87- if (container .endsWith ("/" )) {
88- final Node node = new Node (rdf .createIRI (getIdentifier ().toString ()), getGraph ());
86+ final URI base = getIdentifier ().normalize ();
87+ if (isContainer (base )) {
88+ final String container = normalize (base );
89+ final Node node = new Node (rdf .createIRI (base .toString ()), getGraph ());
8990 try (final Stream <Node .TypedNode > stream = node .getResources ()) {
9091 return stream .filter (child -> verifyContainmentIri (container , child )).map (child -> {
9192 final Metadata .Builder builder = Metadata .newBuilder ();
@@ -100,14 +101,15 @@ public Set<SolidResource> getResources() {
100101
101102 @ Override
102103 public ValidationResult validate () {
103- // Get the normalized container URI
104- final String container = normalize (getIdentifier ());
105104 final List <String > messages = new ArrayList <>();
106105 // Verify that the container URI path ends with a slash
107- if (!container .endsWith ("/" )) {
106+ final URI base = getIdentifier ().normalize ();
107+ if (!isContainer (base )) {
108108 messages .add ("Container URI does not end in a slash" );
109109 }
110110
111+ // Get the normalized container URI
112+ final String container = normalize (base );
111113 // Verify that all ldp:contains triples align with Solid expectations
112114 getGraph ().stream (null , rdf .createIRI (LDP .contains .toString ()), null )
113115 .collect (Collectors .partitioningBy (verifyContainmentTriple (container )))
@@ -121,8 +123,8 @@ public ValidationResult validate() {
121123 return new ValidationResult (false , messages );
122124 }
123125
124- static String normalize (final IRI iri ) {
125- return normalize (URI . create ( iri . getIRIString ()) );
126+ static boolean isContainer (final URI uri ) {
127+ return uri . normalize (). getPath (). endsWith ( "/" );
126128 }
127129
128130 static String normalize (final URI uri ) {
@@ -145,22 +147,44 @@ static Predicate<Triple> verifyContainmentTriple(final String container) {
145147 }
146148
147149 static boolean verifyContainmentIri (final String container , final IRI object ) {
148- if (!object .getIRIString ().startsWith (container )) {
149- // Out-of-domain containment triple object
150+
151+ // URI Structure Tests
152+ final URI base = URI .create (container ).normalize ();
153+ final URI normalized = URI .create (object .getIRIString ()).normalize ();
154+
155+ // Query strings are not allowed in subject or object URI
156+ if (base .getQuery () != null || normalized .getQuery () != null ) {
157+ return false ;
158+ }
159+
160+ // URI fragments are not allowed in subject or object URI
161+ if (base .getFragment () != null || normalized .getFragment () != null ) {
150162 return false ;
151- } else {
152- final String relativePath = object .getIRIString ().substring (container .length ());
153- final String normalizedPath = relativePath .endsWith ("/" ) ?
154- relativePath .substring (0 , relativePath .length () - 1 ) : relativePath ;
155- if (normalizedPath .isEmpty ()) {
156- // Containment triple subject and object cannot be the same
157- return false ;
158- }
159- if (normalizedPath .contains ("/" )) {
160- // Containment cannot skip intermediate nodes
161- return false ;
162- }
163163 }
164+
165+ // Base URI cannot equal the object URI
166+ if (base .getScheme ().equals (normalized .getScheme ()) &&
167+ base .getSchemeSpecificPart ().equals (normalized .getSchemeSpecificPart ())) {
168+ return false ;
169+ }
170+
171+ // Relative path tests
172+ final URI relative = base .relativize (normalized );
173+
174+ // Object URI must be relative to (contained in) the base URI
175+ if (relative .isAbsolute ()) {
176+ return false ;
177+ }
178+
179+ final String relativePath = relative .getPath ();
180+ final String normalizedPath = relativePath .endsWith ("/" ) ?
181+ relativePath .substring (0 , relativePath .length () - 1 ) : relativePath ;
182+
183+ // Containment cannot skip intermediate nodes
184+ if (normalizedPath .contains ("/" )) {
185+ return false ;
186+ }
187+
164188 return true ;
165189 }
166190
0 commit comments