[Issue #546][Issue #513] Adding AFMultipartFormData -throttleBandwidthWithPacketSize:delay:

This commit is contained in:
Mattt Thompson 2012-09-30 17:38:07 -07:00
parent 70b7e0522c
commit 1c1b204513
2 changed files with 36 additions and 2 deletions

View file

@ -501,6 +501,9 @@ extern NSString * const AFNetworkingReachabilityNotificationStatusItem;
#pragma mark - #pragma mark -
extern NSUInteger const kAFUploadStream3GSuggestedPacketSize;
extern NSUInteger const kAFUploadStream3GSuggestedDelay;
/** /**
The `AFMultipartFormData` protocol defines the methods supported by the parameter in the block argument of `AFHTTPClient -multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:`. The `AFMultipartFormData` protocol defines the methods supported by the parameter in the block argument of `AFHTTPClient -multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:`.
*/ */
@ -544,4 +547,15 @@ extern NSString * const AFNetworkingReachabilityNotificationStatusItem;
- (void)appendPartWithFormData:(NSData *)data - (void)appendPartWithFormData:(NSData *)data
name:(NSString *)name; name:(NSString *)name;
/**
Throttles request bandwidth by limiting the packet size and adding a delay for each chunk read from the upload stream.
@param numberOfBytes Maximum packet size, in number of bytes. The default packet size for an input stream is 32kb.
@param delay Duration of delay each time a packet is read. By default, no delay is set.
@discussion When uploading over a 3G or EDGE connection, requests may fail with "request body stream exhausted". Setting a maximum packet size and delay according to the recommended values (`kAFUploadStream3GSuggestedPacketSize` and `kAFUploadStream3GSuggestedDelay`) lowers the risk of the input stream exceeding its allocated bandwidth. Unfortunately, as of iOS 6, there is no definite way to distinguish between a 3G, EDGE, or LTE connection. As such, it is not recommended that you throttle bandwidth based solely on network reachability. Instead, you should consider checking for the "request body stream exhausted" in a failure block, and then retrying the request with throttled bandwidth.
*/
- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes
delay:(NSTimeInterval)delay;
@end @end

View file

@ -708,6 +708,9 @@ static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
#endif #endif
} }
NSUInteger const kAFUploadStream3GSuggestedPacketSize = 1024 * 16;
NSUInteger const kAFUploadStream3GSuggestedDelay = 0.2;
@interface AFHTTPBodyPart : NSObject @interface AFHTTPBodyPart : NSObject
@property (nonatomic, assign) NSStringEncoding stringEncoding; @property (nonatomic, assign) NSStringEncoding stringEncoding;
@ -727,6 +730,8 @@ static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
@interface AFMultipartBodyStream : NSInputStream <NSStreamDelegate> @interface AFMultipartBodyStream : NSInputStream <NSStreamDelegate>
@property (nonatomic, assign) NSUInteger numberOfBytesInPacket;
@property (nonatomic, assign) NSTimeInterval delay;
@property (readonly) unsigned long long contentLength; @property (readonly) unsigned long long contentLength;
@property (readonly, getter = isEmpty) BOOL empty; @property (readonly, getter = isEmpty) BOOL empty;
@ -834,6 +839,13 @@ static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
[self.bodyStream appendHTTPBodyPart:bodyPart]; [self.bodyStream appendHTTPBodyPart:bodyPart];
} }
- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes
delay:(NSTimeInterval)delay
{
self.bodyStream.numberOfBytesInPacket = numberOfBytes;
self.bodyStream.delay = delay;
}
- (NSMutableURLRequest *)requestByFinalizingMultipartFormData { - (NSMutableURLRequest *)requestByFinalizingMultipartFormData {
if ([self.bodyStream isEmpty]) { if ([self.bodyStream isEmpty]) {
return self.request; return self.request;
@ -861,6 +873,8 @@ static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
@property (nonatomic, retain) NSMutableArray *HTTPBodyParts; @property (nonatomic, retain) NSMutableArray *HTTPBodyParts;
@property (nonatomic, retain) NSEnumerator *HTTPBodyPartEnumerator; @property (nonatomic, retain) NSEnumerator *HTTPBodyPartEnumerator;
@property (nonatomic, retain) AFHTTPBodyPart *currentHTTPBodyPart; @property (nonatomic, retain) AFHTTPBodyPart *currentHTTPBodyPart;
@property (nonatomic, retain) NSDate *lastReadAt;
@property (nonatomic, assign) NSInteger lastBytesRead;
@end @end
@implementation AFMultipartBodyStream @implementation AFMultipartBodyStream
@ -870,6 +884,8 @@ static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
@synthesize HTTPBodyParts = _HTTPBodyParts; @synthesize HTTPBodyParts = _HTTPBodyParts;
@synthesize HTTPBodyPartEnumerator = _HTTPBodyPartEnumerator; @synthesize HTTPBodyPartEnumerator = _HTTPBodyPartEnumerator;
@synthesize currentHTTPBodyPart = _currentHTTPBodyPart; @synthesize currentHTTPBodyPart = _currentHTTPBodyPart;
@synthesize numberOfBytesInPacket = _numberOfBytesInPacket;
@synthesize delay = _delay;
- (id)initWithStringEncoding:(NSStringEncoding)encoding { - (id)initWithStringEncoding:(NSStringEncoding)encoding {
self = [super init]; self = [super init];
@ -879,6 +895,7 @@ static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
self.stringEncoding = encoding; self.stringEncoding = encoding;
self.HTTPBodyParts = [NSMutableArray array]; self.HTTPBodyParts = [NSMutableArray array];
self.numberOfBytesInPacket = NSIntegerMax;
return self; return self;
} }
@ -912,13 +929,16 @@ static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
NSInteger bytesRead = 0; NSInteger bytesRead = 0;
while ((NSUInteger)bytesRead < length) { while ((NSUInteger)bytesRead < MIN(length, self.numberOfBytesInPacket)) {
if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) { if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) {
if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) { if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) {
break; break;
} }
} else { } else {
bytesRead += [self.currentHTTPBodyPart read:&buffer[bytesRead] maxLength:length - bytesRead]; bytesRead += [self.currentHTTPBodyPart read:&buffer[bytesRead] maxLength:length - bytesRead];
if (self.delay > 0.0f) {
[NSThread sleepForTimeInterval:self.delay];
}
} }
} }