Skip to content

Commit f7d98aa

Browse files
committed
Merge branch '781-mime-stream-pair' of git://github.com/plausiblelabs/AFNetworking
2 parents 9b2a20c + bea04f4 commit f7d98aa

File tree

1 file changed

+109
-82
lines changed

1 file changed

+109
-82
lines changed

AFNetworking/AFHTTPClient.m

Lines changed: 109 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ - (NSInteger)read:(uint8_t *)buffer
777777
maxLength:(NSUInteger)length;
778778
@end
779779

780-
@interface AFMultipartBodyStream : NSInputStream <NSStreamDelegate>
780+
@interface AFMultipartBodyStreamProvider : NSObject
781781
@property (nonatomic, assign) NSUInteger numberOfBytesInPacket;
782782
@property (nonatomic, assign) NSTimeInterval delay;
783783
@property (nonatomic, readonly) unsigned long long contentLength;
@@ -786,13 +786,15 @@ @interface AFMultipartBodyStream : NSInputStream <NSStreamDelegate>
786786
- (id)initWithStringEncoding:(NSStringEncoding)encoding;
787787
- (void)setInitialAndFinalBoundaries;
788788
- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart;
789+
790+
- (NSInputStream *)inputStream;
789791
@end
790792

791793
#pragma mark -
792794

793795
@interface AFStreamingMultipartFormData ()
794796
@property (readwrite, nonatomic, copy) NSMutableURLRequest *request;
795-
@property (readwrite, nonatomic, strong) AFMultipartBodyStream *bodyStream;
797+
@property (readwrite, nonatomic, strong) AFMultipartBodyStreamProvider *bodyStream;
796798
@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding;
797799
@end
798800

@@ -811,7 +813,7 @@ - (id)initWithURLRequest:(NSMutableURLRequest *)urlRequest
811813

812814
self.request = urlRequest;
813815
self.stringEncoding = encoding;
814-
self.bodyStream = [[AFMultipartBodyStream alloc] initWithStringEncoding:encoding];
816+
self.bodyStream = [[AFMultipartBodyStreamProvider alloc] initWithStringEncoding:encoding];
815817

816818
return self;
817819
}
@@ -931,7 +933,7 @@ - (NSMutableURLRequest *)requestByFinalizingMultipartFormData {
931933

932934
[self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", kAFMultipartFormBoundary] forHTTPHeaderField:@"Content-Type"];
933935
[self.request setValue:[NSString stringWithFormat:@"%llu", [self.bodyStream contentLength]] forHTTPHeaderField:@"Content-Length"];
934-
[self.request setHTTPBodyStream:self.bodyStream];
936+
[self.request setHTTPBodyStream:self.bodyStream.inputStream];
935937

936938
return self.request;
937939
}
@@ -940,7 +942,7 @@ - (NSMutableURLRequest *)requestByFinalizingMultipartFormData {
940942

941943
#pragma mark -
942944

943-
@interface AFMultipartBodyStream () <NSCopying>
945+
@interface AFMultipartBodyStreamProvider () <NSCopying, NSStreamDelegate>
944946
@property (nonatomic, assign) NSStreamStatus streamStatus;
945947
@property (nonatomic, strong) NSError *streamError;
946948

@@ -950,7 +952,15 @@ @interface AFMultipartBodyStream () <NSCopying>
950952
@property (nonatomic, strong) AFHTTPBodyPart *currentHTTPBodyPart;
951953
@end
952954

953-
@implementation AFMultipartBodyStream
955+
static const NSUInteger AFMultipartBodyStreamProviderBufferSize = 4096;
956+
957+
@implementation AFMultipartBodyStreamProvider {
958+
NSInputStream *_inputStream;
959+
NSOutputStream *_outputStream;
960+
NSMutableData *_buffer;
961+
962+
id _keepalive;
963+
}
954964
@synthesize streamStatus = _streamStatus;
955965
@synthesize streamError = _streamError;
956966
@synthesize stringEncoding = _stringEncoding;
@@ -969,10 +979,16 @@ - (id)initWithStringEncoding:(NSStringEncoding)encoding {
969979
self.stringEncoding = encoding;
970980
self.HTTPBodyParts = [NSMutableArray array];
971981
self.numberOfBytesInPacket = NSIntegerMax;
972-
982+
983+
_buffer = [[NSMutableData alloc] init];
984+
973985
return self;
974986
}
975987

988+
- (void)dealloc {
989+
_outputStream.delegate = nil;
990+
}
991+
976992
- (void)setInitialAndFinalBoundaries {
977993
if ([self.HTTPBodyParts count] > 0) {
978994
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
@@ -989,80 +1005,100 @@ - (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart {
9891005
[self.HTTPBodyParts addObject:bodyPart];
9901006
}
9911007

1008+
- (NSInputStream *)inputStream {
1009+
if(_inputStream == nil) {
1010+
CFReadStreamRef readStream;
1011+
CFWriteStreamRef writeStream;
1012+
CFStreamCreateBoundPair(NULL, &readStream, &writeStream, AFMultipartBodyStreamProviderBufferSize);
1013+
_inputStream = CFBridgingRelease(readStream);
1014+
_outputStream = CFBridgingRelease(writeStream);
1015+
1016+
_outputStream.delegate = self;
1017+
if([NSThread isMainThread]) {
1018+
[_outputStream scheduleInRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];
1019+
}
1020+
else {
1021+
dispatch_sync(dispatch_get_main_queue(), ^{
1022+
[_outputStream scheduleInRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];
1023+
});
1024+
}
1025+
[_outputStream open];
1026+
_keepalive = self;
1027+
}
1028+
1029+
return _inputStream;
1030+
}
1031+
9921032
- (BOOL)isEmpty {
9931033
return [self.HTTPBodyParts count] == 0;
9941034
}
9951035

996-
#pragma mark - NSInputStream
1036+
#pragma mark - NSStreamDelegate
9971037

998-
- (NSInteger)read:(uint8_t *)buffer
999-
maxLength:(NSUInteger)length
1000-
{
1001-
if ([self streamStatus] == NSStreamStatusClosed) {
1002-
return 0;
1038+
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
1039+
if(eventCode & NSStreamEventHasSpaceAvailable) {
1040+
[self handleOutputStreamSpaceAvailable];
10031041
}
1004-
NSInteger bytesRead = 0;
1042+
}
10051043

1006-
while ((NSUInteger)bytesRead < MIN(length, self.numberOfBytesInPacket)) {
1007-
if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) {
1008-
if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) {
1009-
break;
1044+
- (void)handleOutputStreamSpaceAvailable {
1045+
while([_outputStream hasSpaceAvailable]) {
1046+
if([_buffer length] > 0) {
1047+
NSInteger ret = [_outputStream write: [_buffer bytes] maxLength: [_buffer length]];
1048+
if(ret < 0) {
1049+
/* I don't think an error should ever actually happen with a bound pair.
1050+
* If it does, we'll just close the stream and give up. */
1051+
[self close];
1052+
return;
1053+
} else {
1054+
/* Delete the written bytes from the buffer. */
1055+
[_buffer replaceBytesInRange: NSMakeRange(0, ret) withBytes: NULL length: 0];
10101056
}
10111057
} else {
1012-
bytesRead += [self.currentHTTPBodyPart read:&buffer[bytesRead] maxLength:(length - (NSUInteger)bytesRead)];
1013-
if (self.delay > 0.0f) {
1014-
[NSThread sleepForTimeInterval:self.delay];
1058+
/* Refill the buffer. */
1059+
1060+
/* Make sure the current body part is valid. */
1061+
if(self.currentHTTPBodyPart == nil) {
1062+
if(self.HTTPBodyPartEnumerator == nil) {
1063+
self.HTTPBodyPartEnumerator = [self.HTTPBodyParts objectEnumerator];
1064+
}
1065+
self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject];
1066+
}
1067+
1068+
/* If the current part is still nil, then it's the end of the road: close the stream and bail. */
1069+
if(self.currentHTTPBodyPart == nil) {
1070+
[self close];
1071+
return;
1072+
}
1073+
1074+
/* Read some data. */
1075+
[_buffer setLength: AFMultipartBodyStreamProviderBufferSize];
1076+
NSInteger ret = [self.currentHTTPBodyPart read: [_buffer mutableBytes] maxLength: [_buffer length]];
1077+
if(ret < 0) {
1078+
/* Not sure how to handle an error currently. Close the output stream and bail out. */
1079+
[self close];
1080+
return;
1081+
}
1082+
1083+
/* Resize the buffer to how much was actually read. */
1084+
[_buffer setLength: ret];
1085+
1086+
/* If we hit EOF, invalidate the current body part so the next pass through will find a new one. */
1087+
if(ret == 0) {
1088+
self.currentHTTPBodyPart = nil;
10151089
}
1090+
1091+
/* Fall off the end. The next loop through will get data out of the buffer. */
10161092
}
10171093
}
1018-
return bytesRead;
1019-
}
1020-
1021-
- (BOOL)getBuffer:(__unused uint8_t **)buffer
1022-
length:(__unused NSUInteger *)len
1023-
{
1024-
return NO;
1025-
}
1026-
1027-
- (BOOL)hasBytesAvailable {
1028-
return [self streamStatus] == NSStreamStatusOpen;
1029-
}
1030-
1031-
#pragma mark - NSStream
1032-
1033-
- (void)open {
1034-
if (self.streamStatus == NSStreamStatusOpen) {
1035-
return;
1036-
}
1037-
1038-
self.streamStatus = NSStreamStatusOpen;
1039-
1040-
[self setInitialAndFinalBoundaries];
1041-
self.HTTPBodyPartEnumerator = [self.HTTPBodyParts objectEnumerator];
10421094
}
10431095

10441096
- (void)close {
1045-
self.streamStatus = NSStreamStatusClosed;
1097+
[_outputStream close];
1098+
_outputStream.delegate = nil;
1099+
_keepalive = nil;
10461100
}
10471101

1048-
- (id)propertyForKey:(__unused NSString *)key {
1049-
return nil;
1050-
}
1051-
1052-
- (BOOL)setProperty:(__unused id)property
1053-
forKey:(__unused NSString *)key
1054-
{
1055-
return NO;
1056-
}
1057-
1058-
- (void)scheduleInRunLoop:(__unused NSRunLoop *)aRunLoop
1059-
forMode:(__unused NSString *)mode
1060-
{}
1061-
1062-
- (void)removeFromRunLoop:(__unused NSRunLoop *)aRunLoop
1063-
forMode:(__unused NSString *)mode
1064-
{}
1065-
10661102
- (unsigned long long)contentLength {
10671103
unsigned long long length = 0;
10681104
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
@@ -1072,26 +1108,10 @@ - (unsigned long long)contentLength {
10721108
return length;
10731109
}
10741110

1075-
#pragma mark - Undocumented CFReadStream Bridged Methods
1076-
1077-
- (void)_scheduleInCFRunLoop:(__unused CFRunLoopRef)aRunLoop
1078-
forMode:(__unused CFStringRef)aMode
1079-
{}
1080-
1081-
- (void)_unscheduleFromCFRunLoop:(__unused CFRunLoopRef)aRunLoop
1082-
forMode:(__unused CFStringRef)aMode
1083-
{}
1084-
1085-
- (BOOL)_setCFClientFlags:(__unused CFOptionFlags)inFlags
1086-
callback:(__unused CFReadStreamClientCallBack)inCallback
1087-
context:(__unused CFStreamClientContext *)inContext {
1088-
return NO;
1089-
}
1090-
10911111
#pragma mark - NSCopying
10921112

10931113
-(id)copyWithZone:(NSZone *)zone {
1094-
AFMultipartBodyStream *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding];
1114+
AFMultipartBodyStreamProvider *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding];
10951115

10961116
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
10971117
[bodyStreamCopy appendHTTPBodyPart:[bodyPart copy]];
@@ -1107,10 +1127,12 @@ -(id)copyWithZone:(NSZone *)zone {
11071127
#pragma mark -
11081128

11091129
typedef enum {
1130+
AFInitialPhase = 0,
11101131
AFEncapsulationBoundaryPhase = 1,
11111132
AFHeaderPhase = 2,
11121133
AFBodyPhase = 3,
11131134
AFFinalBoundaryPhase = 4,
1135+
AFCompletedPhase = 5,
11141136
} AFHTTPBodyPartReadPhase;
11151137

11161138
@interface AFHTTPBodyPart () <NSCopying> {
@@ -1139,6 +1161,7 @@ - (id)init {
11391161
return nil;
11401162
}
11411163

1164+
_phase = AFInitialPhase;
11421165
[self transitionToNextPhase];
11431166

11441167
return self;
@@ -1273,6 +1296,9 @@ - (BOOL)transitionToNextPhase {
12731296
#pragma clang diagnostic push
12741297
#pragma clang diagnostic ignored "-Wcovered-switch-default"
12751298
switch (_phase) {
1299+
case AFInitialPhase:
1300+
_phase = AFEncapsulationBoundaryPhase;
1301+
break;
12761302
case AFEncapsulationBoundaryPhase:
12771303
_phase = AFHeaderPhase;
12781304
break;
@@ -1286,8 +1312,9 @@ - (BOOL)transitionToNextPhase {
12861312
_phase = AFFinalBoundaryPhase;
12871313
break;
12881314
case AFFinalBoundaryPhase:
1315+
case AFCompletedPhase:
12891316
default:
1290-
_phase = AFEncapsulationBoundaryPhase;
1317+
_phase = AFCompletedPhase;
12911318
break;
12921319
}
12931320
_phaseReadOffset = 0;

0 commit comments

Comments
 (0)