diff OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp @ 4640:66109d24d26e

"ETag" headers for metadata and attachments now allow strong comparison (MD5 is included)
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 26 Apr 2021 15:22:44 +0200
parents 37357df3dc27
children da1edb7d6332
line wrap: on
line diff
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Thu Apr 22 13:27:57 2021 +0200
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Mon Apr 26 15:22:44 2021 +0200
@@ -2199,7 +2199,8 @@
                                                 MetadataType type,
                                                 const std::string& value,
                                                 bool hasOldRevision,
-                                                int64_t oldRevision)
+                                                int64_t oldRevision,
+                                                const std::string& oldMD5)
   {
     class Operations : public IReadWriteOperations
     {
@@ -2210,6 +2211,7 @@
       const std::string&  value_;
       bool                hasOldRevision_;
       int64_t             oldRevision_;
+      const std::string&  oldMD5_;
 
     public:
       Operations(int64_t& newRevision,
@@ -2217,13 +2219,15 @@
                  MetadataType type,
                  const std::string& value,
                  bool hasOldRevision,
-                 int64_t oldRevision) :
+                 int64_t oldRevision,
+                 const std::string& oldMD5) :
         newRevision_(newRevision),
         publicId_(publicId),
         type_(type),
         value_(value),
         hasOldRevision_(hasOldRevision),
-        oldRevision_(oldRevision)
+        oldRevision_(oldRevision),
+        oldMD5_(oldMD5)
       {
       }
 
@@ -2241,15 +2245,19 @@
           int64_t expectedRevision;
           if (transaction.LookupMetadata(oldValue, expectedRevision, id, type_))
           {
-            if (hasOldRevision_ &&
-                expectedRevision != oldRevision_)
+            if (hasOldRevision_)
             {
-              throw OrthancException(ErrorCode_Revision);
+              std::string expectedMD5;
+              Toolbox::ComputeMD5(expectedMD5, oldValue);
+
+              if (expectedRevision != oldRevision_ ||
+                  expectedMD5 != oldMD5_)
+              {
+                throw OrthancException(ErrorCode_Revision);
+              }              
             }
-            else
-            {
-              newRevision_ = expectedRevision + 1;
-            }
+            
+            newRevision_ = expectedRevision + 1;
           }
           else
           {
@@ -2268,7 +2276,7 @@
       }
     };
 
-    Operations operations(newRevision, publicId, type, value, hasOldRevision, oldRevision);
+    Operations operations(newRevision, publicId, type, value, hasOldRevision, oldRevision, oldMD5);
     Apply(operations);
   }
 
@@ -2278,14 +2286,15 @@
                                                       const std::string& value)
   {
     int64_t newRevision;  // Unused
-    SetMetadata(newRevision, publicId, type, value, false /* no old revision */, -1 /* dummy */);
+    SetMetadata(newRevision, publicId, type, value, false /* no old revision */, -1 /* dummy */, "" /* dummy */);
   }
 
 
   bool StatelessDatabaseOperations::DeleteMetadata(const std::string& publicId,
                                                    MetadataType type,
                                                    bool hasRevision,
-                                                   int64_t revision)
+                                                   int64_t revision,
+                                                   const std::string& md5)
   {
     class Operations : public IReadWriteOperations
     {
@@ -2294,17 +2303,20 @@
       MetadataType        type_;
       bool                hasRevision_;
       int64_t             revision_;
+      const std::string&  md5_;
       bool                found_;
 
     public:
       Operations(const std::string& publicId,
                  MetadataType type,
                  bool hasRevision,
-                 int64_t revision) :
+                 int64_t revision,
+                 const std::string& md5) :
         publicId_(publicId),
         type_(type),
         hasRevision_(hasRevision),
         revision_(revision),
+        md5_(md5),
         found_(false)
       {
       }
@@ -2324,19 +2336,25 @@
         }
         else
         {
-          std::string s;
+          std::string value;
           int64_t expectedRevision;
-          if (transaction.LookupMetadata(s, expectedRevision, id, type_))
+          if (transaction.LookupMetadata(value, expectedRevision, id, type_))
           {
-            if (hasRevision_ &&
-                expectedRevision != revision_)
+            if (hasRevision_)
             {
-              throw OrthancException(ErrorCode_Revision);
+              std::string expectedMD5;
+              Toolbox::ComputeMD5(expectedMD5, value);
+
+              if (expectedRevision != revision_ ||
+                  expectedMD5 != md5_)
+              {
+                throw OrthancException(ErrorCode_Revision);
+              }
             }
             
             found_ = true;
             transaction.DeleteMetadata(id, type_);
-
+            
             if (IsUserMetadata(type_))
             {
               transaction.LogChange(id, ChangeType_UpdatedMetadata, resourceType, publicId_);
@@ -2350,7 +2368,7 @@
       }
     };
 
-    Operations operations(publicId, type, hasRevision, revision);
+    Operations operations(publicId, type, hasRevision, revision, md5);
     Apply(operations);
     return operations.HasFound();
   }
@@ -2485,7 +2503,8 @@
   bool StatelessDatabaseOperations::DeleteAttachment(const std::string& publicId,
                                                      FileContentType type,
                                                      bool hasRevision,
-                                                     int64_t revision)
+                                                     int64_t revision,
+                                                     const std::string& md5)
   {
     class Operations : public IReadWriteOperations
     {
@@ -2494,17 +2513,20 @@
       FileContentType     type_;
       bool                hasRevision_;
       int64_t             revision_;
+      const std::string&  md5_;
       bool                found_;
 
     public:
       Operations(const std::string& publicId,
                  FileContentType type,
                  bool hasRevision,
-                 int64_t revision) :
+                 int64_t revision,
+                 const std::string& md5) :
         publicId_(publicId),
         type_(type),
         hasRevision_(hasRevision),
         revision_(revision),
+        md5_(md5),
         found_(false)
       {
       }
@@ -2529,7 +2551,8 @@
           if (transaction.LookupAttachment(info, expectedRevision, id, type_))
           {
             if (hasRevision_ &&
-                expectedRevision != revision_)
+                (expectedRevision != revision_ ||
+                 info.GetUncompressedMD5() != md5_))
             {
               throw OrthancException(ErrorCode_Revision);
             }
@@ -2550,7 +2573,7 @@
       }
     };
 
-    Operations operations(publicId, type, hasRevision, revision);
+    Operations operations(publicId, type, hasRevision, revision, md5);
     Apply(operations);
     return operations.HasFound();
   }
@@ -3261,7 +3284,8 @@
                                                          uint64_t maximumStorageSize,
                                                          unsigned int maximumPatients,
                                                          bool hasOldRevision,
-                                                         int64_t oldRevision)
+                                                         int64_t oldRevision,
+                                                         const std::string& oldMD5)
   {
     class Operations : public IReadWriteOperations
     {
@@ -3274,6 +3298,7 @@
       unsigned int        maximumPatientCount_;
       bool                hasOldRevision_;
       int64_t             oldRevision_;
+      const std::string&  oldMD5_;
 
     public:
       Operations(int64_t& newRevision,
@@ -3282,7 +3307,8 @@
                  uint64_t maximumStorageSize,
                  unsigned int maximumPatientCount,
                  bool hasOldRevision,
-                 int64_t oldRevision) :
+                 int64_t oldRevision,
+                 const std::string& oldMD5) :
         newRevision_(newRevision),
         status_(StoreStatus_Failure),
         attachment_(attachment),
@@ -3290,7 +3316,8 @@
         maximumStorageSize_(maximumStorageSize),
         maximumPatientCount_(maximumPatientCount),
         hasOldRevision_(hasOldRevision),
-        oldRevision_(oldRevision)
+        oldRevision_(oldRevision),
+        oldMD5_(oldMD5)
       {
       }
 
@@ -3316,7 +3343,8 @@
             if (transaction.LookupAttachment(oldFile, expectedRevision, resourceId, attachment_.GetContentType()))
             {
               if (hasOldRevision_ &&
-                  expectedRevision != oldRevision_)
+                  (expectedRevision != oldRevision_ ||
+                   oldFile.GetUncompressedMD5() != oldMD5_))
               {
                 throw OrthancException(ErrorCode_Revision);
               }
@@ -3371,7 +3399,8 @@
     };
 
 
-    Operations operations(newRevision, attachment, publicId, maximumStorageSize, maximumPatients, hasOldRevision, oldRevision);
+    Operations operations(newRevision, attachment, publicId, maximumStorageSize, maximumPatients,
+                          hasOldRevision, oldRevision, oldMD5);
     Apply(operations);
     return operations.GetStatus();
   }