@@ -1123,96 +1123,100 @@ func (bh *blipHandler) processRev(rq *blip.Message, stats *processRevStats) (err
1123
1123
// Pull out attachments
1124
1124
if injectedAttachmentsForDelta || bytes .Contains (bodyBytes , []byte (BodyAttachments )) {
1125
1125
body := newDoc .Body (bh .loggingCtx )
1126
-
1127
- var currentBucketDoc * Document
1128
-
1129
- // Look at attachments with revpos > the last common ancestor's
1130
- minRevpos := 1
1131
- if len (history ) > 0 {
1132
- currentDoc , rawDoc , err := bh .collection .GetDocumentWithRaw (bh .loggingCtx , docID , DocUnmarshalSync )
1133
- // If we're able to obtain current doc data then we should use the common ancestor generation++ for min revpos
1134
- // as we will already have any attachments on the common ancestor so don't need to ask for them.
1135
- // Otherwise we'll have to go as far back as we can in the doc history and choose the last entry in there.
1136
- if err == nil {
1137
- commonAncestor := currentDoc .History .findAncestorFromSet (currentDoc .CurrentRev , history )
1138
- minRevpos , _ = ParseRevID (bh .loggingCtx , commonAncestor )
1139
- minRevpos ++
1140
- rawBucketDoc = rawDoc
1141
- currentBucketDoc = currentDoc
1142
- } else {
1143
- minRevpos , _ = ParseRevID (bh .loggingCtx , history [len (history )- 1 ])
1126
+ // The bytes.Contains([]byte(BodyAttachments)) check will pass even if _attachments is not a toplevel key but rather a nested key or subkey. That check is an optimization to avoid having to unmarshal the document if there are no attachments. Therefore, check again that the unmarshalled body contains BodyAttachments.
1127
+ if body [BodyAttachments ] != nil {
1128
+
1129
+ var currentBucketDoc * Document
1130
+
1131
+ // Look at attachments with revpos > the last common ancestor's
1132
+ minRevpos := 1
1133
+ if len (history ) > 0 {
1134
+ currentDoc , rawDoc , err := bh .collection .GetDocumentWithRaw (bh .loggingCtx , docID , DocUnmarshalSync )
1135
+ // If we're able to obtain current doc data then we should use the common ancestor generation++ for min revpos
1136
+ // as we will already have any attachments on the common ancestor so don't need to ask for them.
1137
+ // Otherwise we'll have to go as far back as we can in the doc history and choose the last entry in there.
1138
+ if err == nil {
1139
+ commonAncestor := currentDoc .History .findAncestorFromSet (currentDoc .CurrentRev , history )
1140
+ minRevpos , _ = ParseRevID (bh .loggingCtx , commonAncestor )
1141
+ minRevpos ++
1142
+ rawBucketDoc = rawDoc
1143
+ currentBucketDoc = currentDoc
1144
+ } else {
1145
+ minRevpos , _ = ParseRevID (bh .loggingCtx , history [len (history )- 1 ])
1146
+ }
1144
1147
}
1145
- }
1146
1148
1147
- // currentDigests is a map from attachment name to the current bucket doc digest,
1148
- // for any attachments on the incoming document that are also on the current bucket doc
1149
- var currentDigests map [string ]string
1150
-
1151
- // Do we have a previous doc? If not don't need to do this check
1152
- if currentBucketDoc != nil {
1153
- bodyAtts := GetBodyAttachments (body )
1154
- currentDigests = make (map [string ]string , len (bodyAtts ))
1155
- for name , value := range bodyAtts {
1156
- // Check if we have this attachment name already, if we do, continue check
1157
- currentAttachment , ok := currentBucketDoc .Attachments [name ]
1158
- if ! ok {
1159
- // If we don't have this attachment already, ensure incoming revpos is greater than minRevPos, otherwise
1160
- // update to ensure it's fetched and uploaded
1161
- bodyAtts [name ].(map [string ]interface {})["revpos" ], _ = ParseRevID (bh .loggingCtx , revID )
1162
- continue
1163
- }
1149
+ // currentDigests is a map from attachment name to the current bucket doc digest,
1150
+ // for any attachments on the incoming document that are also on the current bucket doc
1151
+ var currentDigests map [string ]string
1152
+
1153
+ // Do we have a previous doc? If not don't need to do this check
1154
+ if currentBucketDoc != nil {
1155
+ bodyAtts := GetBodyAttachments (body )
1156
+ currentDigests = make (map [string ]string , len (bodyAtts ))
1157
+ for name , value := range bodyAtts {
1158
+ // Check if we have this attachment name already, if we do, continue check
1159
+ currentAttachment , ok := currentBucketDoc .Attachments [name ]
1160
+ if ! ok {
1161
+ // If we don't have this attachment already, ensure incoming revpos is greater than minRevPos, otherwise
1162
+ // update to ensure it's fetched and uploaded
1163
+ bodyAtts [name ].(map [string ]interface {})["revpos" ], _ = ParseRevID (bh .loggingCtx , revID )
1164
+ continue
1165
+ }
1164
1166
1165
- currentAttachmentMeta , ok := currentAttachment .(map [string ]interface {})
1166
- if ! ok {
1167
- return base .HTTPErrorf (http .StatusInternalServerError , "Current attachment data is invalid" )
1168
- }
1167
+ currentAttachmentMeta , ok := currentAttachment .(map [string ]interface {})
1168
+ if ! ok {
1169
+ return base .HTTPErrorf (http .StatusInternalServerError , "Current attachment data is invalid" )
1170
+ }
1169
1171
1170
- currentAttachmentDigest , ok := currentAttachmentMeta ["digest" ].(string )
1171
- if ! ok {
1172
- return base .HTTPErrorf (http .StatusInternalServerError , "Current attachment data is invalid" )
1173
- }
1174
- currentDigests [name ] = currentAttachmentDigest
1172
+ currentAttachmentDigest , ok := currentAttachmentMeta ["digest" ].(string )
1173
+ if ! ok {
1174
+ return base .HTTPErrorf (http .StatusInternalServerError , "Current attachment data is invalid" )
1175
+ }
1176
+ currentDigests [name ] = currentAttachmentDigest
1175
1177
1176
- incomingAttachmentMeta , ok := value .(map [string ]interface {})
1177
- if ! ok {
1178
- return base .HTTPErrorf (http .StatusBadRequest , "Invalid attachment" )
1179
- }
1178
+ incomingAttachmentMeta , ok := value .(map [string ]interface {})
1179
+ if ! ok {
1180
+ return base .HTTPErrorf (http .StatusBadRequest , "Invalid attachment" )
1181
+ }
1180
1182
1181
- // If this attachment has data then we're fine, this isn't a stub attachment and therefore doesn't
1182
- // need the check.
1183
- if incomingAttachmentMeta ["data" ] != nil {
1184
- continue
1185
- }
1183
+ // If this attachment has data then we're fine, this isn't a stub attachment and therefore doesn't
1184
+ // need the check.
1185
+ if incomingAttachmentMeta ["data" ] != nil {
1186
+ continue
1187
+ }
1186
1188
1187
- incomingAttachmentDigest , ok := incomingAttachmentMeta ["digest" ].(string )
1188
- if ! ok {
1189
- return base .HTTPErrorf (http .StatusBadRequest , "Invalid attachment" )
1190
- }
1189
+ incomingAttachmentDigest , ok := incomingAttachmentMeta ["digest" ].(string )
1190
+ if ! ok {
1191
+ return base .HTTPErrorf (http .StatusBadRequest , "Invalid attachment" )
1192
+ }
1191
1193
1192
- incomingAttachmentRevpos , ok := base .ToInt64 (incomingAttachmentMeta ["revpos" ])
1193
- if ! ok {
1194
- return base .HTTPErrorf (http .StatusBadRequest , "Invalid attachment" )
1195
- }
1194
+ incomingAttachmentRevpos , ok := base .ToInt64 (incomingAttachmentMeta ["revpos" ])
1195
+ if ! ok {
1196
+ return base .HTTPErrorf (http .StatusBadRequest , "Invalid attachment" )
1197
+ }
1196
1198
1197
- // Compare the revpos and attachment digest. If incoming revpos is less than or equal to minRevPos and
1198
- // digest is different we need to override the revpos and set it to the current revision to ensure
1199
- // the attachment is requested and stored
1200
- if int (incomingAttachmentRevpos ) <= minRevpos && currentAttachmentDigest != incomingAttachmentDigest {
1201
- bodyAtts [name ].(map [string ]interface {})["revpos" ], _ = ParseRevID (bh .loggingCtx , revID )
1199
+ // Compare the revpos and attachment digest. If incoming revpos is less than or equal to minRevPos and
1200
+ // digest is different we need to override the revpos and set it to the current revision to ensure
1201
+ // the attachment is requested and stored
1202
+ if int (incomingAttachmentRevpos ) <= minRevpos && currentAttachmentDigest != incomingAttachmentDigest {
1203
+ bodyAtts [name ].(map [string ]interface {})["revpos" ], _ = ParseRevID (bh .loggingCtx , revID )
1204
+ }
1202
1205
}
1206
+
1207
+ body [BodyAttachments ] = bodyAtts
1203
1208
}
1204
1209
1205
- body [BodyAttachments ] = bodyAtts
1206
- }
1210
+ if err := bh .downloadOrVerifyAttachments (rq .Sender , body , minRevpos , docID , currentDigests ); err != nil {
1211
+ base .ErrorfCtx (bh .loggingCtx , "Error during downloadOrVerifyAttachments for doc %s/%s: %v" , base .UD (docID ), revID , err )
1212
+ return err
1213
+ }
1207
1214
1208
- if err := bh . downloadOrVerifyAttachments ( rq . Sender , body , minRevpos , docID , currentDigests ); err != nil {
1209
- base . ErrorfCtx ( bh . loggingCtx , "Error during downloadOrVerifyAttachments for doc %s/%s: %v" , base . UD ( docID ), revID , err )
1210
- return err
1215
+ newDoc . DocAttachments = GetBodyAttachments ( body )
1216
+ delete ( body , BodyAttachments )
1217
+ newDoc . UpdateBody ( body )
1211
1218
}
1212
1219
1213
- newDoc .DocAttachments = GetBodyAttachments (body )
1214
- delete (body , BodyAttachments )
1215
- newDoc .UpdateBody (body )
1216
1220
}
1217
1221
1218
1222
if rawBucketDoc == nil && bh .collectionCtx .checkPendingInsertion (docID ) {
0 commit comments