From 3b3ba5845637a71d0fc265cfa20b1db4ad8cd643 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Mon, 12 Nov 2018 15:08:19 +0100 Subject: [PATCH 01/23] First iteration of simple validation --- lib/handlers/validate.js | 28 ++++++++++++++++++++++++++++ lib/ldp-middleware.js | 7 ++++--- lib/ldp.js | 4 ++++ 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 lib/handlers/validate.js diff --git a/lib/handlers/validate.js b/lib/handlers/validate.js new file mode 100644 index 000000000..57134153f --- /dev/null +++ b/lib/handlers/validate.js @@ -0,0 +1,28 @@ +module.exports = handler + +const bodyParser = require('body-parser') +const error = require('../http-error') +const LDP = require('../ldp') +const $rdf = require('rdflib') +const debug = require('../debug') + +function handler (req, res, next) { + bodyParser.text({ type: () => true })(req, res, () => validate(req, res, next)) +} + +function validate (req, res, next) { + const contentType = req.get('content-type') + if (!LDP.mimetypeIsRdf(contentType)) { + return next() + } + + const resourceGraph = $rdf.graph() + const requestUri = `${req.protocol}//${req.get('host')}${req.originalUrl}` + try { + $rdf.parse(req.body, resourceGraph, requestUri, contentType) + } catch (err) { + debug.handlers('VALIDATE -- Error parsing data: ' + err) + return next(error(400, 'Unable to parse the body of request')) + } + next() +} diff --git a/lib/ldp-middleware.js b/lib/ldp-middleware.js index 1b35d56ad..67c57aa8c 100644 --- a/lib/ldp-middleware.js +++ b/lib/ldp-middleware.js @@ -10,6 +10,7 @@ const del = require('./handlers/delete') const patch = require('./handlers/patch') const index = require('./handlers/index') const copy = require('./handlers/copy') +const validate = require('./handlers/validate') function LdpMiddleware (corsSettings) { const router = express.Router('/') @@ -23,9 +24,9 @@ function LdpMiddleware (corsSettings) { router.copy('/*', allow('Write'), copy) router.get('/*', index, allow('Read'), header.addPermissions, get) - router.post('/*', allow('Append'), post) - router.patch('/*', allow('Append'), patch) - router.put('/*', allow('Write'), put) + router.post('/*', allow('Append'), validate, post) + router.patch('/*', allow('Append'), validate, patch) + router.put('/*', allow('Write'), validate, put) router.delete('/*', allow('Write'), del) return router diff --git a/lib/ldp.js b/lib/ldp.js index 15e05c37d..e61203814 100644 --- a/lib/ldp.js +++ b/lib/ldp.js @@ -451,6 +451,10 @@ class LDP { } return ensureNotExists(this, path.join(containerURI, filename)) } + + static mimetypeIsRdf (mimeType) { + return RDF_MIME_TYPES.indexOf(mimeType) !== -1 + } } module.exports = LDP module.exports.RDF_MIME_TYPES = RDF_MIME_TYPES From ebfe3f3c4946d3d366f8d736cda47768809bb35f Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Tue, 13 Nov 2018 13:17:12 +0100 Subject: [PATCH 02/23] Just a minor commit --- lib/ldp-middleware.js | 8 +++--- test/utils.js | 57 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/lib/ldp-middleware.js b/lib/ldp-middleware.js index 67c57aa8c..cf4904cf2 100644 --- a/lib/ldp-middleware.js +++ b/lib/ldp-middleware.js @@ -10,7 +10,7 @@ const del = require('./handlers/delete') const patch = require('./handlers/patch') const index = require('./handlers/index') const copy = require('./handlers/copy') -const validate = require('./handlers/validate') +// const validate = require('./handlers/validate') function LdpMiddleware (corsSettings) { const router = express.Router('/') @@ -24,9 +24,9 @@ function LdpMiddleware (corsSettings) { router.copy('/*', allow('Write'), copy) router.get('/*', index, allow('Read'), header.addPermissions, get) - router.post('/*', allow('Append'), validate, post) - router.patch('/*', allow('Append'), validate, patch) - router.put('/*', allow('Write'), validate, put) + router.post('/*', allow('Append'), post) + router.patch('/*', allow('Append'), patch) + router.put('/*', allow('Write'), put) router.delete('/*', allow('Write'), del) return router diff --git a/test/utils.js b/test/utils.js index ae181f8cf..f3df05f63 100644 --- a/test/utils.js +++ b/test/utils.js @@ -1,8 +1,10 @@ -var fs = require('fs-extra') -var rimraf = require('rimraf') -var path = require('path') +const fs = require('fs-extra') +const rimraf = require('rimraf') +const path = require('path') const OIDCProvider = require('@solid/oidc-op') const dns = require('dns') +const ldnode = require('../index') +const supertest = require('supertest') const TEST_HOSTS = ['nic.localhost', 'tim.localhost', 'nicola.localhost'] @@ -80,3 +82,52 @@ exports.loadProvider = function loadProvider (configPath) { return provider.initializeKeyChain(config.keys) }) } + +exports.createServer = createServer +function createServer (options) { + return ldnode.createServer(options) +} + +exports.setupSuperServer = setupSuperServer +function setupSuperServer (options) { + const ldpServer = createServer(options) + return supertest(ldpServer) +} + +/** + * Creates a new test basic container via an LDP POST + * (located in `test/resources/{containerName}`) + * @method createTestContainer + * @param server {supertest} An instance of a supertest server + * @param containerName {String} Container name used as slug, no leading `/` + * @return {Promise} Promise obj, for use with Mocha's `before()` etc + */ +exports.createTestContainer = function createTestContainer (server, containerName) { + return new Promise(function (resolve, reject) { + server.post('/') + .set('content-type', 'text/turtle') + .set('slug', containerName) + .set('link', '; rel="type"') + .set('content-type', 'text/turtle') + .end(function (error, res) { + error ? reject(error) : resolve(res) + }) + }) +} + +/** + * Creates a new turtle test resource via an LDP PUT + * (located in `test/resources/{resourceName}`) + * @method createTestResource + * @param resourceName {String} Resource name (should have a leading `/`) + * @return {Promise} Promise obj, for use with Mocha's `before()` etc + */ +exports.createTestResource = function createTestResource (server, resourceName) { + return new Promise(function (resolve, reject) { + server.put(resourceName) + .set('content-type', 'text/turtle') + .end(function (error, res) { + error ? reject(error) : resolve(res) + }) + }) +} From c541613369b48665ba23c3b0a8a95392aeac1f8d Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Wed, 14 Nov 2018 12:37:17 +0100 Subject: [PATCH 03/23] Moving code around, to handle streams correctly And make old tests pass --- lib/handlers/put.js | 43 ++++++++++++++++ lib/handlers/validate.js | 28 ---------- lib/ldp-middleware.js | 1 - lib/ldp.js | 13 ++++- test/integration/validate-tts.js | 59 ++++++++++++++++++++++ test/resources/sampleContainer/invalid.ttl | 13 +++++ 6 files changed, 127 insertions(+), 30 deletions(-) delete mode 100644 lib/handlers/validate.js create mode 100644 test/integration/validate-tts.js create mode 100644 test/resources/sampleContainer/invalid.ttl diff --git a/lib/handlers/put.js b/lib/handlers/put.js index af9110ba9..7a34e8797 100644 --- a/lib/handlers/put.js +++ b/lib/handlers/put.js @@ -1,5 +1,6 @@ module.exports = handler +const bodyParser = require('body-parser') const debug = require('debug')('solid:put') const getContentType = require('../utils').getContentType @@ -20,3 +21,45 @@ async function handler (req, res, next) { return next(err) } } + +// function handler (req, res, next) { +// const ldp = req.app.locals.ldp +// debug(req.originalUrl) +// res.header('MS-Author-Via', 'SPARQL') +// +// const contentType = req.get('content-type') +// if (ldp.mimetypeIsRdf(contentType)) { +// return bodyParser.text({ type: () => true })(req, res, () => putText(req, res, next)) +// } +// return putStream(req, res, next) +// } +// +// function putText (req, res, next) { +// const ldp = req.app.locals.ldp +// const contentType = req.get('content-type') +// const requestUri = `${req.protocol}//${req.get('host')}${req.originalUrl}` +// if (ldp.isValidRdf(req.body, requestUri, contentType)) { +// return ldp.putText(req.hostname, req.path, req.body, handleCallback(res, next)) +// } +// next(error(400, 'RDF file contains invalid syntax')) +// } +// +// function putStream (req, res, next) { +// const ldp = req.app.locals.ldp +// ldp.putStream(req.hostname, req.path, req, handleCallback(res, next)) +// } +// +// function handleCallback (res, next) { +// return function (err) { +// if (err) { +// debug('error putting the file:' + err.message) +// err.message = 'Can\'t write file: ' + err.message +// return next(err) +// } +// +// debug('succeded putting the file') +// +// res.sendStatus(201) +// return next() +// } +// } diff --git a/lib/handlers/validate.js b/lib/handlers/validate.js deleted file mode 100644 index 57134153f..000000000 --- a/lib/handlers/validate.js +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = handler - -const bodyParser = require('body-parser') -const error = require('../http-error') -const LDP = require('../ldp') -const $rdf = require('rdflib') -const debug = require('../debug') - -function handler (req, res, next) { - bodyParser.text({ type: () => true })(req, res, () => validate(req, res, next)) -} - -function validate (req, res, next) { - const contentType = req.get('content-type') - if (!LDP.mimetypeIsRdf(contentType)) { - return next() - } - - const resourceGraph = $rdf.graph() - const requestUri = `${req.protocol}//${req.get('host')}${req.originalUrl}` - try { - $rdf.parse(req.body, resourceGraph, requestUri, contentType) - } catch (err) { - debug.handlers('VALIDATE -- Error parsing data: ' + err) - return next(error(400, 'Unable to parse the body of request')) - } - next() -} diff --git a/lib/ldp-middleware.js b/lib/ldp-middleware.js index cf4904cf2..1b35d56ad 100644 --- a/lib/ldp-middleware.js +++ b/lib/ldp-middleware.js @@ -10,7 +10,6 @@ const del = require('./handlers/delete') const patch = require('./handlers/patch') const index = require('./handlers/index') const copy = require('./handlers/copy') -// const validate = require('./handlers/validate') function LdpMiddleware (corsSettings) { const router = express.Router('/') diff --git a/lib/ldp.js b/lib/ldp.js index e61203814..001f0559e 100644 --- a/lib/ldp.js +++ b/lib/ldp.js @@ -203,6 +203,17 @@ class LDP { return await this.put(path, stream, contentType) } + // isValidRdf (body, requestUri, contentType) { + // const resourceGraph = $rdf.graph() + // try { + // $rdf.parse(body, resourceGraph, requestUri, contentType) + // } catch (err) { + // debug.handlers('VALIDATE -- Error parsing data: ' + err) + // return false + // } + // return true + // } + async put (url, stream, contentType) { // PUT requests not supported on containers. Use POST instead if ((url.url || url).endsWith('/')) { @@ -452,7 +463,7 @@ class LDP { return ensureNotExists(this, path.join(containerURI, filename)) } - static mimetypeIsRdf (mimeType) { + mimetypeIsRdf (mimeType) { return RDF_MIME_TYPES.indexOf(mimeType) !== -1 } } diff --git a/test/integration/validate-tts.js b/test/integration/validate-tts.js new file mode 100644 index 000000000..0d7e42d32 --- /dev/null +++ b/test/integration/validate-tts.js @@ -0,0 +1,59 @@ +const fs = require('fs') +const path = require('path') +const { setupSuperServer } = require('../utils') + +const server = setupSuperServer({ + live: true, + dataBrowserPath: 'default', + root: path.join(__dirname, '../resources'), + auth: 'oidc', + webid: false +}) + +describe('Validate HTTP requests with Turtle syntax', function () { + describe('PUT API', function () { + const putRequestBody = fs.readFileSync(path.join(__dirname, '../resources/sampleContainer/invalid.ttl'), { + 'encoding': 'utf8' + }) + it('should return 400', function (done) { + server.put('/put-resource-1.ttl') + .send(putRequestBody) + .set('content-type', 'text/turtle') + .expect(400, done) + }) + }) + + // describe('POST (multipart)', function () { + // it('should create as many files as the ones passed in multipart', + // function (done) { + // server.post('/sampleContainer/') + // .attach('timbl', path.join(__dirname, '../resources/timbl.jpg')) + // .attach('nicola', path.join(__dirname, '../resources/nicola.jpg')) + // .expect(200) + // .end(function (err) { + // if (err) return done(err) + // + // var sizeNicola = fs.statSync(path.join(__dirname, + // '../resources/nicola.jpg')).size + // var sizeTim = fs.statSync(path.join(__dirname, '../resources/timbl.jpg')).size + // var sizeNicolaLocal = fs.statSync(path.join(__dirname, + // '../resources/sampleContainer/nicola.jpg')).size + // var sizeTimLocal = fs.statSync(path.join(__dirname, + // '../resources/sampleContainer/timbl.jpg')).size + // + // if (sizeNicola === sizeNicolaLocal && sizeTim === sizeTimLocal) { + // return done() + // } else { + // return done(new Error('Either the size (remote/local) don\'t match or files are not stored')) + // } + // }) + // }) + // after(function () { + // // Clean up after POST (multipart) API tests + // return Promise.all([ + // rm('/sampleContainer/nicola.jpg'), + // rm('/sampleContainer/timbl.jpg') + // ]) + // }) + // }) +}) diff --git a/test/resources/sampleContainer/invalid.ttl b/test/resources/sampleContainer/invalid.ttl new file mode 100644 index 000000000..a2bc6473c --- /dev/null +++ b/test/resources/sampleContainer/invalid.ttl @@ -0,0 +1,13 @@ +@prefix ldp: . +@prefix o: . + + + test o:NetWorth; + o:netWorthOf ; + o:asset + , + ; + o:liability + , + , + . From ea9b40c287cd63731efafb0f7ffc69e1cb66e873 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Wed, 14 Nov 2018 13:17:03 +0100 Subject: [PATCH 04/23] Adding test for Patch But no actual implementation in patch handler yet --- test/integration/validate-tts.js | 65 +++++++------------ .../invalid.ttl => invalid1.ttl} | 0 test/resources/invalid2.ttl | 9 +++ test/utils.js | 38 ----------- 4 files changed, 34 insertions(+), 78 deletions(-) rename test/resources/{sampleContainer/invalid.ttl => invalid1.ttl} (100%) create mode 100644 test/resources/invalid2.ttl diff --git a/test/integration/validate-tts.js b/test/integration/validate-tts.js index 0d7e42d32..69551554a 100644 --- a/test/integration/validate-tts.js +++ b/test/integration/validate-tts.js @@ -10,50 +10,35 @@ const server = setupSuperServer({ webid: false }) -describe('Validate HTTP requests with Turtle syntax', function () { - describe('PUT API', function () { - const putRequestBody = fs.readFileSync(path.join(__dirname, '../resources/sampleContainer/invalid.ttl'), { - 'encoding': 'utf8' +const invalidTurtleBody = fs.readFileSync(path.join(__dirname, '../resources/invalid1.ttl'), { + 'encoding': 'utf8' +}) + +describe('HTTP requests with invalid Turtle syntax', () => { + describe('PUT API', () => { + it('should return 400', (done) => { + server.put('/should-not-be-created.ttl') + .send(invalidTurtleBody) + .set('content-type', 'text/turtle') + .expect(400, done) }) - it('should return 400', function (done) { - server.put('/put-resource-1.ttl') - .send(putRequestBody) + }) + + describe.skip('PATCH API', () => { + it('should return 400', (done) => { // TODO: This returns 415 right now + server.patch('/patch-1-initial.ttl') + .send(invalidTurtleBody) .set('content-type', 'text/turtle') .expect(400, done) }) }) - // describe('POST (multipart)', function () { - // it('should create as many files as the ones passed in multipart', - // function (done) { - // server.post('/sampleContainer/') - // .attach('timbl', path.join(__dirname, '../resources/timbl.jpg')) - // .attach('nicola', path.join(__dirname, '../resources/nicola.jpg')) - // .expect(200) - // .end(function (err) { - // if (err) return done(err) - // - // var sizeNicola = fs.statSync(path.join(__dirname, - // '../resources/nicola.jpg')).size - // var sizeTim = fs.statSync(path.join(__dirname, '../resources/timbl.jpg')).size - // var sizeNicolaLocal = fs.statSync(path.join(__dirname, - // '../resources/sampleContainer/nicola.jpg')).size - // var sizeTimLocal = fs.statSync(path.join(__dirname, - // '../resources/sampleContainer/timbl.jpg')).size - // - // if (sizeNicola === sizeNicolaLocal && sizeTim === sizeTimLocal) { - // return done() - // } else { - // return done(new Error('Either the size (remote/local) don\'t match or files are not stored')) - // } - // }) - // }) - // after(function () { - // // Clean up after POST (multipart) API tests - // return Promise.all([ - // rm('/sampleContainer/nicola.jpg'), - // rm('/sampleContainer/timbl.jpg') - // ]) - // }) - // }) + describe.skip('POST API (multipart)', () => { // TODO: Is this something we should validate? + it('should create as many files as the ones passed in multipart', (done) => { + server.post('/') + .attach('timbl', path.join(__dirname, '../resources/invalid1.ttl')) + .attach('nicola', path.join(__dirname, '../resources/invalid2.ttl')) + .expect(400, done) + }) + }) }) diff --git a/test/resources/sampleContainer/invalid.ttl b/test/resources/invalid1.ttl similarity index 100% rename from test/resources/sampleContainer/invalid.ttl rename to test/resources/invalid1.ttl diff --git a/test/resources/invalid2.ttl b/test/resources/invalid2.ttl new file mode 100644 index 000000000..74afdb8bb --- /dev/null +++ b/test/resources/invalid2.ttl @@ -0,0 +1,9 @@ +@prefix txn: . +@prefix srv: . +@prefix log: . +@prefix xsd: . + +txn:123 invalid log:Transaction ; + log:processedBy srv:A ; + log:processedAt "2015-10-16T10:22:23"^^xsd:dateTime ; + log:statusCode 200 . diff --git a/test/utils.js b/test/utils.js index f3df05f63..0a1e8c345 100644 --- a/test/utils.js +++ b/test/utils.js @@ -93,41 +93,3 @@ function setupSuperServer (options) { const ldpServer = createServer(options) return supertest(ldpServer) } - -/** - * Creates a new test basic container via an LDP POST - * (located in `test/resources/{containerName}`) - * @method createTestContainer - * @param server {supertest} An instance of a supertest server - * @param containerName {String} Container name used as slug, no leading `/` - * @return {Promise} Promise obj, for use with Mocha's `before()` etc - */ -exports.createTestContainer = function createTestContainer (server, containerName) { - return new Promise(function (resolve, reject) { - server.post('/') - .set('content-type', 'text/turtle') - .set('slug', containerName) - .set('link', '; rel="type"') - .set('content-type', 'text/turtle') - .end(function (error, res) { - error ? reject(error) : resolve(res) - }) - }) -} - -/** - * Creates a new turtle test resource via an LDP PUT - * (located in `test/resources/{resourceName}`) - * @method createTestResource - * @param resourceName {String} Resource name (should have a leading `/`) - * @return {Promise} Promise obj, for use with Mocha's `before()` etc - */ -exports.createTestResource = function createTestResource (server, resourceName) { - return new Promise(function (resolve, reject) { - server.put(resourceName) - .set('content-type', 'text/turtle') - .end(function (error, res) { - error ? reject(error) : resolve(res) - }) - }) -} From 18a7a049586de5e428baf45ec382e1c5d0a57685 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Thu, 15 Nov 2018 12:18:22 +0100 Subject: [PATCH 05/23] Modified simple validation to only affect ACL files --- lib/handlers/put.js | 7 +++++++ test/integration/validate-tts.js | 27 +++++++++++++++++---------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/handlers/put.js b/lib/handlers/put.js index 7a34e8797..1932735b1 100644 --- a/lib/handlers/put.js +++ b/lib/handlers/put.js @@ -33,6 +33,13 @@ async function handler (req, res, next) { // } // return putStream(req, res, next) // } +// +//} +// +//function isAclFile (req) { +// const originalUrlParts = req.originalUrl.split('.') +// return originalUrlParts[originalUrlParts.length - 1] === 'acl' +//} // // function putText (req, res, next) { // const ldp = req.app.locals.ldp diff --git a/test/integration/validate-tts.js b/test/integration/validate-tts.js index 69551554a..0d8693af0 100644 --- a/test/integration/validate-tts.js +++ b/test/integration/validate-tts.js @@ -16,29 +16,36 @@ const invalidTurtleBody = fs.readFileSync(path.join(__dirname, '../resources/inv describe('HTTP requests with invalid Turtle syntax', () => { describe('PUT API', () => { - it('should return 400', (done) => { - server.put('/should-not-be-created.ttl') + it('is allowed with invalid TTL files', (done) => { + server.put('/invalid1.ttl') + .send(invalidTurtleBody) + .set('content-type', 'text/turtle') + .expect(201, done) + }) + + it('is not allowed with invalid ACL files', (done) => { + server.put('/invalid1.ttl.acl') .send(invalidTurtleBody) .set('content-type', 'text/turtle') .expect(400, done) }) }) - describe.skip('PATCH API', () => { - it('should return 400', (done) => { // TODO: This returns 415 right now + describe('PATCH API', () => { + it('does not support patching of TTL files', (done) => { server.patch('/patch-1-initial.ttl') .send(invalidTurtleBody) .set('content-type', 'text/turtle') - .expect(400, done) + .expect(415, done) }) }) - describe.skip('POST API (multipart)', () => { // TODO: Is this something we should validate? - it('should create as many files as the ones passed in multipart', (done) => { + describe('POST API (multipart)', () => { + it('does not validate files that are posted', (done) => { server.post('/') - .attach('timbl', path.join(__dirname, '../resources/invalid1.ttl')) - .attach('nicola', path.join(__dirname, '../resources/invalid2.ttl')) - .expect(400, done) + .attach('invalid1', path.join(__dirname, '../resources/invalid1.ttl')) + .attach('invalid2', path.join(__dirname, '../resources/invalid2.ttl')) + .expect(200, done) }) }) }) From 0e3392f7d53d97ea8ed665b5b1cdaa873516d382 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Thu, 15 Nov 2018 12:35:47 +0100 Subject: [PATCH 06/23] Trying to make integrations tests a little easier to read --- test/integration/cors-proxy-test.js | 8 ++------ test/integration/errors-test.js | 16 +++------------- test/integration/formats-test.js | 6 ++---- test/integration/http-test.js | 6 ++---- test/integration/validate-tts.js | 4 ++-- test/utils.js | 2 +- 6 files changed, 12 insertions(+), 30 deletions(-) diff --git a/test/integration/cors-proxy-test.js b/test/integration/cors-proxy-test.js index 9bcc9ee48..c4f643e55 100644 --- a/test/integration/cors-proxy-test.js +++ b/test/integration/cors-proxy-test.js @@ -1,18 +1,14 @@ var assert = require('chai').assert -var supertest = require('supertest') var path = require('path') var nock = require('nock') -var { checkDnsSettings } = require('../utils') - -var ldnode = require('../../index') +var { checkDnsSettings, setupSupertestServer } = require('../utils') describe('CORS Proxy', () => { - var ldp = ldnode({ + var server = setupSupertestServer({ root: path.join(__dirname, '../resources'), corsProxy: '/proxy', webid: false }) - var server = supertest(ldp) before(checkDnsSettings) diff --git a/test/integration/errors-test.js b/test/integration/errors-test.js index 8b73d5e2f..effe9f44d 100644 --- a/test/integration/errors-test.js +++ b/test/integration/errors-test.js @@ -1,30 +1,20 @@ -var supertest = require('supertest') var path = require('path') - -// Helper functions for the FS -// var rm = require('./utils').rm -// var write = require('./utils').write -// var cp = require('./utils').cp -var read = require('./../utils').read - -var ldnode = require('../../index') +const { read, setupSupertestServer } = require('./../utils') describe('Error pages', function () { // LDP with error pages - var errorLdp = ldnode({ + const errorServer = setupSupertestServer({ root: path.join(__dirname, '../resources'), errorPages: path.join(__dirname, '../resources/errorPages'), webid: false }) - var errorServer = supertest(errorLdp) // LDP with no error pages - var noErrorLdp = ldnode({ + const noErrorServer = setupSupertestServer({ root: path.join(__dirname, '../resources'), noErrorPages: true, webid: false }) - var noErrorServer = supertest(noErrorLdp) function defaultErrorPage (filepath, expected) { var handler = function (res) { diff --git a/test/integration/formats-test.js b/test/integration/formats-test.js index 994a415a3..9a6c04790 100644 --- a/test/integration/formats-test.js +++ b/test/integration/formats-test.js @@ -1,15 +1,13 @@ -var supertest = require('supertest') -var ldnode = require('../../index') var path = require('path') const assert = require('chai').assert +const { setupSupertestServer } = require('../utils') describe('formats', function () { - var ldp = ldnode.createServer({ + const server = setupSupertestServer({ root: path.join(__dirname, '../resources'), webid: false }) - var server = supertest(ldp) describe('HTML', function () { it('should return HTML containing "Hello, World!" if Accept is set to text/html', function (done) { server.get('/hello.html') diff --git a/test/integration/http-test.js b/test/integration/http-test.js index 4a2f0a538..f4095ed12 100644 --- a/test/integration/http-test.js +++ b/test/integration/http-test.js @@ -1,21 +1,19 @@ -var supertest = require('supertest') var fs = require('fs') var li = require('li') -var ldnode = require('../../index') var rm = require('./../utils').rm var path = require('path') const rdf = require('rdflib') +const { setupSupertestServer } = require('../utils') var suffixAcl = '.acl' var suffixMeta = '.meta' -var ldpServer = ldnode.createServer({ +var server = setupSupertestServer({ live: true, dataBrowserPath: 'default', root: path.join(__dirname, '../resources'), auth: 'oidc', webid: false }) -var server = supertest(ldpServer) var { assert, expect } = require('chai') /** diff --git a/test/integration/validate-tts.js b/test/integration/validate-tts.js index 0d8693af0..56225d021 100644 --- a/test/integration/validate-tts.js +++ b/test/integration/validate-tts.js @@ -1,8 +1,8 @@ const fs = require('fs') const path = require('path') -const { setupSuperServer } = require('../utils') +const { setupSupertestServer } = require('../utils') -const server = setupSuperServer({ +const server = setupSupertestServer({ live: true, dataBrowserPath: 'default', root: path.join(__dirname, '../resources'), diff --git a/test/utils.js b/test/utils.js index 0a1e8c345..5c68a3260 100644 --- a/test/utils.js +++ b/test/utils.js @@ -88,7 +88,7 @@ function createServer (options) { return ldnode.createServer(options) } -exports.setupSuperServer = setupSuperServer +exports.setupSupertestServer = setupSuperServer function setupSuperServer (options) { const ldpServer = createServer(options) return supertest(ldpServer) From 48da61c743b590093e16daba454195a176951ce1 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Mon, 12 Nov 2018 15:08:19 +0100 Subject: [PATCH 07/23] First iteration of simple validation --- lib/handlers/validate.js | 28 ++++++++++++++++++++++++++++ lib/ldp-middleware.js | 7 ++++--- lib/ldp.js | 2 +- 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 lib/handlers/validate.js diff --git a/lib/handlers/validate.js b/lib/handlers/validate.js new file mode 100644 index 000000000..57134153f --- /dev/null +++ b/lib/handlers/validate.js @@ -0,0 +1,28 @@ +module.exports = handler + +const bodyParser = require('body-parser') +const error = require('../http-error') +const LDP = require('../ldp') +const $rdf = require('rdflib') +const debug = require('../debug') + +function handler (req, res, next) { + bodyParser.text({ type: () => true })(req, res, () => validate(req, res, next)) +} + +function validate (req, res, next) { + const contentType = req.get('content-type') + if (!LDP.mimetypeIsRdf(contentType)) { + return next() + } + + const resourceGraph = $rdf.graph() + const requestUri = `${req.protocol}//${req.get('host')}${req.originalUrl}` + try { + $rdf.parse(req.body, resourceGraph, requestUri, contentType) + } catch (err) { + debug.handlers('VALIDATE -- Error parsing data: ' + err) + return next(error(400, 'Unable to parse the body of request')) + } + next() +} diff --git a/lib/ldp-middleware.js b/lib/ldp-middleware.js index 1b35d56ad..67c57aa8c 100644 --- a/lib/ldp-middleware.js +++ b/lib/ldp-middleware.js @@ -10,6 +10,7 @@ const del = require('./handlers/delete') const patch = require('./handlers/patch') const index = require('./handlers/index') const copy = require('./handlers/copy') +const validate = require('./handlers/validate') function LdpMiddleware (corsSettings) { const router = express.Router('/') @@ -23,9 +24,9 @@ function LdpMiddleware (corsSettings) { router.copy('/*', allow('Write'), copy) router.get('/*', index, allow('Read'), header.addPermissions, get) - router.post('/*', allow('Append'), post) - router.patch('/*', allow('Append'), patch) - router.put('/*', allow('Write'), put) + router.post('/*', allow('Append'), validate, post) + router.patch('/*', allow('Append'), validate, patch) + router.put('/*', allow('Write'), validate, put) router.delete('/*', allow('Write'), del) return router diff --git a/lib/ldp.js b/lib/ldp.js index 001f0559e..3f505a727 100644 --- a/lib/ldp.js +++ b/lib/ldp.js @@ -463,7 +463,7 @@ class LDP { return ensureNotExists(this, path.join(containerURI, filename)) } - mimetypeIsRdf (mimeType) { + static mimetypeIsRdf (mimeType) { return RDF_MIME_TYPES.indexOf(mimeType) !== -1 } } From f35e458bf147cbb944ae59f8882ea57ab39e8127 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Tue, 13 Nov 2018 13:17:12 +0100 Subject: [PATCH 08/23] Just a minor commit --- lib/ldp-middleware.js | 8 ++++---- test/utils.js | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/lib/ldp-middleware.js b/lib/ldp-middleware.js index 67c57aa8c..cf4904cf2 100644 --- a/lib/ldp-middleware.js +++ b/lib/ldp-middleware.js @@ -10,7 +10,7 @@ const del = require('./handlers/delete') const patch = require('./handlers/patch') const index = require('./handlers/index') const copy = require('./handlers/copy') -const validate = require('./handlers/validate') +// const validate = require('./handlers/validate') function LdpMiddleware (corsSettings) { const router = express.Router('/') @@ -24,9 +24,9 @@ function LdpMiddleware (corsSettings) { router.copy('/*', allow('Write'), copy) router.get('/*', index, allow('Read'), header.addPermissions, get) - router.post('/*', allow('Append'), validate, post) - router.patch('/*', allow('Append'), validate, patch) - router.put('/*', allow('Write'), validate, put) + router.post('/*', allow('Append'), post) + router.patch('/*', allow('Append'), patch) + router.put('/*', allow('Write'), put) router.delete('/*', allow('Write'), del) return router diff --git a/test/utils.js b/test/utils.js index 5c68a3260..f3df05f63 100644 --- a/test/utils.js +++ b/test/utils.js @@ -88,8 +88,46 @@ function createServer (options) { return ldnode.createServer(options) } -exports.setupSupertestServer = setupSuperServer +exports.setupSuperServer = setupSuperServer function setupSuperServer (options) { const ldpServer = createServer(options) return supertest(ldpServer) } + +/** + * Creates a new test basic container via an LDP POST + * (located in `test/resources/{containerName}`) + * @method createTestContainer + * @param server {supertest} An instance of a supertest server + * @param containerName {String} Container name used as slug, no leading `/` + * @return {Promise} Promise obj, for use with Mocha's `before()` etc + */ +exports.createTestContainer = function createTestContainer (server, containerName) { + return new Promise(function (resolve, reject) { + server.post('/') + .set('content-type', 'text/turtle') + .set('slug', containerName) + .set('link', '; rel="type"') + .set('content-type', 'text/turtle') + .end(function (error, res) { + error ? reject(error) : resolve(res) + }) + }) +} + +/** + * Creates a new turtle test resource via an LDP PUT + * (located in `test/resources/{resourceName}`) + * @method createTestResource + * @param resourceName {String} Resource name (should have a leading `/`) + * @return {Promise} Promise obj, for use with Mocha's `before()` etc + */ +exports.createTestResource = function createTestResource (server, resourceName) { + return new Promise(function (resolve, reject) { + server.put(resourceName) + .set('content-type', 'text/turtle') + .end(function (error, res) { + error ? reject(error) : resolve(res) + }) + }) +} From 6d845b15c7c944b4eaa96646664b03daca6809e2 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Wed, 14 Nov 2018 12:37:17 +0100 Subject: [PATCH 09/23] Moving code around, to handle streams correctly And make old tests pass --- lib/handlers/validate.js | 28 ---------------------- lib/ldp-middleware.js | 1 - lib/ldp.js | 2 +- test/resources/sampleContainer/invalid.ttl | 13 ++++++++++ 4 files changed, 14 insertions(+), 30 deletions(-) delete mode 100644 lib/handlers/validate.js create mode 100644 test/resources/sampleContainer/invalid.ttl diff --git a/lib/handlers/validate.js b/lib/handlers/validate.js deleted file mode 100644 index 57134153f..000000000 --- a/lib/handlers/validate.js +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = handler - -const bodyParser = require('body-parser') -const error = require('../http-error') -const LDP = require('../ldp') -const $rdf = require('rdflib') -const debug = require('../debug') - -function handler (req, res, next) { - bodyParser.text({ type: () => true })(req, res, () => validate(req, res, next)) -} - -function validate (req, res, next) { - const contentType = req.get('content-type') - if (!LDP.mimetypeIsRdf(contentType)) { - return next() - } - - const resourceGraph = $rdf.graph() - const requestUri = `${req.protocol}//${req.get('host')}${req.originalUrl}` - try { - $rdf.parse(req.body, resourceGraph, requestUri, contentType) - } catch (err) { - debug.handlers('VALIDATE -- Error parsing data: ' + err) - return next(error(400, 'Unable to parse the body of request')) - } - next() -} diff --git a/lib/ldp-middleware.js b/lib/ldp-middleware.js index cf4904cf2..1b35d56ad 100644 --- a/lib/ldp-middleware.js +++ b/lib/ldp-middleware.js @@ -10,7 +10,6 @@ const del = require('./handlers/delete') const patch = require('./handlers/patch') const index = require('./handlers/index') const copy = require('./handlers/copy') -// const validate = require('./handlers/validate') function LdpMiddleware (corsSettings) { const router = express.Router('/') diff --git a/lib/ldp.js b/lib/ldp.js index 3f505a727..001f0559e 100644 --- a/lib/ldp.js +++ b/lib/ldp.js @@ -463,7 +463,7 @@ class LDP { return ensureNotExists(this, path.join(containerURI, filename)) } - static mimetypeIsRdf (mimeType) { + mimetypeIsRdf (mimeType) { return RDF_MIME_TYPES.indexOf(mimeType) !== -1 } } diff --git a/test/resources/sampleContainer/invalid.ttl b/test/resources/sampleContainer/invalid.ttl new file mode 100644 index 000000000..a2bc6473c --- /dev/null +++ b/test/resources/sampleContainer/invalid.ttl @@ -0,0 +1,13 @@ +@prefix ldp: . +@prefix o: . + + + test o:NetWorth; + o:netWorthOf ; + o:asset + , + ; + o:liability + , + , + . From 5b94a22eba7644361bc94fccfce814f443516d1a Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Wed, 14 Nov 2018 13:17:03 +0100 Subject: [PATCH 10/23] Adding test for Patch But no actual implementation in patch handler yet --- test/resources/sampleContainer/invalid.ttl | 13 -------- test/utils.js | 38 ---------------------- 2 files changed, 51 deletions(-) delete mode 100644 test/resources/sampleContainer/invalid.ttl diff --git a/test/resources/sampleContainer/invalid.ttl b/test/resources/sampleContainer/invalid.ttl deleted file mode 100644 index a2bc6473c..000000000 --- a/test/resources/sampleContainer/invalid.ttl +++ /dev/null @@ -1,13 +0,0 @@ -@prefix ldp: . -@prefix o: . - - - test o:NetWorth; - o:netWorthOf ; - o:asset - , - ; - o:liability - , - , - . diff --git a/test/utils.js b/test/utils.js index f3df05f63..0a1e8c345 100644 --- a/test/utils.js +++ b/test/utils.js @@ -93,41 +93,3 @@ function setupSuperServer (options) { const ldpServer = createServer(options) return supertest(ldpServer) } - -/** - * Creates a new test basic container via an LDP POST - * (located in `test/resources/{containerName}`) - * @method createTestContainer - * @param server {supertest} An instance of a supertest server - * @param containerName {String} Container name used as slug, no leading `/` - * @return {Promise} Promise obj, for use with Mocha's `before()` etc - */ -exports.createTestContainer = function createTestContainer (server, containerName) { - return new Promise(function (resolve, reject) { - server.post('/') - .set('content-type', 'text/turtle') - .set('slug', containerName) - .set('link', '; rel="type"') - .set('content-type', 'text/turtle') - .end(function (error, res) { - error ? reject(error) : resolve(res) - }) - }) -} - -/** - * Creates a new turtle test resource via an LDP PUT - * (located in `test/resources/{resourceName}`) - * @method createTestResource - * @param resourceName {String} Resource name (should have a leading `/`) - * @return {Promise} Promise obj, for use with Mocha's `before()` etc - */ -exports.createTestResource = function createTestResource (server, resourceName) { - return new Promise(function (resolve, reject) { - server.put(resourceName) - .set('content-type', 'text/turtle') - .end(function (error, res) { - error ? reject(error) : resolve(res) - }) - }) -} From 331dc0cccbf34b2d0b6e9f508a0a4d5b437b40c3 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Thu, 15 Nov 2018 12:35:47 +0100 Subject: [PATCH 11/23] Trying to make integrations tests a little easier to read --- test/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils.js b/test/utils.js index 0a1e8c345..5c68a3260 100644 --- a/test/utils.js +++ b/test/utils.js @@ -88,7 +88,7 @@ function createServer (options) { return ldnode.createServer(options) } -exports.setupSuperServer = setupSuperServer +exports.setupSupertestServer = setupSuperServer function setupSuperServer (options) { const ldpServer = createServer(options) return supertest(ldpServer) From afbe557f61d145453e898921208f2951ca798699 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Thu, 15 Nov 2018 23:15:20 +0100 Subject: [PATCH 12/23] Changes to code based on feedback --- lib/handlers/get.js | 2 ++ lib/ldp.js | 12 ++++++++---- lib/models/account-template.js | 12 ++++++------ test/integration/http-test.js | 4 ++-- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/handlers/get.js b/lib/handlers/get.js index 27f70973b..c2b888006 100644 --- a/lib/handlers/get.js +++ b/lib/handlers/get.js @@ -15,6 +15,8 @@ const translate = require('../utils.js').translate const error = require('../http-error') const RDFs = require('../ldp').RDF_MIME_TYPES +// const LDP = require('../ldp') +// const RDFs = LDP.mimeTypesAsArray() async function handler (req, res, next) { const ldp = req.app.locals.ldp diff --git a/lib/ldp.js b/lib/ldp.js index 001f0559e..d77e9aefe 100644 --- a/lib/ldp.js +++ b/lib/ldp.js @@ -17,6 +17,7 @@ const parse = require('./utils').parse const fetch = require('node-fetch') const { promisify } = require('util') +// TODO: apply new Set const RDF_MIME_TYPES = [ 'text/turtle', // .ttl 'text/n3', // .n3 @@ -28,7 +29,7 @@ const RDF_MIME_TYPES = [ 'application/rdf+xml', // .rdf 'application/ld+json', // .jsonld 'application/x-turtle' -] +]) class LDP { constructor (argv = {}) { @@ -463,9 +464,12 @@ class LDP { return ensureNotExists(this, path.join(containerURI, filename)) } - mimetypeIsRdf (mimeType) { - return RDF_MIME_TYPES.indexOf(mimeType) !== -1 + static mimeTypeIsRdf (mimeType) { + return RDF_MIME_TYPES.has(mimeType) + } + + static mimeTypesAsArray () { + return Array.from(RDF_MIME_TYPES) } } module.exports = LDP -module.exports.RDF_MIME_TYPES = RDF_MIME_TYPES diff --git a/lib/models/account-template.js b/lib/models/account-template.js index dfedc916e..a645271b6 100644 --- a/lib/models/account-template.js +++ b/lib/models/account-template.js @@ -5,8 +5,8 @@ const mime = require('mime-types') const recursiveRead = require('recursive-readdir') const fsUtils = require('../common/fs-utils') const templateUtils = require('../common/template-utils') +const LDP = require('../ldp') -const RDF_MIME_TYPES = require('../ldp').RDF_MIME_TYPES const TEMPLATE_EXTENSIONS = [ '.acl', '.meta', '.json', '.hbs', '.handlebars' ] const TEMPLATE_FILES = [ 'card' ] @@ -31,7 +31,6 @@ class AccountTemplate { */ constructor (options = {}) { this.substitutions = options.substitutions || {} - this.rdfMimeTypes = options.rdfMimeTypes || RDF_MIME_TYPES this.templateExtensions = options.templateExtensions || TEMPLATE_EXTENSIONS this.templateFiles = options.templateFiles || TEMPLATE_FILES } @@ -136,11 +135,12 @@ class AccountTemplate { * @return {boolean} */ isTemplate (filePath) { - let parsed = path.parse(filePath) + const parsed = path.parse(filePath) - let isRdf = this.rdfMimeTypes.includes(mime.lookup(filePath)) - let isTemplateExtension = this.templateExtensions.includes(parsed.ext) - let isTemplateFile = this.templateFiles.includes(parsed.base) || + const mimeType = mime.lookup(filePath) + const isRdf = LDP.mimeTypeIsRdf(mimeType) + const isTemplateExtension = this.templateExtensions.includes(parsed.ext) + const isTemplateFile = this.templateFiles.includes(parsed.base) || this.templateExtensions.includes(parsed.base) // the '/.acl' case return isRdf || isTemplateExtension || isTemplateFile diff --git a/test/integration/http-test.js b/test/integration/http-test.js index f4095ed12..ad74a20af 100644 --- a/test/integration/http-test.js +++ b/test/integration/http-test.js @@ -473,10 +473,10 @@ describe('HTTP APIs', function () { .expect(hasHeader('acl', 'baz.ttl' + suffixAcl)) .expect(201, done) }) - it('should return 409 code when trying to put to a container', + it('should fail when trying to put to a container', function (done) { server.put('/') - .expect(409, done) + .expect(405, done) } ) // Cleanup From 29c115febdf8f5b8e7a6afc8c0b896fb672c68d7 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Tue, 20 Nov 2018 15:56:34 +0100 Subject: [PATCH 13/23] A couple of fixes --- test/integration/validate-tts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/validate-tts.js b/test/integration/validate-tts.js index 56225d021..1b45ebd92 100644 --- a/test/integration/validate-tts.js +++ b/test/integration/validate-tts.js @@ -16,7 +16,7 @@ const invalidTurtleBody = fs.readFileSync(path.join(__dirname, '../resources/inv describe('HTTP requests with invalid Turtle syntax', () => { describe('PUT API', () => { - it('is allowed with invalid TTL files', (done) => { + it('is allowed with invalid TTL files in general', (done) => { server.put('/invalid1.ttl') .send(invalidTurtleBody) .set('content-type', 'text/turtle') From 1be27f72b35ace00470e9a476a0346ce5301b74b Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Mon, 12 Nov 2018 15:08:19 +0100 Subject: [PATCH 14/23] First iteration of simple validation --- lib/handlers/validate.js | 28 ++++++++++++++++++++++++++++ lib/ldp-middleware.js | 7 ++++--- 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 lib/handlers/validate.js diff --git a/lib/handlers/validate.js b/lib/handlers/validate.js new file mode 100644 index 000000000..57134153f --- /dev/null +++ b/lib/handlers/validate.js @@ -0,0 +1,28 @@ +module.exports = handler + +const bodyParser = require('body-parser') +const error = require('../http-error') +const LDP = require('../ldp') +const $rdf = require('rdflib') +const debug = require('../debug') + +function handler (req, res, next) { + bodyParser.text({ type: () => true })(req, res, () => validate(req, res, next)) +} + +function validate (req, res, next) { + const contentType = req.get('content-type') + if (!LDP.mimetypeIsRdf(contentType)) { + return next() + } + + const resourceGraph = $rdf.graph() + const requestUri = `${req.protocol}//${req.get('host')}${req.originalUrl}` + try { + $rdf.parse(req.body, resourceGraph, requestUri, contentType) + } catch (err) { + debug.handlers('VALIDATE -- Error parsing data: ' + err) + return next(error(400, 'Unable to parse the body of request')) + } + next() +} diff --git a/lib/ldp-middleware.js b/lib/ldp-middleware.js index 1b35d56ad..67c57aa8c 100644 --- a/lib/ldp-middleware.js +++ b/lib/ldp-middleware.js @@ -10,6 +10,7 @@ const del = require('./handlers/delete') const patch = require('./handlers/patch') const index = require('./handlers/index') const copy = require('./handlers/copy') +const validate = require('./handlers/validate') function LdpMiddleware (corsSettings) { const router = express.Router('/') @@ -23,9 +24,9 @@ function LdpMiddleware (corsSettings) { router.copy('/*', allow('Write'), copy) router.get('/*', index, allow('Read'), header.addPermissions, get) - router.post('/*', allow('Append'), post) - router.patch('/*', allow('Append'), patch) - router.put('/*', allow('Write'), put) + router.post('/*', allow('Append'), validate, post) + router.patch('/*', allow('Append'), validate, patch) + router.put('/*', allow('Write'), validate, put) router.delete('/*', allow('Write'), del) return router From 5a39e8e2ae01a88fcc376a78253506adbf299180 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Tue, 13 Nov 2018 13:17:12 +0100 Subject: [PATCH 15/23] Just a minor commit --- lib/ldp-middleware.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ldp-middleware.js b/lib/ldp-middleware.js index 67c57aa8c..cf4904cf2 100644 --- a/lib/ldp-middleware.js +++ b/lib/ldp-middleware.js @@ -10,7 +10,7 @@ const del = require('./handlers/delete') const patch = require('./handlers/patch') const index = require('./handlers/index') const copy = require('./handlers/copy') -const validate = require('./handlers/validate') +// const validate = require('./handlers/validate') function LdpMiddleware (corsSettings) { const router = express.Router('/') @@ -24,9 +24,9 @@ function LdpMiddleware (corsSettings) { router.copy('/*', allow('Write'), copy) router.get('/*', index, allow('Read'), header.addPermissions, get) - router.post('/*', allow('Append'), validate, post) - router.patch('/*', allow('Append'), validate, patch) - router.put('/*', allow('Write'), validate, put) + router.post('/*', allow('Append'), post) + router.patch('/*', allow('Append'), patch) + router.put('/*', allow('Write'), put) router.delete('/*', allow('Write'), del) return router From a0232e28a00a36c166e79e464bd77ffd62144eda Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Wed, 14 Nov 2018 12:37:17 +0100 Subject: [PATCH 16/23] Moving code around, to handle streams correctly And make old tests pass --- lib/handlers/validate.js | 28 ---------------------- lib/ldp-middleware.js | 1 - test/resources/sampleContainer/invalid.ttl | 13 ++++++++++ 3 files changed, 13 insertions(+), 29 deletions(-) delete mode 100644 lib/handlers/validate.js create mode 100644 test/resources/sampleContainer/invalid.ttl diff --git a/lib/handlers/validate.js b/lib/handlers/validate.js deleted file mode 100644 index 57134153f..000000000 --- a/lib/handlers/validate.js +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = handler - -const bodyParser = require('body-parser') -const error = require('../http-error') -const LDP = require('../ldp') -const $rdf = require('rdflib') -const debug = require('../debug') - -function handler (req, res, next) { - bodyParser.text({ type: () => true })(req, res, () => validate(req, res, next)) -} - -function validate (req, res, next) { - const contentType = req.get('content-type') - if (!LDP.mimetypeIsRdf(contentType)) { - return next() - } - - const resourceGraph = $rdf.graph() - const requestUri = `${req.protocol}//${req.get('host')}${req.originalUrl}` - try { - $rdf.parse(req.body, resourceGraph, requestUri, contentType) - } catch (err) { - debug.handlers('VALIDATE -- Error parsing data: ' + err) - return next(error(400, 'Unable to parse the body of request')) - } - next() -} diff --git a/lib/ldp-middleware.js b/lib/ldp-middleware.js index cf4904cf2..1b35d56ad 100644 --- a/lib/ldp-middleware.js +++ b/lib/ldp-middleware.js @@ -10,7 +10,6 @@ const del = require('./handlers/delete') const patch = require('./handlers/patch') const index = require('./handlers/index') const copy = require('./handlers/copy') -// const validate = require('./handlers/validate') function LdpMiddleware (corsSettings) { const router = express.Router('/') diff --git a/test/resources/sampleContainer/invalid.ttl b/test/resources/sampleContainer/invalid.ttl new file mode 100644 index 000000000..a2bc6473c --- /dev/null +++ b/test/resources/sampleContainer/invalid.ttl @@ -0,0 +1,13 @@ +@prefix ldp: . +@prefix o: . + + + test o:NetWorth; + o:netWorthOf ; + o:asset + , + ; + o:liability + , + , + . From af58d660da5adda20993f23daa1881397d98db49 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Wed, 14 Nov 2018 13:17:03 +0100 Subject: [PATCH 17/23] Adding test for Patch But no actual implementation in patch handler yet --- test/resources/sampleContainer/invalid.ttl | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 test/resources/sampleContainer/invalid.ttl diff --git a/test/resources/sampleContainer/invalid.ttl b/test/resources/sampleContainer/invalid.ttl deleted file mode 100644 index a2bc6473c..000000000 --- a/test/resources/sampleContainer/invalid.ttl +++ /dev/null @@ -1,13 +0,0 @@ -@prefix ldp: . -@prefix o: . - - - test o:NetWorth; - o:netWorthOf ; - o:asset - , - ; - o:liability - , - , - . From 8b0e8e744b764beb18cd77a02958842866206a0a Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Mon, 12 Nov 2018 15:08:19 +0100 Subject: [PATCH 18/23] First iteration of simple validation --- lib/handlers/validate.js | 28 ++++++++++++++++++++++++++++ lib/ldp-middleware.js | 7 ++++--- 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 lib/handlers/validate.js diff --git a/lib/handlers/validate.js b/lib/handlers/validate.js new file mode 100644 index 000000000..57134153f --- /dev/null +++ b/lib/handlers/validate.js @@ -0,0 +1,28 @@ +module.exports = handler + +const bodyParser = require('body-parser') +const error = require('../http-error') +const LDP = require('../ldp') +const $rdf = require('rdflib') +const debug = require('../debug') + +function handler (req, res, next) { + bodyParser.text({ type: () => true })(req, res, () => validate(req, res, next)) +} + +function validate (req, res, next) { + const contentType = req.get('content-type') + if (!LDP.mimetypeIsRdf(contentType)) { + return next() + } + + const resourceGraph = $rdf.graph() + const requestUri = `${req.protocol}//${req.get('host')}${req.originalUrl}` + try { + $rdf.parse(req.body, resourceGraph, requestUri, contentType) + } catch (err) { + debug.handlers('VALIDATE -- Error parsing data: ' + err) + return next(error(400, 'Unable to parse the body of request')) + } + next() +} diff --git a/lib/ldp-middleware.js b/lib/ldp-middleware.js index 1b35d56ad..67c57aa8c 100644 --- a/lib/ldp-middleware.js +++ b/lib/ldp-middleware.js @@ -10,6 +10,7 @@ const del = require('./handlers/delete') const patch = require('./handlers/patch') const index = require('./handlers/index') const copy = require('./handlers/copy') +const validate = require('./handlers/validate') function LdpMiddleware (corsSettings) { const router = express.Router('/') @@ -23,9 +24,9 @@ function LdpMiddleware (corsSettings) { router.copy('/*', allow('Write'), copy) router.get('/*', index, allow('Read'), header.addPermissions, get) - router.post('/*', allow('Append'), post) - router.patch('/*', allow('Append'), patch) - router.put('/*', allow('Write'), put) + router.post('/*', allow('Append'), validate, post) + router.patch('/*', allow('Append'), validate, patch) + router.put('/*', allow('Write'), validate, put) router.delete('/*', allow('Write'), del) return router From fae913dd438a70a5e50e2f7708393d621b63222f Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Tue, 13 Nov 2018 13:17:12 +0100 Subject: [PATCH 19/23] Just a minor commit --- lib/ldp-middleware.js | 8 ++++---- test/utils.js | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/lib/ldp-middleware.js b/lib/ldp-middleware.js index 67c57aa8c..cf4904cf2 100644 --- a/lib/ldp-middleware.js +++ b/lib/ldp-middleware.js @@ -10,7 +10,7 @@ const del = require('./handlers/delete') const patch = require('./handlers/patch') const index = require('./handlers/index') const copy = require('./handlers/copy') -const validate = require('./handlers/validate') +// const validate = require('./handlers/validate') function LdpMiddleware (corsSettings) { const router = express.Router('/') @@ -24,9 +24,9 @@ function LdpMiddleware (corsSettings) { router.copy('/*', allow('Write'), copy) router.get('/*', index, allow('Read'), header.addPermissions, get) - router.post('/*', allow('Append'), validate, post) - router.patch('/*', allow('Append'), validate, patch) - router.put('/*', allow('Write'), validate, put) + router.post('/*', allow('Append'), post) + router.patch('/*', allow('Append'), patch) + router.put('/*', allow('Write'), put) router.delete('/*', allow('Write'), del) return router diff --git a/test/utils.js b/test/utils.js index 5c68a3260..f3df05f63 100644 --- a/test/utils.js +++ b/test/utils.js @@ -88,8 +88,46 @@ function createServer (options) { return ldnode.createServer(options) } -exports.setupSupertestServer = setupSuperServer +exports.setupSuperServer = setupSuperServer function setupSuperServer (options) { const ldpServer = createServer(options) return supertest(ldpServer) } + +/** + * Creates a new test basic container via an LDP POST + * (located in `test/resources/{containerName}`) + * @method createTestContainer + * @param server {supertest} An instance of a supertest server + * @param containerName {String} Container name used as slug, no leading `/` + * @return {Promise} Promise obj, for use with Mocha's `before()` etc + */ +exports.createTestContainer = function createTestContainer (server, containerName) { + return new Promise(function (resolve, reject) { + server.post('/') + .set('content-type', 'text/turtle') + .set('slug', containerName) + .set('link', '; rel="type"') + .set('content-type', 'text/turtle') + .end(function (error, res) { + error ? reject(error) : resolve(res) + }) + }) +} + +/** + * Creates a new turtle test resource via an LDP PUT + * (located in `test/resources/{resourceName}`) + * @method createTestResource + * @param resourceName {String} Resource name (should have a leading `/`) + * @return {Promise} Promise obj, for use with Mocha's `before()` etc + */ +exports.createTestResource = function createTestResource (server, resourceName) { + return new Promise(function (resolve, reject) { + server.put(resourceName) + .set('content-type', 'text/turtle') + .end(function (error, res) { + error ? reject(error) : resolve(res) + }) + }) +} From 9a936fcf3ab9b290600ae94ae7f9b540bb42ff96 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Wed, 14 Nov 2018 12:37:17 +0100 Subject: [PATCH 20/23] Moving code around, to handle streams correctly And make old tests pass --- lib/handlers/validate.js | 28 ---------------------- lib/ldp-middleware.js | 1 - test/resources/sampleContainer/invalid.ttl | 13 ++++++++++ 3 files changed, 13 insertions(+), 29 deletions(-) delete mode 100644 lib/handlers/validate.js create mode 100644 test/resources/sampleContainer/invalid.ttl diff --git a/lib/handlers/validate.js b/lib/handlers/validate.js deleted file mode 100644 index 57134153f..000000000 --- a/lib/handlers/validate.js +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = handler - -const bodyParser = require('body-parser') -const error = require('../http-error') -const LDP = require('../ldp') -const $rdf = require('rdflib') -const debug = require('../debug') - -function handler (req, res, next) { - bodyParser.text({ type: () => true })(req, res, () => validate(req, res, next)) -} - -function validate (req, res, next) { - const contentType = req.get('content-type') - if (!LDP.mimetypeIsRdf(contentType)) { - return next() - } - - const resourceGraph = $rdf.graph() - const requestUri = `${req.protocol}//${req.get('host')}${req.originalUrl}` - try { - $rdf.parse(req.body, resourceGraph, requestUri, contentType) - } catch (err) { - debug.handlers('VALIDATE -- Error parsing data: ' + err) - return next(error(400, 'Unable to parse the body of request')) - } - next() -} diff --git a/lib/ldp-middleware.js b/lib/ldp-middleware.js index cf4904cf2..1b35d56ad 100644 --- a/lib/ldp-middleware.js +++ b/lib/ldp-middleware.js @@ -10,7 +10,6 @@ const del = require('./handlers/delete') const patch = require('./handlers/patch') const index = require('./handlers/index') const copy = require('./handlers/copy') -// const validate = require('./handlers/validate') function LdpMiddleware (corsSettings) { const router = express.Router('/') diff --git a/test/resources/sampleContainer/invalid.ttl b/test/resources/sampleContainer/invalid.ttl new file mode 100644 index 000000000..a2bc6473c --- /dev/null +++ b/test/resources/sampleContainer/invalid.ttl @@ -0,0 +1,13 @@ +@prefix ldp: . +@prefix o: . + + + test o:NetWorth; + o:netWorthOf ; + o:asset + , + ; + o:liability + , + , + . From cd5dfdd8220f2468ebdd75650aec767a50bd79ed Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Wed, 14 Nov 2018 13:17:03 +0100 Subject: [PATCH 21/23] Adding test for Patch But no actual implementation in patch handler yet --- test/resources/sampleContainer/invalid.ttl | 13 -------- test/utils.js | 38 ---------------------- 2 files changed, 51 deletions(-) delete mode 100644 test/resources/sampleContainer/invalid.ttl diff --git a/test/resources/sampleContainer/invalid.ttl b/test/resources/sampleContainer/invalid.ttl deleted file mode 100644 index a2bc6473c..000000000 --- a/test/resources/sampleContainer/invalid.ttl +++ /dev/null @@ -1,13 +0,0 @@ -@prefix ldp: . -@prefix o: . - - - test o:NetWorth; - o:netWorthOf ; - o:asset - , - ; - o:liability - , - , - . diff --git a/test/utils.js b/test/utils.js index f3df05f63..0a1e8c345 100644 --- a/test/utils.js +++ b/test/utils.js @@ -93,41 +93,3 @@ function setupSuperServer (options) { const ldpServer = createServer(options) return supertest(ldpServer) } - -/** - * Creates a new test basic container via an LDP POST - * (located in `test/resources/{containerName}`) - * @method createTestContainer - * @param server {supertest} An instance of a supertest server - * @param containerName {String} Container name used as slug, no leading `/` - * @return {Promise} Promise obj, for use with Mocha's `before()` etc - */ -exports.createTestContainer = function createTestContainer (server, containerName) { - return new Promise(function (resolve, reject) { - server.post('/') - .set('content-type', 'text/turtle') - .set('slug', containerName) - .set('link', '; rel="type"') - .set('content-type', 'text/turtle') - .end(function (error, res) { - error ? reject(error) : resolve(res) - }) - }) -} - -/** - * Creates a new turtle test resource via an LDP PUT - * (located in `test/resources/{resourceName}`) - * @method createTestResource - * @param resourceName {String} Resource name (should have a leading `/`) - * @return {Promise} Promise obj, for use with Mocha's `before()` etc - */ -exports.createTestResource = function createTestResource (server, resourceName) { - return new Promise(function (resolve, reject) { - server.put(resourceName) - .set('content-type', 'text/turtle') - .end(function (error, res) { - error ? reject(error) : resolve(res) - }) - }) -} From b5cfcf687068f63923fd34afde1aba5da41e5780 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Thu, 15 Nov 2018 12:35:47 +0100 Subject: [PATCH 22/23] Trying to make integrations tests a little easier to read --- test/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils.js b/test/utils.js index 0a1e8c345..5c68a3260 100644 --- a/test/utils.js +++ b/test/utils.js @@ -88,7 +88,7 @@ function createServer (options) { return ldnode.createServer(options) } -exports.setupSuperServer = setupSuperServer +exports.setupSupertestServer = setupSuperServer function setupSuperServer (options) { const ldpServer = createServer(options) return supertest(ldpServer) From d939f7c57bef67c9562c329a9417a49ff81edb8f Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Wed, 28 Nov 2018 13:26:51 +0100 Subject: [PATCH 23/23] Rebased on v5.0.0 --- lib/handlers/get.js | 4 +- lib/handlers/put.js | 78 +++++++++++++---------------------- lib/ldp.js | 23 +++++------ test/integration/http-test.js | 4 +- 4 files changed, 42 insertions(+), 67 deletions(-) diff --git a/lib/handlers/get.js b/lib/handlers/get.js index c2b888006..df2d4a8f0 100644 --- a/lib/handlers/get.js +++ b/lib/handlers/get.js @@ -14,9 +14,7 @@ const allow = require('./allow') const translate = require('../utils.js').translate const error = require('../http-error') -const RDFs = require('../ldp').RDF_MIME_TYPES -// const LDP = require('../ldp') -// const RDFs = LDP.mimeTypesAsArray() +const RDFs = require('../ldp').mimeTypesAsArray() async function handler (req, res, next) { const ldp = req.app.locals.ldp diff --git a/lib/handlers/put.js b/lib/handlers/put.js index 1932735b1..52dba2461 100644 --- a/lib/handlers/put.js +++ b/lib/handlers/put.js @@ -3,14 +3,25 @@ module.exports = handler const bodyParser = require('body-parser') const debug = require('debug')('solid:put') const getContentType = require('../utils').getContentType +const HTTPError = require('../http-error') +const { stringToStream } = require('../utils') +const LDP = require('../ldp') async function handler (req, res, next) { - const ldp = req.app.locals.ldp debug(req.originalUrl) res.header('MS-Author-Via', 'SPARQL') + const contentType = req.get('content-type') + if (LDP.mimeTypeIsRdf(contentType) && isAclFile(req)) { + return bodyParser.text({ type: () => true })(req, res, () => putAcl(req, res, next)) + } + return putStream(req, res, next) +} + +async function putStream (req, res, next, stream = req) { + const ldp = req.app.locals.ldp try { - await ldp.put(req, req, getContentType(req.headers)) + await ldp.put(req, stream, getContentType(req.headers)) debug('succeded putting the file') res.sendStatus(201) @@ -22,51 +33,18 @@ async function handler (req, res, next) { } } -// function handler (req, res, next) { -// const ldp = req.app.locals.ldp -// debug(req.originalUrl) -// res.header('MS-Author-Via', 'SPARQL') -// -// const contentType = req.get('content-type') -// if (ldp.mimetypeIsRdf(contentType)) { -// return bodyParser.text({ type: () => true })(req, res, () => putText(req, res, next)) -// } -// return putStream(req, res, next) -// } -// -//} -// -//function isAclFile (req) { -// const originalUrlParts = req.originalUrl.split('.') -// return originalUrlParts[originalUrlParts.length - 1] === 'acl' -//} -// -// function putText (req, res, next) { -// const ldp = req.app.locals.ldp -// const contentType = req.get('content-type') -// const requestUri = `${req.protocol}//${req.get('host')}${req.originalUrl}` -// if (ldp.isValidRdf(req.body, requestUri, contentType)) { -// return ldp.putText(req.hostname, req.path, req.body, handleCallback(res, next)) -// } -// next(error(400, 'RDF file contains invalid syntax')) -// } -// -// function putStream (req, res, next) { -// const ldp = req.app.locals.ldp -// ldp.putStream(req.hostname, req.path, req, handleCallback(res, next)) -// } -// -// function handleCallback (res, next) { -// return function (err) { -// if (err) { -// debug('error putting the file:' + err.message) -// err.message = 'Can\'t write file: ' + err.message -// return next(err) -// } -// -// debug('succeded putting the file') -// -// res.sendStatus(201) -// return next() -// } -// } +async function putAcl (req, res, next) { + const ldp = req.app.locals.ldp + const contentType = req.get('content-type') + const requestUri = `${req.protocol}//${req.get('host')}${req.originalUrl}` + if (ldp.isValidRdf(req.body, requestUri, contentType)) { + const stream = stringToStream(req.body) + return putStream(req, res, next, stream) + } + next(new HTTPError(400, 'RDF file contains invalid syntax')) +} + +function isAclFile (req) { + const originalUrlParts = req.originalUrl.split('.') + return originalUrlParts[originalUrlParts.length - 1] === 'acl' +} diff --git a/lib/ldp.js b/lib/ldp.js index d77e9aefe..b5b6d9671 100644 --- a/lib/ldp.js +++ b/lib/ldp.js @@ -17,8 +17,7 @@ const parse = require('./utils').parse const fetch = require('node-fetch') const { promisify } = require('util') -// TODO: apply new Set -const RDF_MIME_TYPES = [ +const RDF_MIME_TYPES = new Set([ 'text/turtle', // .ttl 'text/n3', // .n3 'text/html', // RDFa @@ -204,16 +203,16 @@ class LDP { return await this.put(path, stream, contentType) } - // isValidRdf (body, requestUri, contentType) { - // const resourceGraph = $rdf.graph() - // try { - // $rdf.parse(body, resourceGraph, requestUri, contentType) - // } catch (err) { - // debug.handlers('VALIDATE -- Error parsing data: ' + err) - // return false - // } - // return true - // } + isValidRdf (body, requestUri, contentType) { + const resourceGraph = $rdf.graph() + try { + $rdf.parse(body, resourceGraph, requestUri, contentType) + } catch (err) { + debug.ldp('VALIDATE -- Error parsing data: ' + err) + return false + } + return true + } async put (url, stream, contentType) { // PUT requests not supported on containers. Use POST instead diff --git a/test/integration/http-test.js b/test/integration/http-test.js index ad74a20af..f4095ed12 100644 --- a/test/integration/http-test.js +++ b/test/integration/http-test.js @@ -473,10 +473,10 @@ describe('HTTP APIs', function () { .expect(hasHeader('acl', 'baz.ttl' + suffixAcl)) .expect(201, done) }) - it('should fail when trying to put to a container', + it('should return 409 code when trying to put to a container', function (done) { server.put('/') - .expect(405, done) + .expect(409, done) } ) // Cleanup