Redecode unknown protobuf fields before writing

This commit is contained in:
Fedor Indutny 2021-07-28 16:44:58 -07:00 committed by GitHub
parent efe5d86424
commit 6e4a3561f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 7 deletions

View file

@ -50,18 +50,38 @@ index 491dd30..ec03e9f 100644
("}") ("}")
diff --git a/node_modules/protobufjs/src/encoder.js b/node_modules/protobufjs/src/encoder.js diff --git a/node_modules/protobufjs/src/encoder.js b/node_modules/protobufjs/src/encoder.js
index c803e99..d3c6e86 100644 index c803e99..50cc3e6 100644
--- a/node_modules/protobufjs/src/encoder.js --- a/node_modules/protobufjs/src/encoder.js
+++ b/node_modules/protobufjs/src/encoder.js +++ b/node_modules/protobufjs/src/encoder.js
@@ -94,6 +94,13 @@ function encoder(mtype) { @@ -36,6 +36,21 @@ function encoder(mtype) {
// "when a message is serialized its known fields should be written sequentially by field number"
var fields = /* initializes */ mtype.fieldsArray.slice().sort(util.compareFieldsById);
+ var unknownRef = "m" + util.safeProp("__unknownFields");
+
+ // Redecode unknown fields and apply them to the message before encoding
+ gen
+ ("var fullyUnknown=[]")
+ ("if(%s) {", unknownRef)
+ ("for(var i=0;i<%s.length;++i) {", unknownRef)
+ ("try {")
+ ("var known=this.ctor.decode(%s[i])", unknownRef)
+ ("fullyUnknown=fullyUnknown.concat(known.__unknownFields||[])")
+ ("m=Object.assign(known,m)")
+ ("}catch(_){}")
+ ("}")
+ ("}")
+
for (var i = 0; i < fields.length; ++i) {
var field = fields[i].resolve(),
index = mtype._fieldsArray.indexOf(field),
@@ -94,6 +109,11 @@ function encoder(mtype) {
} }
} }
+ var unknownRef = "m" + util.safeProp("__unknownFields");
+ gen + gen
+ ("if (%s) {", unknownRef) + ("for(var i=0;i<fullyUnknown.length;++i) {")
+ ("for (var i=0;i<%s.length;++i)", unknownRef) + ("w.__unknownField(fullyUnknown[i])")
+ ("w.__unknownField(%s[i])", unknownRef)
+ ("}") + ("}")
+ +
return gen return gen

View file

@ -88,8 +88,31 @@ describe('Proto#__unknownFields', () => {
const decodedConcat = Full.decode(concat); const decodedConcat = Full.decode(concat);
assert.strictEqual(decodedConcat.a, 'hello'); assert.strictEqual(decodedConcat.a, 'hello');
assert.strictEqual(decodedConcat.b, true); assert.isTrue(decodedConcat.b);
assert.strictEqual(decodedConcat.c, 42); assert.strictEqual(decodedConcat.c, 42);
assert.strictEqual(Buffer.from(decodedConcat.d).toString(), 'ohai'); assert.strictEqual(Buffer.from(decodedConcat.d).toString(), 'ohai');
}); });
it('should decode unknown fields before reencoding them', () => {
const full = Full.encode({
a: 'hello',
b: true,
c: 42,
d: Buffer.from('ohai'),
}).finish();
const partial = Partial.decode(full);
assert.isUndefined(partial.b);
const encoded = Full.encode({
...partial,
b: false,
}).finish();
const decoded = Full.decode(encoded);
assert.strictEqual(decoded.a, 'hello');
assert.isFalse(decoded.b);
assert.strictEqual(decoded.c, 42);
assert.strictEqual(Buffer.from(decoded.d).toString(), 'ohai');
});
}); });