nodejs/node

responses corresponding to requests queued by http agent are attached to incorrect domain

Open

#25.460 geöffnet am 12. Jan. 2019

Auf GitHub ansehen
 (2 Kommentare) (0 Reaktionen) (0 zugewiesene Personen)JavaScript (35.535 Forks)batch import
domainhelp wantedhttpstale

Repository-Metriken

Stars
 (117.218 Stars)
PR-Merge-Metriken
 (Durchschn. Merge 18T 17h) (219 gemergte PRs in 30 T)

Beschreibung

  • Version: Current tip of master (cf9bcdeabe), but possibly most versions.
  • Platform: All platforms.
  • Subsystem: domain, http.

Running the following code:

'use strict';

const common = require('../common');
const domain = require('domain');
const http = require('http');

const server = http.createServer((req, res) => {
    res.end();
});

function performHttpRequestWithDomain(domainId, agent, cb) {
    const d = domain.create();
    d._id = domainId;
    d.run(() => {
        const req = http.get({
            host: '127.0.0.1', port: server.address().port, agent
        }, res => {
            if (req.domain._id !== domainId) {
                console.log('req.domain._id !== domainId');
                console.log('req.domain._id:', req.domain._id);
                console.log('domainId:', domainId);
                process.exit(1);
            }

            if (req.domain._id !== res.domain._id) {
		        console.log('req.domain._id !== res.domain._id');
                console.log('req.domain._id:', req.domain._id);
                console.log('res.domain._id:', res.domain._id);
                process.exit(1);
            }

            res.on('data', () => {});
            res.on('end', cb);
        });

        req.end();
    });

    d.on('error', (domainErr) => {
        console.log('got domain error:', domainErr);
        process.exit(1);
    });
}

server.listen(0, '127.0.0.1', () => {
    const agent = new http.Agent({maxSockets: 1});
    let nbReqComplete = 0;

    function maybeCloseServer() {
        if (nbReqComplete === 2) {
            server.close();
        }
    }

    performHttpRequestWithDomain(1, agent, common.mustCall(() => {
        ++nbReqComplete;
        maybeCloseServer();
    }));

    performHttpRequestWithDomain(2, agent, common.mustCall(() => {
        ++nbReqComplete;
        maybeCloseServer();
    }));
});

exits with a status code of 1 when I'd expect it to exit with a status code of 0:

$ ./node test/parallel/test-agent-queued-request-domain.js 
req.domain._id !== res.domain._id
req.domain._id: 2
res.domain._id: 1
$ echo $?
1
$ 

In this repro, we basically force the http agent to queue the second request. When the first request finishes, the second request is assigned a socket from the agent's 'free' event handler.

However, it seems that event handler's execution is scheduled from within the lifecycle of the first request, and thus its active domain is the one of the first request.

As a result, when the parser for the response is instantiated and its corresponding async resource is initialized, it is attached to the first request's domain, and not to the active domain when the http request was originally created.

I'll see if I can put together a PR that fixes this.

Contributor Guide