Skip to content

Commit 7ae2bcc

Browse files
authored
Merge pull request #1754 from nodeSolidServer/accept-headers
Accept-Patch Accept-Post Accept-Put headers
2 parents 7c8ccc6 + 4dc7849 commit 7ae2bcc

File tree

8 files changed

+78
-20
lines changed

8 files changed

+78
-20
lines changed

lib/create-app.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const corsSettings = cors({
3232
methods: [
3333
'OPTIONS', 'HEAD', 'GET', 'PATCH', 'POST', 'PUT', 'DELETE'
3434
],
35-
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',
35+
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',
3636
credentials: true,
3737
maxAge: 1728000,
3838
origin: true,

lib/handlers/get.js

+7
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,13 @@ async function handler (req, res, next) {
2727
const requestedType = negotiator.mediaType()
2828
const possibleRDFType = negotiator.mediaType(RDFs)
2929

30+
// deprecated kept for compatibility
3031
res.header('MS-Author-Via', 'SPARQL')
3132

33+
res.header('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match')
34+
res.header('Accept-Post', '*/*')
35+
if (!path.endsWith('/') && !glob.hasMagic(path)) res.header('Accept-Put', '*/*')
36+
3237
// Set live updates
3338
if (ldp.live) {
3439
res.header('Updates-Via', ldp.resourceMapper.resolveUrl(req.hostname).replace(/^http/, 'ws'))
@@ -49,6 +54,8 @@ async function handler (req, res, next) {
4954
try {
5055
ret = await ldp.get(options, req.accepts(['html', 'turtle', 'rdf+xml', 'n3', 'ld+json']) === 'html')
5156
} catch (err) {
57+
// set Accept-Put if container do not exist
58+
if (err.status === 404 && path.endsWith('/')) res.header('Accept-Put', 'text/turtle')
5259
// use globHandler if magic is detected
5360
if (err.status === 404 && glob.hasMagic(path)) {
5461
debug('forwarding to glob request')

lib/handlers/options.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module.exports = handler
88
function handler (req, res, next) {
99
linkServiceEndpoint(req, res)
1010
linkAuthProvider(req, res)
11-
linkSparqlEndpoint(res)
11+
linkAcceptEndpoint(res)
1212

1313
res.status(204)
1414

@@ -28,6 +28,8 @@ function linkServiceEndpoint (req, res) {
2828
addLink(res, serviceEndpoint, 'service')
2929
}
3030

31-
function linkSparqlEndpoint (res) {
32-
res.header('Accept-Patch', 'application/sparql-update')
31+
function linkAcceptEndpoint (res) {
32+
res.header('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match')
33+
res.header('Accept-Post', '*/*')
34+
res.header('Accept-Put', '*/*')
3335
}

lib/handlers/patch.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ function contentForNew (contentType) {
3939
// Handles a PATCH request
4040
async function patchHandler (req, res, next) {
4141
debug(`PATCH -- ${req.originalUrl}`)
42-
res.header('MS-Author-Via', 'SPARQL')
4342
try {
4443
// Obtain details of the target resource
4544
const ldp = req.app.locals.ldp
@@ -77,7 +76,7 @@ async function patchHandler (req, res, next) {
7776
if (!parsePatch) {
7877
throw error(415, `Unsupported patch content type: ${patch.contentType}`)
7978
}
80-
79+
res.header('Accept-Patch', patch.contentType) // is this needed ?
8180
// Parse the patch document and verify permissions
8281
const patchObject = await parsePatch(url, patch.uri, patch.text)
8382
await checkPermission(req, patchObject, resourceExists)

lib/handlers/put.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ const { stringToStream } = require('../utils')
88

99
async function handler (req, res, next) {
1010
debug(req.originalUrl)
11-
res.header('MS-Author-Via', 'SPARQL')
11+
// deprecated kept for compatibility
12+
res.header('MS-Author-Via', 'SPARQL') // is this needed ?
1213
const contentType = req.get('content-type')
1314

1415
// check whether a folder or resource with same name exists

test/integration/header-test.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('Header handler', () => {
2020
request = supertest(server)
2121
})
2222

23-
describe('MS-Author-Via', () => {
23+
describe('MS-Author-Via', () => { // deprecated
2424
describeHeaderTest('read/append for the public', {
2525
resource: '/public-ra',
2626
headers: {
@@ -30,6 +30,18 @@ describe('Header handler', () => {
3030
})
3131
})
3232

33+
describe('Accept-* for a resource document', () => {
34+
describeHeaderTest('read/append for the public', {
35+
resource: '/public-ra',
36+
headers: {
37+
'Accept-Patch': 'text/n3, application/sparql-update, application/sparql-update-single-match',
38+
'Accept-Post': '*/*',
39+
'Accept-Put': '*/*',
40+
'Access-Control-Expose-Headers': /(^|,\s*)Accept-Patch, Accept-Post, Accept-Put(,|$)/
41+
}
42+
})
43+
})
44+
3345
describe('WAC-Allow', () => {
3446
describeHeaderTest('read/append for the public', {
3547
resource: '/public-ra',

test/integration/http-test.js

+48-11
Original file line numberDiff line numberDiff line change
@@ -110,26 +110,32 @@ describe('HTTP APIs', function () {
110110
.expect('Access-Control-Allow-Origin', 'http://example.com')
111111
.expect('Access-Control-Allow-Credentials', 'true')
112112
.expect('Access-Control-Allow-Methods', 'OPTIONS,HEAD,GET,PATCH,POST,PUT,DELETE')
113-
.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')
113+
.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')
114114
.expect(204, done)
115115
})
116116

117-
describe('Accept-Patch header', function () {
117+
describe('Accept-* headers', function () {
118118
it('should be present for resources', function (done) {
119119
server.options('/sampleContainer/example1.ttl')
120-
.expect('Accept-Patch', 'application/sparql-update')
120+
.expect('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match')
121+
.expect('Accept-Post', '*/*')
122+
.expect('Accept-Put', '*/*')
121123
.expect(204, done)
122124
})
123125

124126
it('should be present for containers', function (done) {
125127
server.options('/sampleContainer/')
126-
.expect('Accept-Patch', 'application/sparql-update')
128+
.expect('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match')
129+
.expect('Accept-Post', '*/*')
130+
.expect('Accept-Put', '*/*')
127131
.expect(204, done)
128132
})
129133

130134
it('should be present for non-rdf resources', function (done) {
131135
server.options('/sampleContainer/solid.png')
132-
.expect('Accept-Patch', 'application/sparql-update')
136+
.expect('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match')
137+
.expect('Accept-Post', '*/*')
138+
.expect('Accept-Put', '*/*')
133139
.expect(204, done)
134140
})
135141
})
@@ -329,6 +335,11 @@ describe('HTTP APIs', function () {
329335
server.get('/invalidfile.foo')
330336
.expect(404, done)
331337
})
338+
it('should return 404 for non-existent container', function (done) { // alain
339+
server.get('/inexistant/')
340+
.expect('Accept-Put', 'text/turtle')
341+
.expect(404, done)
342+
})
332343
it('should return basic container link for directories', function (done) {
333344
server.get('/')
334345
.expect('Link', /http:\/\/www.w3.org\/ns\/ldp#BasicContainer/)
@@ -411,13 +422,39 @@ describe('HTTP APIs', function () {
411422
.expect('content-type', /text\/turtle/)
412423
.end(done)
413424
})
414-
it('should still redirect to the right container URI if missing / and HTML is requested',
415-
function (done) {
416-
server.get('/sampleContainer')
417-
.set('accept', 'text/html')
418-
.expect('location', /\/sampleContainer\//)
419-
.expect(301, done)
425+
it('should still redirect to the right container URI if missing / and HTML is requested', function (done) {
426+
server.get('/sampleContainer')
427+
.set('accept', 'text/html')
428+
.expect('location', /\/sampleContainer\//)
429+
.expect(301, done)
430+
})
431+
432+
describe('Accept-* headers', function () {
433+
it('should return 404 for non-existent resource', function (done) {
434+
server.get('/invalidfile.foo')
435+
.expect('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match')
436+
.expect('Accept-Post', '*/*')
437+
.expect('Accept-put', '*/*')
438+
.expect(404, done)
439+
})
440+
it('Accept-Put=text/turtle for non-existent container', function (done) {
441+
server.get('/inexistant/')
442+
.expect('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match')
443+
.expect('Accept-Post', '*/*')
444+
.expect('Accept-Put', 'text/turtle')
445+
.expect(404, done)
420446
})
447+
it('Accept-Put header do not exist for existing container', (done) => {
448+
server.get('/sampleContainer/')
449+
.expect(200)
450+
.expect('Accept-Patch', 'text/n3, application/sparql-update, application/sparql-update-single-match')
451+
.expect('Accept-Post', '*/*')
452+
.expect((res) => {
453+
if (res.headers['Accept-Put']) return done(new Error('Accept-Put header should not exist'))
454+
})
455+
.end(done)
456+
})
457+
})
421458
})
422459

423460
describe('HEAD API', function () {

test/integration/patch-test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const serverOptions = {
2222
forceUser: `${serverUri}/profile/card#me`
2323
}
2424

25-
describe('PATCH', () => {
25+
describe('PATCH through text/n3', () => {
2626
let request
2727
let server
2828

0 commit comments

Comments
 (0)