Comparing version 6.2.0 to 6.3.0
@@ -0,4 +1,6 @@ | ||
/*global btoa*/ | ||
var Message = require('./Message'), | ||
RequestLine = require('./RequestLine'), | ||
util = require('util'); | ||
util = require('util'), | ||
_ = require('underscore'); | ||
@@ -8,6 +10,7 @@ function HttpRequest(obj) { | ||
this.encrypted = false; | ||
this.port = 80; | ||
Message.call(this, obj); | ||
} | ||
HttpRequest.metadataPropertyNames = ['encrypted', 'cert', 'key', 'ca']; | ||
HttpRequest.metadataPropertyNames = ['host', 'port', 'encrypted', 'cert', 'key', 'ca', 'rejectUnauthorized']; | ||
@@ -31,2 +34,16 @@ HttpRequest.propertyNames = Message.propertyNames.concat(HttpRequest.metadataPropertyNames).concat(RequestLine.propertyNames).concat(['requestLine']); | ||
Message.prototype.populateFromObject.call(this, obj); | ||
if (typeof obj.url === 'string') { | ||
var fragments = obj.url.split(' '); | ||
if (fragments.length > 1) { | ||
this.method = fragments.shift(); | ||
} | ||
if (fragments.length > 0) { | ||
this.populateFromUrl(fragments[0]); | ||
obj = _.extend({}, obj); | ||
obj.url = this.path; | ||
} | ||
if (fragments.length > 1) { | ||
this.protocol = fragments[1]; | ||
} | ||
} | ||
if (typeof obj.requestLine !== 'undefined') { | ||
@@ -44,2 +61,41 @@ this.requestLine.populate(obj.requestLine); | ||
HttpRequest.prototype.populateFromUrl = function (url) { | ||
var fragments = url.split(' '); | ||
if (fragments.length > 1) { | ||
this.method = fragments.shift(); | ||
} | ||
if (fragments.length > 0) { | ||
var matchUrl = fragments[0].match(/^(https?:)\/\/(?:([^:@\/]+(?::[^@\/]+?))@)?((?:[a-z0-9](?:[\-a-z0-9]*[a-z0-9])?\.)+[a-z][\-a-z]*[a-z]|(?:(?:[0-9]|1?[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|1?[0-9][0-9]|2[0-4][0-9]|25[0-5]))(:\d{1,5})?(\/[\w\-\.~%!$&'\(\)*+,;=:@\/]*(?:\?[\w\-\.~%!$&'\(\)*+,;=:@\/?]*)?(?:#[\w\-\.~%!$&'\(\)*+,;=:@\/?#]*)?)?$/); | ||
if (matchUrl) { | ||
var protocol = matchUrl[1], | ||
auth = matchUrl[2], | ||
host = matchUrl[3], | ||
port = matchUrl[4], | ||
path = matchUrl[5]; | ||
if (!this.headers.has('Host')) { | ||
this.headers.set('Host', host + (port || '')); | ||
} | ||
this.host = host; | ||
if (typeof port !== 'undefined') { | ||
this.port = parseInt(port.substr(1), 10); | ||
} else if (protocol === 'https:') { | ||
this.port = 443; | ||
} | ||
if (typeof auth !== 'undefined') { | ||
this.headers.set('Authorization', 'Basic ' + (typeof Buffer !== 'undefined' ? new Buffer(auth, 'utf-8').toString('base64') : btoa(auth))); | ||
} | ||
if (protocol === 'https:') { | ||
this.encrypted = true; | ||
} | ||
this.path = path || '/'; | ||
} else { | ||
this.path = fragments[0]; | ||
} | ||
} | ||
if (fragments.length >= 2) { | ||
this.protocol = fragments[2]; | ||
} | ||
}; | ||
HttpRequest.prototype.populateFromString = function (str) { | ||
@@ -49,4 +105,14 @@ var matchRequestLine = str.match(/^([^\r\n]*)(\r\n?|\n\r?|$)/); | ||
if (matchRequestLine) { | ||
this.requestLine.populateFromString(matchRequestLine[1]); | ||
Message.prototype.populateFromString.call(this, str.substr(matchRequestLine[0].length)); | ||
var requestLineStr = matchRequestLine[1], | ||
requestLineFragments = requestLineStr.split(' '); | ||
if (requestLineFragments.length === 1) { | ||
requestLineFragments.unshift('GET'); | ||
} | ||
if (requestLineFragments.length >= 2) { | ||
this.populateFromUrl(requestLineFragments[1]); | ||
requestLineFragments[1] = this.path; | ||
} | ||
requestLineStr = requestLineFragments.join(' '); | ||
this.requestLine.populateFromString(requestLineStr); | ||
} | ||
@@ -53,0 +119,0 @@ return this; |
@@ -17,3 +17,5 @@ var Message = require('./Message'), | ||
HttpResponse.prototype.populate = function (obj) { | ||
if (obj && typeof obj === 'object' && (typeof Buffer === 'undefined' || !Buffer.isBuffer(obj))) { | ||
if (typeof obj === 'number') { | ||
this.populateFromObject({ statusCode: obj }); | ||
} else if (obj && typeof obj === 'object' && (typeof Buffer === 'undefined' || !Buffer.isBuffer(obj))) { | ||
this.populateFromObject(obj); | ||
@@ -20,0 +22,0 @@ } else { |
@@ -1,2 +0,2 @@ | ||
/*global unescape, btoa, atob*/ | ||
/*global unescape, btoa, atob, JSON*/ | ||
var Headers = require('./Headers'), | ||
@@ -47,6 +47,14 @@ isRegExp = require('./isRegExp'), | ||
} | ||
if (typeof obj.rawBody !== 'undefined') { | ||
if (typeof obj.parts !== 'undefined') { | ||
this.parts = (Array.isArray(obj.parts) ? obj.parts : [ obj.parts ]).map(function (part) { | ||
return part && part.isMessyMessage ? part : new Message(part); | ||
}); | ||
} else if (typeof obj.rawBody !== 'undefined') { | ||
this.rawBody = obj.rawBody; | ||
} else if (typeof obj.body !== 'undefined') { | ||
this.body = obj.body; | ||
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(obj.body)) { | ||
this.unchunkedBody = obj.body; | ||
} else { | ||
this.body = obj.body; | ||
} | ||
} else if (typeof obj.unchunkedBody !== 'undefined') { | ||
@@ -257,2 +265,3 @@ this.unchunkedBody = obj.unchunkedBody; | ||
} else { | ||
var boundary = this.boundary || ''; | ||
if (this._bodyMustBeBuffer) { | ||
@@ -265,3 +274,3 @@ var chunks = []; | ||
} | ||
chunks.push(new Buffer('--' + this.boundary + '\r\n')); | ||
chunks.push(new Buffer('--' + boundary + '\r\n')); | ||
var serializedPart = part.serialize(); | ||
@@ -274,6 +283,6 @@ if (!Buffer.isBuffer(serializedPart)) { | ||
chunks.push(new Buffer('\r\n--' + this.boundary + '--\r\n')); | ||
chunks.push(new Buffer('\r\n--' + boundary + '--\r\n')); | ||
return Buffer.concat(chunks); | ||
} else { | ||
return '--' + this.boundary + '\r\n' + this._parts.join('\r\n--' + this.boundary + '\r\n') + '\r\n--' + this.boundary + '--\r\n'; | ||
return '--' + boundary + '\r\n' + this._parts.join('\r\n--' + boundary + '\r\n') + '\r\n--' + boundary + '--\r\n'; | ||
} | ||
@@ -363,26 +372,24 @@ } | ||
if (!this._parts && this.isMultipart) { | ||
var boundary = this.boundary; | ||
if (boundary) { | ||
var bodyAsString; | ||
if (typeof Buffer === 'function' && Buffer.isBuffer(this.body)) { | ||
bodyAsString = this.body.toString('ascii'); | ||
} else { | ||
bodyAsString = this.body; | ||
var boundary = this.boundary || '', | ||
bodyAsString; | ||
if (typeof Buffer === 'function' && Buffer.isBuffer(this.body)) { | ||
bodyAsString = this.body.toString('ascii'); | ||
} else { | ||
bodyAsString = this.body; | ||
} | ||
var boundaryRegExp = new RegExp('(^|\r\n?|\n\r?)--' + quoteRegExp(boundary) + '(--)?(?:\r\n?|\n\r?|$)', 'g'), | ||
startIndex = -1, | ||
parts = [], | ||
match; | ||
// TODO: Basic validation of end marker etc. | ||
while ((match = boundaryRegExp.exec(bodyAsString))) { | ||
var index = match.index; | ||
if (startIndex !== -1) { | ||
parts.push(new Message(this.body.slice(startIndex, index))); | ||
} | ||
var boundaryRegExp = new RegExp('(^|\r\n?|\n\r?)--' + quoteRegExp(boundary) + '(--)?(?:\r\n?|\n\r?|$)', 'g'), | ||
startIndex = -1, | ||
parts = [], | ||
match; | ||
// TODO: Basic validation of end marker etc. | ||
while ((match = boundaryRegExp.exec(bodyAsString))) { | ||
var index = match.index; | ||
if (startIndex !== -1) { | ||
parts.push(new Message(this.body.slice(startIndex, index))); | ||
} | ||
startIndex = index + match[0].length; | ||
} | ||
if (parts.length > 0) { | ||
this._parts = parts; | ||
} | ||
startIndex = index + match[0].length; | ||
} | ||
if (parts.length > 0) { | ||
this._parts = parts; | ||
} | ||
} | ||
@@ -389,0 +396,0 @@ return this._parts; |
@@ -10,3 +10,5 @@ function StatusLine(obj) { | ||
StatusLine.prototype.populate = function (obj) { | ||
if (typeof obj === 'string') { | ||
if (typeof obj === 'number') { | ||
this.populateFromObject({ statusCode: obj }); | ||
} else if (typeof obj === 'string') { | ||
this.populateFromString(obj); | ||
@@ -13,0 +15,0 @@ } else if (obj && typeof obj === 'object' && !Buffer.isBuffer(obj)) { |
{ | ||
"name": "messy", | ||
"version": "6.2.0", | ||
"version": "6.3.0", | ||
"description": "Object model for HTTP and RFC822 messages", | ||
@@ -12,3 +12,3 @@ "main": "lib/index.js", | ||
"test": "mocha && npm run lint", | ||
"travis": "npm test && npm run coverage && <coverage/lcov.info coveralls", | ||
"travis": "npm test && npm run coverage && (<coverage/lcov.info coveralls || true)", | ||
"coverage": "NODE_ENV=development istanbul cover _mocha -- --reporter dot && echo google-chrome coverage/lcov-report/index.html" | ||
@@ -29,7 +29,7 @@ }, | ||
"devDependencies": { | ||
"coveralls": "=2.11.1", | ||
"istanbul": "=0.3.0", | ||
"jshint": "=2.5.3", | ||
"mocha": "=1.21.4", | ||
"unexpected": "6.3.1" | ||
"coveralls": "2.11.2", | ||
"istanbul": "0.3.15", | ||
"jshint": "2.8.0", | ||
"mocha": "2.2.5", | ||
"unexpected": "8.0.1" | ||
}, | ||
@@ -36,0 +36,0 @@ "dependencies": { |
@@ -19,3 +19,3 @@ /*global describe, it*/ | ||
expect(httpConversation.exchanges, 'to be a non-empty array whose items satisfy', 'to be an', HttpExchange); | ||
expect(httpConversation.exchanges, 'to have items satisfying', 'to be an', HttpExchange); | ||
expect( | ||
@@ -22,0 +22,0 @@ httpConversation.toString(), |
@@ -162,2 +162,118 @@ /*global describe, it*/ | ||
}); | ||
describe('without a verb in the request line', function () { | ||
it('should assume GET', function () { | ||
expect(new HttpRequest('/foo'), 'to satisfy', { | ||
method: 'GET', | ||
path: '/foo' | ||
}); | ||
}); | ||
}); | ||
it('should accept host and port as options', function () { | ||
expect(new HttpRequest({ host: 'foo.com', port: 987 }), 'to have properties', { | ||
host: 'foo.com', | ||
port: 987 | ||
}); | ||
}); | ||
describe('with a url passed in the request line', function () { | ||
it('should set the Host header', function () { | ||
var httpRequest = new HttpRequest('GET http://foo.com/'); | ||
expect(httpRequest.headers.get('Host'), 'to equal', 'foo.com'); | ||
}); | ||
it('should set the host property', function () { | ||
expect(new HttpRequest('GET http://foo.com/').host, 'to equal', 'foo.com'); | ||
}); | ||
it('should set the port property when explicitly given', function () { | ||
expect(new HttpRequest('GET http://foo.com:987/').port, 'to equal', 987); | ||
}); | ||
it('should set the port property to 80 when http', function () { | ||
expect(new HttpRequest('GET http://foo.com/').port, 'to equal', 80); | ||
}); | ||
it('should set the port property to 443 when https', function () { | ||
expect(new HttpRequest('GET https://foo.com/').port, 'to equal', 443); | ||
}); | ||
it('should set the path', function () { | ||
expect(new HttpRequest('GET http://foo.com/heythere/you').path, 'to equal', '/heythere/you'); | ||
}); | ||
it('should set the Host header and include the port if given', function () { | ||
var httpRequest = new HttpRequest('GET http://foo.com:987/'); | ||
expect(httpRequest.headers.get('Host'), 'to equal', 'foo.com:987'); | ||
}); | ||
it('should not overwrite an explicit Host header', function () { | ||
var httpRequest = new HttpRequest('GET http://foo.com/\r\nHost: bar.com'); | ||
expect(httpRequest.headers.get('Host'), 'to equal', 'bar.com'); | ||
}); | ||
it('should set the "encrypted" property if the protocol is https', function () { | ||
expect(new HttpRequest('GET https://foo.com/'), 'to satisfy', { encrypted: true }); | ||
}); | ||
it('should not set the "encrypted" property if the protocol is http', function () { | ||
expect(new HttpRequest('GET http://foo.com/'), 'to satisfy', { encrypted: expect.it('to be falsy') }); | ||
}); | ||
it('should set the Authorization header if credentials are passed in the url', function () { | ||
var httpRequest = new HttpRequest('GET https://foo:bar@foo.com/'); | ||
expect(httpRequest.headers.get('Authorization'), 'to equal', 'Basic Zm9vOmJhcg=='); | ||
}); | ||
}); | ||
describe('with a url passed in an options object', function () { | ||
it('should set the Host header', function () { | ||
var httpRequest = new HttpRequest({ url: 'GET http://foo.com/' }); | ||
expect(httpRequest.headers.get('Host'), 'to equal', 'foo.com'); | ||
}); | ||
it('should set the host property', function () { | ||
expect(new HttpRequest({ url: 'GET http://foo.com/' }).host, 'to equal', 'foo.com'); | ||
}); | ||
it('should set the port property when explicitly given', function () { | ||
expect(new HttpRequest({ url: 'GET http://foo.com:987/' }).port, 'to equal', 987); | ||
}); | ||
it('should set the port property to 80 when http', function () { | ||
expect(new HttpRequest({ url: 'GET http://foo.com/' }).port, 'to equal', 80); | ||
}); | ||
it('should set the port property to 443 when https', function () { | ||
expect(new HttpRequest({ url: 'GET https://foo.com/' }).port, 'to equal', 443); | ||
}); | ||
it('should set the path', function () { | ||
expect(new HttpRequest({ url: 'GET http://foo.com/heythere/you' }).path, 'to equal', '/heythere/you'); | ||
}); | ||
it('should set the Host header and include the port if given', function () { | ||
var httpRequest = new HttpRequest({ url: 'GET http://foo.com:987/' }); | ||
expect(httpRequest.headers.get('Host'), 'to equal', 'foo.com:987'); | ||
}); | ||
it('should not overwrite an explicit Host header', function () { | ||
var httpRequest = new HttpRequest({ url: 'GET http://foo.com/', headers: { Host: 'bar.com' } }); | ||
expect(httpRequest.headers.get('Host'), 'to equal', 'bar.com'); | ||
}); | ||
it('should set the "encrypted" property if the protocol is https', function () { | ||
expect(new HttpRequest({ url: 'GET https://foo.com/' }), 'to satisfy', { encrypted: true }); | ||
}); | ||
it('should not set the "encrypted" property if the protocol is http', function () { | ||
expect(new HttpRequest({ url: 'GET http://foo.com/' }), 'to satisfy', { encrypted: expect.it('to be falsy') }); | ||
}); | ||
it('should set the Authorization header if credentials are passed in the url', function () { | ||
var httpRequest = new HttpRequest({ url: 'GET https://foo:bar@foo.com/' }); | ||
expect(httpRequest.headers.get('Authorization'), 'to equal', 'Basic Zm9vOmJhcg=='); | ||
}); | ||
}); | ||
}); |
@@ -43,2 +43,8 @@ /*global describe, it*/ | ||
it('should accept a number and interpret it as the status code', function () { | ||
expect(new HttpResponse(404), 'to have properties', { | ||
statusCode: 404 | ||
}); | ||
}); | ||
it('should parse a partial status line', function () { | ||
@@ -45,0 +51,0 @@ expect(new HttpResponse('HTTP/1.1 200'), 'to have properties', { |
@@ -169,2 +169,7 @@ /*global describe, it*/ | ||
it('should treat a body passed as a Buffer as the unchunked body', function () { | ||
var message = new Message({ body: new Buffer([0xff]) }); | ||
expect(message._unchunkedBody, 'to equal', new Buffer([0xff])); | ||
}); | ||
describe('#hasEmptyBody', function () { | ||
@@ -229,2 +234,75 @@ it('should consider a zero length Buffer to be an empty body', function () { | ||
describe('with parts passed to the constructor', function () { | ||
it('should accept both messy.Message instances and valid constructor arguments ', function () { | ||
var message = new Message({ | ||
headers: 'Content-Type: multipart/mixed', | ||
parts: [ | ||
new Message('Content-Type: text/html\r\n\r\n<h1>Hello, world!</h1>'), | ||
{ headers: 'Content-Type: text/plain', body: 'Hello, world!' }, | ||
'Content-Type: text/foo\r\n\r\nhey' | ||
] | ||
}); | ||
expect(message.parts.length, 'to equal', 3); | ||
expect( | ||
message.toString(), | ||
'to equal', | ||
'Content-Type: multipart/mixed\r\n' + | ||
'\r\n' + | ||
'--\r\n' + | ||
'Content-Type: text/html\r\n' + | ||
'\r\n' + | ||
'<h1>Hello, world!</h1>\r\n' + | ||
'--\r\n' + | ||
'Content-Type: text/plain\r\n' + | ||
'\r\n' + | ||
'Hello, world!\r\n' + | ||
'--\r\n' + | ||
'Content-Type: text/foo\r\n' + | ||
'\r\n' + | ||
'hey\r\n' + | ||
'----\r\n' | ||
); | ||
}); | ||
it('should pick up the boundary with boundary', function () { | ||
var message = new Message({ | ||
headers: 'Content-Type: multipart/mixed; boundary=foo', | ||
parts: [ | ||
new Message('Content-Type: text/html\r\n\r\n<h1>Hello, world!</h1>') | ||
] | ||
}); | ||
expect(message.parts.length, 'to equal', 1); | ||
expect( | ||
message.toString(), | ||
'to equal', | ||
'Content-Type: multipart/mixed; boundary=foo\r\n' + | ||
'\r\n' + | ||
'--foo\r\n' + | ||
'Content-Type: text/html\r\n' + | ||
'\r\n' + | ||
'<h1>Hello, world!</h1>\r\n' + | ||
'--foo--\r\n' | ||
); | ||
}); | ||
it('should allow passing a single part', function () { | ||
var message = new Message({ | ||
headers: 'Content-Type: multipart/mixed; boundary=foo', | ||
parts: new Message('Content-Type: text/html\r\n\r\n<h1>Hello, world!</h1>') | ||
}); | ||
expect(message.parts.length, 'to equal', 1); | ||
expect( | ||
message.toString(), | ||
'to equal', | ||
'Content-Type: multipart/mixed; boundary=foo\r\n' + | ||
'\r\n' + | ||
'--foo\r\n' + | ||
'Content-Type: text/html\r\n' + | ||
'\r\n' + | ||
'<h1>Hello, world!</h1>\r\n' + | ||
'--foo--\r\n' | ||
); | ||
}); | ||
}); | ||
describe('with a multipart body', function () { | ||
@@ -533,2 +611,7 @@ var src = | ||
}); | ||
it('should decode application/x-www-form-urlencoded as text', function () { | ||
var src = new Buffer('Content-Type: application/x-www-form-urlencoded\n\nfoo=bar&data=%5B%22foo.txt%22%5D', 'ascii'); | ||
expect(new Message(src).body, 'to equal', 'foo=bar&data=%5B%22foo.txt%22%5D'); | ||
}); | ||
}); | ||
@@ -535,0 +618,0 @@ |
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
146556
3055