Bug 1941128 - Turn off network.dns.native_https_query on Mac again
[gecko.git] / js / xpconnect / loader / ModuleEnvironmentProxy.cpp
blob70238ddc3f36eb98fd9e801ed61d71ddc264bb73
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ModuleEnvironmentProxy.h"
9 #include "mozilla/Assertions.h" // MOZ_ASSERT
10 #include "mozilla/Maybe.h" // mozilla::Maybe
12 #include <stddef.h> // size_t
14 #include "js/Class.h" // JS::ObjectOpResult
15 #include "js/ErrorReport.h" // JS_ReportOutOfMemory
16 #include "js/GCVector.h" // JS::RootedVector
17 #include "js/Id.h" // JS::PropertyKey
18 #include "js/PropertyAndElement.h" // JS::IdVector, JS_HasPropertyById, JS_GetPropertyById, JS_Enumerate
19 #include "js/PropertyDescriptor.h" // JS::PropertyDescriptor, JS_GetOwnPropertyDescriptorById
20 #include "js/Proxy.h" // js::ProxyOptions, js::NewProxyObject, js::GetProxyPrivate
21 #include "js/RootingAPI.h" // JS::Rooted, JS::Handle, JS::MutableHandle
22 #include "js/TypeDecls.h" // JSContext, JSObject, JS::MutableHandleVector
23 #include "js/Value.h" // JS::Value
24 #include "js/friend/ErrorMessages.h" // JSMSG_*
25 #include "js/String.h"
26 #include "js/Modules.h"
28 namespace mozilla {
29 namespace loader {
31 struct ModuleEnvironmentProxyHandler : public js::BaseProxyHandler {
32 ModuleEnvironmentProxyHandler() : js::BaseProxyHandler(&gFamily, false) {}
34 bool defineProperty(JSContext* aCx, JS::Handle<JSObject*> aProxy,
35 JS::Handle<JS::PropertyKey> aId,
36 JS::Handle<JS::PropertyDescriptor> aDesc,
37 JS::ObjectOpResult& aResult) const override {
38 return aResult.fail(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE);
41 bool getPrototype(JSContext* aCx, JS::Handle<JSObject*> aProxy,
42 JS::MutableHandle<JSObject*> aProtop) const override {
43 aProtop.set(nullptr);
44 return true;
47 bool setPrototype(JSContext* aCx, JS::Handle<JSObject*> aProxy,
48 JS::Handle<JSObject*> aProto,
49 JS::ObjectOpResult& aResult) const override {
50 if (!aProto) {
51 return aResult.succeed();
53 return aResult.failCantSetProto();
56 bool getPrototypeIfOrdinary(
57 JSContext* aCx, JS::Handle<JSObject*> aProxy, bool* aIsOrdinary,
58 JS::MutableHandle<JSObject*> aProtop) const override {
59 *aIsOrdinary = false;
60 return true;
63 bool setImmutablePrototype(JSContext* aCx, JS::Handle<JSObject*> aProxy,
64 bool* aSucceeded) const override {
65 *aSucceeded = true;
66 return true;
69 bool preventExtensions(JSContext* aCx, JS::Handle<JSObject*> aProxy,
70 JS::ObjectOpResult& aResult) const override {
71 aResult.succeed();
72 return true;
75 bool isExtensible(JSContext* aCx, JS::Handle<JSObject*> aProxy,
76 bool* aExtensible) const override {
77 *aExtensible = false;
78 return true;
81 bool set(JSContext* aCx, JS::Handle<JSObject*> aProxy,
82 JS::Handle<JS::PropertyKey> aId, JS::Handle<JS::Value> aValue,
83 JS::Handle<JS::Value> aReceiver,
84 JS::ObjectOpResult& aResult) const override {
85 return aResult.failReadOnly();
88 bool delete_(JSContext* aCx, JS::Handle<JSObject*> aProxy,
89 JS::Handle<JS::PropertyKey> aId,
90 JS::ObjectOpResult& aResult) const override {
91 return aResult.failCantDelete();
94 bool getOwnPropertyDescriptor(
95 JSContext* aCx, JS::Handle<JSObject*> aProxy,
96 JS::Handle<JS::PropertyKey> aId,
97 JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> aDesc)
98 const override;
99 bool has(JSContext* aCx, JS::Handle<JSObject*> aProxy,
100 JS::Handle<JS::PropertyKey> aId, bool* aBp) const override;
101 bool get(JSContext* aCx, JS::Handle<JSObject*> aProxy,
102 JS::Handle<JS::Value> receiver, JS::Handle<JS::PropertyKey> aId,
103 JS::MutableHandle<JS::Value> aVp) const override;
104 bool ownPropertyKeys(
105 JSContext* aCx, JS::Handle<JSObject*> aProxy,
106 JS::MutableHandleVector<JS::PropertyKey> aProps) const override;
108 private:
109 static JSObject* getEnvironment(JS::Handle<JSObject*> aProxy) {
110 return &js::GetProxyPrivate(aProxy).toObject();
113 static bool equalsNamespace(JSContext* aCx, JS::Handle<JS::PropertyKey> aId,
114 bool* aMatch) {
115 if (!aId.isString()) {
116 *aMatch = false;
117 return true;
119 return JS_StringEqualsLiteral(aCx, aId.toString(), "*namespace*", aMatch);
122 public:
123 static const char gFamily;
124 static const ModuleEnvironmentProxyHandler gHandler;
127 MOZ_RUNINIT const ModuleEnvironmentProxyHandler
128 ModuleEnvironmentProxyHandler::gHandler;
129 const char ModuleEnvironmentProxyHandler::gFamily = 0;
131 bool ModuleEnvironmentProxyHandler::getOwnPropertyDescriptor(
132 JSContext* aCx, JS::Handle<JSObject*> aProxy,
133 JS::Handle<JS::PropertyKey> aId,
134 JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> aDesc) const {
135 bool isNamespace;
136 if (!equalsNamespace(aCx, aId, &isNamespace)) {
137 return false;
139 if (isNamespace) {
140 aDesc.reset();
141 return true;
144 JS::Rooted<JSObject*> envObj(aCx, getEnvironment(aProxy));
145 if (!JS_GetOwnPropertyDescriptorById(aCx, envObj, aId, aDesc)) {
146 return false;
149 if (aDesc.get().isNothing()) {
150 return true;
153 JS::PropertyDescriptor& desc = *aDesc.get();
155 desc.setConfigurable(false);
156 desc.setWritable(false);
157 desc.setEnumerable(true);
159 return true;
162 bool ModuleEnvironmentProxyHandler::has(JSContext* aCx,
163 JS::Handle<JSObject*> aProxy,
164 JS::Handle<JS::PropertyKey> aId,
165 bool* aBp) const {
166 bool isNamespace;
167 if (!equalsNamespace(aCx, aId, &isNamespace)) {
168 return false;
170 if (isNamespace) {
171 *aBp = false;
172 return true;
175 JS::Rooted<JSObject*> envObj(aCx, getEnvironment(aProxy));
176 return JS_HasOwnPropertyById(aCx, envObj, aId, aBp);
179 bool ModuleEnvironmentProxyHandler::get(
180 JSContext* aCx, JS::Handle<JSObject*> aProxy,
181 JS::Handle<JS::Value> aReceiver, JS::Handle<JS::PropertyKey> aId,
182 JS::MutableHandle<JS::Value> aVp) const {
183 bool isNamespace;
184 if (!equalsNamespace(aCx, aId, &isNamespace)) {
185 return false;
187 if (isNamespace) {
188 aVp.setUndefined();
189 return true;
192 JS::Rooted<JSObject*> envObj(aCx, getEnvironment(aProxy));
193 return JS_GetPropertyById(aCx, envObj, aId, aVp);
196 bool ModuleEnvironmentProxyHandler::ownPropertyKeys(
197 JSContext* aCx, JS::Handle<JSObject*> aProxy,
198 JS::MutableHandleVector<JS::PropertyKey> aProps) const {
199 JS::Rooted<JSObject*> envObj(aCx, getEnvironment(aProxy));
200 JS::Rooted<JS::IdVector> ids(aCx, JS::IdVector(aCx));
201 if (!JS_Enumerate(aCx, envObj, &ids)) {
202 return false;
205 for (size_t i = 0; i < ids.length(); i++) {
206 bool isNamespace;
207 if (!equalsNamespace(aCx, ids[i], &isNamespace)) {
208 return false;
210 if (isNamespace) {
211 continue;
213 if (!aProps.append(ids[i])) {
214 JS_ReportOutOfMemory(aCx);
215 return false;
219 return true;
222 JSObject* CreateModuleEnvironmentProxy(JSContext* aCx,
223 JS::Handle<JSObject*> aModuleObj) {
224 js::ProxyOptions options;
225 options.setLazyProto(true);
227 JS::Rooted<JSObject*> envObj(aCx, JS::GetModuleEnvironment(aCx, aModuleObj));
228 if (!envObj) {
229 return nullptr;
232 JS::Rooted<JS::Value> envVal(aCx, JS::ObjectValue(*envObj));
233 return NewProxyObject(aCx, &ModuleEnvironmentProxyHandler::gHandler, envVal,
234 nullptr, options);
237 } // namespace loader
238 } // namespace mozilla