nodejs/node

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

Open

#25,460 创建于 2019年1月12日

在 GitHub 查看
 (1 评论) (0 反应) (0 负责人)JavaScript (117,218 star) (35,535 fork)batch import
domainhelp wantedhttp

描述

  • 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.

贡献者指南