mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: file-based backend fallback for unknown media types
This commit is contained in:
committed by
Joachim Van Herwegen
parent
fa78bc6856
commit
ff80079000
@@ -12,7 +12,7 @@ import { UnsupportedMediaTypeHttpError } from '../../util/errors/UnsupportedMedi
|
||||
import { guardStream } from '../../util/GuardedStream';
|
||||
import type { Guarded } from '../../util/GuardedStream';
|
||||
import { parseContentType } from '../../util/HeaderUtil';
|
||||
import { joinFilePath, isContainerIdentifier } from '../../util/PathUtil';
|
||||
import { joinFilePath, isContainerIdentifier, isContainerPath } from '../../util/PathUtil';
|
||||
import { parseQuads, serializeQuads } from '../../util/QuadUtil';
|
||||
import { addResourceMetadata, updateModifiedDate } from '../../util/ResourceUtil';
|
||||
import { toLiteral, toNamedTerm } from '../../util/TermUtil';
|
||||
@@ -159,8 +159,14 @@ export class FileDataAccessor implements DataAccessor {
|
||||
*/
|
||||
private async getFileMetadata(link: ResourceLink, stats: Stats):
|
||||
Promise<RepresentationMetadata> {
|
||||
return (await this.getBaseMetadata(link, stats, false))
|
||||
.set(CONTENT_TYPE_TERM, link.contentType);
|
||||
const metadata = await this.getBaseMetadata(link, stats, false);
|
||||
// If the resource is using an unsupported contentType, the original contentType was written to the metadata file.
|
||||
// As a result, we should only set the contentType derived from the file path,
|
||||
// when no previous metadata entry for contentType is present.
|
||||
if (typeof metadata.contentType === 'undefined') {
|
||||
metadata.set(CONTENT_TYPE_TERM, link.contentType);
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,7 +194,12 @@ export class FileDataAccessor implements DataAccessor {
|
||||
metadata.remove(RDF.terms.type, LDP.terms.Container);
|
||||
metadata.remove(RDF.terms.type, LDP.terms.BasicContainer);
|
||||
metadata.removeAll(DC.terms.modified);
|
||||
metadata.removeAll(CONTENT_TYPE_TERM);
|
||||
// When writing metadata for a document, only remove the content-type when dealing with a supported media type.
|
||||
// A media type is supported if the FileIdentifierMapper can correctly store it.
|
||||
// This allows restoring the appropriate content-type on data read (see getFileMetadata).
|
||||
if (isContainerPath(link.filePath) || typeof link.contentType !== 'undefined') {
|
||||
metadata.removeAll(CONTENT_TYPE_TERM);
|
||||
}
|
||||
const quads = metadata.quads();
|
||||
const metadataLink = await this.resourceMapper.mapUrlToFilePath(link.identifier, true);
|
||||
let wroteMetadata: boolean;
|
||||
|
||||
@@ -23,6 +23,8 @@ export class BaseFileIdentifierMapper implements FileIdentifierMapper {
|
||||
protected readonly logger = getLoggerFor(this);
|
||||
protected readonly baseRequestURI: string;
|
||||
protected readonly rootFilepath: string;
|
||||
// Extension to use as a fallback when the media type is not supported (could be made configurable).
|
||||
protected readonly unknownMediaTypeExtension = 'unknown';
|
||||
|
||||
public constructor(base: string, rootFilepath: string) {
|
||||
this.baseRequestURI = trimTrailingSlashes(base);
|
||||
@@ -85,7 +87,10 @@ export class BaseFileIdentifierMapper implements FileIdentifierMapper {
|
||||
*/
|
||||
protected async mapUrlToDocumentPath(identifier: ResourceIdentifier, filePath: string, contentType?: string):
|
||||
Promise<ResourceLink> {
|
||||
contentType = await this.getContentTypeFromUrl(identifier, contentType);
|
||||
// Don't try to get content-type from URL when the file path refers to a document with unknown media type.
|
||||
if (!filePath.endsWith(`.${this.unknownMediaTypeExtension}`)) {
|
||||
contentType = await this.getContentTypeFromUrl(identifier, contentType);
|
||||
}
|
||||
this.logger.debug(`The path for ${identifier.path} is ${filePath}`);
|
||||
return { identifier, filePath, contentType, isMetadata: this.isMetadataPath(filePath) };
|
||||
}
|
||||
|
||||
@@ -64,10 +64,12 @@ export class ExtensionBasedMapper extends BaseFileIdentifierMapper {
|
||||
// If the extension of the identifier matches a different content-type than the one that is given,
|
||||
// we need to add a new extension to match the correct type.
|
||||
} else if (contentType !== await this.getContentTypeFromPath(filePath)) {
|
||||
const extension: string = mime.extension(contentType) || this.customExtensions[contentType];
|
||||
let extension: string = mime.extension(contentType) || this.customExtensions[contentType];
|
||||
if (!extension) {
|
||||
this.logger.warn(`No extension found for ${contentType}`);
|
||||
throw new NotImplementedHttpError(`Unsupported content type ${contentType}`);
|
||||
// When no extension is found for the provided content-type, use a fallback extension.
|
||||
extension = this.unknownMediaTypeExtension;
|
||||
// Signal the fallback by setting the content-type to undefined in the output link.
|
||||
contentType = undefined;
|
||||
}
|
||||
filePath += `$.${extension}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user