private _initialize()

in AutoCollection/HttpRequests.ts [78:174]


    private _initialize() {
        this._isInitialized = true;

        const wrapOnRequestHandler: Function = (onRequest?: Function) => {
            if (!onRequest) {
                return undefined;
            }
            if (typeof onRequest !== 'function') {
                throw new Error('onRequest handler must be a function');
            }
            return (request: http.ServerRequest, response: http.ServerResponse) => {
                CorrelationContextManager.wrapEmitter(request);
                CorrelationContextManager.wrapEmitter(response);
                const shouldCollect: boolean = request && !(<any>request)[AutoCollectHttpRequests.alreadyAutoCollectedFlag];

                if (request && shouldCollect) {
                    // Set up correlation context
                    const requestParser = new HttpRequestParser(request);
                    const correlationContext = this._generateCorrelationContext(requestParser);

                    // Note: Check for if correlation is enabled happens within this method.
                    // If not enabled, function will directly call the callback.
                    CorrelationContextManager.runWithContext(correlationContext, () => {
                        if (this._isEnabled) {
                            // Mark as auto collected
                            (<any>request)[AutoCollectHttpRequests.alreadyAutoCollectedFlag] = true;

                            // Auto collect request
                            AutoCollectHttpRequests.trackRequest(this._client, { request: request, response: response }, requestParser);
                        }

                        if (typeof onRequest === "function") {
                            onRequest(request, response);
                        }
                    });
                } else {
                    if (typeof onRequest === "function") {
                        onRequest(request, response);
                    }
                }
            }
        }

        // The `http.createServer` function will instantiate a new http.Server object.
        // Inside the Server's constructor, it is using addListener to register the
        // onRequest handler. So there are two ways to inject the wrapped onRequest handler:
        // 1) Overwrite Server.prototype.addListener (and .on()) globally and not patching
        //    the http.createServer call. Or
        // 2) Overwrite the http.createServer method and add a patched addListener to the
        //    fresh server instance. This seems more stable for possible future changes as
        //    it also covers the case where the Server might not use addListener to manage
        //    the callback internally.
        //    And also as long as the constructor uses addListener to add the handle, it is
        //    ok to patch the addListener after construction only. Because if we would patch
        //    the prototype one and the createServer method, we would wrap the handler twice
        //    in case of the constructor call.
        const wrapServerEventHandler: Function = (server: (http.Server | https.Server)) => {
            const originalAddListener = server.addListener.bind(server);
            server.addListener = (eventType: string, eventHandler: Function) => {
                switch (eventType) {
                    case 'request':
                    case 'checkContinue':
                        return originalAddListener(eventType, wrapOnRequestHandler(eventHandler));
                    default:
                        return originalAddListener(eventType, eventHandler);
                }
            };
            // on is an alias to addListener only
            server.on = server.addListener;
        }

        const originalHttpServer: any = http.createServer;

        // options parameter was added in Node.js v9.6.0, v8.12.0
        // function createServer(requestListener?: RequestListener): Server;
        // function createServer(options: ServerOptions, requestListener?: RequestListener): Server;
        http.createServer = (param1?: Object, param2?: Function) => {
            // todo: get a pointer to the server so the IP address can be read from server.address
            if (param2 && typeof param2 === 'function') {
                const server: http.Server = originalHttpServer(param1, wrapOnRequestHandler(param2));
                wrapServerEventHandler(server);
                return server;
            }
            else {
                const server: http.Server = originalHttpServer(wrapOnRequestHandler(param1));
                wrapServerEventHandler(server);
                return server;
            }
        }

        const originalHttpsServer = https.createServer;
        https.createServer = (options: https.ServerOptions, onRequest?: Function) => {
            const server: https.Server = originalHttpsServer(options, wrapOnRequestHandler(onRequest));
            wrapServerEventHandler(server);
            return server;
        }
    }