[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 -
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:`.
*/
@ -544,4 +547,15 @@ extern NSString * const AFNetworkingReachabilityNotificationStatusItem;
- (void)appendPartWithFormData:(NSData *)data
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

View file

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