Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added lib/.index.js.swp
Binary file not shown.
44 changes: 43 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,54 @@ exports.encodePacket = function (packet, supportsBinary, utf8encode, callback) {

// data fragment is optional
if (undefined !== packet.data) {
encoded += utf8encode ? utf8.encode(String(packet.data)) : String(packet.data);
if (utf8encode) {
encoded += utf8.encode(sanitizeLoneSurrogates(String(packet.data)));
} else {
encoded += String(packet.data);
}
}

return callback('' + encoded);
};

/**
* Sanitize a WTF-8 string, replacing lone surrogates with
* U+FFFD 'REPLACEMENT CHARACTER'
*/
function sanitizeLoneSurrogates(str) {
var i = 0;
var output = '';
while (i < str.length) {
var code = str.charCodeAt(i);
if (code >= 0xd800 && code <= 0xdbff) {
// High surrogate -- expect next char to be a low surrogate
if (i + 1 < str.length) {
var nextCode = str.charCodeAt(i + 1);
if (nextCode >= 0xdc00 && nextCode <= 0xdfff) {
// Valid surrogate pair
output += str[i];
output += str[i + 1];
i++;
} else {
// High surrogate was not followed by a low surrogate
output += '\ufffd';
}
} else {
// High surrogate was at the end of a string (and therefore
// not followed by a low surrogate)
output += '\ufffd';
}
} else if (code >= 0xdc00 && code <= 0xdfff) {
// Low surrogate by itself -- invalid
output += '\ufffd';
} else {
output += str[i];
}
i++;
}
return output;
}

/**
* Encode Buffer data
*/
Expand Down
18 changes: 17 additions & 1 deletion test/node/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('parser', function() {
var data = new Buffer(5);
for (var i = 0; i < data.length; i++) { data[i] = i; }
encode({ type: 'message', data: data }, function(encoded) {
expect(decode(encoded)).to.eql({ type: 'message', data: data });
expect(decode(encoded)).to.eql({ type: 'message', data: data });
done();
});
});
Expand Down Expand Up @@ -130,6 +130,22 @@ describe('parser', function() {
});
});

it('should encode a string message with lone surrogates replaced', function(done) {
var data = String.fromCharCode(0xd800);
encode({ type: 'message', data: data }, null, true, function(encoded) {
expect(decode(encoded, null, true)).to.eql({ type: 'message', data: '\ufffd' });
done();
});
});

it('should encode a string message with valid surrogate pairs', function(done) {
var data = String.fromCharCode(0xd800) + String.fromCharCode(0xdc00);
encode({ type: 'message', data: data }, null, true, function(encoded) {
expect(decode(encoded, null, true)).to.eql({ type: 'message', data: data });
done();
});
});

});

function areArraysEqual(x, y) {
Expand Down