Skip to content

Commit

Permalink
Merge pull request #4137 from HeroicEric/bugfix-4122
Browse files Browse the repository at this point in the history
[BUGFIX beta] Allow optional spaces when parsing response headers
  • Loading branch information
bmac committed Feb 12, 2016
2 parents 4d220c9 + dce22e3 commit 11627a9
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 21 deletions.
26 changes: 26 additions & 0 deletions addon/-private/utils/parse-response-headers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import EmptyObject from 'ember-data/-private/system/empty-object';

const CLRF = '\u000d\u000a';

export default function parseResponseHeaders(headersString) {
let headers = new EmptyObject();

if (!headersString) {
return headers;
}

let headerPairs = headersString.split(CLRF);

headerPairs.forEach((header) => {
let [field, ...value] = header.split(':');

field = field.trim();
value = value.join(':').trim();

if (value) {
headers[field] = value;
}
});

return headers;
}
22 changes: 1 addition & 21 deletions addon/adapters/rest.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import {
TimeoutError,
AbortError
} from 'ember-data/-private/adapters/errors';
import EmptyObject from "ember-data/-private/system/empty-object";
import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin";
import isEnabled from 'ember-data/-private/features';
import parseResponseHeaders from 'ember-data/-private/utils/parse-response-headers';

const {
MapWithDefault,
Expand Down Expand Up @@ -1006,26 +1006,6 @@ export default Adapter.extend(BuildURLMixin, {
}
});

function parseResponseHeaders(headerStr) {
var headers = new EmptyObject();
if (!headerStr) { return headers; }

var headerPairs = headerStr.split('\u000d\u000a');
for (var i = 0; i < headerPairs.length; i++) {
var headerPair = headerPairs[i];
// Can't use split() here because it does the wrong thing
// if the header value has the string ": " in it.
var index = headerPair.indexOf('\u003a\u0020');
if (index > 0) {
var key = headerPair.substring(0, index);
var val = headerPair.substring(index + 2);
headers[key] = val;
}
}

return headers;
}

//From http://stackoverflow.com/questions/280634/endswith-in-javascript
function endsWith(string, suffix) {
if (typeof String.prototype.endsWith !== 'function') {
Expand Down
67 changes: 67 additions & 0 deletions tests/unit/utils/parse-response-headers-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import EmptyObject from 'ember-data/-private/system/empty-object';
import parseResponseHeaders from 'ember-data/-private/utils/parse-response-headers';
import { module, test } from 'qunit';

const CRLF = '\u000d\u000a';

module('unit/adapters/parse-response-headers');

test('returns an EmptyObject when headersString is undefined', function(assert) {
let headers = parseResponseHeaders(undefined);

assert.deepEqual(headers, new EmptyObject(), 'EmptyObject is returned');
});

test('header parsing', function(assert) {
let headersString = [
'Content-Encoding: gzip',
'content-type: application/json; charset=utf-8',
'date: Fri, 05 Feb 2016 21:47:56 GMT'
].join(CRLF);

let headers = parseResponseHeaders(headersString);

assert.equal(headers['Content-Encoding'], 'gzip', 'parses basic header pair');
assert.equal(headers['content-type'], 'application/json; charset=utf-8', 'parses header with complex value');
assert.equal(headers['date'], 'Fri, 05 Feb 2016 21:47:56 GMT', 'parses header with date value');
});

test('field-name parsing', function(assert) {
let headersString = [
' name-with-leading-whitespace: some value',
'name-with-whitespace-before-colon : another value'
].join(CRLF);

let headers = parseResponseHeaders(headersString);

assert.equal(headers['name-with-leading-whitespace'], 'some value', 'strips leading whitespace from field-name');
assert.equal(headers['name-with-whitespace-before-colon'], 'another value', 'strips whitespace before colon from field-name');
});

test('field-value parsing', function(assert) {
let headersString = [
'value-with-leading-space: value with leading whitespace',
'value-without-leading-space:value without leading whitespace',
'value-with-colon: value with: a colon',
'value-with-trailing-whitespace: banana '
].join(CRLF);

let headers = parseResponseHeaders(headersString);

assert.equal(headers['value-with-leading-space'], 'value with leading whitespace', 'strips leading whitespace in field-value');
assert.equal(headers['value-without-leading-space'], 'value without leading whitespace', 'works without leaading whitespace in field-value');
assert.equal(headers['value-with-colon'], 'value with: a colon', 'has correct value when value contains a colon');
assert.equal(headers['value-with-trailing-whitespace'], 'banana', 'strips trailing whitespace from field-value');
});

test('ignores headers that do not contain a colon', function(assert) {
let headersString = [
'Content-Encoding: gzip',
'I am ignored because I do not contain a colon'
].join(CRLF);

let headers = parseResponseHeaders(headersString);

assert.deepEqual(headers['Content-Encoding'], 'gzip', 'parses basic header pair');
assert.equal(Object.keys(headers).length, 1, 'only has the one valid header');
});

0 comments on commit 11627a9

Please sign in to comment.