public virtual void StartedPart(IDictionary <string, string> headers) { if (document == null) { jsonBuffer = new ByteArrayBuffer(1024); } else { curAttachment = database.GetAttachmentWriter(); string contentDisposition = headers.Get("Content-Disposition"); if (contentDisposition != null && contentDisposition.StartsWith("attachment; filename=" )) { // TODO: Parse this less simplistically. Right now it assumes it's in exactly the same // format generated by -[CBL_Pusher uploadMultipartRevision:]. CouchDB (as of 1.2) doesn't // output any headers at all on attachments so there's no compatibility issue yet. string contentDispositionUnquoted = Misc.UnquoteString(contentDisposition); string name = Sharpen.Runtime.Substring(contentDispositionUnquoted, 21); if (name != null) { attachmentsByName.Put(name, curAttachment); } } } }
public void StartedPart(IDictionary <String, String> headers) { if (document == null) { StartJsonBuffer(headers); } else { Log.To.Sync.V(TAG, "{0} starting attachment #{1}...", this, attachmentsByDigest.Count + 1); curAttachment = database.AttachmentWriter; if (curAttachment == null) { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.AttachmentError, TAG, "Cannot create blob store writer for the attachment"); } var name = default(string); var contentDisposition = headers.Get("Content-Disposition"); if (contentDisposition != null && contentDisposition.StartsWith("attachment; filename=")) { // TODO: Parse this less simplistically. Right now it assumes it's in exactly the same // format generated by -[CBL_Pusher uploadMultipartRevision:]. CouchDB (as of 1.2) doesn't // output any headers at all on attachments so there's no compatibility issue yet. var contentDispositionUnquoted = Misc.UnquoteString(contentDisposition); name = contentDispositionUnquoted.Substring(21); if (name != null) { attachmentsByName[name] = curAttachment; } } var contentEncoding = headers.Get("Content-Encoding"); if (contentEncoding == "gzip") { if (name != null) { try { var attachEncoding = document.GetCast <IDictionary <string, object> >("_attachments"). GetCast <IDictionary <string, object> >(name).GetCast <string>("encoding"); if (attachEncoding != "gzip") { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.UnsupportedType, TAG, "Attachment '{0}' MIME body is gzipped but attachment isn't", new SecureLogString(name, LogMessageSensitivity.PotentiallyInsecure)); } } catch (NullReferenceException) { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.UnsupportedType, TAG, "NullReferenceException caught; _attachments was not present or encoding was " + "not present in _attachments"); } } } else if (contentEncoding != null) { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.UnsupportedType, TAG, "Received unsupported Content-Encoding '{0}'", contentEncoding); } } }
public void StartedPart(IDictionary <String, String> headers) { if (document == null) { StartJsonBuffer(headers); } else { Log.V(TAG, " Starting attachment #{0}...", attachmentsBySHA1Digest.Count + 1); curAttachment = database.AttachmentWriter; if (curAttachment == null) { const string msg = "Cannot create blob store writer for the attachment"; Log.W(TAG, msg); throw new CouchbaseLiteException(msg, StatusCode.AttachmentError); } var name = default(string); var contentDisposition = headers.Get("Content-Disposition"); if (contentDisposition != null && contentDisposition.StartsWith("attachment; filename=")) { // TODO: Parse this less simplistically. Right now it assumes it's in exactly the same // format generated by -[CBL_Pusher uploadMultipartRevision:]. CouchDB (as of 1.2) doesn't // output any headers at all on attachments so there's no compatibility issue yet. var contentDispositionUnquoted = Misc.UnquoteString(contentDisposition); name = contentDispositionUnquoted.Substring(21); if (name != null) { attachmentsByName.Put(name, curAttachment); } } var contentEncoding = headers.Get("Content-Encoding"); if (contentEncoding == "gzip") { if (name != null) { try { var attachEncoding = document.GetCast <IDictionary <string, object> >("_attachments"). GetCast <IDictionary <string, object> >(name).GetCast <string>("encoding"); if (attachEncoding != "gzip") { Log.W(TAG, "Attachment '{0}' MIME body is gzipped but attachment isn't", name); throw new CouchbaseLiteException(StatusCode.UnsupportedType); } } catch (NullReferenceException) { throw new CouchbaseLiteException(StatusCode.UnsupportedType); } } } else if (contentEncoding != null) { Log.W(TAG, "Received unsupported Content-Encoding '{0}'", contentEncoding); throw new CouchbaseLiteException(StatusCode.UnsupportedType); } } }
public void FinishedPart() { if (jsonBuffer != null) { ParseJsonBuffer(); } else { curAttachment.Finish(); String md5String = curAttachment.MD5DigestString(); attachmentsByMd5Digest.Put(md5String, curAttachment); curAttachment = null; } }
public void FinishedPart() { if (jsonBuffer != null) { ParseJsonBuffer(); } else { curAttachment.Finish(); String sha1String = curAttachment.SHA1DigestString(); attachmentsBySHA1Digest.Put(sha1String, curAttachment); curAttachment = null; } }
public void FinishedPart() { if (jsonBuffer != null) { ParseJsonBuffer(); } else { curAttachment.Finish(); var sha1String = curAttachment.SHA1DigestString(); Log.To.Sync.V(TAG, "{0} finished attachment #{1}: {2}", this, attachmentsByDigest.Count + 1, curAttachment); attachmentsByDigest[sha1String] = curAttachment; curAttachment = null; } }
// Update the given attachment using the provided info private static CouchbaseLiteResponse UpdateAttachment(ICouchbaseListenerContext context, Database db, string attachment, string docId, BlobStoreWriter body) { var castContext = context as ICouchbaseListenerContext2; var source = castContext != null && !castContext.IsLoopbackRequest ? castContext.Sender : null; RevisionInternal rev = db.UpdateAttachment(attachment, body, context.RequestHeaders["Content-Type"], AttachmentEncoding.None, docId, (context.GetQueryParam("rev") ?? context.IfMatch()).AsRevID(), source); var response = context.CreateResponse(); response.JsonBody = new Body(new Dictionary <string, object> { { "ok", true }, { "id", rev.DocID }, { "rev", rev.RevID } }); context.CacheWithEtag(rev.RevID.ToString()); if (body != null) { response["Location"] = context.RequestUrl.AbsoluteUri; } return(response); }
// Update the given attachment using the provided info private static CouchbaseLiteResponse UpdateAttachment(ICouchbaseListenerContext context, Database db, string attachment, string docId, BlobStoreWriter body) { RevisionInternal rev = db.UpdateAttachment(attachment, body, context.RequestHeaders["Content-Type"], AttachmentEncoding.None, docId, context.GetQueryParam("rev") ?? context.IfMatch()); var response = context.CreateResponse(); response.JsonBody = new Body(new Dictionary<string, object> { { "ok", true }, { "id", rev.GetDocId() }, { "rev", rev.GetRevId() } }); context.CacheWithEtag(rev.GetRevId()); if (body != null) { response["Location"] = context.RequestUrl.AbsoluteUri; } return response; }
private void RegisterAttachments() { int numAttachmentsInDoc = 0; IDictionary <string, object> attachments = (IDictionary <string, object>)document.Get ("_attachments"); if (attachments == null) { return; } foreach (string attachmentName in attachments.Keys) { IDictionary <string, object> attachment = (IDictionary <string, object>)attachments .Get(attachmentName); int length = 0; if (attachment.ContainsKey("length")) { length = ((int)attachment.Get("length")); } if (attachment.ContainsKey("encoded_length")) { length = ((int)attachment.Get("encoded_length")); } if (attachment.ContainsKey("follows") && ((bool)attachment.Get("follows")) == true) { // Check that each attachment in the JSON corresponds to an attachment MIME body. // Look up the attachment by either its MIME Content-Disposition header or MD5 digest: string digest = (string)attachment.Get("digest"); BlobStoreWriter writer = attachmentsByName.Get(attachmentName); if (writer != null) { // Identified the MIME body by the filename in its Disposition header: string actualDigest = writer.MD5DigestString(); if (digest != null && !digest.Equals(actualDigest) && !digest.Equals(writer.SHA1DigestString ())) { string errMsg = string.Format("Attachment '%s' has incorrect MD5 digest (%s; should be %s)" , attachmentName, digest, actualDigest); throw new InvalidOperationException(errMsg); } attachment.Put("digest", actualDigest); } else { if (digest != null) { writer = attachmentsByMd5Digest.Get(digest); if (writer == null) { string errMsg = string.Format("Attachment '%s' does not appear in MIME body (%s; should be %s)" , attachmentName); throw new InvalidOperationException(errMsg); } } else { if (attachments.Count == 1 && attachmentsByMd5Digest.Count == 1) { // Else there's only one attachment, so just assume it matches & use it: writer = attachmentsByMd5Digest.Values.GetEnumerator().Next(); attachment.Put("digest", writer.MD5DigestString()); } else { // No digest metatata, no filename in MIME body; give up: string errMsg = string.Format("Attachment '%s' has no digest metadata; cannot identify MIME body" , attachmentName); throw new InvalidOperationException(errMsg); } } } // Check that the length matches: if (writer.GetLength() != length) { string errMsg = string.Format("Attachment '%s' has incorrect length field %d (should be %d)" , attachmentName, length, writer.GetLength()); throw new InvalidOperationException(errMsg); } ++numAttachmentsInDoc; } else { if (attachment.ContainsKey("data") && length > 1000) { string msg = string.Format("Attachment '%s' sent inline (len=%d). Large attachments " + "should be sent in MIME parts for reduced memory overhead.", attachmentName); Log.W(Database.Tag, msg); } } } if (numAttachmentsInDoc < attachmentsByMd5Digest.Count) { string msg = string.Format("More MIME bodies (%d) than attachments (%d) ", attachmentsByMd5Digest .Count, numAttachmentsInDoc); throw new InvalidOperationException(msg); } // hand over the (uninstalled) blobs to the database to remember: database.RememberAttachmentWritersForDigests(attachmentsByMd5Digest); }
// Update the given attachment using the provided info private static CouchbaseLiteResponse UpdateAttachment(ICouchbaseListenerContext context, Database db, string attachment, string docId, BlobStoreWriter body) { RevisionInternal rev = db.UpdateAttachment(attachment, body, context.RequestHeaders["Content-Type"], AttachmentEncoding.None, docId, context.GetQueryParam("rev") ?? context.IfMatch()); var response = context.CreateResponse(); response.JsonBody = new Body(new Dictionary <string, object> { { "ok", true }, { "id", rev.GetDocId() }, { "rev", rev.GetRevId() } }); context.CacheWithEtag(rev.GetRevId()); if (body != null) { response["Location"] = context.RequestUrl.AbsoluteUri; } return(response); }
// Update the given attachment using the provided info private static CouchbaseLiteResponse UpdateAttachment(ICouchbaseListenerContext context, Database db, string attachment, string docId, BlobStoreWriter body) { var castContext = context as ICouchbaseListenerContext2; var source = castContext != null && !castContext.IsLoopbackRequest ? castContext.Sender : null; RevisionInternal rev = db.UpdateAttachment(attachment, body, context.RequestHeaders["Content-Type"], AttachmentEncoding.None, docId, (context.GetQueryParam("rev") ?? context.IfMatch()).AsRevID(), source); var response = context.CreateResponse(); response.JsonBody = new Body(new Dictionary<string, object> { { "ok", true }, { "id", rev.DocID }, { "rev", rev.RevID } }); context.CacheWithEtag(rev.RevID.ToString()); if (body != null) { response["Location"] = context.RequestUrl.AbsoluteUri; } return response; }