UNPKG

azurite

Version:

An open source Azure Storage API compatible server

194 lines 9.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getUTF8ByteSize = exports.isEtagValid = exports.newHighPrecisionTimeStamp = exports.newTableEntityEtag = exports.validateTableName = exports.getPayloadFormat = exports.getTimestampString = exports.checkApiVersion = exports.getOdataAnnotations = exports.updateEntityOdataAnnotationsForResponse = exports.getEntityOdataAnnotationsForResponse = exports.getEntityOdataAnnotationsForRequest = exports.updateTableOptionalOdataAnnotationsForResponse = exports.getTablePropertiesOdataAnnotationsForResponse = exports.updateTableOdataAnnotationsForResponse = exports.getTableOdataAnnotationsForResponse = exports.getTableOdataAnnotationsForRequest = void 0; const tslib_1 = require("tslib"); const utils_1 = require("../../common/utils/utils"); const StorageErrorFactory_1 = tslib_1.__importDefault(require("../errors/StorageErrorFactory")); const constants_1 = require("./constants"); function getTableOdataAnnotationsForRequest(account, table) { return getOdataAnnotations(account, "", table); } exports.getTableOdataAnnotationsForRequest = getTableOdataAnnotationsForRequest; function getTableOdataAnnotationsForResponse(account, table, urlPrefix) { return getOdataAnnotations(account, urlPrefix, table); } exports.getTableOdataAnnotationsForResponse = getTableOdataAnnotationsForResponse; function updateTableOdataAnnotationsForResponse(table, account, urlPrefix, accept) { const annotation = getTableOdataAnnotationsForResponse(account, table.table, urlPrefix); if (accept && (accept === constants_1.MINIMAL_METADATA_ACCEPT || accept === constants_1.FULL_METADATA_ACCEPT)) { table.odatametadata = annotation.odatametadata; } if (accept && accept === constants_1.FULL_METADATA_ACCEPT) { table.odatatype = annotation.odatatype; table.odataid = annotation.odataid; table.odataeditLink = annotation.odataeditLink; } return table; } exports.updateTableOdataAnnotationsForResponse = updateTableOdataAnnotationsForResponse; function getTablePropertiesOdataAnnotationsForResponse(tableName, account, urlPrefix, accept) { const table = { tableName }; const annotation = getTableOdataAnnotationsForResponse(account, tableName, urlPrefix); if (accept && accept === constants_1.FULL_METADATA_ACCEPT) { table.odatatype = annotation.odatatype; table.odataid = annotation.odataid; table.odataeditLink = annotation.odataeditLink; } return table; } exports.getTablePropertiesOdataAnnotationsForResponse = getTablePropertiesOdataAnnotationsForResponse; function updateTableOptionalOdataAnnotationsForResponse(tableLike, account, table, urlPrefix, accept) { const annotation = getTableOdataAnnotationsForResponse(account, table, urlPrefix); if (accept && (accept === constants_1.MINIMAL_METADATA_ACCEPT || accept === constants_1.FULL_METADATA_ACCEPT)) { tableLike.odatametadata = annotation.odatametadata; } if (accept && accept === constants_1.FULL_METADATA_ACCEPT) { tableLike.odatatype = annotation.odatatype; tableLike.odataid = annotation.odataid; tableLike.odataeditLink = annotation.odataeditLink; } return tableLike; } exports.updateTableOptionalOdataAnnotationsForResponse = updateTableOptionalOdataAnnotationsForResponse; function getEntityOdataAnnotationsForRequest(account, table, partitionKey, rowKey) { return getOdataAnnotations(account, "", table, partitionKey, rowKey); } exports.getEntityOdataAnnotationsForRequest = getEntityOdataAnnotationsForRequest; function getEntityOdataAnnotationsForResponse(account, table, urlPrefix, partitionKey, rowKey, accept) { const annotation = getOdataAnnotations(account, urlPrefix, table, partitionKey, rowKey); const response = {}; if (accept && (accept === constants_1.MINIMAL_METADATA_ACCEPT || accept === constants_1.FULL_METADATA_ACCEPT)) { response.odatametadata = annotation.odatametadata; } if (accept && accept === constants_1.FULL_METADATA_ACCEPT) { response.odatatype = annotation.odatatype; response.odataid = annotation.odataid; response.odataeditLink = annotation.odataeditLink; } return response; } exports.getEntityOdataAnnotationsForResponse = getEntityOdataAnnotationsForResponse; function updateEntityOdataAnnotationsForResponse(entity, account, table, urlPrefix, accept) { const annotation = getOdataAnnotations(account, table, urlPrefix, entity.PartitionKey, entity.RowKey); if (accept && (accept === constants_1.MINIMAL_METADATA_ACCEPT || accept === constants_1.FULL_METADATA_ACCEPT)) { entity.odatametadata = annotation.odatametadata; } if (accept && accept === constants_1.FULL_METADATA_ACCEPT) { entity.odatatype = annotation.odatatype; entity.odataid = annotation.odataid; entity.odataeditLink = annotation.odataeditLink; } return entity; } exports.updateEntityOdataAnnotationsForResponse = updateEntityOdataAnnotationsForResponse; // table service APIs are in layers // we need to ensure that table, entity, and service // API layers are not affected when we change this odata response. // check that change does not impact query entities & query tables function getOdataAnnotations(account, urlPrefix, table, partitionKey, rowKey) { const urlPrefixEndWithSlash = urlPrefix.endsWith("/") ? urlPrefix : `${urlPrefix}/`; if (typeof partitionKey === "string" && partitionKey.length > 0) { if (typeof rowKey !== "string" || partitionKey.length === 0) { throw TypeError("PartitionKey and RowKey must provide at the same time."); } return { odatametadata: `${urlPrefixEndWithSlash}$metadata#${table}/@Element`, odatatype: `${account}.${table}`, odataid: `${urlPrefixEndWithSlash}${table}(PartitionKey='${partitionKey}',RowKey='${rowKey}')`, odataeditLink: `${table}(PartitionKey='${partitionKey}',RowKey='${rowKey}')` }; } else { return { odatametadata: `${urlPrefixEndWithSlash}$metadata#Tables${table ? "/@Element" : ""}`, odatatype: `${account}.Tables`, odataid: `${urlPrefixEndWithSlash}Tables('${table}')`, odataeditLink: `Tables('${table}')` }; } } exports.getOdataAnnotations = getOdataAnnotations; function checkApiVersion(inputApiVersion, validApiVersions, context) { if (!validApiVersions.includes(inputApiVersion)) { throw StorageErrorFactory_1.default.getInvalidAPIVersion(context, inputApiVersion); } } exports.checkApiVersion = checkApiVersion; function getTimestampString(date) { return date.toISOString().replace("Z", "0000Z"); } exports.getTimestampString = getTimestampString; function getPayloadFormat(context) { let format = context.request?.getHeader(constants_1.HeaderConstants.ACCEPT); const formatParameter = context.request?.getQuery("$format"); if (typeof formatParameter === "string") { format = formatParameter; } if (format === undefined || format === "") { format = constants_1.XML_METADATA; } if (format === "application/json") { format = constants_1.MINIMAL_METADATA_ACCEPT; } format = format.replace(/\s/g, ""); return format; } exports.getPayloadFormat = getPayloadFormat; // https://docs.microsoft.com/en-us/rest/api/storageservices/understanding-the-table-service-data-model#table-names function validateTableName(context, tableName) { if (tableName !== "" && (tableName.length < 3 || tableName.length > 63)) { throw StorageErrorFactory_1.default.getOutOfRangeName(context); } const reg = new RegExp("^[A-Za-z][A-Za-z0-9]{2,62}$"); if (!reg.test(tableName) && !tableName.startsWith("$Metric")) { throw StorageErrorFactory_1.default.getInvalidResourceName(context); } if (tableName.toLowerCase() === "tables") { throw StorageErrorFactory_1.default.getInvalidResourceName(context); } } exports.validateTableName = validateTableName; function newTableEntityEtag(highPresModTime) { // Etag as returned by Table Storage should match W/"datetime'<ISO8601datetime>'" // as we need the same value for last Modification time, we now only accept a string here return "W/\"datetime'" + encodeURIComponent(highPresModTime) + "'\""; } exports.newTableEntityEtag = newTableEntityEtag; function newHighPrecisionTimeStamp(startTime) { return (0, utils_1.truncatedISO8061Date)(startTime, true, true); } exports.newHighPrecisionTimeStamp = newHighPrecisionTimeStamp; /** * Checks if an eTag is valid * * @export * @param {string} etag * @return {*} {boolean} */ function isEtagValid(etag) { // Weak etag is required. This is parity with Azure and legacy emulator. // Source for regex: https://stackoverflow.com/a/11572348 const match = etag.match(/^[wW]\/"([^"]|\\")*"$/); return match === null; } exports.isEtagValid = isEtagValid; /** * Get the byte size of a string in UTF8. * * @public * @param {Date} requestDate * @returns {string} */ function getUTF8ByteSize(text) { return Buffer.from(text, "utf8").length; } exports.getUTF8ByteSize = getUTF8ByteSize; //# sourceMappingURL=utils.js.map