diff --git a/addon/lib/json-utils.js b/addon/lib/json-utils.js index b98ba26..e3497c7 100644 --- a/addon/lib/json-utils.js +++ b/addon/lib/json-utils.js @@ -7,12 +7,40 @@ export function stringifyJSON(json={}){ export function jsonFromRequest(request){ let json = {}; if (request.requestBody) { - try { - json = JSON.parse(request.requestBody); - } catch(e) { - Ember.Logger.warn(`[FakeServer] Failed to parse json from request.requestBody "${request.requestBody}" (error: ${e})`); + if (contentTypeHeaderIsFormUrlEncoded(request.requestHeaders)) { + json = getJsonFromFormUrlEncodedRequest(request.requestBody); + } else { + try { + json = JSON.parse(request.requestBody); + } catch (e) { + Ember.Logger.warn(`[FakeServer] Failed to parse json from request.requestBody "${request.requestBody}" (error: ${e})`); + } } } return json; } + +function contentTypeHeaderIsFormUrlEncoded(requestHeaders) { + // request headers string example: + // {"Content-Type":"application/x-www-form-urlencoded","Accept":"*/*","X-Requested-With":"XMLHttpRequest"} + const caseInsensitiveformUrlEncodedContentTypeHeader = /content-type[":' ]+application\/x-www-form-urlencoded/gi; + const contentTypeHeaderStringToCheckCaseInsensitive = JSON.stringify(requestHeaders); + const contentTypeHeaderIsFormUrlEncoded = + caseInsensitiveformUrlEncodedContentTypeHeader.test(contentTypeHeaderStringToCheckCaseInsensitive); + + return contentTypeHeaderIsFormUrlEncoded; +} + +function getJsonFromFormUrlEncodedRequest(requestBody) { + let json = {}; + try { + // 'application/x-www-form-urlencoded' request body example: + // "foo=bar&hello=World!" + json = JSON.parse('{"' + decodeURIComponent(requestBody.replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g,'":"')) + '"}'); + } catch(e) { + Ember.Logger.warn(`[FakeServer] Failed to parse json from request.requestBody "${requestBody}" (error: ${e})`); + } + + return json; +} diff --git a/tests/unit/fake-server-test.js b/tests/unit/fake-server-test.js index 06642d8..4a46e23 100644 --- a/tests/unit/fake-server-test.js +++ b/tests/unit/fake-server-test.js @@ -89,6 +89,52 @@ test('#json reads JSON in request payload', (assert) => { }); }); +test('json() function parses x-www-form-urlencoded request payload', (assert) => { + let done = assert.async(); + assert.expect(1); + + const jsonPayload = { + foo: 'bar', + hello: 'World!', + }; + const urlEncodedPayload = "foo=bar&hello=World!"; + + stubRequest('post', '/blah', (request) => { + assert.deepEqual(request.json(), jsonPayload, 'POST payload'); + request.noContent(); + }); + + jQuery.ajax('/blah', { + type: 'POST', + data: urlEncodedPayload, + contentType: 'application/x-www-form-urlencoded', + complete: done + }); +}); + +test('json() function parses x-www-form-urlencoded request payload with special characters', (assert) => { + let done = assert.async(); + assert.expect(1); + + const jsonPayload = { + foo: 'bar', + password: '$€áÉîÖùñÑ', + }; + const urlEncodedPayload = "foo=bar&password=$€áÉîÖùñÑ"; + + stubRequest('post', '/blah', (request) => { + assert.deepEqual(request.json(), jsonPayload, 'POST payload'); + request.noContent(); + }); + + jQuery.ajax('/blah', { + type: 'POST', + data: urlEncodedPayload, + contentType: 'application/x-www-form-urlencoded', + complete: done + }); +}); + test('FakeServer.config.afterResponse can modify responses', (assert) => { let done = assert.async(); assert.expect(6);