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

Should we add a new api, "tls.Server.prototype.removeContexts(servername)" and "tls.Server.prototype.replaceContext(servername,context)" ? #34451

Closed
masx200 opened this issue Jul 20, 2020 · 9 comments
Labels
feature request Issues that request new features to be added to Node.js. stale tls Issues and PRs related to the tls subsystem.

Comments

@masx200
Copy link
Contributor

masx200 commented Jul 20, 2020

Is your feature request related to a problem? Please describe.
Please describe the problem you are trying to solve.

#34110
#34444

After adding the context with "tls.Server.prototype.addContext", the context corresponding to the specified servername cannot be deleted. Should we add a new api, "tls.Server.prototype.removeContexts(servername)"?

This is useful on HTTPS servers that need to replace ssl/tls certificates frequently, such as using "let's encrypt". When the certificate needs to be replaced, you don't want to restart the HTTPS server, you just need to replace the certificate and key.

If multiple secure contexts are added to the same domain name
, the last one added should take effect,

With frequent ssl/tls certificate updates, addContext is called constantly. If the old context is not deleted, the old context will take up more and more memory space, and they are useless. Eventually lead to memory leaks or even memory overflow.

Describe the solution you'd like
Please describe the desired behavior.

add a new api, "tls.Server.prototype.removeContexts(servername)"

the all contexts corresponding to the specified servername should be deleted.

Should we add a new api, "tls.Server.prototype.removeContexts(servername)" and "tls.Server.prototype.replaceContext(servername,context)" ?

"tls.Server.prototype.replaceContext(servername,context)" Its role should be the operation of "tls.Server.prototype.removeContexts(servername)" and "tls.Server.prototype.addContext(servername,context)"

Describe alternatives you've considered
Please describe alternative solutions or features you have considered.

 const server = https.createServer();
const hostname = 'foo.bar.com';
const keypath = 'key.pem';
const certpath = 'cert.pem';
function debounce(callback, timeout) {
    let timer;
    return function (...args) {
        timer && clearTimeout(timer);
        timer = setTimeout(callback, timeout, ...args);
    };
}
const reloadcertkey = debounce(function () {
    let key = fs.readFileSync(keypath);
    let cert = fs.readFileSync(certpath);
    let context = tls.createSecureContext({
        key,
        cert
        
    });
    server.removeContexts(hostname, );
    server.addContext(hostname, context);
}, 1000);
reloadcertkey();
fs.watch(keypath, reloadcertkey);
fs.watch(certpath, reloadcertkey);
 const server = https.createServer();
const hostname = 'foo.bar.com';
const keypath = 'key.pem';
const certpath = 'cert.pem';
function debounce(callback, timeout) {
    let timer;
    return function (...args) {
        timer && clearTimeout(timer);
        timer = setTimeout(callback, timeout, ...args);
    };
}
const reloadcertkey = debounce(function () {
    let key = fs.readFileSync(keypath);
    let cert = fs.readFileSync(certpath);
    let context = tls.createSecureContext({
        key,
        cert
        
    });
    
    server.replaceContext(hostname, context);
}, 1000);
reloadcertkey();
fs.watch(keypath, reloadcertkey);
fs.watch(certpath, reloadcertkey);
@bnoordhuis bnoordhuis added feature request Issues that request new features to be added to Node.js. tls Issues and PRs related to the tls subsystem. labels Jul 21, 2020
@bnoordhuis
Copy link
Member

The problem is that it's really difficult to know when it's safe to remove a context.

Removing it when it's still in use results in segfaults and even when it's gone from node's internal bookkeeping, all kinds of reference counting inside openssl can still keep it alive.

@masx200
Copy link
Contributor Author

masx200 commented Jul 21, 2020

function SNICallback(servername, callback) {

Server.prototype.addContext = function(servername, context) {

@masx200
Copy link
Contributor Author

masx200 commented Jul 21, 2020

I think the operation of "removeContexts" will not affect existing connections, but will only affect new connections in the future.

@masx200
Copy link
Contributor Author

masx200 commented Jul 21, 2020

"tls.Server.prototype.removeContexts(servername)" should be the reverse operation of "tls.Server.prototype.addContext(servername,context)"

@masx200 masx200 changed the title Should we add a new api, tls.Server.prototype.removeContexts(servername)? Should we add a new api, "tls.Server.prototype.removeContexts(servername)" and "tls.Server.prototype.replaceContext(servername,context)" ? Jul 21, 2020
@masx200
Copy link
Contributor Author

masx200 commented Jul 21, 2020

"tls.Server.prototype.replaceContext(servername,context)" Its role should be the operation of "tls.Server.prototype.removeContexts(servername)" and "tls.Server.prototype.addContext(servername,context)"

@bnoordhuis
Copy link
Member

@masx200 I think you misunderstand my previous comment.

server._contexts is an array of SecureContext objects. The array exists in JS land in order to look up the right context based on the servername property. Removing elements from that array is not the issue.

The issue is that removing a SecureContext from the array doesn't mean it's no longer in use. There are a bunch of C++ resources tied to SecureContext objects, all with complex lifecycles.

Establishing when it's safe to release those resources is hard but you have to fix that first before you can fix this:

Eventually lead to memory leaks or even memory overflow.

@KapitanOczywisty
Copy link

This is somewhat edge case, but seems like allowing server._contexts to grow infinitely, itself could be treated as memory leak. I've tested this a bit and seems like using own contexts array and removing old contexts keeps memory more or less the same, but with server.addContext memory is rising constantly.

However, It's possible to clear server's certificates even now using: server._contexts.length = 0;, this is of course internal api, but good enough for testing. With that memory was rising slower but rising nonetheless.

IMO There is no point to keep useless contexts in the server._contexts, but seems like they're kept around by something else - or my testing is flawed.

If one is concerned about memory and constant certificate changes, should use SNICallback, but as mentioned this is edge case and isn't something to be concerned in 99.9% cases.

Result of my quick testing: repeated 50 times: 10 certs loaded/replaced + 10 requests. After last series:

// SNICallback w/ own array
rss: 37 257 216 (+8 773 632)
heapTotal: 9 986 048 (+3 416 064)
heapUsed: 8 805 720 (+3 653 072)
external: 1 499 930 (+535 949)
arrayBuffers: 509 062 (+491 452)

// addContext
rss: 48 406 528 (+19 922 944)
heapTotal: 10 248 192 (+3 678 208)
heapUsed: 8 983 832 (+3 850 184)
external: 1 483 498 (+519 517)
arrayBuffers: 492 630 (+475 020)

// addContext + clearing server._contexts
rss: 44 023 808 (+15 486 976)
heapTotal: 10 248 192 (+3 678 208)
heapUsed: 8 748 112 (+3 595 424)
external: 1 443 396 (+479 415)
arrayBuffers: 451 658 (+434 048)

@github-actions
Copy link
Contributor

There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be closed 6 months after the last non-automated comment.

For more information on how the project manages feature requests, please consult the feature request management document.

@github-actions
Copy link
Contributor

There has been no activity on this feature request and it is being closed. If you feel closing this issue is not the right thing to do, please leave a comment.

For more information on how the project manages feature requests, please consult the feature request management document.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request Issues that request new features to be added to Node.js. stale tls Issues and PRs related to the tls subsystem.
Projects
None yet
Development

No branches or pull requests

3 participants