@homebridge/hap-client
Version:
A client for HAP-NodeJS.
237 lines • 9.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
function httpMessageParser(message) {
const result = {
protocol: null,
httpVersion: null,
statusCode: null,
statusMessage: null,
method: null,
url: null,
headers: null,
body: null,
boundary: null,
multipart: null,
additional: null,
};
let messageString = '';
let headerNewlineIndex = 0;
let fullBoundary = null;
if (httpMessageParser._isBuffer(message)) {
messageString = message.toString();
}
else if (typeof message === 'string') {
messageString = message;
message = httpMessageParser._createBuffer(messageString);
}
else {
return result;
}
messageString = messageString.replace(/\r\n/gim, '\n');
(function () {
const firstNonWhitespaceRegex = /[\w-]+/gim;
const firstNonWhitespaceIndex = messageString.search(firstNonWhitespaceRegex);
if (firstNonWhitespaceIndex > 0) {
message = message.slice(firstNonWhitespaceIndex, message.length);
messageString = message.toString();
}
})();
(function () {
const possibleRequestLine = messageString.split(/\n|\r\n/)[0];
const requestLineMatch = possibleRequestLine.match(httpMessageParser._requestLineRegex);
if (Array.isArray(requestLineMatch) && requestLineMatch.length > 1) {
result.protocol = requestLineMatch[1];
result.httpVersion = parseFloat(requestLineMatch[2]);
result.statusCode = parseInt(requestLineMatch[3], 10);
result.statusMessage = requestLineMatch[4];
}
else {
const responseLineMath = possibleRequestLine.match(httpMessageParser._responseLineRegex);
if (Array.isArray(responseLineMath) && responseLineMath.length > 1) {
result.method = responseLineMath[1];
result.url = responseLineMath[2];
result.httpVersion = parseFloat(responseLineMath[3]);
}
}
})();
(function () {
headerNewlineIndex = messageString.search(httpMessageParser._headerNewlineRegex);
if (headerNewlineIndex > -1) {
headerNewlineIndex = headerNewlineIndex + 1;
}
else {
if (result.httpVersion) {
headerNewlineIndex = messageString.length;
}
}
const headersString = messageString.substr(0, headerNewlineIndex);
const headers = httpMessageParser._parseHeaders(headersString);
if (Object.keys(headers).length > 0) {
result.headers = headers;
}
})();
(function () {
if (!result.boundary) {
const boundaryMatch = messageString.match(httpMessageParser._boundaryRegex);
if (Array.isArray(boundaryMatch) && boundaryMatch.length) {
fullBoundary = boundaryMatch[0].replace(/[\r\n]+/gi, '');
const boundary = fullBoundary.replace(/^--/, '');
result.boundary = boundary;
}
}
})();
(function () {
let start = headerNewlineIndex;
let end = (result.headers && result.headers['Content-Length'] ? result.headers['Content-Length'] + start : messageString.length);
const firstBoundaryIndex = messageString.indexOf(fullBoundary);
if (firstBoundaryIndex > -1 && result.boundary) {
start = headerNewlineIndex;
end = firstBoundaryIndex;
}
if (headerNewlineIndex > -1) {
const body = messageString.slice(start, end);
result.additional = messageString.slice(end);
if (body && body.length) {
if ((result.headers && result.headers['Content-Type'] === 'application/hap+json') ||
(result.headers && result.headers['Content-Type'] === 'application/json')) {
try {
if (result.headers['Content-Length']) {
result.body = body;
}
else {
result.body = body.split('\n')[1];
}
}
catch (err) {
}
}
else {
result.body = body;
}
}
}
})();
(function () {
if (result.boundary) {
const multipartStart = messageString.indexOf(fullBoundary) + fullBoundary.length;
const multipartEnd = messageString.lastIndexOf(fullBoundary);
const multipartBody = messageString.substr(multipartStart, multipartEnd);
const splitRegex = new RegExp('^' + fullBoundary + '.*[\n\r]?$', 'gm');
const parts = multipartBody.split(splitRegex);
result.multipart = parts.filter(httpMessageParser._isTruthy).map(function (part, i) {
const result = {
headers: null,
body: null,
meta: {
body: {
byteOffset: {
start: null,
end: null,
},
},
},
};
const newlineRegex = /\n\n|\r\n\r\n/gim;
let newlineIndex = 0;
let newlineMatch = newlineRegex.exec(part);
let body = null;
if (newlineMatch) {
newlineIndex = newlineMatch.index;
if (newlineMatch.index <= 0) {
newlineMatch = newlineRegex.exec(part);
if (newlineMatch) {
newlineIndex = newlineMatch.index;
}
}
}
const possibleHeadersString = part.substr(0, newlineIndex);
let startOffset = null;
let endOffset = null;
if (newlineIndex > -1) {
const headers = httpMessageParser._parseHeaders(possibleHeadersString);
if (Object.keys(headers).length > 0) {
result.headers = headers;
const boundaryIndexes = [];
for (let j = 0; j >= 0;) {
j = message.indexOf(fullBoundary, j);
if (j >= 0) {
boundaryIndexes.push(j);
j += fullBoundary.length;
}
}
const boundaryNewlineIndexes = [];
boundaryIndexes.slice(0, boundaryIndexes.length - 1).forEach(function (m, k) {
const partBody = message.slice(boundaryIndexes[k], boundaryIndexes[k + 1]).toString();
let headerNewlineIndex = partBody.search(/\n\n|\r\n\r\n/gim) + 2;
headerNewlineIndex = boundaryIndexes[k] + headerNewlineIndex;
boundaryNewlineIndexes.push(headerNewlineIndex);
});
startOffset = boundaryNewlineIndexes[i];
endOffset = boundaryIndexes[i + 1];
body = message.slice(startOffset, endOffset);
}
else {
body = part;
}
}
else {
body = part;
}
result.body = body;
result.meta.body.byteOffset.start = startOffset;
result.meta.body.byteOffset.end = endOffset;
return result;
});
}
})();
return result;
}
httpMessageParser._isTruthy = function _isTruthy(v) {
return !!v;
};
httpMessageParser._isNumeric = function _isNumeric(v) {
if (typeof v === 'number' && !isNaN(v)) {
return true;
}
v = (v || '').toString().trim();
if (!v) {
return false;
}
return !isNaN(v);
};
httpMessageParser._isBuffer = function (item) {
return ((httpMessageParser._isNodeBufferSupported() &&
typeof global === 'object' &&
global.Buffer.isBuffer(item)) ||
(item instanceof Object &&
item._isBuffer));
};
httpMessageParser._isNodeBufferSupported = function () {
return (typeof global === 'object' &&
typeof global.Buffer === 'function' &&
typeof global.Buffer.isBuffer === 'function');
};
httpMessageParser._parseHeaders = function _parseHeaders(body) {
const headers = {};
if (typeof body !== 'string') {
return headers;
}
body.split(/[\r\n]/).forEach(function (string) {
const match = string.match(/([\w-]+):\s*(.*)/i);
if (Array.isArray(match) && match.length === 3) {
const key = match[1];
const value = match[2];
headers[key] = httpMessageParser._isNumeric(value) ? Number(value) : value;
}
});
return headers;
};
httpMessageParser._requestLineRegex = /(HTTP|EVENT)\/(1\.0|1\.1|2\.0)\s+(\d+)\s+([\w\s-_]+)/i;
httpMessageParser._responseLineRegex = /(GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD|TRACE|CONNECT)\s+(.*)\s+HTTP\/(1\.0|1\.1|2\.0)/i;
httpMessageParser._headerNewlineRegex = /^[\r\n]+/gim;
httpMessageParser._boundaryRegex = /(\n|\r\n)+--[\w-]+(\n|\r\n)+/g;
httpMessageParser._createBuffer = function (data) {
return new Buffer(data);
};
exports.default = httpMessageParser;
//# sourceMappingURL=httpParser.js.map