comparison 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
comparison
equal deleted inserted replaced
4639:c638dd444de0 4640:66109d24d26e
2197 void StatelessDatabaseOperations::SetMetadata(int64_t& newRevision, 2197 void StatelessDatabaseOperations::SetMetadata(int64_t& newRevision,
2198 const std::string& publicId, 2198 const std::string& publicId,
2199 MetadataType type, 2199 MetadataType type,
2200 const std::string& value, 2200 const std::string& value,
2201 bool hasOldRevision, 2201 bool hasOldRevision,
2202 int64_t oldRevision) 2202 int64_t oldRevision,
2203 const std::string& oldMD5)
2203 { 2204 {
2204 class Operations : public IReadWriteOperations 2205 class Operations : public IReadWriteOperations
2205 { 2206 {
2206 private: 2207 private:
2207 int64_t& newRevision_; 2208 int64_t& newRevision_;
2208 const std::string& publicId_; 2209 const std::string& publicId_;
2209 MetadataType type_; 2210 MetadataType type_;
2210 const std::string& value_; 2211 const std::string& value_;
2211 bool hasOldRevision_; 2212 bool hasOldRevision_;
2212 int64_t oldRevision_; 2213 int64_t oldRevision_;
2214 const std::string& oldMD5_;
2213 2215
2214 public: 2216 public:
2215 Operations(int64_t& newRevision, 2217 Operations(int64_t& newRevision,
2216 const std::string& publicId, 2218 const std::string& publicId,
2217 MetadataType type, 2219 MetadataType type,
2218 const std::string& value, 2220 const std::string& value,
2219 bool hasOldRevision, 2221 bool hasOldRevision,
2220 int64_t oldRevision) : 2222 int64_t oldRevision,
2223 const std::string& oldMD5) :
2221 newRevision_(newRevision), 2224 newRevision_(newRevision),
2222 publicId_(publicId), 2225 publicId_(publicId),
2223 type_(type), 2226 type_(type),
2224 value_(value), 2227 value_(value),
2225 hasOldRevision_(hasOldRevision), 2228 hasOldRevision_(hasOldRevision),
2226 oldRevision_(oldRevision) 2229 oldRevision_(oldRevision),
2230 oldMD5_(oldMD5)
2227 { 2231 {
2228 } 2232 }
2229 2233
2230 virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE 2234 virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE
2231 { 2235 {
2239 { 2243 {
2240 std::string oldValue; 2244 std::string oldValue;
2241 int64_t expectedRevision; 2245 int64_t expectedRevision;
2242 if (transaction.LookupMetadata(oldValue, expectedRevision, id, type_)) 2246 if (transaction.LookupMetadata(oldValue, expectedRevision, id, type_))
2243 { 2247 {
2244 if (hasOldRevision_ && 2248 if (hasOldRevision_)
2245 expectedRevision != oldRevision_) 2249 {
2246 { 2250 std::string expectedMD5;
2247 throw OrthancException(ErrorCode_Revision); 2251 Toolbox::ComputeMD5(expectedMD5, oldValue);
2248 } 2252
2249 else 2253 if (expectedRevision != oldRevision_ ||
2250 { 2254 expectedMD5 != oldMD5_)
2251 newRevision_ = expectedRevision + 1; 2255 {
2252 } 2256 throw OrthancException(ErrorCode_Revision);
2257 }
2258 }
2259
2260 newRevision_ = expectedRevision + 1;
2253 } 2261 }
2254 else 2262 else
2255 { 2263 {
2256 // The metadata is not existing yet: Ignore "oldRevision" 2264 // The metadata is not existing yet: Ignore "oldRevision"
2257 // and initialize a new sequence of revisions 2265 // and initialize a new sequence of revisions
2266 } 2274 }
2267 } 2275 }
2268 } 2276 }
2269 }; 2277 };
2270 2278
2271 Operations operations(newRevision, publicId, type, value, hasOldRevision, oldRevision); 2279 Operations operations(newRevision, publicId, type, value, hasOldRevision, oldRevision, oldMD5);
2272 Apply(operations); 2280 Apply(operations);
2273 } 2281 }
2274 2282
2275 2283
2276 void StatelessDatabaseOperations::OverwriteMetadata(const std::string& publicId, 2284 void StatelessDatabaseOperations::OverwriteMetadata(const std::string& publicId,
2277 MetadataType type, 2285 MetadataType type,
2278 const std::string& value) 2286 const std::string& value)
2279 { 2287 {
2280 int64_t newRevision; // Unused 2288 int64_t newRevision; // Unused
2281 SetMetadata(newRevision, publicId, type, value, false /* no old revision */, -1 /* dummy */); 2289 SetMetadata(newRevision, publicId, type, value, false /* no old revision */, -1 /* dummy */, "" /* dummy */);
2282 } 2290 }
2283 2291
2284 2292
2285 bool StatelessDatabaseOperations::DeleteMetadata(const std::string& publicId, 2293 bool StatelessDatabaseOperations::DeleteMetadata(const std::string& publicId,
2286 MetadataType type, 2294 MetadataType type,
2287 bool hasRevision, 2295 bool hasRevision,
2288 int64_t revision) 2296 int64_t revision,
2297 const std::string& md5)
2289 { 2298 {
2290 class Operations : public IReadWriteOperations 2299 class Operations : public IReadWriteOperations
2291 { 2300 {
2292 private: 2301 private:
2293 const std::string& publicId_; 2302 const std::string& publicId_;
2294 MetadataType type_; 2303 MetadataType type_;
2295 bool hasRevision_; 2304 bool hasRevision_;
2296 int64_t revision_; 2305 int64_t revision_;
2306 const std::string& md5_;
2297 bool found_; 2307 bool found_;
2298 2308
2299 public: 2309 public:
2300 Operations(const std::string& publicId, 2310 Operations(const std::string& publicId,
2301 MetadataType type, 2311 MetadataType type,
2302 bool hasRevision, 2312 bool hasRevision,
2303 int64_t revision) : 2313 int64_t revision,
2314 const std::string& md5) :
2304 publicId_(publicId), 2315 publicId_(publicId),
2305 type_(type), 2316 type_(type),
2306 hasRevision_(hasRevision), 2317 hasRevision_(hasRevision),
2307 revision_(revision), 2318 revision_(revision),
2319 md5_(md5),
2308 found_(false) 2320 found_(false)
2309 { 2321 {
2310 } 2322 }
2311 2323
2312 bool HasFound() const 2324 bool HasFound() const
2322 { 2334 {
2323 throw OrthancException(ErrorCode_UnknownResource); 2335 throw OrthancException(ErrorCode_UnknownResource);
2324 } 2336 }
2325 else 2337 else
2326 { 2338 {
2327 std::string s; 2339 std::string value;
2328 int64_t expectedRevision; 2340 int64_t expectedRevision;
2329 if (transaction.LookupMetadata(s, expectedRevision, id, type_)) 2341 if (transaction.LookupMetadata(value, expectedRevision, id, type_))
2330 { 2342 {
2331 if (hasRevision_ && 2343 if (hasRevision_)
2332 expectedRevision != revision_) 2344 {
2333 { 2345 std::string expectedMD5;
2334 throw OrthancException(ErrorCode_Revision); 2346 Toolbox::ComputeMD5(expectedMD5, value);
2347
2348 if (expectedRevision != revision_ ||
2349 expectedMD5 != md5_)
2350 {
2351 throw OrthancException(ErrorCode_Revision);
2352 }
2335 } 2353 }
2336 2354
2337 found_ = true; 2355 found_ = true;
2338 transaction.DeleteMetadata(id, type_); 2356 transaction.DeleteMetadata(id, type_);
2339 2357
2340 if (IsUserMetadata(type_)) 2358 if (IsUserMetadata(type_))
2341 { 2359 {
2342 transaction.LogChange(id, ChangeType_UpdatedMetadata, resourceType, publicId_); 2360 transaction.LogChange(id, ChangeType_UpdatedMetadata, resourceType, publicId_);
2343 } 2361 }
2344 } 2362 }
2348 } 2366 }
2349 } 2367 }
2350 } 2368 }
2351 }; 2369 };
2352 2370
2353 Operations operations(publicId, type, hasRevision, revision); 2371 Operations operations(publicId, type, hasRevision, revision, md5);
2354 Apply(operations); 2372 Apply(operations);
2355 return operations.HasFound(); 2373 return operations.HasFound();
2356 } 2374 }
2357 2375
2358 2376
2483 2501
2484 2502
2485 bool StatelessDatabaseOperations::DeleteAttachment(const std::string& publicId, 2503 bool StatelessDatabaseOperations::DeleteAttachment(const std::string& publicId,
2486 FileContentType type, 2504 FileContentType type,
2487 bool hasRevision, 2505 bool hasRevision,
2488 int64_t revision) 2506 int64_t revision,
2507 const std::string& md5)
2489 { 2508 {
2490 class Operations : public IReadWriteOperations 2509 class Operations : public IReadWriteOperations
2491 { 2510 {
2492 private: 2511 private:
2493 const std::string& publicId_; 2512 const std::string& publicId_;
2494 FileContentType type_; 2513 FileContentType type_;
2495 bool hasRevision_; 2514 bool hasRevision_;
2496 int64_t revision_; 2515 int64_t revision_;
2516 const std::string& md5_;
2497 bool found_; 2517 bool found_;
2498 2518
2499 public: 2519 public:
2500 Operations(const std::string& publicId, 2520 Operations(const std::string& publicId,
2501 FileContentType type, 2521 FileContentType type,
2502 bool hasRevision, 2522 bool hasRevision,
2503 int64_t revision) : 2523 int64_t revision,
2524 const std::string& md5) :
2504 publicId_(publicId), 2525 publicId_(publicId),
2505 type_(type), 2526 type_(type),
2506 hasRevision_(hasRevision), 2527 hasRevision_(hasRevision),
2507 revision_(revision), 2528 revision_(revision),
2529 md5_(md5),
2508 found_(false) 2530 found_(false)
2509 { 2531 {
2510 } 2532 }
2511 2533
2512 bool HasFound() const 2534 bool HasFound() const
2527 FileInfo info; 2549 FileInfo info;
2528 int64_t expectedRevision; 2550 int64_t expectedRevision;
2529 if (transaction.LookupAttachment(info, expectedRevision, id, type_)) 2551 if (transaction.LookupAttachment(info, expectedRevision, id, type_))
2530 { 2552 {
2531 if (hasRevision_ && 2553 if (hasRevision_ &&
2532 expectedRevision != revision_) 2554 (expectedRevision != revision_ ||
2555 info.GetUncompressedMD5() != md5_))
2533 { 2556 {
2534 throw OrthancException(ErrorCode_Revision); 2557 throw OrthancException(ErrorCode_Revision);
2535 } 2558 }
2536 2559
2537 found_ = true; 2560 found_ = true;
2548 } 2571 }
2549 } 2572 }
2550 } 2573 }
2551 }; 2574 };
2552 2575
2553 Operations operations(publicId, type, hasRevision, revision); 2576 Operations operations(publicId, type, hasRevision, revision, md5);
2554 Apply(operations); 2577 Apply(operations);
2555 return operations.HasFound(); 2578 return operations.HasFound();
2556 } 2579 }
2557 2580
2558 2581
3259 const FileInfo& attachment, 3282 const FileInfo& attachment,
3260 const std::string& publicId, 3283 const std::string& publicId,
3261 uint64_t maximumStorageSize, 3284 uint64_t maximumStorageSize,
3262 unsigned int maximumPatients, 3285 unsigned int maximumPatients,
3263 bool hasOldRevision, 3286 bool hasOldRevision,
3264 int64_t oldRevision) 3287 int64_t oldRevision,
3288 const std::string& oldMD5)
3265 { 3289 {
3266 class Operations : public IReadWriteOperations 3290 class Operations : public IReadWriteOperations
3267 { 3291 {
3268 private: 3292 private:
3269 int64_t& newRevision_; 3293 int64_t& newRevision_;
3272 const std::string& publicId_; 3296 const std::string& publicId_;
3273 uint64_t maximumStorageSize_; 3297 uint64_t maximumStorageSize_;
3274 unsigned int maximumPatientCount_; 3298 unsigned int maximumPatientCount_;
3275 bool hasOldRevision_; 3299 bool hasOldRevision_;
3276 int64_t oldRevision_; 3300 int64_t oldRevision_;
3301 const std::string& oldMD5_;
3277 3302
3278 public: 3303 public:
3279 Operations(int64_t& newRevision, 3304 Operations(int64_t& newRevision,
3280 const FileInfo& attachment, 3305 const FileInfo& attachment,
3281 const std::string& publicId, 3306 const std::string& publicId,
3282 uint64_t maximumStorageSize, 3307 uint64_t maximumStorageSize,
3283 unsigned int maximumPatientCount, 3308 unsigned int maximumPatientCount,
3284 bool hasOldRevision, 3309 bool hasOldRevision,
3285 int64_t oldRevision) : 3310 int64_t oldRevision,
3311 const std::string& oldMD5) :
3286 newRevision_(newRevision), 3312 newRevision_(newRevision),
3287 status_(StoreStatus_Failure), 3313 status_(StoreStatus_Failure),
3288 attachment_(attachment), 3314 attachment_(attachment),
3289 publicId_(publicId), 3315 publicId_(publicId),
3290 maximumStorageSize_(maximumStorageSize), 3316 maximumStorageSize_(maximumStorageSize),
3291 maximumPatientCount_(maximumPatientCount), 3317 maximumPatientCount_(maximumPatientCount),
3292 hasOldRevision_(hasOldRevision), 3318 hasOldRevision_(hasOldRevision),
3293 oldRevision_(oldRevision) 3319 oldRevision_(oldRevision),
3320 oldMD5_(oldMD5)
3294 { 3321 {
3295 } 3322 }
3296 3323
3297 StoreStatus GetStatus() const 3324 StoreStatus GetStatus() const
3298 { 3325 {
3314 FileInfo oldFile; 3341 FileInfo oldFile;
3315 int64_t expectedRevision; 3342 int64_t expectedRevision;
3316 if (transaction.LookupAttachment(oldFile, expectedRevision, resourceId, attachment_.GetContentType())) 3343 if (transaction.LookupAttachment(oldFile, expectedRevision, resourceId, attachment_.GetContentType()))
3317 { 3344 {
3318 if (hasOldRevision_ && 3345 if (hasOldRevision_ &&
3319 expectedRevision != oldRevision_) 3346 (expectedRevision != oldRevision_ ||
3347 oldFile.GetUncompressedMD5() != oldMD5_))
3320 { 3348 {
3321 throw OrthancException(ErrorCode_Revision); 3349 throw OrthancException(ErrorCode_Revision);
3322 } 3350 }
3323 else 3351 else
3324 { 3352 {
3369 } 3397 }
3370 } 3398 }
3371 }; 3399 };
3372 3400
3373 3401
3374 Operations operations(newRevision, attachment, publicId, maximumStorageSize, maximumPatients, hasOldRevision, oldRevision); 3402 Operations operations(newRevision, attachment, publicId, maximumStorageSize, maximumPatients,
3403 hasOldRevision, oldRevision, oldMD5);
3375 Apply(operations); 3404 Apply(operations);
3376 return operations.GetStatus(); 3405 return operations.GetStatus();
3377 } 3406 }
3378 } 3407 }