From 399308c07aa8906087234f7eb7042a7ad8f3ff05 Mon Sep 17 00:00:00 2001 From: bourgeoa Date: Mon, 5 Feb 2024 17:41:58 +0100 Subject: [PATCH 1/5] missing Accept-Patch/Accept-Post headers --- lib/handlers/get.js | 4 ++++ test/integration/header-test.js | 12 +++++++++++- test/integration/patch-test.js | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/handlers/get.js b/lib/handlers/get.js index f4aed8eeb..63003835f 100644 --- a/lib/handlers/get.js +++ b/lib/handlers/get.js @@ -27,8 +27,12 @@ async function handler (req, res, next) { const requestedType = negotiator.mediaType() const possibleRDFType = negotiator.mediaType(RDFs) + // deprecated kept for compatibility res.header('MS-Author-Via', 'SPARQL') + res.header('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match') + res.header('Accept-Post', '*/*') + // Set live updates if (ldp.live) { res.header('Updates-Via', ldp.resourceMapper.resolveUrl(req.hostname).replace(/^http/, 'ws')) diff --git a/test/integration/header-test.js b/test/integration/header-test.js index e535d7a1f..0659364fd 100644 --- a/test/integration/header-test.js +++ b/test/integration/header-test.js @@ -20,7 +20,7 @@ describe('Header handler', () => { request = supertest(server) }) - describe('MS-Author-Via', () => { + describe('MS-Author-Via', () => { // deprecated describeHeaderTest('read/append for the public', { resource: '/public-ra', headers: { @@ -30,6 +30,16 @@ describe('Header handler', () => { }) }) + describe('Accept-Patch', () => { + describeHeaderTest('read/append for the public', { + resource: '/public-ra', + headers: { + 'Accept-Patch': 'text/n3, application/sparql-update, application/sparql-update-single-match', + 'Access-Control-Expose-Headers': /(^|,\s*)Accept-Patch(,|$)/ + } + }) + }) + describe('WAC-Allow', () => { describeHeaderTest('read/append for the public', { resource: '/public-ra', diff --git a/test/integration/patch-test.js b/test/integration/patch-test.js index 34f9d3519..53ddb90e3 100644 --- a/test/integration/patch-test.js +++ b/test/integration/patch-test.js @@ -22,7 +22,7 @@ const serverOptions = { forceUser: `${serverUri}/profile/card#me` } -describe('PATCH', () => { +describe('PATCH through text/n3', () => { let request let server From 777d037a0d17c832e9a40229c6dd451ac089ebf6 Mon Sep 17 00:00:00 2001 From: bourgeoa Date: Mon, 5 Feb 2024 17:50:38 +0100 Subject: [PATCH 2/5] add GET accept-post test --- test/integration/header-test.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/integration/header-test.js b/test/integration/header-test.js index 0659364fd..3ea555146 100644 --- a/test/integration/header-test.js +++ b/test/integration/header-test.js @@ -40,6 +40,16 @@ describe('Header handler', () => { }) }) + describe('Accept-Post', () => { + describeHeaderTest('read/append for the public', { + resource: '/public-ra', + headers: { + 'Accept-Post': '*/*', + 'Access-Control-Expose-Headers': /(^|,\s*)Accept-Post(,|$)/ + } + }) + }) + describe('WAC-Allow', () => { describeHeaderTest('read/append for the public', { resource: '/public-ra', From ab0545f1c8d1967dcc3aad8f481375007ac8588f Mon Sep 17 00:00:00 2001 From: bourgeoa Date: Mon, 5 Feb 2024 17:59:04 +0100 Subject: [PATCH 3/5] cleaning --- lib/handlers/patch.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/handlers/patch.js b/lib/handlers/patch.js index 5dac51d3d..15535e917 100644 --- a/lib/handlers/patch.js +++ b/lib/handlers/patch.js @@ -39,7 +39,6 @@ function contentForNew (contentType) { // Handles a PATCH request async function patchHandler (req, res, next) { debug(`PATCH -- ${req.originalUrl}`) - res.header('MS-Author-Via', 'SPARQL') try { // Obtain details of the target resource const ldp = req.app.locals.ldp @@ -70,7 +69,7 @@ async function patchHandler (req, res, next) { if (!parsePatch) { throw error(415, `Unsupported patch content type: ${patch.contentType}`) } - + res.header('Accept-Patch', patch.contentType) // is this needed ? // Parse the patch document and verify permissions const patchObject = await parsePatch(url, patch.uri, patch.text) await checkPermission(req, patchObject, resourceExists) From 37173c10a367f76975343c37ded22ca2fb7eb7c7 Mon Sep 17 00:00:00 2001 From: bourgeoa Date: Tue, 6 Feb 2024 19:38:52 +0100 Subject: [PATCH 4/5] Accept-Put header --- lib/create-app.js | 2 +- lib/handlers/get.js | 3 ++ lib/handlers/options.js | 8 +++-- lib/handlers/put.js | 3 +- test/integration/header-test.js | 14 ++------ test/integration/http-test.js | 59 +++++++++++++++++++++++++++------ 6 files changed, 62 insertions(+), 27 deletions(-) diff --git a/lib/create-app.js b/lib/create-app.js index 34b9e17eb..f384634ac 100644 --- a/lib/create-app.js +++ b/lib/create-app.js @@ -32,7 +32,7 @@ const corsSettings = cors({ methods: [ 'OPTIONS', 'HEAD', 'GET', 'PATCH', 'POST', 'PUT', 'DELETE' ], - exposedHeaders: 'Authorization, User, Location, Link, Vary, Last-Modified, ETag, Accept-Patch, Accept-Post, Updates-Via, Allow, WAC-Allow, Content-Length, WWW-Authenticate, MS-Author-Via, X-Powered-By', + exposedHeaders: 'Authorization, User, Location, Link, Vary, Last-Modified, ETag, Accept-Patch, Accept-Post, Accept-Put, Updates-Via, Allow, WAC-Allow, Content-Length, WWW-Authenticate, MS-Author-Via, X-Powered-By', credentials: true, maxAge: 1728000, origin: true, diff --git a/lib/handlers/get.js b/lib/handlers/get.js index 63003835f..d370dc161 100644 --- a/lib/handlers/get.js +++ b/lib/handlers/get.js @@ -32,6 +32,7 @@ async function handler (req, res, next) { res.header('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match') res.header('Accept-Post', '*/*') + if (!path.endsWith('/') && !glob.hasMagic(path)) res.header('Accept-Put', '*/*') // Set live updates if (ldp.live) { @@ -53,6 +54,8 @@ async function handler (req, res, next) { try { ret = await ldp.get(options, req.accepts(['html', 'turtle', 'rdf+xml', 'n3', 'ld+json']) === 'html') } catch (err) { + // set Accept-Put if container do not exist + if (err.status === 404 && path.endsWith('/')) res.header('Accept-Put', 'text/turtle') // use globHandler if magic is detected if (err.status === 404 && glob.hasMagic(path)) { debug('forwarding to glob request') diff --git a/lib/handlers/options.js b/lib/handlers/options.js index def5dfc4d..70d0eca17 100644 --- a/lib/handlers/options.js +++ b/lib/handlers/options.js @@ -8,7 +8,7 @@ module.exports = handler function handler (req, res, next) { linkServiceEndpoint(req, res) linkAuthProvider(req, res) - linkSparqlEndpoint(res) + linkAcceptEndpoint(res) res.status(204) @@ -28,6 +28,8 @@ function linkServiceEndpoint (req, res) { addLink(res, serviceEndpoint, 'service') } -function linkSparqlEndpoint (res) { - res.header('Accept-Patch', 'application/sparql-update') +function linkAcceptEndpoint (res) { + res.header('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match') + res.header('Accept-Post', '*/*') + res.header('Accept-Put', '*/*') } diff --git a/lib/handlers/put.js b/lib/handlers/put.js index 419f35dd4..f0dd81038 100644 --- a/lib/handlers/put.js +++ b/lib/handlers/put.js @@ -8,7 +8,8 @@ const { stringToStream } = require('../utils') async function handler (req, res, next) { debug(req.originalUrl) - res.header('MS-Author-Via', 'SPARQL') + // deprecated kept for compatibility + res.header('MS-Author-Via', 'SPARQL') // is this needed ? const contentType = req.get('content-type') // check for valid rdf content for auxiliary resource and /profile/card diff --git a/test/integration/header-test.js b/test/integration/header-test.js index 3ea555146..ca5aff503 100644 --- a/test/integration/header-test.js +++ b/test/integration/header-test.js @@ -30,22 +30,14 @@ describe('Header handler', () => { }) }) - describe('Accept-Patch', () => { + describe('Accept-* for a resource document', () => { describeHeaderTest('read/append for the public', { resource: '/public-ra', headers: { 'Accept-Patch': 'text/n3, application/sparql-update, application/sparql-update-single-match', - 'Access-Control-Expose-Headers': /(^|,\s*)Accept-Patch(,|$)/ - } - }) - }) - - describe('Accept-Post', () => { - describeHeaderTest('read/append for the public', { - resource: '/public-ra', - headers: { 'Accept-Post': '*/*', - 'Access-Control-Expose-Headers': /(^|,\s*)Accept-Post(,|$)/ + 'Accept-Put': '*/*', + 'Access-Control-Expose-Headers': /(^|,\s*)Accept-Patch, Accept-Post, Accept-Put(,|$)/ } }) }) diff --git a/test/integration/http-test.js b/test/integration/http-test.js index cbe7d5bc9..4ca15bb99 100644 --- a/test/integration/http-test.js +++ b/test/integration/http-test.js @@ -110,26 +110,32 @@ describe('HTTP APIs', function () { .expect('Access-Control-Allow-Origin', 'http://example.com') .expect('Access-Control-Allow-Credentials', 'true') .expect('Access-Control-Allow-Methods', 'OPTIONS,HEAD,GET,PATCH,POST,PUT,DELETE') - .expect('Access-Control-Expose-Headers', 'Authorization, User, Location, Link, Vary, Last-Modified, ETag, Accept-Patch, Accept-Post, Updates-Via, Allow, WAC-Allow, Content-Length, WWW-Authenticate, MS-Author-Via, X-Powered-By') + .expect('Access-Control-Expose-Headers', 'Authorization, User, Location, Link, Vary, Last-Modified, ETag, Accept-Patch, Accept-Post, Accept-Put, Updates-Via, Allow, WAC-Allow, Content-Length, WWW-Authenticate, MS-Author-Via, X-Powered-By') .expect(204, done) }) - describe('Accept-Patch header', function () { + describe('Accept-* headers', function () { it('should be present for resources', function (done) { server.options('/sampleContainer/example1.ttl') - .expect('Accept-Patch', 'application/sparql-update') + .expect('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match') + .expect('Accept-Post', '*/*') + .expect('Accept-Put', '*/*') .expect(204, done) }) it('should be present for containers', function (done) { server.options('/sampleContainer/') - .expect('Accept-Patch', 'application/sparql-update') + .expect('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match') + .expect('Accept-Post', '*/*') + .expect('Accept-Put', '*/*') .expect(204, done) }) it('should be present for non-rdf resources', function (done) { server.options('/sampleContainer/solid.png') - .expect('Accept-Patch', 'application/sparql-update') + .expect('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match') + .expect('Accept-Post', '*/*') + .expect('Accept-Put', '*/*') .expect(204, done) }) }) @@ -314,6 +320,11 @@ describe('HTTP APIs', function () { server.get('/invalidfile.foo') .expect(404, done) }) + it('should return 404 for non-existent container', function (done) { // alain + server.get('/inexistant/') + .expect('Accept-Put', 'text/turtle') + .expect(404, done) + }) it('should return basic container link for directories', function (done) { server.get('/') .expect('Link', /http:\/\/www.w3.org\/ns\/ldp#BasicContainer/) @@ -396,13 +407,39 @@ describe('HTTP APIs', function () { .expect('content-type', /text\/turtle/) .end(done) }) - it('should still redirect to the right container URI if missing / and HTML is requested', - function (done) { - server.get('/sampleContainer') - .set('accept', 'text/html') - .expect('location', /\/sampleContainer\//) - .expect(301, done) + it('should still redirect to the right container URI if missing / and HTML is requested', function (done) { + server.get('/sampleContainer') + .set('accept', 'text/html') + .expect('location', /\/sampleContainer\//) + .expect(301, done) + }) + + describe('Accept-* headers', function () { + it('should return 404 for non-existent resource', function (done) { + server.get('/invalidfile.foo') + .expect('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match') + .expect('Accept-Post', '*/*') + .expect('Accept-put', '*/*') + .expect(404, done) + }) + it('Accept-Put=text/turtle for non-existent container', function (done) { + server.get('/inexistant/') + .expect('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match') + .expect('Accept-Post', '*/*') + .expect('Accept-Put', 'text/turtle') + .expect(404, done) }) + it('Accept-Put header do not exist for existing container', (done) => { + server.get('/sampleContainer/') + .expect(200) + .expect('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match') + .expect('Accept-Post', '*/*') + .expect((res) => { + if (res.headers['Accept-Put']) return done(new Error('Accept-Put header should not exist')) + }) + .end(done) + }) + }) }) describe('HEAD API', function () { From 4dc7849c1c8af58651d7af85659d6217a7339438 Mon Sep 17 00:00:00 2001 From: Alain Bourgeois Date: Tue, 6 Feb 2024 23:11:25 +0100 Subject: [PATCH 5/5] Update put.js --- lib/handlers/put.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/handlers/put.js b/lib/handlers/put.js index ebff69e97..740bf346a 100644 --- a/lib/handlers/put.js +++ b/lib/handlers/put.js @@ -8,13 +8,8 @@ const { stringToStream } = require('../utils') async function handler (req, res, next) { debug(req.originalUrl) - // deprecated kept for compatibility res.header('MS-Author-Via', 'SPARQL') // is this needed ? - - - - const contentType = req.get('content-type') // check whether a folder or resource with same name exists