export function tableStorageContextMiddleware()

in src/table/middleware/tableStorageContext.middleware.ts [40:200]


export function tableStorageContextMiddleware(
  req: Request,
  res: Response,
  next: NextFunction,
  skipApiVersionCheck?: boolean,
  disableProductStyleUrl?: boolean
): void {
  // Set server header in every Azurite response
  res.setHeader(HeaderConstants.SERVER, `Azurite-Table/${VERSION}`);

  const requestID = uuid();

  const tableContext = new TableStorageContext(
    res.locals,
    DEFAULT_TABLE_CONTEXT_PATH
  );

  tableContext.accept = req.headers.accept;
  tableContext.startTime = new Date();
  tableContext.xMsRequestID = requestID;

  if (!skipApiVersionCheck) {
    const apiVersion = req.header(HeaderConstants.X_MS_VERSION);
    if (apiVersion !== undefined) {
      checkApiVersion(apiVersion, ValidAPIVersions, tableContext);
    }
  }

  logger.info(
    `TableStorageContextMiddleware: RequestMethod=${req.method} RequestURL=${
      req.protocol
    }://${req.hostname}${req.url} RequestHeaders:${JSON.stringify(
      req.headers
    )} ClientIP=${req.ip} Protocol=${req.protocol} HTTPVersion=${
      req.httpVersion
    }`,
    requestID
  );

  // tslint:disable-next-line: prefer-const
  let [account, tableSection, isSecondary] = extractStoragePartsFromPath(
    req.hostname,
    req.path,
    disableProductStyleUrl
  );

  tableContext.isSecondary = isSecondary;

  const isGet = req.method.toUpperCase() === "GET";

  // Candidate tableSection
  // undefined - Set Table Service Properties
  // Tables - Create Tables, Query Tables
  // Tables() - Create Tables, Query Tables
  // Tables('mytable')	- Delete Tables, Query Entities
  // mytable - Get/Set Table ACL, Insert Entity, Query Entities
  // mytable(PartitionKey='<partition-key>',RowKey='<row-key>') -
  //        Query Entities, Update Entity, Merge Entity, Delete Entity
  // mytable() - Query Entities
  // TODO: Not allowed create Table with Tables as name
  if (tableSection === undefined || tableSection === "") {
    // Service level operation
    tableContext.tableName = undefined;
  } else if (tableSection === "Tables" || tableSection === "Tables()") {
    // Table name in request body
    tableSection = "Tables";
    tableContext.tableName = undefined;
  } else if (
    tableSection.startsWith("Tables('") &&
    tableSection.endsWith("')")
  ) {
    // Tables('mytable')
    tableContext.tableName = tableSection.substring(8, tableSection.length - 2);

    // Workaround for query entity
    if (isGet) {
      tableSection = `${tableContext.tableName}()`;
    }
  } else if (!tableSection.includes("(") && !tableSection.includes(")")) {
    // mytable
    tableContext.tableName = tableSection;

    // Workaround for query entity
    if (isGet) {
      tableSection = `${tableContext.tableName}()`;
    }
  } else if (
    tableSection.includes("(") &&
    tableSection.includes(")") &&
    tableSection.includes("PartitionKey='") &&
    tableSection.includes("RowKey='")
  ) {
    // mytable(PartitionKey='<partition-key>',RowKey='<row-key>')
    tableContext.tableName = tableSection.substring(
      0,
      tableSection.indexOf("(")
    );
    
    const regex = /'([^']|'')*'/g;
    const matches = tableSection?.match(regex);
    tableContext.partitionKey = matches? matches[0].replace(/^'|'$/g, '').replace(/''/g, "'"): undefined;
    tableContext.rowKey = matches? matches[1].replace(/^'|'$/g, '').replace(/''/g, "'"): undefined;

    tableSection = `${tableContext.tableName}(PartitionKey='PLACEHOLDER',RowKey='PLACEHOLDER')`;
  } else if (
    tableSection.includes("(") &&
    tableSection.includes(")") &&
    tableSection.indexOf(")") - tableSection.indexOf("(") === 1
  ) {
    // mytable()
    tableContext.tableName = tableSection.substr(0, tableSection.indexOf("("));
  } else {
    logger.error(
      `tableStorageContextMiddleware: Cannot extract table name from URL path=${req.path}`,
      requestID
    );
    return next(
      new Error(
        `tableStorageContextMiddleware: Cannot extract table name from URL path=${req.path}`
      )
    );
  }

  tableContext.account = account;

  tableContext.authenticationPath = req.path;

  if (isSecondary) {
    const pos = tableContext.authenticationPath.search(SECONDARY_SUFFIX);
    if (pos !== -1)
    {
      tableContext.authenticationPath =
      tableContext.authenticationPath.substr(0, pos) +
      tableContext.authenticationPath.substr(pos + SECONDARY_SUFFIX.length);
    }
  }

  // Emulator's URL pattern is like http://hostname[:port]/account/table
  // (or, alternatively, http[s]://account.localhost[:port]/table/)
  // Create a router to exclude account name from req.path, as url path in swagger doesn't include account
  // Exclude account name from req.path for dispatchMiddleware
  tableContext.dispatchPattern =
    tableSection !== undefined ? `/${tableSection}` : "/";

  logger.debug(
    `tableStorageContextMiddleware: Dispatch pattern string: ${tableContext.dispatchPattern}`,
    requestID
  );

  // validate table name, when table name has value (not undefined or empty string)
  // skip check for system table
  if (tableContext.tableName && !tableContext.tableName.startsWith("$")) {
    validateTableName(tableContext, tableContext.tableName);
  }

  logger.info(
    `tableStorageContextMiddleware: Account=${account} tableName=${tableContext.tableName}`,
    requestID
  );
  next();
}