Skip to content
This repository has been archived by the owner on Mar 9, 2022. It is now read-only.

Commit

Permalink
Make direct PUT to attachment URL work with streamed request body
Browse files Browse the repository at this point in the history
This case was accidentally not fixed back in commit 7f24896.
Fixes #198.
  • Loading branch information
snej committed Dec 12, 2012
1 parent 8f6ba32 commit d752da8
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 18 deletions.
36 changes: 29 additions & 7 deletions Source/TDRouter+Handlers.m
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,10 @@ - (TDStatus) do_DELETE: (TD_Database*)db docID: (NSString*)docID {
}


- (TDStatus) updateAttachment: (NSString*)attachment docID: (NSString*)docID body: (NSData*)body {
- (TDStatus) updateAttachment: (NSString*)attachment
docID: (NSString*)docID
body: (TDBlobStoreWriter*)body
{
TDStatus status;
TD_Revision* rev = [_db updateAttachment: attachment
body: body
Expand All @@ -874,16 +877,35 @@ - (TDStatus) updateAttachment: (NSString*)attachment docID: (NSString*)docID bod


- (TDStatus) do_PUT: (TD_Database*)db docID: (NSString*)docID attachment: (NSString*)attachment {
return [self updateAttachment: attachment
docID: docID
body: (_request.HTTPBody ?: [NSData data])];
TDBlobStoreWriter* blob = db.attachmentWriter;
NSInputStream* bodyStream = _request.HTTPBodyStream;
if (bodyStream) {
// OPT: Should read this asynchronously
NSMutableData* buffer = [NSMutableData dataWithLength: 32768];
NSInteger bytesRead;
do {
bytesRead = [bodyStream read: buffer.mutableBytes maxLength: buffer.length];
if (bytesRead > 0) {
[blob appendData: [NSData dataWithBytesNoCopy: buffer.mutableBytes
length: bytesRead freeWhenDone: NO]];
}
} while (bytesRead > 0);
if (bytesRead < 0)
return kTDStatusBadAttachment;

} else {
NSData* body = _request.HTTPBody;
if (body)
[blob appendData: body];
}
[blob finish];

return [self updateAttachment: attachment docID: docID body: blob];
}


- (TDStatus) do_DELETE: (TD_Database*)db docID: (NSString*)docID attachment: (NSString*)attachment {
return [self updateAttachment: attachment
docID: docID
body: nil];
return [self updateAttachment: attachment docID: docID body: nil];
}


Expand Down
2 changes: 1 addition & 1 deletion Source/TD_Database+Attachments.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ typedef enum {
/** Updates or deletes an attachment, creating a new document revision in the process.
Used by the PUT / DELETE methods called on attachment URLs. */
- (TD_Revision*) updateAttachment: (NSString*)filename
body: (NSData*)body
body: (TDBlobStoreWriter*)body
type: (NSString*)contentType
encoding: (TDAttachmentEncoding)encoding
ofDocID: (NSString*)docID
Expand Down
17 changes: 10 additions & 7 deletions Source/TD_Database+Attachments.m
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ - (void) rememberPendingKey: (TDBlobKey)key forDigest: (NSString*)digest {
}


- (void) rememberAttachmentWriter: (TDBlobStoreWriter*)writer forDigest:(NSString*)digest {
if (!_pendingAttachmentsByDigest)
_pendingAttachmentsByDigest = [[NSMutableDictionary alloc] init];
_pendingAttachmentsByDigest[digest] = writer;
}


// This is ONLY FOR TESTS (see TDMultipartDownloader.m)
#if DEBUG
- (id) attachmentWriterForAttachment: (NSDictionary*)attachment {
Expand Down Expand Up @@ -561,7 +568,7 @@ - (TDMultipartWriter*) multipartWriterForRevision: (TD_Revision*)rev


- (TD_Revision*) updateAttachment: (NSString*)filename
body: (NSData*)body
body: (TDBlobStoreWriter*)body
type: (NSString*)contentType
encoding: (TDAttachmentEncoding)encoding
ofDocID: (NSString*)docID
Expand Down Expand Up @@ -593,14 +600,10 @@ - (TD_Revision*) updateAttachment: (NSString*)filename
if (!attachments)
attachments = $mdict();
if (body) {
TDBlobKey key;
if (![self storeBlob: body creatingKey: &key]) {
*outStatus = kTDStatusAttachmentError;
return nil;
}
TDBlobKey key = body.blobKey;
NSString* digest = [@"sha1-" stringByAppendingString: [TDBase64 encode: &key
length: sizeof(key)]];
[self rememberPendingKey: key forDigest: digest];
[self rememberAttachmentWriter: body forDigest: digest];
NSString* encodingName = (encoding == kTDAttachmentEncodingGZIP) ? @"gzip" : nil;
attachments[filename] = $dict({@"digest", digest},
{@"length", @(body.length)},
Expand Down
21 changes: 18 additions & 3 deletions Source/TD_Database_Tests.m
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,14 @@ static void insertAttachment(TD_Database* db, NSData* blob,
}


static TDBlobStoreWriter* blobForData(TD_Database* db, NSData* data) {
TDBlobStoreWriter* blob = db.attachmentWriter;
[blob appendData: data];
[blob finish];
return blob;
}


TestCase(TD_Database_PutAttachment) {
RequireTestCase(TD_Database_Attachments);
// Start with a fresh database in /tmp:
Expand Down Expand Up @@ -607,17 +615,20 @@ static void insertAttachment(TD_Database* db, NSData* blob,

// Update the attachment directly:
NSData* attachv2 = [@"Replaced body of attach" dataUsingEncoding: NSUTF8StringEncoding];
[db updateAttachment: @"attach" body: attachv2 type: @"application/foo"
[db updateAttachment: @"attach" body: blobForData(db, attachv2)
type: @"application/foo"
encoding: kTDAttachmentEncodingNone
ofDocID: rev1.docID revID: nil
status: &status];
CAssertEq(status, kTDStatusConflict);
[db updateAttachment: @"attach" body: attachv2 type: @"application/foo"
[db updateAttachment: @"attach" body: blobForData(db, attachv2)
type: @"application/foo"
encoding: kTDAttachmentEncodingNone
ofDocID: rev1.docID revID: @"1-bogus"
status: &status];
CAssertEq(status, kTDStatusConflict);
TD_Revision* rev2 = [db updateAttachment: @"attach" body: attachv2 type: @"application/foo"
TD_Revision* rev2 = [db updateAttachment: @"attach" body: blobForData(db, attachv2)
type: @"application/foo"
encoding: kTDAttachmentEncodingNone
ofDocID: rev1.docID revID: rev1.revID
status: &status];
Expand All @@ -633,6 +644,10 @@ static void insertAttachment(TD_Database* db, NSData* blob,
{@"length", @(23)},
{@"stub", $true},
{@"revpos", @2})}));

NSData* gotAttach = [db getAttachmentForSequence: gotRev2.sequence named: @"attach"
type: NULL encoding: NULL status: &status];
CAssertEqual(gotAttach, attachv2);

// Delete the attachment:
[db updateAttachment: @"nosuchattach" body: nil type: nil
Expand Down

0 comments on commit d752da8

Please sign in to comment.