export function getServer()

in src/server.ts [37:167]


export function getServer(
  userFunction: HandlerFunction,
  options: FrameworkOptions,
): http.Server {
  // App to use for function executions.
  const app = express();

  // Express middleware

  // Set request-specific values in the very first middleware.
  app.use('/*', (req, res, next) => {
    setLatestRes(res);
    res.locals.functionExecutionFinished = false;
    next();
  });

  /**
   * Retains a reference to the raw body buffer to allow access to the raw body
   * for things like request signature validation.  This is used as the "verify"
   * function in body-parser options.
   * @param req - Express request object
   * @param res - Express response object
   * @param buf - Buffer to be saved
   */
  function rawBodySaver(req: Request, res: Response, buf: Buffer) {
    req.rawBody = buf;
  }

  // Set limit to a value larger than 32MB, which is maximum limit of higher
  // level layers anyway.
  const requestLimit = '1024mb';
  const defaultBodySavingOptions = {
    limit: requestLimit,
    verify: rawBodySaver,
  };
  const cloudEventsBodySavingOptions = {
    type: 'application/cloudevents+json',
    limit: requestLimit,
    verify: rawBodySaver,
  };
  const rawBodySavingOptions = {
    limit: requestLimit,
    verify: rawBodySaver,
    type: '*/*',
  };

  // Use extended query string parsing for URL-encoded bodies.
  const urlEncodedOptions = {
    limit: requestLimit,
    verify: rawBodySaver,
    extended: true,
  };

  // Apply middleware
  app.use(bodyParser.json(cloudEventsBodySavingOptions));
  app.use(bodyParser.json(defaultBodySavingOptions));
  app.use(bodyParser.text(defaultBodySavingOptions));
  app.use(bodyParser.urlencoded(urlEncodedOptions));
  // The parser will process ALL content types so MUST come last.
  // Subsequent parsers will be skipped when one is matched.
  app.use(bodyParser.raw(rawBodySavingOptions));
  app.enable('trust proxy'); // To respect X-Forwarded-For header.

  // Disable Express 'x-powered-by' header:
  // http://expressjs.com/en/advanced/best-practice-security.html#at-a-minimum-disable-x-powered-by-header
  app.disable('x-powered-by');

  // Disable Express eTag response header
  app.set('etag', false);

  // Get execution context.
  app.use(executionContextMiddleware);
  // Store execution context to async local storge.
  app.use(asyncLocalStorageMiddleware);

  if (
    options.signatureType === 'event' ||
    options.signatureType === 'cloudevent'
  ) {
    // If a Pub/Sub subscription is configured to invoke a user's function directly, the request body
    // needs to be marshalled into the structure that wrapEventFunction expects. This unblocks local
    // development with the Pub/Sub emulator
    app.use(legacyPubSubEventMiddleware);
  }

  if (options.signatureType === 'event') {
    app.use(cloudEventToBackgroundEventMiddleware);
  }
  if (options.signatureType === 'cloudevent') {
    app.use(backgroundEventToCloudEventMiddleware);
  }
  if (options.ignoredRoutes !== null) {
    // Ignored routes is a configuration option that allows requests to specific paths to be prevented
    // from invoking the user's function. An empty string indicates that no routes should be filtered.
    if (options.ignoredRoutes.trim() !== '') {
      // Any non-empty string is the used a route expression to return 404 for.
      app.use(options.ignoredRoutes, (req, res) => {
        res.status(404).send(null);
      });
    }
  } else if (options.signatureType === 'http') {
    // We configure some default ignored routes, only for HTTP functions.
    app.use('/favicon.ico|/robots.txt', (req, res) => {
      // Neither crawlers nor browsers attempting to pull the icon find the body
      // contents particularly useful, so we filter these requests out from invoking
      // the user's function by default.
      res.status(404).send(null);
    });
  }

  if (options.signatureType === 'http') {
    app.use('/*', (req, res, next) => {
      onFinished(res, (err, res) => {
        res.locals.functionExecutionFinished = true;
      });
      next();
    });
  }

  app.use(timeoutMiddleware(options.timeoutMilliseconds));

  // Set up the routes for the user's function
  const requestHandler = wrapUserFunction(userFunction, options.signatureType);
  if (options.signatureType === 'http') {
    app.all('/*', requestHandler);
  } else {
    app.post('/*', requestHandler);
  }

  return http.createServer(app);
}