diff --git a/SQDebug/AFNetworking/AFNetworking-4.0.1-Debug/AFNetworking-Debug.xcodeproj/project.pbxproj b/SQDebug/AFNetworking/AFNetworking-4.0.1-Debug/AFNetworking-Debug.xcodeproj/project.pbxproj index 5a718f4f..97a929b8 100644 --- a/SQDebug/AFNetworking/AFNetworking-4.0.1-Debug/AFNetworking-Debug.xcodeproj/project.pbxproj +++ b/SQDebug/AFNetworking/AFNetworking-4.0.1-Debug/AFNetworking-Debug.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 143474D1256BFA8300149168 /* SQURLRequestSerializationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 143474D0256BFA8300149168 /* SQURLRequestSerializationTest.m */; }; + 14560566256E957F00746C4A /* SQMultipartBodyStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 14560565256E957F00746C4A /* SQMultipartBodyStream.m */; }; 14963573256BEC5200B1E31B /* SQHTTPBodyPart.m in Sources */ = {isa = PBXBuildFile; fileRef = 14963572256BEC5200B1E31B /* SQHTTPBodyPart.m */; }; 149635AB256BFA3600B1E31B /* AFNetworking_DebugTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 149635AA256BFA3600B1E31B /* AFNetworking_DebugTests.m */; }; 14A334872568D62400772436 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 14A334862568D62400772436 /* AppDelegate.m */; }; @@ -35,6 +36,8 @@ /* Begin PBXFileReference section */ 002F3802D60E85956ACBBB58 /* Pods-AFNetworking-Debug.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AFNetworking-Debug.release.xcconfig"; path = "Target Support Files/Pods-AFNetworking-Debug/Pods-AFNetworking-Debug.release.xcconfig"; sourceTree = ""; }; 143474D0256BFA8300149168 /* SQURLRequestSerializationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQURLRequestSerializationTest.m; sourceTree = ""; }; + 14560564256E957F00746C4A /* SQMultipartBodyStream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQMultipartBodyStream.h; sourceTree = ""; }; + 14560565256E957F00746C4A /* SQMultipartBodyStream.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SQMultipartBodyStream.m; sourceTree = ""; }; 14963571256BEC5200B1E31B /* SQHTTPBodyPart.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQHTTPBodyPart.h; sourceTree = ""; }; 14963572256BEC5200B1E31B /* SQHTTPBodyPart.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SQHTTPBodyPart.m; sourceTree = ""; }; 149635A8256BFA3600B1E31B /* AFNetworking-DebugTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "AFNetworking-DebugTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -122,6 +125,8 @@ 14ED0255256A480700D370FD /* SQQueryStringPair.m */, 14963571256BEC5200B1E31B /* SQHTTPBodyPart.h */, 14963572256BEC5200B1E31B /* SQHTTPBodyPart.m */, + 14560564256E957F00746C4A /* SQMultipartBodyStream.h */, + 14560565256E957F00746C4A /* SQMultipartBodyStream.m */, 14ED0265256A4AD700D370FD /* SQURLRequestSerialization.h */, 14ED0266256A4AD700D370FD /* SQURLRequestSerialization.m */, 14A3348E2568D62400772436 /* Main.storyboard */, @@ -304,6 +309,7 @@ files = ( 14A3348D2568D62400772436 /* ViewController.m in Sources */, 14963573256BEC5200B1E31B /* SQHTTPBodyPart.m in Sources */, + 14560566256E957F00746C4A /* SQMultipartBodyStream.m in Sources */, 14A334872568D62400772436 /* AppDelegate.m in Sources */, 14ED0267256A4AD700D370FD /* SQURLRequestSerialization.m in Sources */, 14A334982568D62500772436 /* main.m in Sources */, diff --git a/SQDebug/AFNetworking/AFNetworking-4.0.1-Debug/AFNetworking-Debug/SQMultipartBodyStream.h b/SQDebug/AFNetworking/AFNetworking-4.0.1-Debug/AFNetworking-Debug/SQMultipartBodyStream.h new file mode 100644 index 00000000..5d22719b --- /dev/null +++ b/SQDebug/AFNetworking/AFNetworking-4.0.1-Debug/AFNetworking-Debug/SQMultipartBodyStream.h @@ -0,0 +1,28 @@ +// +// SQMultipartBodyStream.h +// AFNetworking-Debug +// +// Created by 朱双泉 on 2020/11/25. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class SQHTTPBodyPart; + +@interface SQMultipartBodyStream : NSInputStream + +@property (nonatomic, assign) NSUInteger numberOfBytesInPacket; +@property (nonatomic, assign) NSTimeInterval delay; +@property (nonatomic, strong) NSInputStream *inputStream; +@property (readonly, nonatomic, assign) unsigned long long contentLength; +@property (readonly, nonatomic, assign, getter=isEmpty) BOOL empty; + +- (instancetype)initWithStringEncoding:(NSStringEncoding)encoding; +- (void)setInitialAndFinalBoundaries; +- (void)appendHTTPBodyPart:(SQHTTPBodyPart *)bodyPart; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SQDebug/AFNetworking/AFNetworking-4.0.1-Debug/AFNetworking-Debug/SQMultipartBodyStream.m b/SQDebug/AFNetworking/AFNetworking-4.0.1-Debug/AFNetworking-Debug/SQMultipartBodyStream.m new file mode 100644 index 00000000..36cbcb72 --- /dev/null +++ b/SQDebug/AFNetworking/AFNetworking-4.0.1-Debug/AFNetworking-Debug/SQMultipartBodyStream.m @@ -0,0 +1,164 @@ +// +// SQMultipartBodyStream.m +// AFNetworking-Debug +// +// Created by 朱双泉 on 2020/11/25. +// + +#import "SQMultipartBodyStream.h" +#import "SQHTTPBodyPart.h" + +@interface NSStream () +@property (readwrite) NSStreamStatus streamStatus; +@property (readwrite, copy) NSError *streamError; +@end + +@interface SQMultipartBodyStream () +@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding; +@property (readwrite, nonatomic, strong) NSMutableArray *HTTPBodyParts; +@property (readwrite, nonatomic, strong) NSEnumerator *HTTPBodyPartEnumerator; +@property (readwrite, nonatomic, strong) SQHTTPBodyPart *currentHTTPBodyPart; +@property (readwrite, nonatomic, strong) NSOutputStream *outputStream; +@property (readwrite, nonatomic, strong) NSMutableData *buffer; +@end + +@implementation SQMultipartBodyStream + +@synthesize delegate; +@synthesize streamStatus; +@synthesize streamError; + +- (instancetype)initWithStringEncoding:(NSStringEncoding)encoding { + self = [super init]; + if (!self) { + return nil; + } + self.stringEncoding = encoding; + self.HTTPBodyParts = [NSMutableArray array]; + self.numberOfBytesInPacket = NSIntegerMax; + return self; +} + +- (void)setInitialAndFinalBoundaries { + if ([self.HTTPBodyParts count] > 0) { + for (SQHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + bodyPart.hasInitialBoundary = NO; + bodyPart.hasFinalBoundary = NO; + } + [[self.HTTPBodyParts firstObject] setHasInitialBoundary:YES]; + [[self.HTTPBodyParts lastObject] setHasFinalBoundary:YES]; + } +} + +- (void)appendHTTPBodyPart:(SQHTTPBodyPart *)bodyPart { + [self.HTTPBodyParts addObject:bodyPart]; +} + +- (BOOL)isEmpty { + return [self.HTTPBodyParts count] == 0; +} + +#pragma mark - NSInputStream + +- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)length { + if ([self streamStatus] == NSStreamStatusClosed) { + return 0; + } + + NSInteger totalNumberOfBytesRead = 0; + + while ((NSUInteger)totalNumberOfBytesRead < MIN(length, self.numberOfBytesInPacket)) { + if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) { + if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) { + break; + } + } else { + NSUInteger maxLength = MIN(length, self.numberOfBytesInPacket) - (NSUInteger)totalNumberOfBytesRead; + NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:&buffer[totalNumberOfBytesRead] maxLength:maxLength]; + if (numberOfBytesRead == -1) { + self.streamError = self.currentHTTPBodyPart.inputStream.streamError; + break; + } else { + totalNumberOfBytesRead += numberOfBytesRead; + if (self.delay > 0.0f) { + [NSThread sleepForTimeInterval:self.delay]; + } + } + } + } + return totalNumberOfBytesRead; +} + +- (BOOL)getBuffer:(__unused uint8_t * _Nullable *)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 { + self.streamStatus = NSStreamStatusClosed; +} + +- (id)propertyForKey:(__unused NSStreamPropertyKey)key { + return nil; +} + +- (BOOL)setProperty:(__unused id)property forKey:(__unused NSStreamPropertyKey)key { + return NO; +} + +- (void)scheduleInRunLoop:(__unused NSRunLoop *)aRunLoop forMode:(__unused NSRunLoopMode)mode { + +} + +- (void)removeFromRunLoop:(__unused NSRunLoop *)aRunLoop forMode:(__unused NSRunLoopMode)mode { + +} + +- (unsigned long long)contentLength { + unsigned long long length = 0; + for (SQHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + length += [bodyPart contentLength]; + } + 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 + +- (instancetype)copyWithZone:(NSZone *)zone { + SQMultipartBodyStream *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding]; + for (SQHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + [bodyStreamCopy appendHTTPBodyPart:[bodyPart copy]]; + } + [bodyStreamCopy setInitialAndFinalBoundaries]; + return bodyStreamCopy; +} + +@end diff --git a/SQDebug/AFNetworking/AFNetworking.xmind b/SQDebug/AFNetworking/AFNetworking.xmind new file mode 100644 index 00000000..3ce8c7bd Binary files /dev/null and b/SQDebug/AFNetworking/AFNetworking.xmind differ diff --git a/SQDebug/AFNetworking/README.md b/SQDebug/AFNetworking/README.md index b612d53a..6f80a4e1 100644 --- a/SQDebug/AFNetworking/README.md +++ b/SQDebug/AFNetworking/README.md @@ -1507,6 +1507,198 @@ content-type: application/json; charset=UTF-8 ``` +>2020-11-25 + +```objc +@interface NSStream () +@property (readwrite) NSStreamStatus streamStatus; +@property (readwrite, copy) NSError *streamError; +@end + +@interface AFMultipartBodyStream : NSInputStream +@property (nonatomic, assign) NSUInteger numberOfBytesInPacket; +@property (nonatomic, assign) NSTimeInterval delay; +@property (nonatomic, strong) NSInputStream *inputStream; +@property (readonly, nonatomic, assign) unsigned long long contentLength; +@property (readonly, nonatomic, assign, getter = isEmpty) BOOL empty; + +- (instancetype)initWithStringEncoding:(NSStringEncoding)encoding; +- (void)setInitialAndFinalBoundaries; +- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart; +@end +``` + +```objc +@interface AFMultipartBodyStream () +@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding; +@property (readwrite, nonatomic, strong) NSMutableArray *HTTPBodyParts; +@property (readwrite, nonatomic, strong) NSEnumerator *HTTPBodyPartEnumerator; +@property (readwrite, nonatomic, strong) AFHTTPBodyPart *currentHTTPBodyPart; +@property (readwrite, nonatomic, strong) NSOutputStream *outputStream; +@property (readwrite, nonatomic, strong) NSMutableData *buffer; +@end + +@implementation AFMultipartBodyStream +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1100) +@synthesize delegate; +#endif +@synthesize streamStatus; +@synthesize streamError; + +- (instancetype)initWithStringEncoding:(NSStringEncoding)encoding { + self = [super init]; + if (!self) { + return nil; + } + + self.stringEncoding = encoding; + self.HTTPBodyParts = [NSMutableArray array]; + self.numberOfBytesInPacket = NSIntegerMax; + + return self; +} + +- (void)setInitialAndFinalBoundaries { + if ([self.HTTPBodyParts count] > 0) { + for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + bodyPart.hasInitialBoundary = NO; + bodyPart.hasFinalBoundary = NO; + } + + [[self.HTTPBodyParts firstObject] setHasInitialBoundary:YES]; + [[self.HTTPBodyParts lastObject] setHasFinalBoundary:YES]; + } +} + +- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart { + [self.HTTPBodyParts addObject:bodyPart]; +} + +- (BOOL)isEmpty { + return [self.HTTPBodyParts count] == 0; +} + +#pragma mark - NSInputStream + +- (NSInteger)read:(uint8_t *)buffer + maxLength:(NSUInteger)length +{ + if ([self streamStatus] == NSStreamStatusClosed) { + return 0; + } + + NSInteger totalNumberOfBytesRead = 0; + + while ((NSUInteger)totalNumberOfBytesRead < MIN(length, self.numberOfBytesInPacket)) { + if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) { + if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) { + break; + } + } else { + NSUInteger maxLength = MIN(length, self.numberOfBytesInPacket) - (NSUInteger)totalNumberOfBytesRead; + NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:&buffer[totalNumberOfBytesRead] maxLength:maxLength]; + if (numberOfBytesRead == -1) { + self.streamError = self.currentHTTPBodyPart.inputStream.streamError; + break; + } else { + totalNumberOfBytesRead += numberOfBytesRead; + + if (self.delay > 0.0f) { + [NSThread sleepForTimeInterval:self.delay]; + } + } + } + } + + return totalNumberOfBytesRead; +} + +- (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 { + self.streamStatus = NSStreamStatusClosed; +} + +- (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 length = 0; + for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + length += [bodyPart contentLength]; + } + + 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 + +- (instancetype)copyWithZone:(NSZone *)zone { + AFMultipartBodyStream *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding]; + + for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + [bodyStreamCopy appendHTTPBodyPart:[bodyPart copy]]; + } + + [bodyStreamCopy setInitialAndFinalBoundaries]; + + return bodyStreamCopy; +} + +@end +``` ```objc #import "AFURLSessionManager.h"