Comparing version 0.2.1 to 0.3.0
var foldHeaderLine = require('./foldHeaderLine'), | ||
formatHeaderName = require('./formatHeaderName'); | ||
function Headers(valuesByName) { | ||
function Headers(objectOrString) { | ||
this.valuesByName = {}; | ||
if (valuesByName && typeof valuesByName === 'object') { | ||
this.setAll(valuesByName); | ||
} | ||
this.populate(objectOrString); | ||
} | ||
Headers.prototype.populate = function (objectOrString) { | ||
if (typeof objectOrString === 'string') { | ||
this.populateFromString(objectOrString); | ||
} else if (objectOrString && typeof objectOrString === 'object') { | ||
this.setAll(objectOrString); | ||
} | ||
}; | ||
Headers.prototype.populateFromString = function (str) { | ||
var that = this, | ||
state = 'startLine', | ||
currentHeaderName = '', | ||
currentValue = ''; | ||
function flush() { | ||
if (currentHeaderName.length > 0) { | ||
that.set(currentHeaderName, currentValue); | ||
} | ||
currentHeaderName = ''; | ||
currentValue = ''; | ||
state = 'startLine'; | ||
} | ||
for (var i = 0 ; i < str.length ; i += 1) { | ||
var ch = str[i]; | ||
if (state === 'startLine') { | ||
if (ch === ':') { | ||
state = 'startHeaderValue'; | ||
} else if (ch === '\r' || ch === '\n') { | ||
// Parse error or terminating CRLFCRLF | ||
if (ch === '\r' && str[i + 1] === '\n' || (ch === '\n' && str[i + 1] === '\r')) { | ||
i += 2; | ||
} else { | ||
i += 1; | ||
} | ||
flush(); | ||
return i; | ||
} else { | ||
currentHeaderName += ch; | ||
} | ||
} else if (state === 'startHeaderValue' || state === 'headerValue') { | ||
if (state === 'startHeaderValue') { | ||
if (ch === ' ') { | ||
// Ignore space after : | ||
continue; | ||
} else { | ||
state = 'headerValue'; | ||
} | ||
} | ||
if (ch === '\r') { | ||
if (str[i + 1] === '\n') { | ||
if (/[ \t]/.test(str[i + 2])) { | ||
// Skip past CRLF\s fold | ||
i += 2; | ||
} else { | ||
i += 1; | ||
flush(); | ||
} | ||
} else if (/[ \t]/.test(str[i + 1])) { | ||
// Skip past CR\s fold | ||
i += 1; | ||
} else { | ||
flush(); | ||
} | ||
} else if (ch === '\n') { | ||
if (str[i + 1] === '\r') { | ||
if (/[ \t]/.test(str[i + 2])) { | ||
// Skip past LFCR\s fold | ||
i += 2; | ||
} else { | ||
i += 1; | ||
flush(); | ||
} | ||
} else if (/[ \t]/.test(str[i + 1])) { | ||
// Skip past LF\s fold | ||
i += 1; | ||
} else { | ||
flush(); | ||
} | ||
} else { | ||
currentValue += ch; | ||
} | ||
} | ||
} | ||
flush(); | ||
return i; | ||
}; | ||
Headers.prototype.setAll = function (valuesByName) { | ||
@@ -70,2 +156,20 @@ Object.keys(valuesByName).forEach(function (headerName) { | ||
// hasHeader('Content-Length') | ||
// hasHeader('Content-Type', 'text/html'); | ||
// hasHeader('Cookie', ['foo=bar', 'baz=quux']); | ||
Headers.prototype.hasHeader = function (headerName, stringOrArray) { | ||
var values = this.valuesByName[headerName.toLowerCase()]; | ||
if (typeof stringOrArray === 'undefined') { | ||
return !!values; | ||
} else { | ||
if (Array.isArray(stringOrArray)) { | ||
return stringOrArray.every(function (expectedValue) { | ||
return values.indexOf(String(expectedValue)) !== -1; | ||
}); | ||
} else { | ||
return values.length === 1 && values[0] === String(stringOrArray); | ||
} | ||
} | ||
}; | ||
Headers.prototype.equals = function (other) { | ||
@@ -72,0 +176,0 @@ var headerNames = this.getNames(), |
@@ -29,7 +29,7 @@ var Message = require('./Message'), | ||
HttpResponse.prototype.populateStatusLineFromString = function (statusLine) { | ||
var statusLineFragments = statusLine.split(/\s+/); | ||
if (statusLineFragments.length === 3) { | ||
this.protocol = statusLineFragments[0]; | ||
this.statusCode = parseInt(statusLineFragments[1], 10); | ||
this.statusMessage = statusLineFragments[2]; | ||
var matchStatusLine = statusLine.match(/^(\S+) (\d+) (.+)$/); | ||
if (matchStatusLine) { | ||
this.protocol = matchStatusLine[1]; | ||
this.statusCode = parseInt(matchStatusLine[2], 10); | ||
this.statusMessage = matchStatusLine[3]; | ||
} else { | ||
@@ -36,0 +36,0 @@ throw new Error('Could not parse status line: ' + statusLine); |
@@ -11,3 +11,8 @@ /*global unescape*/ | ||
} else if (stringOrObjectOrBuffer && typeof stringOrObjectOrBuffer === 'object') { | ||
this.headers.setAll(stringOrObjectOrBuffer); | ||
if (typeof stringOrObjectOrBuffer.headers !== 'undefined') { | ||
this.headers.populate(stringOrObjectOrBuffer.headers); | ||
} | ||
if (typeof stringOrObjectOrBuffer.body !== 'undefined') { | ||
this.body = stringOrObjectOrBuffer.body; | ||
} | ||
} | ||
@@ -17,25 +22,5 @@ } | ||
Message.prototype.populateFromBuffer = function (buffer) { | ||
var endOfHeadersIndex = 0, | ||
latestLineBreaks = ''; | ||
while (endOfHeadersIndex < buffer.length) { | ||
var octet = buffer[endOfHeadersIndex]; | ||
if (octet === 0xd || octet === 0xa) { // \r | ||
latestLineBreaks += octet === 0xd ? '\r' : '\n'; | ||
if (/\r\r$|\n\n$|\r\n\r\n$|\n\r\n\r$/.test(latestLineBreaks)) { | ||
endOfHeadersIndex += 1; | ||
break; | ||
} | ||
} else { | ||
latestLineBreaks = ''; | ||
} | ||
endOfHeadersIndex += 1; | ||
} | ||
if (endOfHeadersIndex < buffer.length) { | ||
this.body = buffer.slice(endOfHeadersIndex); | ||
} | ||
// Hack: Interpret non-ASCII in headers as iso-8859-1: | ||
var str = ''; | ||
for (var i = 0 ; i < endOfHeadersIndex ; i += 1) { | ||
for (var i = 0 ; i < buffer.length ; i += 1) { | ||
var octet = buffer[i]; | ||
@@ -47,88 +32,18 @@ if (octet > 127) { | ||
} | ||
if (/\r\r$|\n\n$|\r\n\r\n$|\n\r\n\r$/.test(str)) { | ||
i += 1; | ||
if (i < buffer.length) { | ||
this.body = buffer.slice(i); | ||
} | ||
break; | ||
} | ||
} | ||
this.populateFromString(str, true); | ||
this.headers.populateFromString(str, true); | ||
}; | ||
Message.prototype.populateFromString = function (str, ignoreBody) { | ||
var that = this, | ||
state = 'startLine', | ||
currentHeaderName = '', | ||
currentValue = ''; | ||
function flush() { | ||
if (currentHeaderName.length > 0) { | ||
that.headers.set(currentHeaderName, currentValue); | ||
} | ||
currentHeaderName = ''; | ||
currentValue = ''; | ||
state = 'startLine'; | ||
Message.prototype.populateFromString = function (str) { | ||
var bodyStartIndex = this.headers.populateFromString(str); | ||
if (bodyStartIndex < str.length) { | ||
this.body = str.substr(bodyStartIndex); | ||
} | ||
for (var i = 0 ; i < str.length ; i += 1) { | ||
var ch = str[i]; | ||
if (state === 'startLine') { | ||
if (ch === ':') { | ||
state = 'startHeaderValue'; | ||
} else if (ch === '\r' || ch === '\n') { | ||
// Parse error or terminating CRLFCRLF | ||
if (!ignoreBody) { | ||
if (ch === '\r' && str[i + 1] === '\n' || (ch === '\n' && str[i + 1] === '\r')) { | ||
if (str.length >= i + 2) { | ||
that.body = str.substr(i + 2); | ||
} | ||
} else { | ||
if (str.length >= i + 1) { | ||
that.body = str.substr(i + 1); | ||
} | ||
} | ||
} | ||
flush(); | ||
return; | ||
} else { | ||
currentHeaderName += ch; | ||
} | ||
} else if (state === 'startHeaderValue' || state === 'headerValue') { | ||
if (state === 'startHeaderValue') { | ||
if (ch === ' ') { | ||
// Ignore space after : | ||
continue; | ||
} else { | ||
state = 'headerValue'; | ||
} | ||
} | ||
if (ch === '\r') { | ||
if (str[i + 1] === '\n') { | ||
if (/[ \t]/.test(str[i + 2])) { | ||
// Skip past CRLF\s fold | ||
i += 2; | ||
} else { | ||
i += 1; | ||
flush(); | ||
} | ||
} else if (/[ \t]/.test(str[i + 1])) { | ||
// Skip past CR\s fold | ||
i += 1; | ||
} else { | ||
flush(); | ||
} | ||
} else if (ch === '\n') { | ||
if (str[i + 1] === '\r') { | ||
if (/[ \t]/.test(str[i + 2])) { | ||
// Skip past LFCR\s fold | ||
i += 2; | ||
} else { | ||
i += 1; | ||
flush(); | ||
} | ||
} else if (/[ \t]/.test(str[i + 1])) { | ||
// Skip past LF\s fold | ||
i += 1; | ||
} else { | ||
flush(); | ||
} | ||
} else { | ||
currentValue += ch; | ||
} | ||
} | ||
} | ||
flush(); | ||
}; | ||
@@ -135,0 +50,0 @@ |
{ | ||
"name": "messy", | ||
"version": "0.2.1", | ||
"version": "0.3.0", | ||
"description": "Object model for HTTP and RFC822 messages", | ||
@@ -13,3 +13,3 @@ "main": "lib/index.js", | ||
"travis": "npm test && npm run coverage && <coverage/lcov.info coveralls", | ||
"coverage": "NODE_ENV=development istanbul cover _mocha -- --reporter dot" | ||
"coverage": "NODE_ENV=development istanbul cover _mocha -- --reporter dot && echo google-chrome coverage/lcov-report/index.html" | ||
}, | ||
@@ -16,0 +16,0 @@ "keywords": [ |
@@ -6,2 +6,8 @@ /*global describe, it*/ | ||
describe('Headers', function () { | ||
it('should accept a string', function () { | ||
var headers = new Headers('Subject: hey, dude!'); | ||
expect(headers.get('subject'), 'to equal', 'hey, dude!'); | ||
expect(headers.toString(), 'to equal', 'Subject: hey, dude!\r\n'); | ||
}); | ||
it('should fold the lines when serializing', function () { | ||
@@ -8,0 +14,0 @@ var headers = new Headers({subject: 'hey there, dude!'}); |
@@ -14,2 +14,10 @@ /*global describe, it*/ | ||
it('should parse a status line with more than one word in the status message', function () { | ||
var httpResponse = new HttpResponse('HTTP/1.1 412 Precondition Failed'); | ||
expect(httpResponse.protocol, 'to equal', 'HTTP/1.1'); | ||
expect(httpResponse.statusCode, 'to equal', 412); | ||
expect(httpResponse.statusMessage, 'to equal', 'Precondition Failed'); | ||
expect(httpResponse.toString(), 'to equal', 'HTTP/1.1 412 Precondition Failed\r\n\r\n'); | ||
}); | ||
it('should parse a status line followed by headers', function () { | ||
@@ -16,0 +24,0 @@ var httpResponse = new HttpResponse('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n'); |
@@ -6,2 +6,16 @@ /*global describe, it*/ | ||
describe('Message', function () { | ||
it('should accept an options object with headers and body', function () { | ||
var message = new Message({ | ||
headers: { | ||
Received: ['foo', 'bar'], | ||
Subject: 'hey' | ||
}, | ||
body: 'abc' | ||
}); | ||
expect(message.body, 'to equal', 'abc'); | ||
expect(message.headers.getAll('received'), 'to equal', ['foo', 'bar']); | ||
expect(message.headers.getAll('subject'), 'to equal', ['hey']); | ||
expect(message.toString(), 'to equal', 'Received: foo\r\nReceived: bar\r\nSubject: hey\r\n\r\nabc'); | ||
}); | ||
it('should parse the headers from the input', function () { | ||
@@ -159,4 +173,4 @@ var message = new Message('From: thisguy@example.com\r\nTo: thisotherguy@example.com'); | ||
expect(message.body, 'to equal', Buffer.concat([new Buffer('this is the:body', 'utf-8'), new Buffer([0xf8, 0xe6])])); | ||
expect(message.toString(), 'to equal', 'Foo: bar\r\n\r\nthis is the:body��'); | ||
expect(message.toString(), 'to equal', 'Foo: bar\r\n\r\nthis is the:body\ufffd\ufffd'); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
44036
845