Skip to content
Snippets Groups Projects
Commit 394cad63 authored by Quazgar's avatar Quazgar
Browse files

Merge branch 'f-fix-14' into 'dev'

fix #14

See merge request caosdb/caosdb-server!20
parents 3e044b0a 275f0f07
No related branches found
No related tags found
No related merge requests found
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [Unreleased]
...@@ -33,6 +33,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ...@@ -33,6 +33,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- NaN Double Values (see #41) - NaN Double Values (see #41)
- #14 - Handle files on file system without File entity: Those entries are
returned without ID but with a notice now.
### Security (in case of vulnerabilities) ### Security (in case of vulnerabilities)
- TLS is by default restricted to v1.2 and v1.3 now. - TLS is by default restricted to v1.2 and v1.3 now.
......
...@@ -27,6 +27,7 @@ package caosdb.server.database.backend.transaction; ...@@ -27,6 +27,7 @@ package caosdb.server.database.backend.transaction;
import caosdb.server.caching.Cache; import caosdb.server.caching.Cache;
import caosdb.server.database.CacheableBackendTransaction; import caosdb.server.database.CacheableBackendTransaction;
import caosdb.server.database.backend.interfaces.GetFileRecordByPathImpl; import caosdb.server.database.backend.interfaces.GetFileRecordByPathImpl;
import caosdb.server.database.exceptions.EntityDoesNotExistException;
import caosdb.server.database.exceptions.TransactionException; import caosdb.server.database.exceptions.TransactionException;
import caosdb.server.database.proto.SparseEntity; import caosdb.server.database.proto.SparseEntity;
import org.apache.commons.jcs.access.behavior.ICacheAccess; import org.apache.commons.jcs.access.behavior.ICacheAccess;
...@@ -62,7 +63,11 @@ public class GetFileRecordByPath extends CacheableBackendTransaction<String, Spa ...@@ -62,7 +63,11 @@ public class GetFileRecordByPath extends CacheableBackendTransaction<String, Spa
@Override @Override
public SparseEntity executeNoCache() throws TransactionException { public SparseEntity executeNoCache() throws TransactionException {
final GetFileRecordByPathImpl t = getImplementation(GetFileRecordByPathImpl.class); final GetFileRecordByPathImpl t = getImplementation(GetFileRecordByPathImpl.class);
return t.execute(getKey()); SparseEntity result = t.execute(getKey());
if (result == null) {
throw new EntityDoesNotExistException();
}
return result;
} }
public Integer getId() { public Integer getId() {
......
...@@ -79,8 +79,8 @@ public class Message extends Exception implements Comparable<Message>, ToElement ...@@ -79,8 +79,8 @@ public class Message extends Exception implements Comparable<Message>, ToElement
this(type, code, null, null); this(type, code, null, null);
} }
public Message(final Integer code, final String description) { public Message(Integer code, String description) {
this("Message", code, description, null); this(MessageType.Info, code, description);
} }
public Message(final MessageType type, final Integer code, final String description) { public Message(final MessageType type, final Integer code, final String description) {
...@@ -96,6 +96,10 @@ public class Message extends Exception implements Comparable<Message>, ToElement ...@@ -96,6 +96,10 @@ public class Message extends Exception implements Comparable<Message>, ToElement
this(type, code, description, null); this(type, code, description, null);
} }
public Message(MessageType type, String description) {
this(type.toString(), 0, description);
}
public Message( public Message(
final String type, final Integer code, final String description, final String body) { final String type, final Integer code, final String description, final String body) {
this.code = code; this.code = code;
......
...@@ -26,9 +26,12 @@ import static caosdb.server.FileSystem.getFromFileSystem; ...@@ -26,9 +26,12 @@ import static caosdb.server.FileSystem.getFromFileSystem;
import static java.net.URLDecoder.decode; import static java.net.URLDecoder.decode;
import caosdb.server.database.backend.implementation.MySQL.ConnectionException; import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
import caosdb.server.database.exceptions.EntityDoesNotExistException;
import caosdb.server.database.misc.TransactionBenchmark; import caosdb.server.database.misc.TransactionBenchmark;
import caosdb.server.entity.Entity; import caosdb.server.entity.Entity;
import caosdb.server.entity.FileProperties; import caosdb.server.entity.FileProperties;
import caosdb.server.entity.Message;
import caosdb.server.entity.Message.MessageType;
import caosdb.server.entity.RetrieveEntity; import caosdb.server.entity.RetrieveEntity;
import caosdb.server.entity.container.TransactionContainer; import caosdb.server.entity.container.TransactionContainer;
import caosdb.server.permissions.EntityPermission; import caosdb.server.permissions.EntityPermission;
...@@ -56,6 +59,11 @@ import org.restlet.representation.Representation; ...@@ -56,6 +59,11 @@ import org.restlet.representation.Representation;
*/ */
public class FileSystemResource extends AbstractCaosDBServerResource { public class FileSystemResource extends AbstractCaosDBServerResource {
public static Message ORPHANED_FILE_WARNING =
new Message(
MessageType.Warning,
"Orphaned file. The file is not tracked. This is probably a harmless inconsistency but it might be a sign of other problems.");
/** /**
* Download a File from the CaosDBFileSystem. Only one File per Request. * Download a File from the CaosDBFileSystem. Only one File per Request.
* *
...@@ -124,6 +132,13 @@ public class FileSystemResource extends AbstractCaosDBServerResource { ...@@ -124,6 +132,13 @@ public class FileSystemResource extends AbstractCaosDBServerResource {
} else { } else {
try {
getEntity(specifier).checkPermission(EntityPermission.RETRIEVE_FILE);
} catch (EntityDoesNotExistException exception) {
// This file in the file system has no corresponding File record.
return error(ServerMessages.NOT_PERMITTED, Status.CLIENT_ERROR_FORBIDDEN);
}
final MediaType mt = MediaType.valueOf(FileUtils.getMimeType(file)); final MediaType mt = MediaType.valueOf(FileUtils.getMimeType(file));
final FileRepresentation ret = new FileRepresentation(file, mt); final FileRepresentation ret = new FileRepresentation(file, mt);
ret.setDisposition(new Disposition(Disposition.TYPE_ATTACHMENT)); ret.setDisposition(new Disposition(Disposition.TYPE_ATTACHMENT));
...@@ -149,19 +164,39 @@ public class FileSystemResource extends AbstractCaosDBServerResource { ...@@ -149,19 +164,39 @@ public class FileSystemResource extends AbstractCaosDBServerResource {
return null; return null;
} }
/**
* Return an element for the given file on a file system.
*
* <p>If there is no File entity for this file, an element without `id` is returned, instead a
* corresponding message is added to the element.
*/
Element getFileElement(final String directory, final File file) throws Exception { Element getFileElement(final String directory, final File file) throws Exception {
final Element celem = new Element("file"); final Element celem = new Element("file");
celem.setAttribute(
"id",
getEntityID((directory.endsWith("/") ? directory : directory + "/") + file.getName()));
celem.setAttribute("name", file.getName()); celem.setAttribute("name", file.getName());
try {
final String entId =
getEntityID((directory.endsWith("/") ? directory : directory + "/") + file.getName());
celem.setAttribute("id", entId);
} catch (EntityDoesNotExistException exception) {
// This file in the file system has no corresponding File record.
ORPHANED_FILE_WARNING.addToElement(celem);
}
return celem; return celem;
} }
protected String getEntityID(final String path) throws Exception { protected String getEntityID(final String path) throws Exception {
return getEntity(path).getId().toString(); final Entity fileEnt = getEntity(path);
return fileEnt.getId().toString();
} }
/**
* Throws EntityDoesNotExistException when there is not entity with that path.
*
* @param path
* @return
* @throws Exception
*/
private Entity getEntity(final String path) throws Exception { private Entity getEntity(final String path) throws Exception {
final long t1 = System.currentTimeMillis(); final long t1 = System.currentTimeMillis();
final TransactionContainer c = new TransactionContainer(); final TransactionContainer c = new TransactionContainer();
...@@ -178,19 +213,9 @@ public class FileSystemResource extends AbstractCaosDBServerResource { ...@@ -178,19 +213,9 @@ public class FileSystemResource extends AbstractCaosDBServerResource {
protected File getFile(final String path) throws Exception { protected File getFile(final String path) throws Exception {
final File ret = getFromFileSystem(path); final File ret = getFromFileSystem(path);
if (ret != null && ret.isFile()) {
checkPermissions(path);
}
return ret; return ret;
} }
private final void checkPermissions(final String path) throws Exception {
final long t1 = System.currentTimeMillis();
getEntity(path).checkPermission(EntityPermission.RETRIEVE_FILE);
final long t2 = System.currentTimeMillis();
getBenchmark().addMeasurement(this.getClass().getSimpleName() + ".checkPermissions", t2 - t1);
}
@Override @Override
protected Representation httpPostInChildClass(final Representation entity) protected Representation httpPostInChildClass(final Representation entity)
throws ConnectionException, JDOMException { throws ConnectionException, JDOMException {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment