internal static IDictionary <string, object> InstallAttachmentBodies(IDictionary <string , object> attachments, Database database) { IDictionary <string, object> updatedAttachments = new Dictionary <string, object>(); foreach (string name in attachments.Keys) { object value = attachments.Get(name); if (value is Couchbase.Lite.Attachment) { Couchbase.Lite.Attachment attachment = (Couchbase.Lite.Attachment)value; IDictionary <string, object> metadataMutable = new Dictionary <string, object>(); metadataMutable.PutAll(attachment.GetMetadata()); InputStream body = attachment.GetBodyIfNew(); if (body != null) { // Copy attachment body into the database's blob store: BlobStoreWriter writer = BlobStoreWriterForBody(body, database); metadataMutable.Put("length", (long)writer.GetLength()); metadataMutable.Put("digest", writer.MD5DigestString()); metadataMutable.Put("follows", true); database.RememberAttachmentWriter(writer); } updatedAttachments.Put(name, metadataMutable); } else { if (value is AttachmentInternal) { throw new ArgumentException("AttachmentInternal objects not expected here. Could indicate a bug" ); } else { if (value != null) { updatedAttachments.Put(name, value); } } } } return(updatedAttachments); }
/// <summary>Updates or deletes an attachment, creating a new document revision in the process. /// </summary> /// <remarks> /// Updates or deletes an attachment, creating a new document revision in the process. /// Used by the PUT / DELETE methods called on attachment URLs. /// </remarks> /// <exclude></exclude> /// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> internal RevisionInternal UpdateAttachment(string filename, BlobStoreWriter body, string contentType, AttachmentEncoding encoding, string docID, string oldRevID) { if(StringEx.IsNullOrWhiteSpace(filename) || (body != null && contentType == null) || (oldRevID != null && docID == null) || (body != null && docID == null)) { throw new CouchbaseLiteException(StatusCode.BadAttachment); } var oldRev = new RevisionInternal(docID, oldRevID, false); if (oldRevID != null) { // Load existing revision if this is a replacement: try { oldRev = LoadRevisionBody(oldRev); } catch (CouchbaseLiteException e) { if (e.Code == StatusCode.NotFound && GetDocument(docID, null, false) != null) { throw new CouchbaseLiteException(StatusCode.Conflict); } throw; } } else { // If this creates a new doc, it needs a body: oldRev.SetBody(new Body(new Dictionary<string, object>())); } // Update the _attachments dictionary: var attachments = oldRev.GetProperties().Get("_attachments").AsDictionary<string, object>(); if (attachments == null) { attachments = new Dictionary<string, object>(); } if (body != null) { var key = body.GetBlobKey(); string digest = key.Base64Digest(); RememberAttachmentWriter(body); string encodingName = (encoding == AttachmentEncoding.GZIP) ? "gzip" : null; attachments[filename] = new NonNullDictionary<string, object> { { "digest", digest }, { "length", body.GetLength() }, { "follows", true }, { "content_type", contentType }, { "encoding", encodingName } }; } else { if (oldRevID != null && attachments.Get(filename) == null) { throw new CouchbaseLiteException(StatusCode.AttachmentNotFound); } attachments.Remove(filename); } var properties = oldRev.GetProperties(); properties["_attachments"] = attachments; oldRev.SetProperties(properties); Status status = new Status(); var newRev = PutRevision(oldRev, oldRevID, false, status); if (status.IsError) { throw new CouchbaseLiteException(status.Code); } return newRev; }
/// <summary>Updates or deletes an attachment, creating a new document revision in the process. /// </summary> /// <remarks> /// Updates or deletes an attachment, creating a new document revision in the process. /// Used by the PUT / DELETE methods called on attachment URLs. /// </remarks> /// <exclude></exclude> /// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> internal RevisionInternal UpdateAttachment(string filename, BlobStoreWriter body, string contentType, AttachmentEncoding encoding, string docID, string oldRevID) { var isSuccessful = false; if (String.IsNullOrEmpty (filename) || (body != null && contentType == null) || (oldRevID != null && docID == null) || (body != null && docID == null)) { throw new CouchbaseLiteException(StatusCode.BadRequest); } BeginTransaction(); try { var oldRev = new RevisionInternal(docID, oldRevID, false, this); if (oldRevID != null) { // Load existing revision if this is a replacement: try { LoadRevisionBody(oldRev, DocumentContentOptions.None); } catch (CouchbaseLiteException e) { if (e.GetCBLStatus().GetCode() == StatusCode.NotFound && ExistsDocumentWithIDAndRev(docID, null)) { throw new CouchbaseLiteException(StatusCode.Conflict); } } } else { // If this creates a new doc, it needs a body: oldRev.SetBody(new Body(new Dictionary<string, object>())); } // Update the _attachments dictionary: var oldRevProps = oldRev.GetProperties(); IDictionary<string, object> attachments = null; if (oldRevProps != null) { attachments = (IDictionary<string, object>)oldRevProps.Get("_attachments"); } if (attachments == null) { attachments = new Dictionary<string, object>(); } if (body != null) { var key = body.GetBlobKey(); var digest = key.Base64Digest(); var blobsByDigest = new Dictionary<string, BlobStoreWriter>(); blobsByDigest.Put(digest, body); RememberAttachmentWritersForDigests(blobsByDigest); var encodingName = (encoding == AttachmentEncoding.AttachmentEncodingGZIP) ? "gzip" : null; var dict = new Dictionary<string, object>(); dict.Put("digest", digest); dict.Put("length", body.GetLength()); dict.Put("follows", true); dict.Put("content_type", contentType); dict.Put("encoding", encodingName); attachments.Put(filename, dict); } else { if (oldRevID != null && !attachments.ContainsKey(filename)) { throw new CouchbaseLiteException(StatusCode.NotFound); } attachments.Remove(filename); } var properties = oldRev.GetProperties(); properties.Put("_attachments", attachments); oldRev.SetProperties(properties); // Create a new revision: var putStatus = new Status(); var newRev = PutRevision(oldRev, oldRevID, false, putStatus); isSuccessful = true; return newRev; } catch (SQLException e) { Log.E(Tag, "Error updating attachment", e); throw new CouchbaseLiteException(StatusCode.InternalServerError); } finally { EndTransaction(isSuccessful); } }
/// <summary>Updates or deletes an attachment, creating a new document revision in the process. /// </summary> /// <remarks> /// Updates or deletes an attachment, creating a new document revision in the process. /// Used by the PUT / DELETE methods called on attachment URLs. Used by the listener; /// </remarks> internal RevisionInternal UpdateAttachment(string filename, BlobStoreWriter body, string contentType, AttachmentEncoding encoding, string docID, RevisionID oldRevID, Uri source) { if(StringEx.IsNullOrWhiteSpace(filename)) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.BadAttachment, TAG, "Invalid filename (null or whitespace) in UpdateAttachment"); } if(body != null && contentType == null) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.BadAttachment, TAG, "Body provided, but content type is null in UpdateAttachment"); } if(oldRevID != null && docID == null) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.BadAttachment, TAG, "oldRevID provided ({0}) but docID is null in UpdateAttachment", oldRevID); } if(body != null && docID == null) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.BadAttachment, TAG, "body provided but docID is null in UpdateAttachment"); } var oldRev = new RevisionInternal(docID, oldRevID, false); if(oldRevID != null) { // Load existing revision if this is a replacement: try { oldRev = LoadRevisionBody(oldRev); } catch(CouchbaseLiteException e) { if(e.Code == StatusCode.NotFound && GetDocument(docID, null, false) != null) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.Conflict, TAG, "Conflict detected in UpdateAttachment"); } Log.To.Database.E(TAG, "Error loading revision body in UpdateAttachment, rethrowing..."); throw; } } else { // If this creates a new doc, it needs a body: oldRev.SetBody(new Body(new Dictionary<string, object>())); } // Update the _attachments dictionary: var attachments = oldRev.GetProperties().Get("_attachments").AsDictionary<string, object>(); if(attachments == null) { attachments = new Dictionary<string, object>(); } if(body != null) { var key = body.GetBlobKey(); string digest = key.Base64Digest(); RememberAttachmentWriter(body, digest); string encodingName = (encoding == AttachmentEncoding.GZIP) ? "gzip" : null; attachments[filename] = new NonNullDictionary<string, object> { { "digest", digest }, { "length", body.GetLength() }, { "follows", true }, { "content_type", contentType }, { "encoding", encodingName } }; } else { if(oldRevID != null && attachments.Get(filename) == null) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.AttachmentNotFound, TAG, "Attachment {0} not found", new SecureLogString(filename, LogMessageSensitivity.PotentiallyInsecure)); } attachments.Remove(filename); } var properties = oldRev.GetProperties(); properties["_attachments"] = attachments; oldRev.SetProperties(properties); var newRev = PutRevision(oldRev, oldRevID, false, source); return newRev; }