Skip to content
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
116 changes: 116 additions & 0 deletions lib/core/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
module.exports = {
convertObject,
safeParseURL,
createTransparentProxy,
};

function convertObject(obj, ignore, ignoreKeyPaths) {
Expand Down Expand Up @@ -90,3 +91,118 @@
return null;
}
}

/**
* Create a Proxy that behaves like the real object, but remains transparent to
* monkeypatch libraries (e.g. defineProperty-based overrides).
*
* - Lazily creates the real object on first access.
* - Allows overriding properties on the proxy target (overlay) to take effect.
* - Delegates everything else to the real object.
*
* @param {Object} options

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 24)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 24)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 22)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 22)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 20)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 20)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 20)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 20)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 16)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 16)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 24)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 24)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 16)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 16)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 14)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 14)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 14)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 14)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 22)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 22)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 24)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 24)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 22)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 22)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 14)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 14)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 16)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 16)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 20)

Missing JSDoc @param "options" description

Check warning on line 103 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 20)

Missing JSDoc @param "options" description
* @param {Function} options.createReal Create the real object (lazy)
* @param {boolean} [options.bindFunctions=true] Bind real methods to the real object
* @return {Proxy}

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 24)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 24)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 22)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 22)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 20)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 20)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 20)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 20)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 16)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 16)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 24)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 24)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 16)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 16)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 14)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 14)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 14)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 14)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 22)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 22)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 24)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 24)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 22)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 22)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 14)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 14)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 16)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 16)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 20)

Missing JSDoc @return description

Check warning on line 106 in lib/core/utils.js

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 20)

Missing JSDoc @return description
*/
function createTransparentProxy({ createReal, bindFunctions = true }) {
if (typeof createReal !== 'function') {
throw new TypeError('createReal must be a function');
}

let real = null;
let error = null;
let initialized = false;

const init = () => {
if (initialized) {
if (error) throw error;
return;
}
initialized = true;
try {
real = createReal();
} catch (err) {
error = err;
throw err;
}
};

return new Proxy({}, {
get(target, prop, receiver) {
init();
// Check if property is defined on proxy target (monkeypatch overlay)
if (Object.getOwnPropertyDescriptor(target, prop)) {
return Reflect.get(target, prop, receiver);
}
const value = real[prop];
if (bindFunctions && typeof value === 'function') {
return value.bind(real);
}
return value;
},

set(target, prop, value, receiver) {
init();
if (Object.getOwnPropertyDescriptor(target, prop)) {
return Reflect.set(target, prop, value, receiver);
}
return Reflect.set(real, prop, value);
},

has(target, prop) {
init();
return prop in target || prop in real;
},

ownKeys(target) {
init();
const keys = new Set([ ...Reflect.ownKeys(real), ...Reflect.ownKeys(target) ]);
return Array.from(keys);
},

getOwnPropertyDescriptor(target, prop) {
init();
return Object.getOwnPropertyDescriptor(target, prop)
|| Object.getOwnPropertyDescriptor(real, prop);
},

deleteProperty(target, prop) {
init();
if (Object.getOwnPropertyDescriptor(target, prop)) {
return delete target[prop];
}
return delete real[prop];
},

getPrototypeOf() {
init();
return Object.getPrototypeOf(real);
},

setPrototypeOf(_target, proto) {
init();
return Reflect.setPrototypeOf(real, proto);
},

isExtensible() {
init();
return Reflect.isExtensible(real);
},

preventExtensions(target) {
init();
// Must also prevent extensions on target to satisfy Proxy invariants
const result = Reflect.preventExtensions(real);
if (result) {
Reflect.preventExtensions(target);
}
return result;
},

defineProperty(target, prop, descriptor) {
// Used by monkeypatch libs: keep overrides on proxy target (overlay layer).
return Reflect.defineProperty(target, prop, descriptor);
},
});
}
35 changes: 3 additions & 32 deletions lib/egg.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,39 +316,10 @@ class EggApplication extends EggCore {
options.lookup = options.lookup ?? self.config.httpclient.lookup;
realClient = new self.HttpClientNext(self, options);
};
return new Proxy({}, {
get(_target, prop) {
return utils.createTransparentProxy({
createReal() {
init();
const value = realClient[prop];
if (typeof value === 'function') {
return value.bind(realClient);
}
return value;
},
set(_target, prop, value) {
init();
realClient[prop] = value;
return true;
},
has(_target, prop) {
init();
return prop in realClient;
},
ownKeys() {
init();
return Reflect.ownKeys(realClient);
},
getOwnPropertyDescriptor(_target, prop) {
init();
return Object.getOwnPropertyDescriptor(realClient, prop);
},
deleteProperty(_target, prop) {
init();
return delete realClient[prop];
},
getPrototypeOf() {
init();
return Object.getPrototypeOf(realClient);
return realClient;
},
});
}
Expand Down
36 changes: 9 additions & 27 deletions test/lib/core/httpclient.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,16 @@ describe('test/lib/core/httpclient.test.js', () => {
});
});

it('should Proxy be fully functional', () => {
it('should Proxy be fully functional', async () => {
const httpclient = app.httpclient;
mm(app.httpclient, 'request', async () => ({
status: 500,
headers: { 'x-oss-request-id': 'mock request id' },
}));

const res = await app.curl(url + '/get_headers', { dataType: 'json' });
assert(res.status === 500);
mm.restore();

// Test get trap - method access
assert(typeof httpclient.request === 'function');
Expand All @@ -399,35 +407,9 @@ describe('test/lib/core/httpclient.test.js', () => {
const ownKeys = Reflect.ownKeys(httpclient);
assert(ownKeys.length > 0);

httpclient.testProp = 'test';
const customDescriptor = Object.getOwnPropertyDescriptor(httpclient, 'testProp');
assert(customDescriptor);
assert.equal(customDescriptor.value, 'test');
assert.equal(customDescriptor.writable, true);
assert.equal(customDescriptor.enumerable, true);
assert.equal(customDescriptor.configurable, true);

const proto = Object.getPrototypeOf(httpclient);
assert(proto);
assert(proto instanceof HttpclientNext);
assert(proto.constructor);

httpclient.customProperty = 'test-value';
assert.equal(httpclient.customProperty, 'test-value');

delete httpclient.customProperty;
assert.equal(httpclient.customProperty, undefined);

delete httpclient.testProp;
assert.equal(httpclient.testProp, undefined);

// Test that methods are properly bound
const { request } = httpclient;
assert(typeof request === 'function');

// Test Object.getOwnPropertyNames() which uses ownKeys trap
const propNames = Object.getOwnPropertyNames(httpclient);
assert(Array.isArray(propNames));
});
});

Expand Down
Loading
Loading