Skip to content

Commit

Permalink
#49: Fix error on invalid request body (#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
markwylde committed May 24, 2021
1 parent 18bf8a2 commit 14da6cb
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 25 deletions.
65 changes: 50 additions & 15 deletions lib/httpHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ const validateAlphaNumericDashDot = require('../utils/validateAlphaNumericDashDo
const selectRandomItemFromArray = require('../utils/selectRandomItemFromArray');
const orderByFields = require('../utils/orderByFields');

function handleInvalidRequestBody (error) {
if (error.message.includes('Unexpected token')) {
throw Object.assign(new Error('request body not valid json'), { statusCode: 400 });
} else {
throw Object.assign(new Error('empty request body not allowed'), { statusCode: 400 });
}
}

const {
COMMAND,
STATUS,
Expand Down Expand Up @@ -158,7 +166,8 @@ async function handleCount (state, request, response, { collectionId, url }) {
}

async function handlePost (state, request, response, { collectionId }) {
const body = await finalStream(request).then(JSON.parse);
const body = await finalStream(request).then(JSON.parse)
.catch(handleInvalidRequestBody);

const documents = Array.isArray(body) ? body : [body];

Expand Down Expand Up @@ -189,7 +198,8 @@ async function handlePost (state, request, response, { collectionId }) {
}

async function handlePutOne (state, request, response, { collectionId, resourceId }) {
const body = await finalStream(request).then(JSON.parse);
const body = await finalStream(request).then(JSON.parse)
.catch(handleInvalidRequestBody);

const responses = await askOnAllNodes(state, {
[COMMAND]: PUT,
Expand All @@ -216,7 +226,8 @@ async function handlePutOne (state, request, response, { collectionId, resourceI
}

async function handlePutAll (state, request, response, { collectionId, url }) {
const body = await finalStream(request).then(JSON.parse);
const body = await finalStream(request).then(JSON.parse)
.catch(handleInvalidRequestBody);

const responses = await askOnAllNodes(state, {
[COMMAND]: PUT,
Expand All @@ -238,7 +249,8 @@ async function handlePutAll (state, request, response, { collectionId, url }) {
}

async function handlePatchOne (state, request, response, { collectionId, resourceId }) {
const body = await finalStream(request).then(JSON.parse);
const body = await finalStream(request).then(JSON.parse)
.catch(handleInvalidRequestBody);

const responses = await askOnAllNodes(state, {
[COMMAND]: PATCH,
Expand All @@ -265,7 +277,8 @@ async function handlePatchOne (state, request, response, { collectionId, resourc
}

async function handlePatchAll (state, request, response, { collectionId, url }) {
const body = await finalStream(request).then(JSON.parse);
const body = await finalStream(request).then(JSON.parse)
.catch(handleInvalidRequestBody);

const responses = await askOnAllNodes(state, {
[COMMAND]: PATCH,
Expand Down Expand Up @@ -370,6 +383,18 @@ async function handleUnlock (state, request, response, { resourceId }) {
writeResponse(200, {}, response);
}

function handleError (request, response) {
return error => {
if (error.statusCode) {
writeResponse(error.statusCode, { error: error.message }, response);
return;
}

console.log(error);
writeResponse(500, { error: 'unexpected server error' }, response);
};
}

function handleSystem (state, request, response, { url }) {
const [,, collectionId, resourceId] = url.pathname.split('/');

Expand Down Expand Up @@ -426,52 +451,62 @@ function handleExternal (state, request, response) {
}

if (request.method === 'GET' && resourceId) {
handleGetOne(state, request, response, { collectionId, resourceId, url });
handleGetOne(state, request, response, { collectionId, resourceId, url })
.catch(handleError(request, response));
return;
}

if (request.method === 'GET' && url.searchParams.get('count') && !resourceId) {
handleCount(state, request, response, { collectionId, url });
handleCount(state, request, response, { collectionId, url })
.catch(handleError(request, response));
return;
}

if (request.method === 'GET' && !resourceId) {
handleGetAll(state, request, response, { collectionId, url });
handleGetAll(state, request, response, { collectionId, url })
.catch(handleError(request, response));
return;
}

if (request.method === 'POST') {
handlePost(state, request, response, { collectionId, resourceId });
handlePost(state, request, response, { collectionId, resourceId })
.catch(handleError(request, response));
return;
}

if (request.method === 'PUT' && resourceId) {
handlePutOne(state, request, response, { collectionId, resourceId });
handlePutOne(state, request, response, { collectionId, resourceId })
.catch(handleError(request, response));
return;
}

if (request.method === 'PUT' && !resourceId) {
handlePutAll(state, request, response, { collectionId, url });
handlePutAll(state, request, response, { collectionId, url })
.catch(handleError(request, response));
return;
}

if (request.method === 'PATCH' && resourceId) {
handlePatchOne(state, request, response, { collectionId, resourceId });
handlePatchOne(state, request, response, { collectionId, resourceId })
.catch(handleError(request, response));
return;
}

if (request.method === 'PATCH' && !resourceId) {
handlePatchAll(state, request, response, { collectionId, url });
handlePatchAll(state, request, response, { collectionId, url })
.catch(handleError(request, response));
return;
}

if (request.method === 'DELETE' && resourceId) {
handleDeleteOne(state, request, response, { collectionId, resourceId });
handleDeleteOne(state, request, response, { collectionId, resourceId })
.catch(handleError(request, response));
return;
}

if (request.method === 'DELETE' && !resourceId) {
handleDeleteAll(state, request, response, { collectionId, url });
handleDeleteAll(state, request, response, { collectionId, url })
.catch(handleError(request, response));
return;
}

Expand Down
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"lockbase": "^1.0.9",
"minimist": "^1.2.5",
"ndjson-fe": "^1.2.7",
"npm": "^7.13.0",
"npm": "^7.14.0",
"qs": "^6.10.1",
"reconnecting-websocket": "^4.4.0",
"server-destroy": "^1.0.1",
Expand Down
38 changes: 38 additions & 0 deletions test/integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,49 @@ function rootMethodNotAllowed (method) {
};
}

function validateBodyExists (method) {
return async t => {
t.plan(2);

const node = await canhazdb({ host: 'localhost', port: 7071, queryPort: 8071, tls, single: true });

const request = await httpRequest(`${node.url}/exampleCollection`, { method });

await node.close();

t.deepEqual(request.data, { error: 'empty request body not allowed' });
t.equal(request.status, 400);
};
}

function validateBodyJson (method) {
return async t => {
t.plan(2);

const node = await canhazdb({ host: 'localhost', port: 7071, queryPort: 8071, tls, single: true });

const request = await httpRequest(`${node.url}/exampleCollection`, { method, data: 'not json' });

await node.close();

t.deepEqual(request.data, { error: 'request body not valid json' });
t.equal(request.status, 400);
};
}

test('post: root pathname', rootMethodNotAllowed('post'));
test('put: root pathname', rootMethodNotAllowed('put'));
test('patch: root pathname', rootMethodNotAllowed('patch'));
test('delete: root pathname', rootMethodNotAllowed('delete'));

test('post: body exists', validateBodyExists('post'));
test('put: body exists', validateBodyExists('put'));
test('patch: body exists', validateBodyExists('patch'));

test('post: body is json', validateBodyJson('post'));
test('put: body is json', validateBodyJson('put'));
test('patch: body is json', validateBodyJson('patch'));

test('post: and get some data', async t => {
t.plan(3);

Expand Down

0 comments on commit 14da6cb

Please sign in to comment.