function responseHandler(filterRules, config, io) {
  const filters = Filters(filterRules);

  return (brokerToken) => ({ url, headers = {}, method, body = null, streamingID = '' } = {}, emit) => {
    const logContext = {
      url,
      method,
      headers,
      requestId: headers['snyk-request-id'] || uuid(),
      streamingID,
    };

    logger.debug(logContext, 'received request over webscoket connection');

    filters({ url, method, body, headers }, (error, result) => {
      if (error) {
        const reason = 'Response does not match any accept rule, blocking websocket request';
        logContext.error = error;
        error.reason = reason;
        logger.warn(logContext, reason);
        return emit({
          status: 401,
          body: {
            message: error.message,
            reason,
            url,
          },
        });
      }

      if (result.url.startsWith('http') === false) {
        result.url = 'https://' + result.url;
        logContext.resultUrlSchemeAdded = true;
      }

      logContext.httpUrl = result.url;

      if (!headers['user-agent']) {
        headers['user-agent'] = 'Snyk Broker ' + version;
        logContext.userAgentHeaderSet = true;
      }

      if (result.auth) {
        headers.authorization = result.auth;
        logContext.authHeaderSetByRuleAuth = true;
      } else {
        const parsed = parse(result.url);
        if (parsed.auth) {
          // if URL contains basic auth,
          // remove authorization header to prefer auth on the URL.
          if (parsed.auth.includes(':')) {
            delete headers.authorization;
          }

          // if URL contains token auth,
          // put the token in the authorization header
          // instead of on the URL.
          else {
            headers.authorization = `token ${parsed.auth}`;
            // then strip from the url
            delete parsed.auth;
            result.url = format(parsed);
          }

          logContext.authHeaderSetByRuleUrl = true;
        }
      }

      // if the request is all good - and at this point it is, we'll check
      // whether we want to do variable substitution on the body
      //
      // Variable substitution - for those who forgot - is substituting a part
      // of a given string (e.g. "${SOME_ENV_VAR}/rest/of/string")
      // with an env var of the same name (SOME_ENV_VAR).
      // This is used (for example) to substitute the snyk url
      // with the broker's url when defining the target for an incoming webhook.
      if (body) {
        const parsedBody = tryJSONParse(body);

        if (parsedBody.BROKER_VAR_SUB) {
          logContext.bodyVarsSubstitution = parsedBody.BROKER_VAR_SUB;
          for (const path of parsedBody.BROKER_VAR_SUB) {
            let source = undefsafe(parsedBody, path); // get the value
            source = replace(source, config); // replace the variables
            undefsafe(parsedBody, path, source); // put it back in
          }
          body = JSON.stringify(parsedBody);
        }
      }

      // check whether we want to do variable substitution on the headers
      if (headers && headers['x-broker-var-sub']) {
        logContext.headerVarsSubstitution = headers['x-broker-var-sub'];
        for (const path of headers['x-broker-var-sub'].split(',')) {
          let source = undefsafe(headers, path.trim()); // get the value
          source = replace(source, config); // replace the variables
          undefsafe(headers, path.trim(), source); // put it back in
        }
      }

      // remove headers that we don't want to relay
      // (because they corrupt the request)
      [
        'x-forwarded-for',
        'x-forwarded-proto',
        'content-length',
        'host',
      ].map(_ => delete headers[_]);

      if (brokerToken) {
        Object.assign(headers, {'X-Broker-Token': brokerToken});
      }

      logger.debug(logContext, 'sending websocket request over HTTP connection');

      var req = {
        url: result.url,
        headers: headers,
        method,
        body,
        agentOptions: {
          ca: config.caCert, // Optional CA cert
        },
      };

      // check if this is a streaming request for binary data
      if (streamingID) {
        logger.debug(logContext, 'serving stream request');

        req.encoding = null; // no encoding for binary data

        request(req).on('response', response => {
          const status = (response && response.statusCode) || 500;
          logResponse(logContext, status, response.headers);
          io.send('chunk', streamingID, '', false, {
            status,
            headers : response.headers
          });
        }).on('data', chunk => {
          io.send('chunk', streamingID, chunk, false);
        }).on('end', () => {
          io.send('chunk', streamingID, '', true);
        }).on('error', error => {
          logError(logContext, error);
          io.send('chunk', streamingID, error.message, true, {
            status : 500
          });
        });
        return;
      }

      request(req, (error, response, body) => {
        if (error) {
          logError(logContext, error);
          return emit({
            status: 500,
            body: error.message
          });
        }

        const status = (response && response.statusCode) || 500;
        logResponse(logContext, status, response.headers);
        emit({ status, body, headers: response.headers });
      });
    });
  };
}
// 5. Send response over websocket conn
5. Send response over websocket conn
5 . Send response over websocket conn
function responseHandler(filterRules, config, io) {
  const filters = Filters(filterRules);
  return (brokerToken) => ({ url, headers = {}, method, body = null, streamingID = '' } = {}, emit) => {
    const logContext = {
      url,
      method,
      headers,
      requestId: headers['snyk-request-id'] || uuid(),
      streamingID,
    };
    logger.debug(logContext, 'received request over webscoket connection');
    filters({ url, method, body, headers }, (error, result) => {
      if (error) {
        const reason = 'Response does not match any accept rule, blocking websocket request';
        logContext.error = error;
        error.reason = reason;
        logger.warn(logContext, reason);
        return emit({
          status: 401,
          body: {
            message: error.message,
            reason,
            url,
          },
        });
      }
      if (result.url.startsWith('http') === false) {
        result.url = 'https:' + result.url;
        logContext.resultUrlSchemeAdded = true;
      }
      logContext.httpUrl = result.url;
      if (!headers['user-agent']) {
        headers['user-agent'] = 'Snyk Broker ' + version;
        logContext.userAgentHeaderSet = true;
      }
      if (result.auth) {
        headers.authorization = result.auth;
        logContext.authHeaderSetByRuleAuth = true;
      } else {
        const parsed = parse(result.url);
        if (parsed.auth) {
          if (parsed.auth.includes(':')) {
            delete headers.authorization;
          }
          else {
            headers.authorization = `token ${parsed.auth}`;
            delete parsed.auth;
            result.url = format(parsed);
          }
          logContext.authHeaderSetByRuleUrl = true;
        }
      }
       Variable substitution - for those who forgot - is substituting a part
       of a given string (e.g. "${SOME_ENV_VAR}/rest/of/string")
       with an env var of the same name (SOME_ENV_VAR).
       This is used (for example) to substitute the snyk url
       with the broker's url when defining the target for an incoming webhook.
      if (body) {
        const parsedBody = tryJSONParse(body);
        if (parsedBody.BROKER_VAR_SUB) {
          logContext.bodyVarsSubstitution = parsedBody.BROKER_VAR_SUB;
          for (const path of parsedBody.BROKER_VAR_SUB) {
            let source = undefsafe(parsedBody, path);  get the value
            source = replace(source, config);  replace the variables
            undefsafe(parsedBody, path, source);  put it back in
          }
          body = JSON.stringify(parsedBody);
        }
      }
       check whether we want to do variable substitution on the headers
      if (headers && headers['x-broker-var-sub']) {
        logContext.headerVarsSubstitution = headers['x-broker-var-sub'];
        for (const path of headers['x-broker-var-sub'].split(',')) {
          let source = undefsafe(headers, path.trim());  get the value
          source = replace(source, config);  replace the variables
          undefsafe(headers, path.trim(), source);  put it back in
        }
      }
       remove headers that we don't want to relay
       (because they corrupt the request)
      [
        'x-forwarded-for',
        'x-forwarded-proto',
        'content-length',
        'host',
      ].map(_ => delete headers[_]);
      if (brokerToken) {
        Object.assign(headers, {'X-Broker-Token': brokerToken});
      }
      logger.debug(logContext, 'sending websocket request over HTTP connection');
      var req = {
        url: result.url,
        headers: headers,
        method,
        body,
        agentOptions: {
          ca: config.caCert,  Optional CA cert
        },
      };
       check if this is a streaming request for binary data
      if (streamingID) {
        logger.debug(logContext, 'serving stream request');
        req.encoding = null;  no encoding for binary data
        request(req).on('response', response => {
          const status = (response && response.statusCode) || 500;
          logResponse(logContext, status, response.headers);
          io.send('chunk', streamingID, '', false, {
            status,
            headers : response.headers
          });
        }).on('data', chunk => {
          io.send('chunk', streamingID, chunk, false);
        }).on('end', () => {
          io.send('chunk', streamingID, '', true);
        }).on('error', error => {
          logError(logContext, error);
          io.send('chunk', streamingID, error.message, true, {
            status : 500
          });
        });
        return;
      }
      request(req, (error, response, body) => {
        if (error) {
          logError(logContext, error);
          return emit({
            status: 500,
            body: error.message
          });
        }
        const status = (response && response.statusCode) || 500;
        logResponse(logContext, status, response.headers);
        emit({ status, body, headers: response.headers });
      });
    });
  };
}
function responseHandler ( filterRules , config , io ) { const filters = Filters ( filterRules ) ; return ( brokerToken ) => ( { url , headers = { } , method , body = null , streamingID = '' } = { } , emit ) => { const logContext = { url , method , headers , requestId : headers [ 'snyk-request-id' ] || uuid ( ) , streamingID , } ; logger . debug ( logContext , 'received request over webscoket connection' ) ; filters ( { url , method , body , headers } , ( error , result ) => { if ( error ) { const reason = 'Response does not match any accept rule, blocking websocket request' ; logContext . error = error ; error . reason = reason ; logger . warn ( logContext , reason ) ; return emit ( { status : 401 , body : { message : error . message , reason , url , } , } ) ; } if ( result . url . startsWith ( 'http' ) === false ) { result . url = 'https://' + result . url ; logContext . resultUrlSchemeAdded = true ; } logContext . httpUrl = result . url ; if ( ! headers [ 'user-agent' ] ) { headers [ 'user-agent' ] = 'Snyk Broker ' + version ; logContext . userAgentHeaderSet = true ; } if ( result . auth ) { headers . authorization = result . auth ; logContext . authHeaderSetByRuleAuth = true ; } else { const parsed = parse ( result . url ) ; if ( parsed . auth ) { if ( parsed . auth . includes ( ':' ) ) { delete headers . authorization ; } else { headers . authorization = ` ${ parsed . auth } ` ; delete parsed . auth ; result . url = format ( parsed ) ; } logContext . authHeaderSetByRuleUrl = true ; } } if ( body ) { const parsedBody = tryJSONParse ( body ) ; if ( parsedBody . BROKER_VAR_SUB ) { logContext . bodyVarsSubstitution = parsedBody . BROKER_VAR_SUB ; for ( const path of parsedBody . BROKER_VAR_SUB ) { let source = undefsafe ( parsedBody , path ) ; source = replace ( source , config ) ; undefsafe ( parsedBody , path , source ) ; } body = JSON . stringify ( parsedBody ) ; } } if ( headers && headers [ 'x-broker-var-sub' ] ) { logContext . headerVarsSubstitution = headers [ 'x-broker-var-sub' ] ; for ( const path of headers [ 'x-broker-var-sub' ] . split ( ',' ) ) { let source = undefsafe ( headers , path . trim ( ) ) ; source = replace ( source , config ) ; undefsafe ( headers , path . trim ( ) , source ) ; } } [ 'x-forwarded-for' , 'x-forwarded-proto' , 'content-length' , 'host' , ] . map ( _ => delete headers [ _ ] ) ; if ( brokerToken ) { Object . assign ( headers , { 'X-Broker-Token' : brokerToken } ) ; } logger . debug ( logContext , 'sending websocket request over HTTP connection' ) ; var req = { url : result . url , headers : headers , method , body , agentOptions : { ca : config . caCert , } , } ; if ( streamingID ) { logger . debug ( logContext , 'serving stream request' ) ; req . encoding = null ; request ( req ) . on ( 'response' , response => { const status = ( response && response . statusCode ) || 500 ; logResponse ( logContext , status , response . headers ) ; io . send ( 'chunk' , streamingID , '' , false , { status , headers : response . headers } ) ; } ) . on ( 'data' , chunk => { io . send ( 'chunk' , streamingID , chunk , false ) ; } ) . on ( 'end' , ( ) => { io . send ( 'chunk' , streamingID , '' , true ) ; } ) . on ( 'error' , error => { logError ( logContext , error ) ; io . send ( 'chunk' , streamingID , error . message , true , { status : 500 } ) ; } ) ; return ; } request ( req , ( error , response , body ) => { if ( error ) { logError ( logContext , error ) ; return emit ( { status : 500 , body : error . message } ) ; } const status = ( response && response . statusCode ) || 500 ; logResponse ( logContext , status , response . headers ) ; emit ( { status , body , headers : response . headers } ) ; } ) ; } ) ; } ; }
5.
5 .
// if URL contains basic auth, // remove authorization header to prefer auth on the URL. // if URL contains token auth, // put the token in the authorization header // instead of on the URL. // then strip from the url // if the request is all good - and at this point it is, we'll check // whether we want to do variable substitution on the body // // Variable substitution - for those who forgot - is substituting a part // of a given string (e.g. "${SOME_ENV_VAR}/rest/of/string") // with an env var of the same name (SOME_ENV_VAR). // This is used (for example) to substitute the snyk url // with the broker's url when defining the target for an incoming webhook. // get the value // replace the variables // put it back in // check whether we want to do variable substitution on the headers // get the value // replace the variables // put it back in // remove headers that we don't want to relay // (because they corrupt the request) // Optional CA cert // check if this is a streaming request for binary data // no encoding for binary data