rejigger things to do callbacks and end-of-stream read properly

This commit is contained in:
Max Lansing 2012-07-19 22:23:38 -07:00
parent d434de241f
commit c7f6fb09bf
2 changed files with 383 additions and 387 deletions

View file

@ -503,7 +503,7 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
__block AFStreamingMultipartFormData * formData = [[[AFStreamingMultipartFormData alloc] initWithURLRequest:request stringEncoding:self.stringEncoding] autorelease]; __block AFStreamingMultipartFormData * formData = [[[AFStreamingMultipartFormData alloc] initWithURLRequest:request stringEncoding:self.stringEncoding] autorelease];
// __block AFMultipartFormData *formData = [[[AFMultipartFormData alloc] initWithURLRequest:request stringEncoding:self.stringEncoding] autorelease]; // __block AFMultipartFormData *formData = [[[AFMultipartFormData alloc] initWithURLRequest:request stringEncoding:self.stringEncoding] autorelease];
for (AFQueryStringComponent *component in AFQueryStringComponentsFromKeyAndValue(nil, parameters)) { for (AFQueryStringComponent *component in AFQueryStringComponentsFromKeyAndValue(nil, parameters)) {
NSData *data = nil; NSData *data = nil;
@ -813,7 +813,7 @@ static inline NSString * AFMultipartFormFinalBoundary() {
stringEncoding = NSUTF8StringEncoding; stringEncoding = NSUTF8StringEncoding;
streamStatus = NSStreamStatusNotOpen; streamStatus = NSStreamStatusNotOpen;
[self resetCursors]; [self resetCursors];
[self setDelegate:self]; // [self setDelegate:self];
return self; return self;
} }
@ -938,7 +938,7 @@ static inline NSString * AFMultipartFormFinalBoundary() {
} }
-(NSInteger)readData:(NSData *)data intoBuffer:(uint8_t *)buffer maxLength:(NSUInteger)len offsetCursor:(NSUInteger*)offsetCursorPtr { -(NSInteger)readData:(NSData *)data intoBuffer:(uint8_t *)buffer maxLength:(NSUInteger)len offsetCursor:(NSUInteger*)offsetCursorPtr {
NSUInteger bytesAvailable = [data length] - *offsetCursorPtr; NSInteger bytesAvailable = [data length] - *offsetCursorPtr;
if (len > bytesAvailable) { if (len > bytesAvailable) {
[data getBytes:buffer range:NSMakeRange(*offsetCursorPtr, bytesAvailable)]; [data getBytes:buffer range:NSMakeRange(*offsetCursorPtr, bytesAvailable)];
*offsetCursorPtr += bytesAvailable; *offsetCursorPtr += bytesAvailable;
@ -979,7 +979,7 @@ static inline NSString * AFMultipartFormFinalBoundary() {
} }
-(NSUInteger)totalElements { -(NSUInteger)totalElements {
return [formDatas count] + [fileURLs count]; return [formDatas count] + [fileURLs count] + 1; //one extra for final boundary
} }
-(NSData *)finalBoundaryData { -(NSData *)finalBoundaryData {
@ -1036,10 +1036,14 @@ static inline NSString * AFMultipartFormFinalBoundary() {
#pragma mark - NSInputStream subclass overrides #pragma mark - NSInputStream subclass overrides
-(NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len { -(NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len {
if ([self streamStatus] == NSStreamStatusClosed) {
return 0;
}
assert ([self streamStatus] == NSStreamStatusOpen); assert ([self streamStatus] == NSStreamStatusOpen);
NSUInteger bytesRead = 0; NSInteger bytesRead = 0;
NSUInteger readFileCursor = (readElementCursor - [formNames count]); NSInteger readFileCursor = (readElementCursor - [formNames count]);
if (readElementCursor < [formNames count]) { if (readElementCursor < [formNames count]) {
//reading from formDatas //reading from formDatas
@ -1056,7 +1060,7 @@ static inline NSString * AFMultipartFormFinalBoundary() {
[self nextElement]; [self nextElement];
} }
} }
else if (readElementCursor >= [formNames count] && readFileCursor < [fileNames count]) { else if (readFileCursor >= 0 && readFileCursor < [fileNames count]) {
//reading from files //reading from files
NSString * currentFileName = [fileNames objectAtIndex:readFileCursor]; NSString * currentFileName = [fileNames objectAtIndex:readFileCursor];
NSURL * currentFileURL = [fileURLs objectForKey:currentFileName]; NSURL * currentFileURL = [fileURLs objectForKey:currentFileName];
@ -1069,7 +1073,7 @@ static inline NSString * AFMultipartFormFinalBoundary() {
} else { } else {
if (!currentFileStream) { if (!currentFileStream) {
currentFileStream = [[NSInputStream inputStreamWithURL:currentFileURL] retain]; currentFileStream = [[NSInputStream inputStreamWithURL:currentFileURL] retain];
currentFileStream.delegate = self; // currentFileStream.delegate = self;
[currentFileStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; [currentFileStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[currentFileStream open]; [currentFileStream open];
} }
@ -1081,44 +1085,37 @@ static inline NSString * AFMultipartFormFinalBoundary() {
} }
} }
} }
else { else if (readElementCursor < [self totalElements]) {
//add final boundary //add final boundary
bytesRead = [self readData:[self finalBoundaryData] intoBuffer:buffer maxLength:len offsetCursor:&readOffsetCursor]; bytesRead = [self readData:[self finalBoundaryData] intoBuffer:buffer maxLength:len offsetCursor:&readOffsetCursor];
if (readOffsetCursor == [[self finalBoundaryData] length]) { if (readOffsetCursor == [[self finalBoundaryData] length]) {
[self nextElement]; [self nextElement];
} }
} }
else {
if (bytesRead < len && readElementCursor <= [self totalElements]) { [self nextElement];
//recurse to fill out the buffer, this is critical if the above read operations produce a zero length buffer for some reason (empty form data, end of file) because returning zero from this method will result in the stream being closed.
bytesRead += [self read:buffer+bytesRead maxLength:len-bytesRead];
} }
if (readElementCursor <= [self totalElements]) {
if (bytesRead < len) {
bytesRead += [self read:buffer+bytesRead maxLength:len-bytesRead];
} else {
// no deeper recursion so call callback if necessary
if (copiedCallback && (requestedEvents & kCFStreamEventHasBytesAvailable)) {
copiedCallback((CFReadStreamRef)self, kCFStreamEventHasBytesAvailable, &copiedContext);
}
}
}
//doesn't seem to make a diff if we do the callbacks or not for the HTTP request use anyway,
//and it sometimes crashes if the callback reciever or context have been released.
// if (CFReadStreamGetStatus((CFReadStreamRef)self) == kCFStreamStatusOpen) {
// double delayInSeconds = 0;
// dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
// dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// if (copiedCallback && (requestedEvents & kCFStreamEventHasBytesAvailable)) {
// NSLog(@"callback kCFStreamEventHasBytesAvailable... bytes read: %d", bytesRead);
// copiedCallback((CFReadStreamRef)self, kCFStreamEventHasBytesAvailable, &copiedContext);
// }
// });
// }
assert(bytesRead > 0); //really should never return zero from this call
return bytesRead; return bytesRead;
} }
-(BOOL)hasBytesAvailable { -(BOOL)hasBytesAvailable {
if ([self totalElements] == 0) { if ([self streamStatus] != NSStreamStatusOpen) {
return NO; return NO;
} else if (readElementCursor < ([self totalElements] + 1)) { }
else {
return YES; return YES;
} else {
return NO;
} }
} }
@ -1161,7 +1158,6 @@ static inline NSString * AFMultipartFormFinalBoundary() {
} }
@end @end