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;
}
}