Revert "Merge branch '781-mime-stream-pair' of git://github.com/plausiblelabs/AFNetworking"
This reverts commitf7d98aac9c, reversing changes made to9b2a20c0a1. Conflicts: AFNetworking/AFHTTPClient.m
This commit is contained in:
parent
7ed9b807c9
commit
8434140929
1 changed files with 89 additions and 125 deletions
|
|
@ -801,8 +801,8 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
||||||
maxLength:(NSUInteger)length;
|
maxLength:(NSUInteger)length;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface AFMultipartBodyStreamProvider : NSObject
|
@interface AFMultipartBodyStream : NSInputStream <NSStreamDelegate>
|
||||||
@property (nonatomic, assign) NSUInteger bufferLength;
|
@property (nonatomic, assign) NSUInteger numberOfBytesInPacket;
|
||||||
@property (nonatomic, assign) NSTimeInterval delay;
|
@property (nonatomic, assign) NSTimeInterval delay;
|
||||||
@property (nonatomic, strong) NSInputStream *inputStream;
|
@property (nonatomic, strong) NSInputStream *inputStream;
|
||||||
@property (nonatomic, readonly) unsigned long long contentLength;
|
@property (nonatomic, readonly) unsigned long long contentLength;
|
||||||
|
|
@ -817,7 +817,7 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
||||||
|
|
||||||
@interface AFStreamingMultipartFormData ()
|
@interface AFStreamingMultipartFormData ()
|
||||||
@property (readwrite, nonatomic, copy) NSMutableURLRequest *request;
|
@property (readwrite, nonatomic, copy) NSMutableURLRequest *request;
|
||||||
@property (readwrite, nonatomic, strong) AFMultipartBodyStreamProvider *bodyStream;
|
@property (readwrite, nonatomic, strong) AFMultipartBodyStream *bodyStream;
|
||||||
@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding;
|
@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
@ -836,7 +836,7 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
||||||
|
|
||||||
self.request = urlRequest;
|
self.request = urlRequest;
|
||||||
self.stringEncoding = encoding;
|
self.stringEncoding = encoding;
|
||||||
self.bodyStream = [[AFMultipartBodyStreamProvider alloc] initWithStringEncoding:encoding];
|
self.bodyStream = [[AFMultipartBodyStream alloc] initWithStringEncoding:encoding];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
@ -968,7 +968,7 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
||||||
- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes
|
- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes
|
||||||
delay:(NSTimeInterval)delay
|
delay:(NSTimeInterval)delay
|
||||||
{
|
{
|
||||||
self.bodyStream.bufferLength = numberOfBytes;
|
self.bodyStream.numberOfBytesInPacket = numberOfBytes;
|
||||||
self.bodyStream.delay = delay;
|
self.bodyStream.delay = delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -982,7 +982,7 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
||||||
|
|
||||||
[self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", kAFMultipartFormBoundary] forHTTPHeaderField:@"Content-Type"];
|
[self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", kAFMultipartFormBoundary] forHTTPHeaderField:@"Content-Type"];
|
||||||
[self.request setValue:[NSString stringWithFormat:@"%llu", [self.bodyStream contentLength]] forHTTPHeaderField:@"Content-Length"];
|
[self.request setValue:[NSString stringWithFormat:@"%llu", [self.bodyStream contentLength]] forHTTPHeaderField:@"Content-Length"];
|
||||||
[self.request setHTTPBodyStream:self.bodyStream.inputStream];
|
[self.request setHTTPBodyStream:self.bodyStream];
|
||||||
|
|
||||||
return self.request;
|
return self.request;
|
||||||
}
|
}
|
||||||
|
|
@ -991,7 +991,9 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
@interface AFMultipartBodyStreamProvider () <NSCopying, NSStreamDelegate>
|
@interface AFMultipartBodyStream () <NSCopying>
|
||||||
|
@property (nonatomic, assign) NSStreamStatus streamStatus;
|
||||||
|
@property (nonatomic, strong) NSError *streamError;
|
||||||
@property (nonatomic, assign) NSStringEncoding stringEncoding;
|
@property (nonatomic, assign) NSStringEncoding stringEncoding;
|
||||||
@property (nonatomic, strong) NSMutableArray *HTTPBodyParts;
|
@property (nonatomic, strong) NSMutableArray *HTTPBodyParts;
|
||||||
@property (nonatomic, strong) NSEnumerator *HTTPBodyPartEnumerator;
|
@property (nonatomic, strong) NSEnumerator *HTTPBodyPartEnumerator;
|
||||||
|
|
@ -1000,13 +1002,9 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
||||||
@property (nonatomic, strong) NSMutableData *buffer;
|
@property (nonatomic, strong) NSMutableData *buffer;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
static const NSUInteger AFMultipartBodyStreamProviderDefaultBufferLength = 4096;
|
@implementation AFMultipartBodyStream
|
||||||
|
@synthesize streamStatus = _streamStatus;
|
||||||
@implementation AFMultipartBodyStreamProvider {
|
@synthesize streamError = _streamError;
|
||||||
@private
|
|
||||||
// Workaround for stream delegates being weakly referenced, but otherwise unowned
|
|
||||||
__strong id _self;
|
|
||||||
}
|
|
||||||
@synthesize stringEncoding = _stringEncoding;
|
@synthesize stringEncoding = _stringEncoding;
|
||||||
@synthesize HTTPBodyParts = _HTTPBodyParts;
|
@synthesize HTTPBodyParts = _HTTPBodyParts;
|
||||||
@synthesize HTTPBodyPartEnumerator = _HTTPBodyPartEnumerator;
|
@synthesize HTTPBodyPartEnumerator = _HTTPBodyPartEnumerator;
|
||||||
|
|
@ -1014,7 +1012,7 @@ static const NSUInteger AFMultipartBodyStreamProviderDefaultBufferLength = 4096;
|
||||||
@synthesize inputStream = _inputStream;
|
@synthesize inputStream = _inputStream;
|
||||||
@synthesize outputStream = _outputStream;
|
@synthesize outputStream = _outputStream;
|
||||||
@synthesize buffer = _buffer;
|
@synthesize buffer = _buffer;
|
||||||
@synthesize bufferLength = _numberOfBytesInPacket;
|
@synthesize numberOfBytesInPacket = _numberOfBytesInPacket;
|
||||||
@synthesize delay = _delay;
|
@synthesize delay = _delay;
|
||||||
|
|
||||||
- (id)initWithStringEncoding:(NSStringEncoding)encoding {
|
- (id)initWithStringEncoding:(NSStringEncoding)encoding {
|
||||||
|
|
@ -1025,18 +1023,11 @@ static const NSUInteger AFMultipartBodyStreamProviderDefaultBufferLength = 4096;
|
||||||
|
|
||||||
self.stringEncoding = encoding;
|
self.stringEncoding = encoding;
|
||||||
self.HTTPBodyParts = [NSMutableArray array];
|
self.HTTPBodyParts = [NSMutableArray array];
|
||||||
self.bufferLength = NSIntegerMax;
|
self.numberOfBytesInPacket = NSIntegerMax;
|
||||||
|
|
||||||
self.buffer = [[NSMutableData alloc] init];
|
|
||||||
self.bufferLength = AFMultipartBodyStreamProviderDefaultBufferLength;
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
|
||||||
_outputStream.delegate = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setInitialAndFinalBoundaries {
|
- (void)setInitialAndFinalBoundaries {
|
||||||
if ([self.HTTPBodyParts count] > 0) {
|
if ([self.HTTPBodyParts count] > 0) {
|
||||||
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
|
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
|
||||||
|
|
@ -1053,116 +1044,80 @@ static const NSUInteger AFMultipartBodyStreamProviderDefaultBufferLength = 4096;
|
||||||
[self.HTTPBodyParts addObject:bodyPart];
|
[self.HTTPBodyParts addObject:bodyPart];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSInputStream *)inputStream {
|
|
||||||
if (_inputStream == nil) {
|
|
||||||
CFReadStreamRef readStream;
|
|
||||||
CFWriteStreamRef writeStream;
|
|
||||||
CFStreamCreateBoundPair(NULL, &readStream, &writeStream, (NSInteger)self.bufferLength);
|
|
||||||
_inputStream = CFBridgingRelease(readStream);
|
|
||||||
_outputStream = CFBridgingRelease(writeStream);
|
|
||||||
|
|
||||||
_outputStream.delegate = self;
|
|
||||||
if ([NSThread isMainThread]) {
|
|
||||||
[_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
|
||||||
} else {
|
|
||||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
|
||||||
[_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
[_outputStream open];
|
|
||||||
|
|
||||||
_self = self;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _inputStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isEmpty {
|
- (BOOL)isEmpty {
|
||||||
return [self.HTTPBodyParts count] == 0;
|
return [self.HTTPBodyParts count] == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - NSStreamDelegate
|
#pragma mark - NSInputStream
|
||||||
|
|
||||||
|
- (NSInteger)read:(uint8_t *)buffer
|
||||||
// This retry works around a nasty problem in which mutli-part uploads will fail due to the stream delegate being sent a `NSStreamEventHasSpaceAvailable` event before the input stream has finished opening.
|
maxLength:(NSUInteger)length
|
||||||
// This workaround simply replays the event after allowing the run-loop to cycle, providing enough time for the input stream to finish opening. It appears that this bug is in the CFNetwork layer.
|
{
|
||||||
// See: https://github.com/AFNetworking/AFNetworking/issues/948
|
if ([self streamStatus] == NSStreamStatusClosed) {
|
||||||
- (void)retryWrite:(NSStream *)stream {
|
return 0;
|
||||||
[self stream:stream handleEvent:NSStreamEventHasSpaceAvailable];
|
|
||||||
}
|
}
|
||||||
|
NSInteger bytesRead = 0;
|
||||||
|
|
||||||
- (void)stream:(NSStream *)stream
|
while ((NSUInteger)bytesRead < MIN(length, self.numberOfBytesInPacket)) {
|
||||||
handleEvent:(NSStreamEvent)eventCode {
|
if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) {
|
||||||
if (eventCode & NSStreamEventHasSpaceAvailable) {
|
if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) {
|
||||||
if (self.inputStream.streamStatus < NSStreamStatusOpen) {
|
break;
|
||||||
[self performSelector:@selector(retryWrite:) withObject:stream afterDelay:0.1];
|
}
|
||||||
} else {
|
} else {
|
||||||
[self handleOutputStreamSpaceAvailable];
|
bytesRead += [self.currentHTTPBodyPart read:&buffer[bytesRead] maxLength:(length - (NSUInteger)bytesRead)];
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)handleOutputStreamSpaceAvailable {
|
|
||||||
while ([_outputStream hasSpaceAvailable]) {
|
|
||||||
if ([_buffer length] > 0) {
|
|
||||||
NSInteger numberOfBytesWritten = [_outputStream write:(uint8_t const *)[_buffer bytes] maxLength:[_buffer length]];
|
|
||||||
if (numberOfBytesWritten < 0) {
|
|
||||||
[self close];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[_buffer replaceBytesInRange:NSMakeRange(0, (NSUInteger)numberOfBytesWritten) withBytes:NULL length:0];
|
|
||||||
} else {
|
|
||||||
if (!self.currentHTTPBodyPart) {
|
|
||||||
if (!self.HTTPBodyPartEnumerator) {
|
|
||||||
self.HTTPBodyPartEnumerator = [self.HTTPBodyParts objectEnumerator];
|
|
||||||
}
|
|
||||||
self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!self.currentHTTPBodyPart) {
|
|
||||||
[self close];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[_buffer setLength:self.bufferLength];
|
|
||||||
|
|
||||||
NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:(uint8_t *)[_buffer mutableBytes] maxLength:[_buffer length]];
|
|
||||||
if (numberOfBytesRead < 0) {
|
|
||||||
[self close];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[_buffer setLength:(NSUInteger)numberOfBytesRead];
|
|
||||||
|
|
||||||
if (numberOfBytesRead == 0) {
|
|
||||||
self.currentHTTPBodyPart = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.delay > 0.0f) {
|
if (self.delay > 0.0f) {
|
||||||
[NSThread sleepForTimeInterval:self.delay];
|
[NSThread sleepForTimeInterval:self.delay];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)getBuffer:(__unused uint8_t **)buffer
|
||||||
|
length:(__unused NSUInteger *)len
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasBytesAvailable {
|
||||||
|
return [self streamStatus] == NSStreamStatusOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSStream
|
||||||
|
|
||||||
|
- (void)open {
|
||||||
|
if (self.streamStatus == NSStreamStatusOpen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.streamStatus = NSStreamStatusOpen;
|
||||||
|
|
||||||
|
[self setInitialAndFinalBoundaries];
|
||||||
|
self.HTTPBodyPartEnumerator = [self.HTTPBodyParts objectEnumerator];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)close {
|
- (void)close {
|
||||||
NSOutputStream *outputStream = self.outputStream;
|
self.streamStatus = NSStreamStatusClosed;
|
||||||
|
|
||||||
[outputStream close];
|
|
||||||
outputStream.delegate = nil;
|
|
||||||
|
|
||||||
// Workaround for a race condition in CFStream _CFStreamCopyRunLoopsAndModes. This outputstream needs to be retained just a little longer.
|
|
||||||
// See: https://github.com/AFNetworking/AFNetworking/issues/907
|
|
||||||
NSTimeInterval delay = 2.0;
|
|
||||||
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC));
|
|
||||||
dispatch_after(popTime, dispatch_get_main_queue(), ^{
|
|
||||||
outputStream.delegate = nil;
|
|
||||||
});
|
|
||||||
|
|
||||||
_self = nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id)propertyForKey:(__unused NSString *)key {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)setProperty:(__unused id)property
|
||||||
|
forKey:(__unused NSString *)key
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)scheduleInRunLoop:(__unused NSRunLoop *)aRunLoop
|
||||||
|
forMode:(__unused NSString *)mode
|
||||||
|
{}
|
||||||
|
|
||||||
|
- (void)removeFromRunLoop:(__unused NSRunLoop *)aRunLoop
|
||||||
|
forMode:(__unused NSString *)mode
|
||||||
|
{}
|
||||||
|
|
||||||
- (unsigned long long)contentLength {
|
- (unsigned long long)contentLength {
|
||||||
unsigned long long length = 0;
|
unsigned long long length = 0;
|
||||||
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
|
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
|
||||||
|
|
@ -1172,10 +1127,26 @@ static const NSUInteger AFMultipartBodyStreamProviderDefaultBufferLength = 4096;
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Undocumented CFReadStream Bridged Methods
|
||||||
|
|
||||||
|
- (void)_scheduleInCFRunLoop:(__unused CFRunLoopRef)aRunLoop
|
||||||
|
forMode:(__unused CFStringRef)aMode
|
||||||
|
{}
|
||||||
|
|
||||||
|
- (void)_unscheduleFromCFRunLoop:(__unused CFRunLoopRef)aRunLoop
|
||||||
|
forMode:(__unused CFStringRef)aMode
|
||||||
|
{}
|
||||||
|
|
||||||
|
- (BOOL)_setCFClientFlags:(__unused CFOptionFlags)inFlags
|
||||||
|
callback:(__unused CFReadStreamClientCallBack)inCallback
|
||||||
|
context:(__unused CFStreamClientContext *)inContext {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - NSCopying
|
#pragma mark - NSCopying
|
||||||
|
|
||||||
-(id)copyWithZone:(NSZone *)zone {
|
-(id)copyWithZone:(NSZone *)zone {
|
||||||
AFMultipartBodyStreamProvider *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding];
|
AFMultipartBodyStream *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding];
|
||||||
|
|
||||||
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
|
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
|
||||||
[bodyStreamCopy appendHTTPBodyPart:[bodyPart copy]];
|
[bodyStreamCopy appendHTTPBodyPart:[bodyPart copy]];
|
||||||
|
|
@ -1191,12 +1162,10 @@ static const NSUInteger AFMultipartBodyStreamProviderDefaultBufferLength = 4096;
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AFInitialPhase = 0,
|
|
||||||
AFEncapsulationBoundaryPhase = 1,
|
AFEncapsulationBoundaryPhase = 1,
|
||||||
AFHeaderPhase = 2,
|
AFHeaderPhase = 2,
|
||||||
AFBodyPhase = 3,
|
AFBodyPhase = 3,
|
||||||
AFFinalBoundaryPhase = 4,
|
AFFinalBoundaryPhase = 4,
|
||||||
AFCompletedPhase = 5,
|
|
||||||
} AFHTTPBodyPartReadPhase;
|
} AFHTTPBodyPartReadPhase;
|
||||||
|
|
||||||
@interface AFHTTPBodyPart () <NSCopying> {
|
@interface AFHTTPBodyPart () <NSCopying> {
|
||||||
|
|
@ -1301,7 +1270,6 @@ typedef enum {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSInteger)read:(uint8_t *)buffer
|
- (NSInteger)read:(uint8_t *)buffer
|
||||||
|
|
@ -1365,9 +1333,6 @@ typedef enum {
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wcovered-switch-default"
|
#pragma clang diagnostic ignored "-Wcovered-switch-default"
|
||||||
switch (_phase) {
|
switch (_phase) {
|
||||||
case AFInitialPhase:
|
|
||||||
_phase = AFEncapsulationBoundaryPhase;
|
|
||||||
break;
|
|
||||||
case AFEncapsulationBoundaryPhase:
|
case AFEncapsulationBoundaryPhase:
|
||||||
_phase = AFHeaderPhase;
|
_phase = AFHeaderPhase;
|
||||||
break;
|
break;
|
||||||
|
|
@ -1381,9 +1346,8 @@ typedef enum {
|
||||||
_phase = AFFinalBoundaryPhase;
|
_phase = AFFinalBoundaryPhase;
|
||||||
break;
|
break;
|
||||||
case AFFinalBoundaryPhase:
|
case AFFinalBoundaryPhase:
|
||||||
case AFCompletedPhase:
|
|
||||||
default:
|
default:
|
||||||
_phase = AFCompletedPhase;
|
_phase = AFEncapsulationBoundaryPhase;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_phaseReadOffset = 0;
|
_phaseReadOffset = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue