Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(NODE-4769)!: remove ISO-8859-1 string support from Binary #602

Merged
merged 1 commit into from
Jul 28, 2023
Merged
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
65 changes: 16 additions & 49 deletions src/binary.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isUint8Array } from './parser/utils';
import { isAnyArrayBuffer, isUint8Array } from './parser/utils';
import type { EJSONOptions } from './extended_json';
import { BSONError } from './error';
import { BSON_BINARY_SUBTYPE_UUID_NEW } from './constants';
Expand Down Expand Up @@ -65,27 +65,19 @@ export class Binary extends BSONValue {

/**
* Create a new Binary instance.
*
* This constructor can accept a string as its first argument. In this case,
* this string will be encoded using ISO-8859-1, **not** using UTF-8.
* This is almost certainly not what you want. Use `new Binary(Buffer.from(string))`
* instead to convert the string to a Buffer using UTF-8 first.
*
* @param buffer - a buffer object containing the binary data.
* @param subType - the option binary type.
*/
constructor(buffer?: string | BinarySequence, subType?: number) {
constructor(buffer?: BinarySequence, subType?: number) {
super();
if (
!(buffer == null) &&
!(typeof buffer === 'string') &&
typeof buffer === 'string' &&
!ArrayBuffer.isView(buffer) &&
!(buffer instanceof ArrayBuffer) &&
!isAnyArrayBuffer(buffer) &&
!Array.isArray(buffer)
) {
throw new BSONError(
'Binary can only be constructed from string, Buffer, TypedArray, or Array<number>'
);
throw new BSONError('Binary can only be constructed from Uint8Array or number[]');
}

this.sub_type = subType ?? Binary.BSON_BINARY_SUBTYPE_DEFAULT;
Expand All @@ -95,17 +87,9 @@ export class Binary extends BSONValue {
this.buffer = ByteUtils.allocate(Binary.BUFFER_SIZE);
this.position = 0;
} else {
if (typeof buffer === 'string') {
// string
this.buffer = ByteUtils.fromISO88591(buffer);
} else if (Array.isArray(buffer)) {
// number[]
this.buffer = ByteUtils.fromNumberArray(buffer);
} else {
// Buffer | TypedArray | ArrayBuffer
this.buffer = ByteUtils.toLocalBufferType(buffer);
}

this.buffer = Array.isArray(buffer)
? ByteUtils.fromNumberArray(buffer)
: ByteUtils.toLocalBufferType(buffer);
this.position = this.buffer.byteLength;
}
}
Expand Down Expand Up @@ -147,12 +131,12 @@ export class Binary extends BSONValue {
}

/**
* Writes a buffer or string to the binary.
* Writes a buffer to the binary.
*
* @param sequence - a string or buffer to be written to the Binary BSON object.
* @param offset - specify the binary of where to write the content.
*/
write(sequence: string | BinarySequence, offset: number): void {
write(sequence: BinarySequence, offset: number): void {
offset = typeof offset === 'number' ? offset : this.position;

// If the buffer is to small let's extend the buffer
Expand All @@ -169,10 +153,7 @@ export class Binary extends BSONValue {
this.position =
offset + sequence.byteLength > this.position ? offset + sequence.length : this.position;
} else if (typeof sequence === 'string') {
const bytes = ByteUtils.fromISO88591(sequence);
this.buffer.set(bytes, offset);
this.position =
offset + sequence.length > this.position ? offset + sequence.length : this.position;
throw new BSONError('input cannot be string');
}
}

Expand All @@ -189,26 +170,12 @@ export class Binary extends BSONValue {
return this.buffer.slice(position, position + length);
}

/**
* Returns the value of this binary as a string.
* @param asRaw - Will skip converting to a string
* @remarks
* This is handy when calling this function conditionally for some key value pairs and not others
*/
value(asRaw?: boolean): string | BinarySequence {
asRaw = !!asRaw;

/** returns a view of the binary value as a Uint8Array */
value(): Uint8Array {
// Optimize to serialize for the situation where the data == size of buffer
if (asRaw && this.buffer.length === this.position) {
return this.buffer;
}

// If it's a node.js buffer object
if (asRaw) {
return this.buffer.slice(0, this.position);
}
// TODO(NODE-4361): remove binary string support, value(true) should be the default / only option here.
return ByteUtils.toISO88591(this.buffer.subarray(0, this.position));
return this.buffer.length === this.position
? this.buffer
: this.buffer.subarray(0, this.position);
}

/** the length of the binary sequence */
Expand Down
12 changes: 5 additions & 7 deletions test/node/bson_node_only_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const Buffer = require('buffer').Buffer;

describe('BSON - Node only', function () {
it('Should Correctly Serialize and Deserialize a big Binary object', function (done) {
var data = fs.readFileSync(path.resolve(__dirname, './data/test_gs_weird_bug.png'), 'binary');
var data = fs.readFileSync(path.resolve(__dirname, './data/test_gs_weird_bug.png'));
var bin = new Binary();
bin.write(data);
var doc = { doc: bin };
Expand All @@ -26,18 +26,17 @@ describe('BSON - Node only', function () {
});

describe('Full BSON - Node only', function () {
it('Should Correctly Serialize and Deserialize a big Binary object', function (done) {
var data = fs.readFileSync(path.resolve(__dirname, './data/test_gs_weird_bug.png'), 'binary');
it('Should Correctly Serialize and Deserialize a big Binary object', function () {
var data = fs.readFileSync(path.resolve(__dirname, './data/test_gs_weird_bug.png'));
var bin = new Binary();
bin.write(data);
var doc = { doc: bin };
var serialized_data = BSON.serialize(doc);
var deserialized_data = BSON.deserialize(serialized_data);
expect(doc.doc.value()).to.equal(deserialized_data.doc.value());
done();
expect(doc.doc.value()).to.deep.equal(deserialized_data.doc.value());
});

it('Should Correctly Deserialize bson file from mongodump', function (done) {
it('Should Correctly Deserialize bson file from mongodump', function () {
var data = fs.readFileSync(path.resolve(__dirname, './data/test.bson'), { encoding: null });
data = Buffer.from(data);
var docs = [];
Expand All @@ -46,6 +45,5 @@ describe('Full BSON - Node only', function () {
bsonIndex = BSON.deserializeStream(data, bsonIndex, 1, docs, docs.length, { isArray: true });

expect(docs.length).to.equal(1);
done();
});
});
2 changes: 1 addition & 1 deletion test/node/bson_types_construction_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('Constructing BSON types', function () {
expect(() => new BSON.ObjectId()).to.not.throw();
expect(() => new BSON.BSONRegExp('aaa')).to.not.throw();
expect(() => new BSON.BSONSymbol('aaa')).to.not.throw();
expect(() => new BSON.Binary('aaa')).to.not.throw();
expect(() => new BSON.Binary(new Uint8Array())).to.not.throw();
expect(() => new BSON.Code(function () {})).to.not.throw();
expect(() => new BSON.Decimal128('123')).to.not.throw();
expect(() => new BSON.Double(2.3)).to.not.throw();
Expand Down
4 changes: 2 additions & 2 deletions test/node/extended_json.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ describe('Extended JSON', function () {

it('should serialize from BSON object to EJSON object', function () {
const doc = {
binary: new Binary(''),
binary: new Binary(new Uint8Array([0, 0, 0]), 0xef),
code: new Code('function() {}'),
dbRef: new DBRef('tests', new Int32(1), 'test'),
decimal128: new Decimal128('128'),
Expand All @@ -203,7 +203,7 @@ describe('Extended JSON', function () {

const result = EJSON.serialize(doc, { relaxed: false });
expect(result).to.deep.equal({
binary: { $binary: { base64: '', subType: '00' } },
binary: { $binary: { base64: 'AAAA', subType: 'ef' } },
code: { $code: 'function() {}' },
dbRef: { $ref: 'tests', $id: { $numberInt: '1' }, $db: 'test' },
decimal128: { $numberDecimal: '128' },
Expand Down
7 changes: 3 additions & 4 deletions test/node/test_full_bson.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,17 +260,16 @@ describe('Full BSON', function () {
/**
* @ignore
*/
it('Should Correctly Serialize and Deserialize a Binary object', function (done) {
it('Should Correctly Serialize and Deserialize a Binary object', function () {
var bin = new Binary();
var string = 'binstring';
for (var index = 0; index < string.length; index++) {
bin.put(string.charAt(index));
bin.put(string[index]);
}
var doc = { doc: bin };
var serialized_data = BSON.serialize(doc);
var deserialized_data = BSON.deserialize(serialized_data);
expect(doc.doc.value()).to.equal(deserialized_data.doc.value());
done();
expect(doc.doc.value()).to.deep.equal(deserialized_data.doc.value());
});

it('Should Correctly Serialize and Deserialize a ArrayBuffer object', function () {
Expand Down