public async Task <HttpResponseMessage> DocPut(string docId) { RavenJObject json; try { json = await ReadJsonAsync(); } catch (InvalidOperationException e) { Log.Debug("Failed to deserialize document request." + e); return(GetMessageWithObject(new { Message = "Could not understand json, please check its validity." }, (HttpStatusCode)422)); //http code 422 - Unprocessable entity } catch (InvalidDataException e) { Log.Debug("Failed to deserialize document request." + e); return(GetMessageWithObject(new { e.Message }, (HttpStatusCode)422)); //http code 422 - Unprocessable entity } var putResult = Database.Documents.Put(docId, GetEtag(), json, ReadInnerHeaders.FilterHeadersToObject(), GetRequestTransaction()); return(GetMessageWithObject(putResult, HttpStatusCode.Created)); }
public async Task <HttpResponseMessage> DocsPost() { RavenJObject json; try { json = await ReadJsonAsync(); } catch (InvalidOperationException e) { Log.DebugException("Failed to read json document.", e); return(GetMessageWithObject(new { Message = "Could not understand json, please check its validity." }, (HttpStatusCode)422)); //http code 422 - Unprocessable entity } catch (InvalidDataException e) { Log.DebugException("Failed to read json document.", e); return(GetMessageWithObject(new { e.Message }, (HttpStatusCode)422)); //http code 422 - Unprocessable entity } var id = Database.Documents.Put(null, Etag.Empty, json, ReadInnerHeaders.FilterHeadersToObject(), GetRequestTransaction()); return(GetMessageWithObject(id)); }
public async Task <HttpResponseMessage> DocPut(string docId) { var json = await ReadJsonAsync(); var putResult = Database.Documents.Put(docId, GetEtag(), json, ReadInnerHeaders.FilterHeadersToObject(), GetRequestTransaction()); return(GetMessageWithObject(putResult, HttpStatusCode.Created)); }
public async Task <HttpResponseMessage> DocsPost() { var json = await ReadJsonAsync(); var id = Database.Documents.Put(null, Etag.Empty, json, ReadInnerHeaders.FilterHeadersToObject(), GetRequestTransaction()); return(GetMessageWithObject(id)); }
public async Task <HttpResponseMessage> GlobalSettingsPut() { var etag = GetEtag(); var globalSettingsDoc = await ReadJsonObjectAsync <GlobalSettingsDocument>().ConfigureAwait(false); GlobalSettingsDocumentProtector.Protect(globalSettingsDoc); var json = RavenJObject.FromObject(globalSettingsDoc); var metadata = (etag != null) ? ReadInnerHeaders.FilterHeadersToObject() : new RavenJObject(); var putResult = Database.Documents.Put(Constants.Global.GlobalSettingsDocumentKey, etag, json, metadata, null); return(GetMessageWithObject(putResult)); }
public async Task <HttpResponseMessage> DatabasesPut(string id) { if (IsSystemDatabase(id)) { return(GetMessageWithString("System database document cannot be changed!", HttpStatusCode.Forbidden)); } MessageWithStatusCode databaseNameFormat = CheckNameFormat(id, Database.Configuration.DataDirectory); if (databaseNameFormat.Message != null) { return(GetMessageWithString(databaseNameFormat.Message, databaseNameFormat.ErrorCode)); } Etag etag = GetEtag(); string error = CheckExistingDatabaseName(id, etag); if (error != null) { return(GetMessageWithString(error, HttpStatusCode.BadRequest)); } var dbDoc = await ReadJsonObjectAsync <DatabaseDocument>(); string bundles; if (dbDoc.Settings.TryGetValue(Constants.ActiveBundles, out bundles) && bundles.Contains("Encryption")) { if (dbDoc.SecuredSettings == null || !dbDoc.SecuredSettings.ContainsKey(Constants.EncryptionKeySetting) || !dbDoc.SecuredSettings.ContainsKey(Constants.AlgorithmTypeSetting)) { return(GetMessageWithString(string.Format("Failed to create '{0}' database, because of invalid encryption configuration.", id), HttpStatusCode.BadRequest)); } } //TODO: check if paths in document are legal DatabasesLandlord.Protect(dbDoc); var json = RavenJObject.FromObject(dbDoc); json.Remove("Id"); var metadata = (etag != null) ? ReadInnerHeaders.FilterHeadersToObject() : new RavenJObject(); var docKey = Constants.Database.Prefix + id; var putResult = Database.Documents.Put(docKey, etag, json, metadata, null); return((etag == null) ? GetEmptyMessage() : GetMessageWithObject(putResult)); }
public async Task <HttpResponseMessage> Put(string id) { if (IsSystemDatabase(id)) { return(GetMessageWithString("System database document cannot be changed!", HttpStatusCode.Forbidden)); } MessageWithStatusCode nameFormatErrorMessage; if (IsValidName(id, Database.Configuration.DataDirectory, out nameFormatErrorMessage) == false) { return(GetMessageWithString(nameFormatErrorMessage.Message, nameFormatErrorMessage.ErrorCode)); } Etag etag = GetEtag(); string error = CheckExistingDatabaseName(id, etag); if (error != null) { return(GetMessageWithString(error, HttpStatusCode.BadRequest)); } var dbDoc = await ReadJsonObjectAsync <DatabaseDocument>().ConfigureAwait(false); string bundles; if (dbDoc.Settings.TryGetValue(Constants.ActiveBundles, out bundles) && bundles.Contains("Encryption")) { if (dbDoc.SecuredSettings == null || !dbDoc.SecuredSettings.ContainsKey(Constants.EncryptionKeySetting) || !dbDoc.SecuredSettings.ContainsKey(Constants.AlgorithmTypeSetting)) { return(GetMessageWithString(string.Format("Failed to create '{0}' database, because of invalid encryption configuration.", id), HttpStatusCode.BadRequest)); } } //TODO: check if paths in document are legal if (dbDoc.IsClusterDatabase() && ClusterManager.IsActive()) { string dataDir; if (dbDoc.Settings.TryGetValue("Raven/DataDir", out dataDir) == false || string.IsNullOrEmpty(dataDir)) { return(GetMessageWithString(string.Format("Failed to create '{0}' database, because 'Raven/DataDir' setting is missing.", id), HttpStatusCode.BadRequest)); } dataDir = dataDir.ToFullPath(SystemConfiguration.DataDirectory); // if etag is not null, it means we want to update existing database if (Directory.Exists(dataDir) && etag == null) { return(GetMessageWithString(string.Format("Failed to create '{0}' database, because data directory '{1}' exists and it is forbidden to create non-empty cluster-wide databases.", id, dataDir), HttpStatusCode.BadRequest)); } var changesAppliedMre = new ManualResetEventSlim(false); Etag newEtag = null; var documentKey = Constants.Database.Prefix + id; Action <DocumentDatabase, DocumentChangeNotification, RavenJObject> onDocumentAction = (database, notification, jObject) => { if (notification.Type == DocumentChangeTypes.Put && notification.Id == documentKey) { newEtag = notification.Etag; changesAppliedMre.Set(); } }; Database.Notifications.OnDocumentChange += onDocumentAction; try { await ClusterManager.Client.SendDatabaseUpdateAsync(id, dbDoc).ConfigureAwait(false); changesAppliedMre.Wait(TimeSpan.FromSeconds(15)); } finally { Database.Notifications.OnDocumentChange -= onDocumentAction; } var clusterPutResult = new PutResult { ETag = newEtag, Key = documentKey }; return((etag == null) ? GetEmptyMessage() : GetMessageWithObject(clusterPutResult)); } DatabasesLandlord.Protect(dbDoc); var json = RavenJObject.FromObject(dbDoc); json.Remove("Id"); var metadata = (etag != null) ? ReadInnerHeaders.FilterHeadersToObject() : new RavenJObject(); var docKey = Constants.Database.Prefix + id; var putResult = Database.Documents.Put(docKey, etag, json, metadata, null); return((etag == null) ? GetEmptyMessage() : GetMessageWithObject(putResult)); }
public HttpResponseMessage StaticPost(string id) { var filename = id; var newEtagPost = Database.Attachments.PutStatic(filename, GetEtag(), null, ReadInnerHeaders.FilterHeadersAttachment()); var msg = GetMessageWithObject(newEtagPost); WriteETag(newEtagPost, msg); return(msg); }
public async Task <HttpResponseMessage> StaticPut(string filename) { var newEtag = Database.Attachments.PutStatic(filename, GetEtag(), await InnerRequest.Content.ReadAsStreamAsync(), ReadInnerHeaders.FilterHeadersAttachment()); var msg = GetEmptyMessage(HttpStatusCode.Created); msg.Headers.Location = Database.Configuration.GetFullUrl("static/" + filename); WriteETag(newEtag, msg); return(msg); }
public async Task <HttpResponseMessage> MultipartProceed(string fileSystemName) { if (!Request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } var fileName = Request.Headers.GetValues(SyncingMultipartConstants.FileName).FirstOrDefault(); var canonicalFilename = FileHeader.Canonize(fileName); var tempFileName = RavenFileNameHelper.DownloadingFileName(canonicalFilename); var sourceServerInfo = ReadInnerHeaders.Value <ServerInfo>(SyncingMultipartConstants.SourceServerInfo); var sourceFileETag = Guid.Parse(GetHeader(Constants.MetadataEtagField).Trim('\"')); var report = new SynchronizationReport(canonicalFilename, sourceFileETag, SynchronizationType.ContentUpdate); Log.Debug("Starting to process multipart synchronization request of a file '{0}' with ETag {1} from {2}", fileName, sourceFileETag, sourceServerInfo); StorageStream localFile = null; var isNewFile = false; var isConflictResolved = false; try { Storage.Batch(accessor => { AssertFileIsNotBeingSynced(canonicalFilename, accessor); FileLockManager.LockByCreatingSyncConfiguration(canonicalFilename, sourceServerInfo, accessor); }); SynchronizationTask.IncomingSynchronizationStarted(canonicalFilename, sourceServerInfo, sourceFileETag, SynchronizationType.ContentUpdate); PublishSynchronizationNotification(fileSystemName, canonicalFilename, sourceServerInfo, report.Type, SynchronizationAction.Start); Storage.Batch(accessor => StartupProceed(canonicalFilename, accessor)); RavenJObject sourceMetadata = GetFilteredMetadataFromHeaders(ReadInnerHeaders); var localMetadata = GetLocalMetadata(canonicalFilename); if (localMetadata != null) { AssertConflictDetection(canonicalFilename, localMetadata, sourceMetadata, sourceServerInfo, out isConflictResolved); localFile = StorageStream.Reading(Storage, canonicalFilename); } else { isNewFile = true; } Historian.UpdateLastModified(sourceMetadata); var synchronizingFile = SynchronizingFileStream.CreatingOrOpeningAndWriting(Storage, Search, StorageOperationsTask, tempFileName, sourceMetadata); var provider = new MultipartSyncStreamProvider(synchronizingFile, localFile); Log.Debug("Starting to process/read multipart content of a file '{0}'", fileName); await Request.Content.ReadAsMultipartAsync(provider); Log.Debug("Multipart content of a file '{0}' was processed/read", fileName); report.BytesCopied = provider.BytesCopied; report.BytesTransfered = provider.BytesTransfered; report.NeedListLength = provider.NumberOfFileParts; synchronizingFile.PreventUploadComplete = false; synchronizingFile.Flush(); synchronizingFile.Dispose(); sourceMetadata["Content-MD5"] = synchronizingFile.FileHash; Storage.Batch(accessor => accessor.UpdateFileMetadata(tempFileName, sourceMetadata)); Storage.Batch(accessor => { StorageOperationsTask.IndicateFileToDelete(canonicalFilename); accessor.RenameFile(tempFileName, canonicalFilename); Search.Delete(tempFileName); Search.Index(canonicalFilename, sourceMetadata); }); if (isNewFile) { Log.Debug("Temporary downloading file '{0}' was renamed to '{1}'. Indexes were updated.", tempFileName, fileName); } else { Log.Debug("Old file '{0}' was deleted. Indexes were updated.", fileName); } if (isConflictResolved) { ConflictArtifactManager.Delete(canonicalFilename); } } catch (Exception ex) { if (ShouldAddExceptionToReport(ex)) { report.Exception = ex; } } finally { if (localFile != null) { localFile.Dispose(); } } if (report.Exception == null) { Log.Debug( "File '{0}' was synchronized successfully from {1}. {2} bytes were transfered and {3} bytes copied. Need list length was {4}", fileName, sourceServerInfo, report.BytesTransfered, report.BytesCopied, report.NeedListLength); } else { Log.WarnException( string.Format("Error has occurred during synchronization of a file '{0}' from {1}", fileName, sourceServerInfo), report.Exception); } FinishSynchronization(canonicalFilename, report, sourceServerInfo, sourceFileETag); PublishFileNotification(fileName, isNewFile ? FileChangeAction.Add : FileChangeAction.Update); PublishSynchronizationNotification(fileSystemName, fileName, sourceServerInfo, report.Type, SynchronizationAction.Finish); if (isConflictResolved) { Publisher.Publish(new ConflictNotification { FileName = fileName, Status = ConflictStatus.Resolved }); } return(GetMessageWithObject(report)); }
public HttpResponseMessage Rename(string fileSystemName, string fileName, string rename) { bool isConflictResolved = false; var canonicalFilename = FileHeader.Canonize(fileName); var canonicalRename = FileHeader.Canonize(rename); var sourceServerInfo = ReadInnerHeaders.Value <ServerInfo>(SyncingMultipartConstants.SourceServerInfo); var sourceFileETag = Guid.Parse(GetHeader(Constants.MetadataEtagField).Trim('\"')); var sourceMetadata = GetFilteredMetadataFromHeaders(ReadInnerHeaders); Log.Debug("Starting to rename a file '{0}' to '{1}' with ETag {2} from {3} because of synchronization", fileName, rename, sourceFileETag, sourceServerInfo); var report = new SynchronizationReport(canonicalFilename, sourceFileETag, SynchronizationType.Rename); try { Storage.Batch(accessor => { AssertFileIsNotBeingSynced(canonicalFilename, accessor); FileLockManager.LockByCreatingSyncConfiguration(canonicalFilename, sourceServerInfo, accessor); }); SynchronizationTask.IncomingSynchronizationStarted(canonicalFilename, sourceServerInfo, sourceFileETag, SynchronizationType.Rename); PublishSynchronizationNotification(fileSystemName, canonicalFilename, sourceServerInfo, report.Type, SynchronizationAction.Start); Storage.Batch(accessor => StartupProceed(canonicalFilename, accessor)); var localMetadata = GetLocalMetadata(canonicalFilename); AssertConflictDetection(canonicalFilename, localMetadata, sourceMetadata, sourceServerInfo, out isConflictResolved); if (isConflictResolved) { ConflictArtifactManager.Delete(canonicalFilename); } StorageOperationsTask.RenameFile(new RenameFileOperation { FileSystem = FileSystem.Name, Name = canonicalFilename, Rename = canonicalRename, MetadataAfterOperation = sourceMetadata.WithETag(sourceFileETag).DropRenameMarkers() }); } catch (Exception ex) { if (ShouldAddExceptionToReport(ex)) { report.Exception = ex; Log.WarnException(string.Format("Error was occurred during renaming synchronization of file '{0}' from {1}", fileName, sourceServerInfo), ex); } } finally { FinishSynchronization(canonicalFilename, report, sourceServerInfo, sourceFileETag); } PublishSynchronizationNotification(fileSystemName, canonicalFilename, sourceServerInfo, report.Type, SynchronizationAction.Finish); if (isConflictResolved) { Publisher.Publish(new ConflictNotification { FileName = fileName, Status = ConflictStatus.Resolved }); } if (report.Exception == null) { Log.Debug("File '{0}' was renamed to '{1}' during synchronization from {2}", fileName, rename, sourceServerInfo); } return(GetMessageWithObject(report)); }
public HttpResponseMessage Delete(string fileSystemName, string fileName) { var canonicalFilename = FileHeader.Canonize(fileName); var sourceServerInfo = ReadInnerHeaders.Value <ServerInfo>(SyncingMultipartConstants.SourceServerInfo); var sourceFileETag = Guid.Parse(GetHeader(Constants.MetadataEtagField).Trim('\"')); Log.Debug("Starting to delete a file '{0}' with ETag {1} from {2} because of synchronization", fileName, sourceFileETag, sourceServerInfo); var report = new SynchronizationReport(canonicalFilename, sourceFileETag, SynchronizationType.Delete); try { Storage.Batch(accessor => { AssertFileIsNotBeingSynced(canonicalFilename, accessor); FileLockManager.LockByCreatingSyncConfiguration(canonicalFilename, sourceServerInfo, accessor); }); SynchronizationTask.IncomingSynchronizationStarted(canonicalFilename, sourceServerInfo, sourceFileETag, SynchronizationType.Delete); PublishSynchronizationNotification(fileSystemName, canonicalFilename, sourceServerInfo, report.Type, SynchronizationAction.Start); Storage.Batch(accessor => StartupProceed(canonicalFilename, accessor)); var localMetadata = GetLocalMetadata(canonicalFilename); if (localMetadata != null) { // REVIEW: Use InnerHeaders for consistency? var sourceMetadata = GetFilteredMetadataFromHeaders(Request.Headers); // Request.Headers.FilterHeadersToObject(); bool isConflictResolved; AssertConflictDetection(canonicalFilename, localMetadata, sourceMetadata, sourceServerInfo, out isConflictResolved); Storage.Batch(accessor => { StorageOperationsTask.IndicateFileToDelete(canonicalFilename); var tombstoneMetadata = new RavenJObject { { SynchronizationConstants.RavenSynchronizationHistory, localMetadata[SynchronizationConstants.RavenSynchronizationHistory] }, { SynchronizationConstants.RavenSynchronizationVersion, localMetadata[SynchronizationConstants.RavenSynchronizationVersion] }, { SynchronizationConstants.RavenSynchronizationSource, localMetadata[SynchronizationConstants.RavenSynchronizationSource] } }.WithDeleteMarker(); Historian.UpdateLastModified(tombstoneMetadata); accessor.PutFile(canonicalFilename, 0, tombstoneMetadata, true); }); PublishFileNotification(fileName, FileChangeAction.Delete); } } catch (Exception ex) { if (ShouldAddExceptionToReport(ex)) { report.Exception = ex; Log.WarnException(string.Format("Error was occurred during deletion synchronization of file '{0}' from {1}", fileName, sourceServerInfo), ex); } } finally { FinishSynchronization(canonicalFilename, report, sourceServerInfo, sourceFileETag); } PublishSynchronizationNotification(fileSystemName, fileName, sourceServerInfo, report.Type, SynchronizationAction.Finish); if (report.Exception == null) { Log.Debug("File '{0}' was deleted during synchronization from {1}", fileName, sourceServerInfo); } return(this.GetMessageWithObject(report, HttpStatusCode.OK)); }
public HttpResponseMessage UpdateMetadata(string fileSystemName, string fileName) { bool isConflictResolved = false; var canonicalFilename = FileHeader.Canonize(fileName); var sourceServerInfo = ReadInnerHeaders.Value <ServerInfo>(SyncingMultipartConstants.SourceServerInfo); // REVIEW: (Oren) It works, but it seems to me it is not an scalable solution. var sourceFileETag = Guid.Parse(GetHeader(Constants.MetadataEtagField).Trim('\"')); Log.Debug("Starting to update a metadata of file '{0}' with ETag {1} from {2} because of synchronization", fileName, sourceFileETag, sourceServerInfo); var report = new SynchronizationReport(canonicalFilename, sourceFileETag, SynchronizationType.MetadataUpdate); try { Storage.Batch(accessor => { AssertFileIsNotBeingSynced(canonicalFilename, accessor); FileLockManager.LockByCreatingSyncConfiguration(canonicalFilename, sourceServerInfo, accessor); }); SynchronizationTask.IncomingSynchronizationStarted(canonicalFilename, sourceServerInfo, sourceFileETag, SynchronizationType.MetadataUpdate); PublishSynchronizationNotification(fileSystemName, canonicalFilename, sourceServerInfo, report.Type, SynchronizationAction.Start); Storage.Batch(accessor => StartupProceed(canonicalFilename, accessor)); var localMetadata = GetLocalMetadata(canonicalFilename); var sourceMetadata = GetFilteredMetadataFromHeaders(ReadInnerHeaders); AssertConflictDetection(canonicalFilename, localMetadata, sourceMetadata, sourceServerInfo, out isConflictResolved); Historian.UpdateLastModified(sourceMetadata); Storage.Batch(accessor => accessor.UpdateFileMetadata(canonicalFilename, sourceMetadata)); Search.Index(canonicalFilename, sourceMetadata); if (isConflictResolved) { ConflictArtifactManager.Delete(canonicalFilename); } PublishFileNotification(fileName, FileChangeAction.Update); } catch (Exception ex) { if (ShouldAddExceptionToReport(ex)) { report.Exception = ex; Log.WarnException( string.Format("Error was occurred during metadata synchronization of file '{0}' from {1}", fileName, sourceServerInfo), ex); } } finally { FinishSynchronization(canonicalFilename, report, sourceServerInfo, sourceFileETag); } PublishSynchronizationNotification(fileSystemName, fileName, sourceServerInfo, report.Type, SynchronizationAction.Finish); if (isConflictResolved) { Publisher.Publish(new ConflictNotification { FileName = fileName, Status = ConflictStatus.Resolved }); } if (report.Exception == null) { Log.Debug("Metadata of file '{0}' was synchronized successfully from {1}", fileName, sourceServerInfo); } return(this.GetMessageWithObject(report, HttpStatusCode.OK)); }
public async Task <HttpResponseMessage> Put(string id) { if (IsSystemDatabase(id)) { return(GetMessageWithString("System database document cannot be changed!", HttpStatusCode.Forbidden)); } MessageWithStatusCode nameFormatErrorMessage; if (IsValidName(id, Database.Configuration.Core.DataDirectory, out nameFormatErrorMessage) == false) { return(GetMessageWithString(nameFormatErrorMessage.Message, nameFormatErrorMessage.ErrorCode)); } Etag etag = GetEtag(); string error = CheckExistingDatabaseName(id, etag); if (error != null) { return(GetMessageWithString(error, HttpStatusCode.BadRequest)); } var dbDoc = await ReadJsonObjectAsync <DatabaseDocument>().ConfigureAwait(false); string bundles; if (dbDoc.Settings.TryGetValue(RavenConfiguration.GetKey(x => x.Core._ActiveBundlesString), out bundles) && bundles.Contains("Encryption")) { if (dbDoc.SecuredSettings == null || !dbDoc.SecuredSettings.ContainsKey(RavenConfiguration.GetKey(x => x.Encryption.EncryptionKey)) || !dbDoc.SecuredSettings.ContainsKey(RavenConfiguration.GetKey(x => x.Encryption.AlgorithmType))) { return(GetMessageWithString(string.Format("Failed to create '{0}' database, because of invalid encryption configuration.", id), HttpStatusCode.BadRequest)); } } //TODO: check if paths in document are legal if (dbDoc.IsClusterDatabase() && ClusterManager.IsActive()) { string dataDir; if (dbDoc.Settings.TryGetValue("Raven/DataDir", out dataDir) == false || string.IsNullOrEmpty(dataDir)) { return(GetMessageWithString(string.Format("Failed to create '{0}' database, because 'Raven/DataDir' setting is missing.", id), HttpStatusCode.BadRequest)); } dataDir = dataDir.ToFullPath(SystemConfiguration.Core.DataDirectory); if (Directory.Exists(dataDir)) { return(GetMessageWithString(string.Format("Failed to create '{0}' database, because data directory '{1}' exists and it is forbidden to create non-empty cluster-wide databases.", id, dataDir), HttpStatusCode.BadRequest)); } await ClusterManager.Client.SendDatabaseUpdateAsync(id, dbDoc).ConfigureAwait(false); return(GetEmptyMessage()); } DatabasesLandlord.Protect(dbDoc); var json = RavenJObject.FromObject(dbDoc); json.Remove("Id"); var metadata = (etag != null) ? ReadInnerHeaders.FilterHeadersToObject() : new RavenJObject(); var docKey = Constants.Database.Prefix + id; var putResult = Database.Documents.Put(docKey, etag, json, metadata, null); return((etag == null) ? GetEmptyMessage() : GetMessageWithObject(putResult)); }