@@ -777,7 +777,7 @@ - (NSInteger)read:(uint8_t *)buffer
777
777
maxLength : (NSUInteger )length ;
778
778
@end
779
779
780
- @interface AFMultipartBodyStream : NSInputStream < NSStreamDelegate >
780
+ @interface AFMultipartBodyStreamProvider : NSObject
781
781
@property (nonatomic , assign ) NSUInteger numberOfBytesInPacket;
782
782
@property (nonatomic , assign ) NSTimeInterval delay;
783
783
@property (nonatomic , readonly ) unsigned long long contentLength;
@@ -786,13 +786,15 @@ @interface AFMultipartBodyStream : NSInputStream <NSStreamDelegate>
786
786
- (id )initWithStringEncoding : (NSStringEncoding )encoding ;
787
787
- (void )setInitialAndFinalBoundaries ;
788
788
- (void )appendHTTPBodyPart : (AFHTTPBodyPart *)bodyPart ;
789
+
790
+ - (NSInputStream *)inputStream ;
789
791
@end
790
792
791
793
#pragma mark -
792
794
793
795
@interface AFStreamingMultipartFormData ()
794
796
@property (readwrite , nonatomic , copy ) NSMutableURLRequest *request;
795
- @property (readwrite , nonatomic , strong ) AFMultipartBodyStream *bodyStream;
797
+ @property (readwrite , nonatomic , strong ) AFMultipartBodyStreamProvider *bodyStream;
796
798
@property (readwrite , nonatomic , assign ) NSStringEncoding stringEncoding;
797
799
@end
798
800
@@ -811,7 +813,7 @@ - (id)initWithURLRequest:(NSMutableURLRequest *)urlRequest
811
813
812
814
self.request = urlRequest;
813
815
self.stringEncoding = encoding;
814
- self.bodyStream = [[AFMultipartBodyStream alloc ] initWithStringEncoding: encoding];
816
+ self.bodyStream = [[AFMultipartBodyStreamProvider alloc ] initWithStringEncoding: encoding];
815
817
816
818
return self;
817
819
}
@@ -931,7 +933,7 @@ - (NSMutableURLRequest *)requestByFinalizingMultipartFormData {
931
933
932
934
[self .request setValue: [NSString stringWithFormat: @" multipart/form-data; boundary=%@ " , kAFMultipartFormBoundary ] forHTTPHeaderField: @" Content-Type" ];
933
935
[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 ];
935
937
936
938
return self.request ;
937
939
}
@@ -940,7 +942,7 @@ - (NSMutableURLRequest *)requestByFinalizingMultipartFormData {
940
942
941
943
#pragma mark -
942
944
943
- @interface AFMultipartBodyStream () <NSCopying >
945
+ @interface AFMultipartBodyStreamProvider () <NSCopying , NSStreamDelegate >
944
946
@property (nonatomic , assign ) NSStreamStatus streamStatus;
945
947
@property (nonatomic , strong ) NSError *streamError;
946
948
@@ -950,7 +952,15 @@ @interface AFMultipartBodyStream () <NSCopying>
950
952
@property (nonatomic , strong ) AFHTTPBodyPart *currentHTTPBodyPart;
951
953
@end
952
954
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
+ }
954
964
@synthesize streamStatus = _streamStatus;
955
965
@synthesize streamError = _streamError;
956
966
@synthesize stringEncoding = _stringEncoding;
@@ -969,10 +979,16 @@ - (id)initWithStringEncoding:(NSStringEncoding)encoding {
969
979
self.stringEncoding = encoding;
970
980
self.HTTPBodyParts = [NSMutableArray array ];
971
981
self.numberOfBytesInPacket = NSIntegerMax;
972
-
982
+
983
+ _buffer = [[NSMutableData alloc ] init ];
984
+
973
985
return self;
974
986
}
975
987
988
+ - (void )dealloc {
989
+ _outputStream.delegate = nil ;
990
+ }
991
+
976
992
- (void )setInitialAndFinalBoundaries {
977
993
if ([self .HTTPBodyParts count ] > 0 ) {
978
994
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts ) {
@@ -989,80 +1005,100 @@ - (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart {
989
1005
[self .HTTPBodyParts addObject: bodyPart];
990
1006
}
991
1007
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
+
992
1032
- (BOOL )isEmpty {
993
1033
return [self .HTTPBodyParts count ] == 0 ;
994
1034
}
995
1035
996
- #pragma mark - NSInputStream
1036
+ #pragma mark - NSStreamDelegate
997
1037
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 ];
1003
1041
}
1004
- NSInteger bytesRead = 0 ;
1042
+ }
1005
1043
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 ];
1010
1056
}
1011
1057
} 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 ;
1015
1089
}
1090
+
1091
+ /* Fall off the end. The next loop through will get data out of the buffer. */
1016
1092
}
1017
1093
}
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 ];
1042
1094
}
1043
1095
1044
1096
- (void )close {
1045
- self.streamStatus = NSStreamStatusClosed;
1097
+ [_outputStream close ];
1098
+ _outputStream.delegate = nil ;
1099
+ _keepalive = nil ;
1046
1100
}
1047
1101
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
-
1066
1102
- (unsigned long long )contentLength {
1067
1103
unsigned long long length = 0 ;
1068
1104
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts ) {
@@ -1072,26 +1108,10 @@ - (unsigned long long)contentLength {
1072
1108
return length;
1073
1109
}
1074
1110
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
-
1091
1111
#pragma mark - NSCopying
1092
1112
1093
1113
-(id )copyWithZone : (NSZone *)zone {
1094
- AFMultipartBodyStream *bodyStreamCopy = [[[self class ] allocWithZone: zone] initWithStringEncoding: self .stringEncoding];
1114
+ AFMultipartBodyStreamProvider *bodyStreamCopy = [[[self class ] allocWithZone: zone] initWithStringEncoding: self .stringEncoding];
1095
1115
1096
1116
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts ) {
1097
1117
[bodyStreamCopy appendHTTPBodyPart: [bodyPart copy ]];
@@ -1107,10 +1127,12 @@ -(id)copyWithZone:(NSZone *)zone {
1107
1127
#pragma mark -
1108
1128
1109
1129
typedef enum {
1130
+ AFInitialPhase = 0 ,
1110
1131
AFEncapsulationBoundaryPhase = 1 ,
1111
1132
AFHeaderPhase = 2 ,
1112
1133
AFBodyPhase = 3 ,
1113
1134
AFFinalBoundaryPhase = 4 ,
1135
+ AFCompletedPhase = 5 ,
1114
1136
} AFHTTPBodyPartReadPhase;
1115
1137
1116
1138
@interface AFHTTPBodyPart () <NSCopying > {
@@ -1139,6 +1161,7 @@ - (id)init {
1139
1161
return nil ;
1140
1162
}
1141
1163
1164
+ _phase = AFInitialPhase;
1142
1165
[self transitionToNextPhase ];
1143
1166
1144
1167
return self;
@@ -1273,6 +1296,9 @@ - (BOOL)transitionToNextPhase {
1273
1296
#pragma clang diagnostic push
1274
1297
#pragma clang diagnostic ignored "-Wcovered-switch-default"
1275
1298
switch (_phase) {
1299
+ case AFInitialPhase:
1300
+ _phase = AFEncapsulationBoundaryPhase;
1301
+ break ;
1276
1302
case AFEncapsulationBoundaryPhase:
1277
1303
_phase = AFHeaderPhase;
1278
1304
break ;
@@ -1286,8 +1312,9 @@ - (BOOL)transitionToNextPhase {
1286
1312
_phase = AFFinalBoundaryPhase;
1287
1313
break ;
1288
1314
case AFFinalBoundaryPhase:
1315
+ case AFCompletedPhase:
1289
1316
default :
1290
- _phase = AFEncapsulationBoundaryPhase ;
1317
+ _phase = AFCompletedPhase ;
1291
1318
break ;
1292
1319
}
1293
1320
_phaseReadOffset = 0 ;
0 commit comments