mirror of
https://github.com/apache/thrift.git
synced 2026-10-29 17:05:46 +08:00
Client: js,nodejs,ts generate_deserialize_map_element emitted map[key] = value with key read from the peer. On a plain object "__proto__" is not an ordinary member name: the assignment runs the setter inherited from Object.prototype, which swaps the object's prototype when the value is an object and silently discards the entry when it is not. Neither stores the pair. Measured on generated code before the change, over a map<string, struct>: a map entry whose key is "__proto__" left the decoded map with no own keys and its prototype replaced by the value, so a member the application never received resolved to something the peer chose. For map<string, string> the entry simply vanished. defineProperty stores the pair in both cases, keeps Object.prototype, and leaves every other key on the plain assignment. The guard is emitted for every map, not only those whose values can be objects, because the silent-drop half applies to the rest. Three alternatives were built out as generated code and round-tripped before settling on this one. Object.create(null) is not viable: the generated writer calls this.<field>.hasOwnProperty(kiter), which such an object does not have, and Thrift.objectLength() returns 0 for it, so a decoded map could not be sent on. A Map changes the decoded type and breaks every caller that indexes it. Skipping the key discards data a peer may legitimately send. The generator has no mode switch here, so this covers browser js, js:node, js:es6, js:ts, js:jquery and the esm variant alike; all eight were generated, syntax-checked and confirmed to carry the guard. Stacked on the json_parse change, and it needs it: under TJSONProtocol the map arrives as an object json_parse built, so without that fix the key has already gone into the prototype before any generated code runs. Seven of the 54 cases below fail on this commit alone for exactly that reason, and pass on the pair. lib/nodejs/test/MapKeyTest.thrift and lib/nodejs/test/map_keys.test.js, written first: 54 cases over the binary, compact and JSON protocols, 27 failing before the change. The IDL sits with the test that uses it rather than in test/, which is the cross-language suite: nothing outside lib/nodejs generates from it, and lib/nodejs/Makefile.am already ships test/ wholesale, so it needs no EXTRA_DIST entry of its own the way test/Makefile.am does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
34 lines
1.2 KiB
Thrift
34 lines
1.2 KiB
Thrift
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
// Maps whose keys come off the wire, in the JavaScript generator's output. The
|
|
// value types differ on purpose: a generated map is a plain object, and what a
|
|
// member name does to one depends on what is being stored under it.
|
|
|
|
struct MapValue {
|
|
1: string s
|
|
}
|
|
|
|
struct MapKeyHolder {
|
|
1: map<string, MapValue> structValues
|
|
2: map<string, string> stringValues
|
|
3: map<string, list<string>> listValues
|
|
4: map<string, map<string, string>> mapValues
|
|
}
|