UNPKG

@solid/community-server

Version:

Community Solid Server: an open and modular implementation of the Solid specifications

99 lines 4.95 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.addResourceMetadata = addResourceMetadata; exports.updateModifiedDate = updateModifiedDate; exports.addTemplateMetadata = addTemplateMetadata; exports.cloneRepresentation = cloneRepresentation; exports.assertReadConditions = assertReadConditions; const n3_1 = require("n3"); const BasicRepresentation_1 = require("../http/representation/BasicRepresentation"); const RepresentationMetadata_1 = require("../http/representation/RepresentationMetadata"); const NotModifiedHttpError_1 = require("./errors/NotModifiedHttpError"); const StreamUtil_1 = require("./StreamUtil"); const TermUtil_1 = require("./TermUtil"); const Vocabularies_1 = require("./Vocabularies"); /** * Helper function to generate type quads for a Container or Resource. * * @param metadata - Metadata to add to. * @param isContainer - If the identifier corresponds to a container. */ function addResourceMetadata(metadata, isContainer) { if (isContainer) { metadata.add(Vocabularies_1.RDF.terms.type, Vocabularies_1.LDP.terms.Container); metadata.add(Vocabularies_1.RDF.terms.type, Vocabularies_1.LDP.terms.BasicContainer); } metadata.add(Vocabularies_1.RDF.terms.type, Vocabularies_1.LDP.terms.Resource); } /** * Updates the dc:modified time to the given time. * * @param metadata - Metadata to update. * @param date - Last modified date. Defaults to current time. */ function updateModifiedDate(metadata, date = new Date()) { // Milliseconds get lost in some serializations, potentially causing mismatches const lastModified = new Date(date); lastModified.setMilliseconds(0); metadata.set(Vocabularies_1.DC.terms.modified, (0, TermUtil_1.toLiteral)(lastModified.toISOString(), Vocabularies_1.XSD.terms.dateTime)); } /** * Links a template file with a given content-type to the metadata using the SOLID_META.template predicate. * * @param metadata - Metadata to update. * @param templateFile - Path to the template. * @param contentType - Content-type of the template after it is rendered. */ function addTemplateMetadata(metadata, templateFile, contentType) { const templateNode = n3_1.DataFactory.namedNode(templateFile); metadata.add(Vocabularies_1.SOLID_META.terms.template, templateNode); metadata.addQuad(templateNode, Vocabularies_1.CONTENT_TYPE_TERM, contentType); } /** * Helper function to clone a representation, the original representation can still be used. * This function loads the entire stream in memory. * * @param representation - The representation to clone. * * @returns The cloned representation. */ async function cloneRepresentation(representation) { const data = await (0, StreamUtil_1.arrayifyStream)(representation.data); const result = new BasicRepresentation_1.BasicRepresentation(data, new RepresentationMetadata_1.RepresentationMetadata(representation.metadata), representation.binary); representation.data = (0, StreamUtil_1.guardedStreamFrom)(data); return result; } /** * Verify whether the given {@link Representation} matches the given conditions. * If true, add the corresponding ETag to the body metadata. * If not, destroy the data stream and throw a {@link NotModifiedHttpError} with the same ETag. * If `conditions` is not defined, nothing will happen. * * This uses the strict conditions check which takes the content type into account; * therefore, this should only be called after content negotiation, when it is certain what the output will be. * * Note that browsers only keep track of one ETag, and the Vary header has no impact on this, * meaning the browser could send us the ETag for a Turtle resource even though it is requesting JSON-LD; * this is why we have to check ETags after content negotiation. * * @param body - The representation to compare the conditions against. * @param eTagHandler - Used to generate the ETag to return with the 304 response. * @param conditions - The conditions to assert. */ function assertReadConditions(body, eTagHandler, conditions) { const eTag = eTagHandler.getETag(body.metadata); if (conditions && !conditions.matchesMetadata(body.metadata, true)) { body.data.destroy(); const error = new NotModifiedHttpError_1.NotModifiedHttpError(eTag); // From RFC 9111: // > the cache MUST add each header field in the provided response to the stored response, // > replacing field values that are already present // So we need to make sure to send either no partial headers, or the exact same headers. // By adding the metadata of the original resource here, we ensure we send the same headers. error.metadata.identifier = body.metadata.identifier; error.metadata.addQuads(body.metadata.quads()); throw error; } body.metadata.set(Vocabularies_1.HH.terms.etag, eTag); } //# sourceMappingURL=ResourceUtil.js.map