diff --git a/lib/create-app.js b/lib/create-app.js index 34b9e17e..f384634a 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 63003835..d370dc16 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 def5dfc4..70d0eca1 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 419f35dd..f0dd8103 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 3ea55514..ca5aff50 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 cbe7d5bc..4ca15bb9 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 () {