private bool TryGetLock(string fileId, out LockInfo lockInfo) { //TODO: This lock implementation is not thread safe and not persisted and all in all just an example. if (Locks.TryGetValue(fileId, out lockInfo)) { if (lockInfo.Expired) { Locks.Remove(fileId); return false; } return true; } return false; }
public async Task<IActionResult> PerformAction(string id, [FromQuery]string access_token) { var editSession = await GetEditSessionAsync(id); string wopiOverrideHeader = HttpContext.Request.Headers[WopiHeaders.WopiOverride]; //TODO: Replace the else-ifs with separate methods (https://github.com/petrsvihlik/WopiHost/issues/7) // http://stackoverflow.com/questions/39302121/header-based-routing-in-asp-net-core if (wopiOverrideHeader.Equals("COBALT")) { var responseAction = editSession.SetFileContent(await HttpContext.Request.Body.ReadBytesAsync()); HttpContext.Response.Headers.Add(WopiHeaders.CorrelationId, HttpContext.Request.Headers[WopiHeaders.CorrelationId]); HttpContext.Response.Headers.Add("request-id", HttpContext.Request.Headers[WopiHeaders.CorrelationId]); return new Results.FileResult(responseAction, "application/octet-stream"); } else if (wopiOverrideHeader.Equals("LOCK") || wopiOverrideHeader.Equals("UNLOCK") || wopiOverrideHeader.Equals("REFRESH_LOCK") || wopiOverrideHeader.Equals("GET_LOCK")) { string oldLock = Request.Headers[WopiHeaders.OldLock]; string newLock = Request.Headers[WopiHeaders.Lock]; LockInfo existingLock = null; bool lockAcquired = TryGetLock(id, out existingLock); lock (Locks) { switch (wopiOverrideHeader) { case "GET_LOCK": break; case "LOCK": if (oldLock != null) { if (lockAcquired) { if (existingLock.Lock == oldLock) { // Replace the existing lock with the new one Locks[id] = new LockInfo { DateCreated = DateTime.UtcNow, Lock = newLock }; Response.Headers[WopiHeaders.OldLock] = newLock; return new OkResult(); } else { // The existing lock doesn't match the requested one. Return a lock mismatch error along with the current lock return ReturnLockMismatch(Response, existingLock.Lock); } } else { // The requested lock does not exist. That's also a lock mismatch error. return ReturnLockMismatch(Response, reason: "File not locked"); } } else { if (lockAcquired) { // There is a valid existing lock on the file return ReturnLockMismatch(Response, existingLock.Lock); } else { // The file is not currently locked, create and store new lock information Locks[id] = new LockInfo { DateCreated = DateTime.UtcNow, Lock = newLock }; return new OkResult(); } } case "UNLOCK": if (lockAcquired) { if (existingLock.Lock == newLock) { // Remove valid lock Locks.Remove(id); return new OkResult(); } else { // The existing lock doesn't match the requested one. Return a lock mismatch error along with the current lock return ReturnLockMismatch(Response, existingLock.Lock); } } else { // The requested lock does not exist. return ReturnLockMismatch(Response, reason: "File not locked"); } case "REFRESH_LOCK": if (lockAcquired) { if (existingLock.Lock == newLock) { // Extend the lock timeout existingLock.DateCreated = DateTime.UtcNow; return new OkResult(); } else { // The existing lock doesn't match the requested one. Return a lock mismatch error along with the current lock return ReturnLockMismatch(Response, existingLock.Lock); } } else { // The requested lock does not exist. That's also a lock mismatch error. return ReturnLockMismatch(Response, reason: "File not locked"); } } } return new OkResult(); } else { // Unsupported action return new NotImplementedResult(); } }