Version 6.29.20

All pages

Interoperability report

What Solid Memo's end-to-end tests find wrong on the advisory Solid servers, one entry per cause, written for the people who build those servers. Each entry says what the specification asks for, what the server does, where in its code, and the fewest HTTP requests that show it, with no Solid Memo involved.

The tests and how they run are in testing.md. The Interop workflow runs them weekly and on changes to the app's Solid code. Each server's e2e/pod/servers/<id>/expected-failures.json names the tests a cause fails, by the cause's id on this page.

A cause here is one that the tests hit and a live run reproduced. The servers are set up for testing, and each entry says when the setup plays a part. A server not on this page, or with no entries, passes every test.

How to read an entry

JavaScript Solid Server

Version 0.0.224 from npm, started with --conneg (Turtle as well as JSON-LD) and --public (no access control), files in the container. The source links are at gitHead 7c9b0de7.

IdCauseRequirement
jss-lang-tagSPARQL Update drops the language tag of a literal in its bodyDefinition (RDF 1.1); optional feature
jss-own-iriA document's own IRI is stored as ".", which reads back as its containerMUST (N3 Patch)
jss-acl-turtlePUT of a Turtle ACL gets 415, though Accept-Put lists TurtleMUST (Accept-Put)
jss-no-extensionA Turtle document without a file extension is served as application/octet-streamMUST

jss-lang-tag

SPARQL Update drops the language tag of a literal in its body. "x"@en in a PATCH with Content-Type: application/sparql-update becomes "x"^^rdf:langString with no tag. An INSERT DATA stores that literal. A DELETE DATA of a stored "x"@en never matches it, so the server answers 409 and applies none of the PATCH.

PUT $POD/lang.ttl
Content-Type: text/turtle

<#a> <http://purl.org/dc/terms/title> "Put"@en .
→ 201 Created

PATCH $POD/lang.ttl
Content-Type: application/sparql-update

INSERT DATA { <#b> <http://purl.org/dc/terms/title> "Patched"@en . }
→ 204 No Content

GET $POD/lang.ttl
Accept: text/turtle
→ 200 OK
<$POD/lang.ttl#a> dc:title "Put"@en .
<$POD/lang.ttl#b> dc:title "Patched"^^rdf:langString .

PATCH $POD/lang.ttl
Content-Type: application/sparql-update

DELETE DATA { <#a> <http://purl.org/dc/terms/title> "Put"@en . }
→ 409 Conflict
{"error":"Conflict","message":"Triple to delete not found: …#a http://purl.org/dc/terms/title"}

The same two changes sent as N3 Patch (text/n3) succeed and keep the tag.

jss-own-iri

A document's own IRI is stored as ".", which reads back as its container. <> in a Turtle PUT, or in an N3 Patch's solid:inserts, is written as the JSON-LD "@id": ".". On read, "." resolves to the parent container, as a subject or an object.

PUT $POD/own/doc.ttl
Content-Type: text/turtle

<> <http://example.org/p> <http://example.org/o> .
<#it> <http://example.org/p> <> .
→ 201 Created

GET $POD/own/doc.ttl
Accept: text/turtle
→ 200 OK
<$POD/own/> <http://example.org/p> <http://example.org/o> .
<$POD/own/doc.ttl#it> <http://example.org/p> <$POD/own/> .

PATCH $POD/own/new.ttl
Content-Type: text/n3

@prefix solid: <http://www.w3.org/ns/solid/terms#> .
_:p a solid:InsertDeletePatch ;
  solid:inserts { <> <http://example.org/q> <http://example.org/r> . } .
→ 201 Created

GET $POD/own/new.ttl
Accept: text/turtle
→ 200 OK
<$POD/own/> <http://example.org/q> <http://example.org/r> .

jss-acl-turtle

PUT of a Turtle ACL gets 415, though Accept-Put lists Turtle. JSS takes an ACL resource on PUT in JSON-LD only, on purpose: PR #339 added the check against data loss in a round trip. PATCH of an ACL, and GET of one as Turtle, work.

OPTIONS $POD/acl/doc.ttl.acl
→ 204 No Content
Accept-Put: application/ld+json, application/json, text/turtle, text/n3, */*

PUT $POD/acl/doc.ttl.acl
Content-Type: text/turtle

@prefix acl: <http://www.w3.org/ns/auth/acl#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
<#public> a acl:Authorization ; acl:agentClass foaf:Agent ;
  acl:accessTo <doc.ttl> ; acl:mode acl:Read .
→ 415 Unsupported Media Type
Accept-Put: application/ld+json, application/json
{"error":"Unsupported Media Type","message":"ACL resources must be sent as application/ld+json or application/json."}

jss-no-extension

A Turtle document without a file extension is served as application/octet-stream. A PUT with Content-Type: text/turtle to profile/card succeeds. Every GET then answers with the JSON-LD JSS stored, labeled application/octet-stream, whatever the Accept. HEAD says the same.

PUT $POD/ext/profile/card
Content-Type: text/turtle

<#me> <http://xmlns.com/foaf/0.1/name> "Alice" .
→ 201 Created

GET $POD/ext/profile/card
Accept: text/turtle
→ 200 OK
Content-Type: application/octet-stream
{"@context": {…}, "@id": "#me", "foaf:name": "Alice"}

The same PUT to profile/card.ttl is served as text/turtle.

Solid-Nextcloud

The Solid app at commit a7315d90 (its version 0.11.0), on Nextcloud 32.0.15 with SQLite. The app's lockfile pins pdsinterop/solid-crud 0.9.0, where most of these causes are, and pdsinterop/solid-auth 0.15.0. The test pod is apps/solid/~alice/storage/, with a root ACL that gives anyone full access.

IdCauseRequirement
nc-delete-all-valuesA deletion removes every value of the subject and predicateMUST (N3 Patch); definition (SPARQL Update)
nc-acl-linkEvery document's rel="acl" Link names its folder's ACLMUST (WAC)
nc-n3-last-tripleN3 Patch applies only the last triple of each formulaMUST (N3 Patch)
nc-acl-memberA folder holding only its ACL can't be deletedMUST
nc-head-204HEAD answers 204 where GET answers 404MUST (HEAD)
nc-concurrent-patchConcurrent PATCHes lose inserts answered 201None (HTTP semantics)
nc-put-typePUT ignores Content-Type, so a Turtle document without an extension can't be read as TurtleMUST
nc-reported-privatelyReported in privateHeld back

nc-delete-all-values

A deletion removes every value of the subject and predicate. A SPARQL Update DELETE DATA, or an N3 Patch's solid:deletes, removes every object of the subject and predicate it names, not the named triple alone. That holds for any predicate IRI with a / in it, and even when the named triple isn't there.

PUT $POD/del.ttl
Content-Type: text/turtle

<http://example.org/s> <http://example.org/p> <http://example.org/a>, <http://example.org/b> .
→ 201 Created

PATCH $POD/del.ttl
Content-Type: application/sparql-update

DELETE DATA { <http://example.org/s> <http://example.org/p> <http://example.org/a> . }
→ 201 Created

GET $POD/del.ttl
Accept: text/turtle
→ 200 OK
(empty: the triple with <http://example.org/b> is gone too)

A DELETE DATA of <s> <p> <zzz>, which isn't in the document, removes both values as well. With the predicate urn:example:q, which has no /, only the named triple goes.

Every document's rel="acl" Link names its folder's ACL. Every response carries Link: <.acl>; rel="acl", which for f/doc.ttl resolves to f/.acl. The server still enforces f/doc.ttl.acl. A client that writes a document's ACL where the Link says, as WAC requires, replaces the folder's ACL.

PUT $POD/acl/doc.ttl
PUT $POD/acl/other.ttl
→ 201 Created

HEAD $POD/acl/doc.ttl
→ 204 No Content
Link: <.acl>; rel="acl"

PUT $POD/acl/doc.ttl.acl
Content-Type: text/turtle

@prefix acl: <http://www.w3.org/ns/auth/acl#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
<#r> a acl:Authorization ; acl:agentClass foaf:Agent ;
  acl:accessTo <doc.ttl> ; acl:mode acl:Read .
→ 201 Created

GET $POD/acl/other.ttl
→ 403 Forbidden

GET $POD/acl/
→ 403 Forbidden

nc-n3-last-triple

N3 Patch applies only the last triple of each formula. With two triples in solid:inserts, only the second is stored; with two in solid:deletes, only the second is removed. The PATCH answers 201.

PUT $POD/n3.ttl
Content-Type: text/turtle
→ 201 Created

PATCH $POD/n3.ttl
Content-Type: text/n3

@prefix solid: <http://www.w3.org/ns/solid/terms#> .
_:p a solid:InsertDeletePatch ; solid:inserts {
  <http://example.org/a> <http://example.org/p> "one" .
  <http://example.org/b> <http://example.org/p> "two" .
} .
→ 201 Created

GET $POD/n3.ttl
Accept: text/turtle
→ 200 OK
<http://example.org/b> <http://example.org/p> "two" .

nc-acl-member

A folder holding only its ACL can't be deleted. The folder's listing names its .acl as a member (ldp:contains). A DELETE on a folder that holds nothing else answers 400 "not empty", and the folder and its ACL stay.

PUT $POD/only-acl/doc.ttl
Content-Type: text/turtle
→ 201 Created

PUT $POD/only-acl/.acl
Content-Type: text/turtle
(an Authorization for <./>)
→ 201 Created

DELETE $POD/only-acl/doc.ttl
→ 204 No Content

GET $POD/only-acl/
Accept: text/turtle
→ 200 OK
<> a ldp:BasicContainer ; ldp:contains <.acl> .

DELETE $POD/only-acl/
→ 400 Bad Request
Only empty containers can be deleted, "/only-acl/" is not empty

nc-head-204

HEAD answers 204 where GET answers 404. Every authorized HEAD answers 204 No Content, whatever GET answers: 404 for a resource that doesn't exist or was deleted, 200 for one that does, and 410, 307 or 308 from link metadata.

GET $POD/never.txt
→ 404 Not Found

HEAD $POD/never.txt
→ 204 No Content
Link: <.acl>; rel="acl"
WAC-Allow: user="read write append control",public="read write append control"

nc-concurrent-patch

Concurrent PATCHes lose inserts answered 201. Of ten PATCHes sent at once to one document, each inserting its own triple, each answers 201, or now and then 500 when another request holds the file's lock, and a few of the triples are stored.

for i in $(seq 1 10); do
  curl -s -o /dev/null -w '%{http_code}\n' -X PATCH "${POD}c.ttl" \
    -H 'Content-Type: application/sparql-update' \
    --data "INSERT DATA { <#a$i> <urn:ex:n> \"$i\" . };" &
done; wait
# 201 each, or now and then 500
curl -s -H 'Accept: text/turtle' "${POD}c.ttl"
# fewer than ten of the subjects

Sent one after the other, all ten are stored.

nc-put-type

PUT ignores Content-Type, so a Turtle document without an extension can't be read as Turtle. Nextcloud types a file by its extension, so profile/card is stored as application/octet-stream. A GET for Turtle has the file's format guessed, which gives one of two results:

PUT $POD/type/card
Content-Type: text/turtle

<#me> <http://xmlns.com/foaf/0.1/name> "Alice" .
→ 201 Created

GET $POD/type/card
Accept: text/turtle
→ 500 Internal Server Error
(log: Could not convert file "type/card" to format "turtle": Failed to parse statement on line 1)

PUT $POD/type/card2
Content-Type: text/turtle

@prefix foaf: <http://xmlns.com/foaf/0.1/> .
<#me> foaf:name "Alice" .
→ 201 Created

GET $POD/type/card2
Accept: text/turtle
→ 200 OK
<http://127.0.0.1/apps/solid/~alice/storage/type/card2#me> foaf:name "Alice" .

The same PUT to card.ttl is served as sent.

nc-reported-privately

Reported to the maintainers in private. It gets an entry like the others once a fixed release is out.