2015-09-18 15:02:15 -07:00
// AFURLRequestSerialization . m
2017-03-09 20:10:44 -08:00
// Copyright ( c ) 2011 – 2016 Alamofire Software Foundation ( http : // alamofire . org / )
2015-09-18 15:02:15 -07:00
//
// Permission is hereby granted , free of charge , to any person obtaining a copy
// of this software and associated documentation files ( the "Software" ) , to deal
// in the Software without restriction , including without limitation the rights
// to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
// copies of the Software , and to permit persons to whom the Software is
// furnished to do so , subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software .
//
// THE SOFTWARE IS PROVIDED "AS IS" , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
// IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
// LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE .
# import "AFURLRequestSerialization.h"
2017-03-09 20:10:44 -08:00
# if TARGET_OS _IOS || TARGET_OS _WATCH || TARGET_OS _TV
2015-09-18 15:02:15 -07:00
# import < MobileCoreServices / MobileCoreServices . h >
# else
# import < CoreServices / CoreServices . h >
# endif
NSString * const AFURLRequestSerializationErrorDomain = @ "com.alamofire.error.serialization.request" ;
NSString * const AFNetworkingOperationFailingURLRequestErrorKey = @ "com.alamofire.serialization.request.error.response" ;
typedef NSString * ( ^ AFQueryStringSerializationBlock ) ( NSURLRequest * request , id parameters , NSError * __autoreleasing * error ) ;
/ * *
Returns a percent - escaped string following RFC 3986 for a query string key or value .
RFC 3986 states that the following characters are "reserved" characters .
- General Delimiters : ":" , "#" , "[" , "]" , "@" , "?" , "/"
- Sub - Delimiters : "!" , "$" , "&" , "'" , "(" , ")" , "*" , "+" , "," , ";" , "="
In RFC 3986 - Section 3.4 , it states that the "?" and "/" characters should not be escaped to allow
query strings to include a URL . Therefore , all "reserved" characters with the exception of "?" and "/"
should be percent - escaped in the query string .
- parameter string : The string to be percent - escaped .
- returns : The percent - escaped string .
* /
2017-03-09 20:10:44 -08:00
NSString * AFPercentEscapedStringFromString ( NSString * string ) {
2015-09-18 15:02:15 -07:00
static NSString * const kAFCharactersGeneralDelimitersToEncode = @ ":#[]@" ; // does not include "?" or "/" due to RFC 3986 - Section 3.4
static NSString * const kAFCharactersSubDelimitersToEncode = @ "!$&'()*+,;=" ;
NSMutableCharacterSet * allowedCharacterSet = [ [ NSCharacterSet URLQueryAllowedCharacterSet ] mutableCopy ] ;
[ allowedCharacterSet removeCharactersInString : [ kAFCharactersGeneralDelimitersToEncode stringByAppendingString : kAFCharactersSubDelimitersToEncode ] ] ;
2017-03-09 20:10:44 -08:00
// FIXME : https : // github . com / AFNetworking / AFNetworking / pull / 3028
// return [ string stringByAddingPercentEncodingWithAllowedCharacters : allowedCharacterSet ] ;
static NSUInteger const batchSize = 50 ;
NSUInteger index = 0 ;
NSMutableString * escaped = @ "" . mutableCopy ;
while ( index < string . length ) {
NSUInteger length = MIN ( string . length - index , batchSize ) ;
NSRange range = NSMakeRange ( index , length ) ;
// To avoid breaking up character sequences such as 👴 🏻 👮 🏽
range = [ string rangeOfComposedCharacterSequencesForRange : range ] ;
NSString * substring = [ string substringWithRange : range ] ;
NSString * encoded = [ substring stringByAddingPercentEncodingWithAllowedCharacters : allowedCharacterSet ] ;
[ escaped appendString : encoded ] ;
index + = range . length ;
}
return escaped ;
2015-09-18 15:02:15 -07:00
}
# pragma mark -
@ interface AFQueryStringPair : NSObject
@ property ( readwrite , nonatomic , strong ) id field ;
@ property ( readwrite , nonatomic , strong ) id value ;
2017-03-09 20:10:44 -08:00
- ( instancetype ) initWithField : ( id ) field value : ( id ) value ;
2015-09-18 15:02:15 -07:00
- ( NSString * ) URLEncodedStringValue ;
@ end
@ implementation AFQueryStringPair
2017-03-09 20:10:44 -08:00
- ( instancetype ) initWithField : ( id ) field value : ( id ) value {
2015-09-18 15:02:15 -07:00
self = [ super init ] ;
if ( ! self ) {
return nil ;
}
self . field = field ;
self . value = value ;
return self ;
}
- ( NSString * ) URLEncodedStringValue {
if ( ! self . value || [ self . value isEqual : [ NSNull null ] ] ) {
return AFPercentEscapedStringFromString ( [ self . field description ] ) ;
} else {
return [ NSString stringWithFormat : @ "%@=%@" , AFPercentEscapedStringFromString ( [ self . field description ] ) , AFPercentEscapedStringFromString ( [ self . value description ] ) ] ;
}
}
@ end
# pragma mark -
2017-03-09 20:10:44 -08:00
FOUNDATION_EXPORT NSArray * AFQueryStringPairsFromDictionary ( NSDictionary * dictionary ) ;
FOUNDATION_EXPORT NSArray * AFQueryStringPairsFromKeyAndValue ( NSString * key , id value ) ;
2015-09-18 15:02:15 -07:00
2017-03-09 20:10:44 -08:00
NSString * AFQueryStringFromParameters ( NSDictionary * parameters ) {
2015-09-18 15:02:15 -07:00
NSMutableArray * mutablePairs = [ NSMutableArray array ] ;
for ( AFQueryStringPair * pair in AFQueryStringPairsFromDictionary ( parameters ) ) {
[ mutablePairs addObject : [ pair URLEncodedStringValue ] ] ;
}
return [ mutablePairs componentsJoinedByString : @ "&" ] ;
}
NSArray * AFQueryStringPairsFromDictionary ( NSDictionary * dictionary ) {
return AFQueryStringPairsFromKeyAndValue ( nil , dictionary ) ;
}
NSArray * AFQueryStringPairsFromKeyAndValue ( NSString * key , id value ) {
NSMutableArray * mutableQueryStringComponents = [ NSMutableArray array ] ;
NSSortDescriptor * sortDescriptor = [ NSSortDescriptor sortDescriptorWithKey : @ "description" ascending : YES selector : @ selector ( compare : ) ] ;
if ( [ value isKindOfClass : [ NSDictionary class ] ] ) {
NSDictionary * dictionary = value ;
// Sort dictionary keys to ensure consistent ordering in query string , which is important when deserializing potentially ambiguous sequences , such as an array of dictionaries
for ( id nestedKey in [ dictionary . allKeys sortedArrayUsingDescriptors : @ [ sortDescriptor ] ] ) {
id nestedValue = dictionary [ nestedKey ] ;
if ( nestedValue ) {
[ mutableQueryStringComponents addObjectsFromArray : AFQueryStringPairsFromKeyAndValue ( ( key ? [ NSString stringWithFormat : @ "%@[%@]" , key , nestedKey ] : nestedKey ) , nestedValue ) ] ;
}
}
} else if ( [ value isKindOfClass : [ NSArray class ] ] ) {
NSArray * array = value ;
for ( id nestedValue in array ) {
[ mutableQueryStringComponents addObjectsFromArray : AFQueryStringPairsFromKeyAndValue ( [ NSString stringWithFormat : @ "%@[]" , key ] , nestedValue ) ] ;
}
} else if ( [ value isKindOfClass : [ NSSet class ] ] ) {
NSSet * set = value ;
for ( id obj in [ set sortedArrayUsingDescriptors : @ [ sortDescriptor ] ] ) {
[ mutableQueryStringComponents addObjectsFromArray : AFQueryStringPairsFromKeyAndValue ( key , obj ) ] ;
}
} else {
[ mutableQueryStringComponents addObject : [ [ AFQueryStringPair alloc ] initWithField : key value : value ] ] ;
}
return mutableQueryStringComponents ;
}
# pragma mark -
@ interface AFStreamingMultipartFormData : NSObject < AFMultipartFormData >
- ( instancetype ) initWithURLRequest : ( NSMutableURLRequest * ) urlRequest
stringEncoding : ( NSStringEncoding ) encoding ;
- ( NSMutableURLRequest * ) requestByFinalizingMultipartFormData ;
@ end
# pragma mark -
static NSArray * AFHTTPRequestSerializerObservedKeyPaths ( ) {
static NSArray * _AFHTTPRequestSerializerObservedKeyPaths = nil ;
static dispatch_once _t onceToken ;
dispatch_once ( & onceToken , ^ {
_AFHTTPRequestSerializerObservedKeyPaths = @ [ NSStringFromSelector ( @ selector ( allowsCellularAccess ) ) , NSStringFromSelector ( @ selector ( cachePolicy ) ) , NSStringFromSelector ( @ selector ( HTTPShouldHandleCookies ) ) , NSStringFromSelector ( @ selector ( HTTPShouldUsePipelining ) ) , NSStringFromSelector ( @ selector ( networkServiceType ) ) , NSStringFromSelector ( @ selector ( timeoutInterval ) ) ] ;
} ) ;
return _AFHTTPRequestSerializerObservedKeyPaths ;
}
static void * AFHTTPRequestSerializerObserverContext = & AFHTTPRequestSerializerObserverContext ;
@ interface AFHTTPRequestSerializer ( )
@ property ( readwrite , nonatomic , strong ) NSMutableSet * mutableObservedChangedKeyPaths ;
@ property ( readwrite , nonatomic , strong ) NSMutableDictionary * mutableHTTPRequestHeaders ;
2017-03-09 20:10:44 -08:00
@ property ( readwrite , nonatomic , strong ) dispatch_queue _t requestHeaderModificationQueue ;
2015-09-18 15:02:15 -07:00
@ property ( readwrite , nonatomic , assign ) AFHTTPRequestQueryStringSerializationStyle queryStringSerializationStyle ;
@ property ( readwrite , nonatomic , copy ) AFQueryStringSerializationBlock queryStringSerialization ;
@ end
@ implementation AFHTTPRequestSerializer
+ ( instancetype ) serializer {
return [ [ self alloc ] init ] ;
}
- ( instancetype ) init {
self = [ super init ] ;
if ( ! self ) {
return nil ;
}
self . stringEncoding = NSUTF8StringEncoding ;
self . mutableHTTPRequestHeaders = [ NSMutableDictionary dictionary ] ;
2017-03-09 20:10:44 -08:00
self . requestHeaderModificationQueue = dispatch_queue _create ( "requestHeaderModificationQueue" , DISPATCH_QUEUE _CONCURRENT ) ;
2015-09-18 15:02:15 -07:00
// Accept - Language HTTP Header ; see http : // www . w3 . org / Protocols / rfc2616 / rfc2616 - sec14 . html # sec14 .4
NSMutableArray * acceptLanguagesComponents = [ NSMutableArray array ] ;
[ [ NSLocale preferredLanguages ] enumerateObjectsUsingBlock : ^ ( id obj , NSUInteger idx , BOOL * stop ) {
float q = 1.0 f - ( idx * 0.1 f ) ;
[ acceptLanguagesComponents addObject : [ NSString stringWithFormat : @ "%@;q=%0.1g" , obj , q ] ] ;
* stop = q <= 0.5 f ;
} ] ;
[ self setValue : [ acceptLanguagesComponents componentsJoinedByString : @ ", " ] forHTTPHeaderField : @ "Accept-Language" ] ;
NSString * userAgent = nil ;
# if TARGET_OS _IOS
// User - Agent Header ; see http : // www . w3 . org / Protocols / rfc2616 / rfc2616 - sec14 . html # sec14 .43
userAgent = [ NSString stringWithFormat : @ "%@/%@ (%@; iOS %@; Scale/%0.2f)" , [ [ NSBundle mainBundle ] infoDictionary ] [ ( __bridge NSString * ) kCFBundleExecutableKey ] ? : [ [ NSBundle mainBundle ] infoDictionary ] [ ( __bridge NSString * ) kCFBundleIdentifierKey ] , [ [ NSBundle mainBundle ] infoDictionary ] [ @ "CFBundleShortVersionString" ] ? : [ [ NSBundle mainBundle ] infoDictionary ] [ ( __bridge NSString * ) kCFBundleVersionKey ] , [ [ UIDevice currentDevice ] model ] , [ [ UIDevice currentDevice ] systemVersion ] , [ [ UIScreen mainScreen ] scale ] ] ;
# elif TARGET_OS _WATCH
// User - Agent Header ; see http : // www . w3 . org / Protocols / rfc2616 / rfc2616 - sec14 . html # sec14 .43
userAgent = [ NSString stringWithFormat : @ "%@/%@ (%@; watchOS %@; Scale/%0.2f)" , [ [ NSBundle mainBundle ] infoDictionary ] [ ( __bridge NSString * ) kCFBundleExecutableKey ] ? : [ [ NSBundle mainBundle ] infoDictionary ] [ ( __bridge NSString * ) kCFBundleIdentifierKey ] , [ [ NSBundle mainBundle ] infoDictionary ] [ @ "CFBundleShortVersionString" ] ? : [ [ NSBundle mainBundle ] infoDictionary ] [ ( __bridge NSString * ) kCFBundleVersionKey ] , [ [ WKInterfaceDevice currentDevice ] model ] , [ [ WKInterfaceDevice currentDevice ] systemVersion ] , [ [ WKInterfaceDevice currentDevice ] screenScale ] ] ;
# elif defined ( __MAC _OS _X _VERSION _MIN _REQUIRED )
userAgent = [ NSString stringWithFormat : @ "%@/%@ (Mac OS X %@)" , [ [ NSBundle mainBundle ] infoDictionary ] [ ( __bridge NSString * ) kCFBundleExecutableKey ] ? : [ [ NSBundle mainBundle ] infoDictionary ] [ ( __bridge NSString * ) kCFBundleIdentifierKey ] , [ [ NSBundle mainBundle ] infoDictionary ] [ @ "CFBundleShortVersionString" ] ? : [ [ NSBundle mainBundle ] infoDictionary ] [ ( __bridge NSString * ) kCFBundleVersionKey ] , [ [ NSProcessInfo processInfo ] operatingSystemVersionString ] ] ;
# endif
if ( userAgent ) {
if ( ! [ userAgent canBeConvertedToEncoding : NSASCIIStringEncoding ] ) {
NSMutableString * mutableUserAgent = [ userAgent mutableCopy ] ;
if ( CFStringTransform ( ( __bridge CFMutableStringRef ) ( mutableUserAgent ) , NULL , ( __bridge CFStringRef ) @ "Any-Latin; Latin-ASCII; [:^ASCII:] Remove" , false ) ) {
userAgent = mutableUserAgent ;
}
}
[ self setValue : userAgent forHTTPHeaderField : @ "User-Agent" ] ;
}
// HTTP Method Definitions ; see http : // www . w3 . org / Protocols / rfc2616 / rfc2616 - sec9 . html
self . HTTPMethodsEncodingParametersInURI = [ NSSet setWithObjects : @ "GET" , @ "HEAD" , @ "DELETE" , nil ] ;
self . mutableObservedChangedKeyPaths = [ NSMutableSet set ] ;
for ( NSString * keyPath in AFHTTPRequestSerializerObservedKeyPaths ( ) ) {
if ( [ self respondsToSelector : NSSelectorFromString ( keyPath ) ] ) {
[ self addObserver : self forKeyPath : keyPath options : NSKeyValueObservingOptionNew context : AFHTTPRequestSerializerObserverContext ] ;
}
}
return self ;
}
- ( void ) dealloc {
for ( NSString * keyPath in AFHTTPRequestSerializerObservedKeyPaths ( ) ) {
if ( [ self respondsToSelector : NSSelectorFromString ( keyPath ) ] ) {
[ self removeObserver : self forKeyPath : keyPath context : AFHTTPRequestSerializerObserverContext ] ;
}
}
}
# pragma mark -
// Workarounds for crashing behavior using Key - Value Observing with XCTest
// See https : // github . com / AFNetworking / AFNetworking / issues / 2523
- ( void ) setAllowsCellularAccess : ( BOOL ) allowsCellularAccess {
[ self willChangeValueForKey : NSStringFromSelector ( @ selector ( allowsCellularAccess ) ) ] ;
_allowsCellularAccess = allowsCellularAccess ;
[ self didChangeValueForKey : NSStringFromSelector ( @ selector ( allowsCellularAccess ) ) ] ;
}
- ( void ) setCachePolicy : ( NSURLRequestCachePolicy ) cachePolicy {
[ self willChangeValueForKey : NSStringFromSelector ( @ selector ( cachePolicy ) ) ] ;
_cachePolicy = cachePolicy ;
[ self didChangeValueForKey : NSStringFromSelector ( @ selector ( cachePolicy ) ) ] ;
}
- ( void ) setHTTPShouldHandleCookies : ( BOOL ) HTTPShouldHandleCookies {
[ self willChangeValueForKey : NSStringFromSelector ( @ selector ( HTTPShouldHandleCookies ) ) ] ;
_HTTPShouldHandleCookies = HTTPShouldHandleCookies ;
[ self didChangeValueForKey : NSStringFromSelector ( @ selector ( HTTPShouldHandleCookies ) ) ] ;
}
- ( void ) setHTTPShouldUsePipelining : ( BOOL ) HTTPShouldUsePipelining {
[ self willChangeValueForKey : NSStringFromSelector ( @ selector ( HTTPShouldUsePipelining ) ) ] ;
_HTTPShouldUsePipelining = HTTPShouldUsePipelining ;
[ self didChangeValueForKey : NSStringFromSelector ( @ selector ( HTTPShouldUsePipelining ) ) ] ;
}
- ( void ) setNetworkServiceType : ( NSURLRequestNetworkServiceType ) networkServiceType {
[ self willChangeValueForKey : NSStringFromSelector ( @ selector ( networkServiceType ) ) ] ;
_networkServiceType = networkServiceType ;
[ self didChangeValueForKey : NSStringFromSelector ( @ selector ( networkServiceType ) ) ] ;
}
- ( void ) setTimeoutInterval : ( NSTimeInterval ) timeoutInterval {
[ self willChangeValueForKey : NSStringFromSelector ( @ selector ( timeoutInterval ) ) ] ;
_timeoutInterval = timeoutInterval ;
[ self didChangeValueForKey : NSStringFromSelector ( @ selector ( timeoutInterval ) ) ] ;
}
# pragma mark -
- ( NSDictionary * ) HTTPRequestHeaders {
2017-03-09 20:10:44 -08:00
NSDictionary __block * value ;
dispatch_sync ( self . requestHeaderModificationQueue , ^ {
value = [ NSDictionary dictionaryWithDictionary : self . mutableHTTPRequestHeaders ] ;
} ) ;
return value ;
2015-09-18 15:02:15 -07:00
}
- ( void ) setValue : ( NSString * ) value
forHTTPHeaderField : ( NSString * ) field
{
2017-03-09 20:10:44 -08:00
dispatch_barrier _async ( self . requestHeaderModificationQueue , ^ {
[ self . mutableHTTPRequestHeaders setValue : value forKey : field ] ;
} ) ;
2015-09-18 15:02:15 -07:00
}
- ( NSString * ) valueForHTTPHeaderField : ( NSString * ) field {
2017-03-09 20:10:44 -08:00
NSString __block * value ;
dispatch_sync ( self . requestHeaderModificationQueue , ^ {
value = [ self . mutableHTTPRequestHeaders valueForKey : field ] ;
} ) ;
return value ;
2015-09-18 15:02:15 -07:00
}
- ( void ) setAuthorizationHeaderFieldWithUsername : ( NSString * ) username
password : ( NSString * ) password
{
2017-03-09 20:10:44 -08:00
NSData * basicAuthCredentials = [ [ NSString stringWithFormat : @ "%@:%@" , username , password ] dataUsingEncoding : NSUTF8StringEncoding ] ;
NSString * base64AuthCredentials = [ basicAuthCredentials base64EncodedStringWithOptions : ( NSDataBase64EncodingOptions ) 0 ] ;
[ self setValue : [ NSString stringWithFormat : @ "Basic %@" , base64AuthCredentials ] forHTTPHeaderField : @ "Authorization" ] ;
2015-09-18 15:02:15 -07:00
}
- ( void ) clearAuthorizationHeader {
2017-03-09 20:10:44 -08:00
dispatch_barrier _async ( self . requestHeaderModificationQueue , ^ {
[ self . mutableHTTPRequestHeaders removeObjectForKey : @ "Authorization" ] ;
} ) ;
2015-09-18 15:02:15 -07:00
}
# pragma mark -
- ( void ) setQueryStringSerializationWithStyle : ( AFHTTPRequestQueryStringSerializationStyle ) style {
self . queryStringSerializationStyle = style ;
self . queryStringSerialization = nil ;
}
- ( void ) setQueryStringSerializationWithBlock : ( NSString * ( ^ ) ( NSURLRequest * , id , NSError * __autoreleasing * ) ) block {
self . queryStringSerialization = block ;
}
# pragma mark -
- ( NSMutableURLRequest * ) requestWithMethod : ( NSString * ) method
URLString : ( NSString * ) URLString
parameters : ( id ) parameters
error : ( NSError * __autoreleasing * ) error
{
NSParameterAssert ( method ) ;
NSParameterAssert ( URLString ) ;
NSURL * url = [ NSURL URLWithString : URLString ] ;
NSParameterAssert ( url ) ;
NSMutableURLRequest * mutableRequest = [ [ NSMutableURLRequest alloc ] initWithURL : url ] ;
mutableRequest . HTTPMethod = method ;
for ( NSString * keyPath in AFHTTPRequestSerializerObservedKeyPaths ( ) ) {
if ( [ self . mutableObservedChangedKeyPaths containsObject : keyPath ] ) {
[ mutableRequest setValue : [ self valueForKeyPath : keyPath ] forKey : keyPath ] ;
}
}
mutableRequest = [ [ self requestBySerializingRequest : mutableRequest withParameters : parameters error : error ] mutableCopy ] ;
return mutableRequest ;
}
- ( NSMutableURLRequest * ) multipartFormRequestWithMethod : ( NSString * ) method
URLString : ( NSString * ) URLString
parameters : ( NSDictionary * ) parameters
constructingBodyWithBlock : ( void ( ^ ) ( id < AFMultipartFormData > formData ) ) block
error : ( NSError * __autoreleasing * ) error
{
NSParameterAssert ( method ) ;
NSParameterAssert ( ! [ method isEqualToString : @ "GET" ] && ! [ method isEqualToString : @ "HEAD" ] ) ;
NSMutableURLRequest * mutableRequest = [ self requestWithMethod : method URLString : URLString parameters : nil error : error ] ;
__block AFStreamingMultipartFormData * formData = [ [ AFStreamingMultipartFormData alloc ] initWithURLRequest : mutableRequest stringEncoding : NSUTF8StringEncoding ] ;
if ( parameters ) {
for ( AFQueryStringPair * pair in AFQueryStringPairsFromDictionary ( parameters ) ) {
NSData * data = nil ;
if ( [ pair . value isKindOfClass : [ NSData class ] ] ) {
data = pair . value ;
} else if ( [ pair . value isEqual : [ NSNull null ] ] ) {
data = [ NSData data ] ;
} else {
data = [ [ pair . value description ] dataUsingEncoding : self . stringEncoding ] ;
}
if ( data ) {
[ formData appendPartWithFormData : data name : [ pair . field description ] ] ;
}
}
}
if ( block ) {
block ( formData ) ;
}
return [ formData requestByFinalizingMultipartFormData ] ;
}
- ( NSMutableURLRequest * ) requestWithMultipartFormRequest : ( NSURLRequest * ) request
writingStreamContentsToFile : ( NSURL * ) fileURL
completionHandler : ( void ( ^ ) ( NSError * error ) ) handler
{
NSParameterAssert ( request . HTTPBodyStream ) ;
NSParameterAssert ( [ fileURL isFileURL ] ) ;
NSInputStream * inputStream = request . HTTPBodyStream ;
NSOutputStream * outputStream = [ [ NSOutputStream alloc ] initWithURL : fileURL append : NO ] ;
__block NSError * error = nil ;
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT , 0 ) , ^ {
[ inputStream scheduleInRunLoop : [ NSRunLoop currentRunLoop ] forMode : NSDefaultRunLoopMode ] ;
[ outputStream scheduleInRunLoop : [ NSRunLoop currentRunLoop ] forMode : NSDefaultRunLoopMode ] ;
[ inputStream open ] ;
[ outputStream open ] ;
while ( [ inputStream hasBytesAvailable ] && [ outputStream hasSpaceAvailable ] ) {
uint8_t buffer [ 1024 ] ;
NSInteger bytesRead = [ inputStream read : buffer maxLength : 1024 ] ;
if ( inputStream . streamError || bytesRead < 0 ) {
error = inputStream . streamError ;
break ;
}
NSInteger bytesWritten = [ outputStream write : buffer maxLength : ( NSUInteger ) bytesRead ] ;
if ( outputStream . streamError || bytesWritten < 0 ) {
error = outputStream . streamError ;
break ;
}
if ( bytesRead = = 0 && bytesWritten = = 0 ) {
break ;
}
}
[ outputStream close ] ;
[ inputStream close ] ;
if ( handler ) {
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
handler ( error ) ;
} ) ;
}
} ) ;
NSMutableURLRequest * mutableRequest = [ request mutableCopy ] ;
mutableRequest . HTTPBodyStream = nil ;
return mutableRequest ;
}
# pragma mark - AFURLRequestSerialization
- ( NSURLRequest * ) requestBySerializingRequest : ( NSURLRequest * ) request
withParameters : ( id ) parameters
error : ( NSError * __autoreleasing * ) error
{
NSParameterAssert ( request ) ;
NSMutableURLRequest * mutableRequest = [ request mutableCopy ] ;
[ self . HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock : ^ ( id field , id value , BOOL * __unused stop ) {
if ( ! [ request valueForHTTPHeaderField : field ] ) {
[ mutableRequest setValue : value forHTTPHeaderField : field ] ;
}
} ] ;
2017-03-09 20:10:44 -08:00
NSString * query = nil ;
2015-09-18 15:02:15 -07:00
if ( parameters ) {
if ( self . queryStringSerialization ) {
NSError * serializationError ;
query = self . queryStringSerialization ( request , parameters , & serializationError ) ;
if ( serializationError ) {
if ( error ) {
* error = serializationError ;
}
return nil ;
}
} else {
switch ( self . queryStringSerializationStyle ) {
case AFHTTPRequestQueryStringDefaultStyle :
query = AFQueryStringFromParameters ( parameters ) ;
break ;
}
}
2017-03-09 20:10:44 -08:00
}
2015-09-18 15:02:15 -07:00
2017-03-09 20:10:44 -08:00
if ( [ self . HTTPMethodsEncodingParametersInURI containsObject : [ [ request HTTPMethod ] uppercaseString ] ] ) {
if ( query && query . length > 0 ) {
2015-09-18 15:02:15 -07:00
mutableRequest . URL = [ NSURL URLWithString : [ [ mutableRequest . URL absoluteString ] stringByAppendingFormat : mutableRequest . URL . query ? @ "&%@" : @ "?%@" , query ] ] ;
}
2017-03-09 20:10:44 -08:00
} else {
// #2864 : an empty string is a valid x - www - form - urlencoded payload
if ( ! query ) {
query = @ "" ;
}
if ( ! [ mutableRequest valueForHTTPHeaderField : @ "Content-Type" ] ) {
[ mutableRequest setValue : @ "application/x-www-form-urlencoded" forHTTPHeaderField : @ "Content-Type" ] ;
}
[ mutableRequest setHTTPBody : [ query dataUsingEncoding : self . stringEncoding ] ] ;
2015-09-18 15:02:15 -07:00
}
return mutableRequest ;
}
# pragma mark - NSKeyValueObserving
+ ( BOOL ) automaticallyNotifiesObserversForKey : ( NSString * ) key {
if ( [ AFHTTPRequestSerializerObservedKeyPaths ( ) containsObject : key ] ) {
return NO ;
}
return [ super automaticallyNotifiesObserversForKey : key ] ;
}
- ( void ) observeValueForKeyPath : ( NSString * ) keyPath
ofObject : ( __unused id ) object
change : ( NSDictionary * ) change
context : ( void * ) context
{
if ( context = = AFHTTPRequestSerializerObserverContext ) {
if ( [ change [ NSKeyValueChangeNewKey ] isEqual : [ NSNull null ] ] ) {
[ self . mutableObservedChangedKeyPaths removeObject : keyPath ] ;
} else {
[ self . mutableObservedChangedKeyPaths addObject : keyPath ] ;
}
}
}
# pragma mark - NSSecureCoding
+ ( BOOL ) supportsSecureCoding {
return YES ;
}
2017-03-09 20:10:44 -08:00
- ( instancetype ) initWithCoder : ( NSCoder * ) decoder {
2015-09-18 15:02:15 -07:00
self = [ self init ] ;
if ( ! self ) {
return nil ;
}
self . mutableHTTPRequestHeaders = [ [ decoder decodeObjectOfClass : [ NSDictionary class ] forKey : NSStringFromSelector ( @ selector ( mutableHTTPRequestHeaders ) ) ] mutableCopy ] ;
2017-03-09 20:10:44 -08:00
self . queryStringSerializationStyle = ( AFHTTPRequestQueryStringSerializationStyle ) [ [ decoder decodeObjectOfClass : [ NSNumber class ] forKey : NSStringFromSelector ( @ selector ( queryStringSerializationStyle ) ) ] unsignedIntegerValue ] ;
2015-09-18 15:02:15 -07:00
return self ;
}
- ( void ) encodeWithCoder : ( NSCoder * ) coder {
2017-03-09 20:10:44 -08:00
dispatch_sync ( self . requestHeaderModificationQueue , ^ {
[ coder encodeObject : self . mutableHTTPRequestHeaders forKey : NSStringFromSelector ( @ selector ( mutableHTTPRequestHeaders ) ) ] ;
} ) ;
2015-09-18 15:02:15 -07:00
[ coder encodeInteger : self . queryStringSerializationStyle forKey : NSStringFromSelector ( @ selector ( queryStringSerializationStyle ) ) ] ;
}
# pragma mark - NSCopying
2017-03-09 20:10:44 -08:00
- ( instancetype ) copyWithZone : ( NSZone * ) zone {
2015-09-18 15:02:15 -07:00
AFHTTPRequestSerializer * serializer = [ [ [ self class ] allocWithZone : zone ] init ] ;
2017-03-09 20:10:44 -08:00
dispatch_sync ( self . requestHeaderModificationQueue , ^ {
serializer . mutableHTTPRequestHeaders = [ self . mutableHTTPRequestHeaders mutableCopyWithZone : zone ] ;
} ) ;
2015-09-18 15:02:15 -07:00
serializer . queryStringSerializationStyle = self . queryStringSerializationStyle ;
serializer . queryStringSerialization = self . queryStringSerialization ;
return serializer ;
}
@ end
# pragma mark -
static NSString * AFCreateMultipartFormBoundary ( ) {
return [ NSString stringWithFormat : @ "Boundary+%08X%08X" , arc4random ( ) , arc4random ( ) ] ;
}
static NSString * const kAFMultipartFormCRLF = @ "\r\n" ;
static inline NSString * AFMultipartFormInitialBoundary ( NSString * boundary ) {
return [ NSString stringWithFormat : @ "--%@%@" , boundary , kAFMultipartFormCRLF ] ;
}
static inline NSString * AFMultipartFormEncapsulationBoundary ( NSString * boundary ) {
return [ NSString stringWithFormat : @ "%@--%@%@" , kAFMultipartFormCRLF , boundary , kAFMultipartFormCRLF ] ;
}
static inline NSString * AFMultipartFormFinalBoundary ( NSString * boundary ) {
return [ NSString stringWithFormat : @ "%@--%@--%@" , kAFMultipartFormCRLF , boundary , kAFMultipartFormCRLF ] ;
}
static inline NSString * AFContentTypeForPathExtension ( NSString * extension ) {
NSString * UTI = ( __bridge _transfer NSString * ) UTTypeCreatePreferredIdentifierForTag ( kUTTagClassFilenameExtension , ( __bridge CFStringRef ) extension , NULL ) ;
NSString * contentType = ( __bridge _transfer NSString * ) UTTypeCopyPreferredTagWithClass ( ( __bridge CFStringRef ) UTI , kUTTagClassMIMEType ) ;
if ( ! contentType ) {
return @ "application/octet-stream" ;
} else {
return contentType ;
}
}
NSUInteger const kAFUploadStream3GSuggestedPacketSize = 1024 * 16 ;
NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2 ;
@ interface AFHTTPBodyPart : NSObject
@ property ( nonatomic , assign ) NSStringEncoding stringEncoding ;
@ property ( nonatomic , strong ) NSDictionary * headers ;
@ property ( nonatomic , copy ) NSString * boundary ;
@ property ( nonatomic , strong ) id body ;
@ property ( nonatomic , assign ) unsigned long long bodyContentLength ;
@ property ( nonatomic , strong ) NSInputStream * inputStream ;
@ property ( nonatomic , assign ) BOOL hasInitialBoundary ;
@ property ( nonatomic , assign ) BOOL hasFinalBoundary ;
@ property ( readonly , nonatomic , assign , getter = hasBytesAvailable ) BOOL bytesAvailable ;
@ property ( readonly , nonatomic , assign ) unsigned long long contentLength ;
- ( NSInteger ) read : ( uint8_t * ) buffer
maxLength : ( NSUInteger ) length ;
@ end
@ interface AFMultipartBodyStream : NSInputStream < NSStreamDelegate >
@ 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 ;
2017-03-09 20:10:44 -08:00
- ( instancetype ) initWithStringEncoding : ( NSStringEncoding ) encoding ;
2015-09-18 15:02:15 -07:00
- ( void ) setInitialAndFinalBoundaries ;
- ( void ) appendHTTPBodyPart : ( AFHTTPBodyPart * ) bodyPart ;
@ end
# pragma mark -
@ interface AFStreamingMultipartFormData ( )
@ property ( readwrite , nonatomic , copy ) NSMutableURLRequest * request ;
@ property ( readwrite , nonatomic , assign ) NSStringEncoding stringEncoding ;
@ property ( readwrite , nonatomic , copy ) NSString * boundary ;
@ property ( readwrite , nonatomic , strong ) AFMultipartBodyStream * bodyStream ;
@ end
@ implementation AFStreamingMultipartFormData
2017-03-09 20:10:44 -08:00
- ( instancetype ) initWithURLRequest : ( NSMutableURLRequest * ) urlRequest
stringEncoding : ( NSStringEncoding ) encoding
2015-09-18 15:02:15 -07:00
{
self = [ super init ] ;
if ( ! self ) {
return nil ;
}
self . request = urlRequest ;
self . stringEncoding = encoding ;
self . boundary = AFCreateMultipartFormBoundary ( ) ;
self . bodyStream = [ [ AFMultipartBodyStream alloc ] initWithStringEncoding : encoding ] ;
return self ;
}
- ( BOOL ) appendPartWithFileURL : ( NSURL * ) fileURL
name : ( NSString * ) name
error : ( NSError * __autoreleasing * ) error
{
NSParameterAssert ( fileURL ) ;
NSParameterAssert ( name ) ;
NSString * fileName = [ fileURL lastPathComponent ] ;
NSString * mimeType = AFContentTypeForPathExtension ( [ fileURL pathExtension ] ) ;
return [ self appendPartWithFileURL : fileURL name : name fileName : fileName mimeType : mimeType error : error ] ;
}
- ( BOOL ) appendPartWithFileURL : ( NSURL * ) fileURL
name : ( NSString * ) name
fileName : ( NSString * ) fileName
mimeType : ( NSString * ) mimeType
error : ( NSError * __autoreleasing * ) error
{
NSParameterAssert ( fileURL ) ;
NSParameterAssert ( name ) ;
NSParameterAssert ( fileName ) ;
NSParameterAssert ( mimeType ) ;
if ( ! [ fileURL isFileURL ] ) {
NSDictionary * userInfo = @ { NSLocalizedFailureReasonErrorKey : NSLocalizedStringFromTable ( @ "Expected URL to be a file URL" , @ "AFNetworking" , nil ) } ;
if ( error ) {
* error = [ [ NSError alloc ] initWithDomain : AFURLRequestSerializationErrorDomain code : NSURLErrorBadURL userInfo : userInfo ] ;
}
return NO ;
} else if ( [ fileURL checkResourceIsReachableAndReturnError : error ] = = NO ) {
NSDictionary * userInfo = @ { NSLocalizedFailureReasonErrorKey : NSLocalizedStringFromTable ( @ "File URL not reachable." , @ "AFNetworking" , nil ) } ;
if ( error ) {
* error = [ [ NSError alloc ] initWithDomain : AFURLRequestSerializationErrorDomain code : NSURLErrorBadURL userInfo : userInfo ] ;
}
return NO ;
}
NSDictionary * fileAttributes = [ [ NSFileManager defaultManager ] attributesOfItemAtPath : [ fileURL path ] error : error ] ;
if ( ! fileAttributes ) {
return NO ;
}
NSMutableDictionary * mutableHeaders = [ NSMutableDictionary dictionary ] ;
[ mutableHeaders setValue : [ NSString stringWithFormat : @ "form-data; name=\" % @ \ "; filename=\" % @ \ "" , name , fileName ] forKey : @ "Content-Disposition" ] ;
[ mutableHeaders setValue : mimeType forKey : @ "Content-Type" ] ;
AFHTTPBodyPart * bodyPart = [ [ AFHTTPBodyPart alloc ] init ] ;
bodyPart . stringEncoding = self . stringEncoding ;
bodyPart . headers = mutableHeaders ;
bodyPart . boundary = self . boundary ;
bodyPart . body = fileURL ;
bodyPart . bodyContentLength = [ fileAttributes [ NSFileSize ] unsignedLongLongValue ] ;
[ self . bodyStream appendHTTPBodyPart : bodyPart ] ;
return YES ;
}
- ( void ) appendPartWithInputStream : ( NSInputStream * ) inputStream
name : ( NSString * ) name
fileName : ( NSString * ) fileName
length : ( int64_t ) length
mimeType : ( NSString * ) mimeType
{
NSParameterAssert ( name ) ;
NSParameterAssert ( fileName ) ;
NSParameterAssert ( mimeType ) ;
NSMutableDictionary * mutableHeaders = [ NSMutableDictionary dictionary ] ;
[ mutableHeaders setValue : [ NSString stringWithFormat : @ "form-data; name=\" % @ \ "; filename=\" % @ \ "" , name , fileName ] forKey : @ "Content-Disposition" ] ;
[ mutableHeaders setValue : mimeType forKey : @ "Content-Type" ] ;
AFHTTPBodyPart * bodyPart = [ [ AFHTTPBodyPart alloc ] init ] ;
bodyPart . stringEncoding = self . stringEncoding ;
bodyPart . headers = mutableHeaders ;
bodyPart . boundary = self . boundary ;
bodyPart . body = inputStream ;
bodyPart . bodyContentLength = ( unsigned long long ) length ;
[ self . bodyStream appendHTTPBodyPart : bodyPart ] ;
}
- ( void ) appendPartWithFileData : ( NSData * ) data
name : ( NSString * ) name
fileName : ( NSString * ) fileName
mimeType : ( NSString * ) mimeType
{
NSParameterAssert ( name ) ;
NSParameterAssert ( fileName ) ;
NSParameterAssert ( mimeType ) ;
NSMutableDictionary * mutableHeaders = [ NSMutableDictionary dictionary ] ;
[ mutableHeaders setValue : [ NSString stringWithFormat : @ "form-data; name=\" % @ \ "; filename=\" % @ \ "" , name , fileName ] forKey : @ "Content-Disposition" ] ;
[ mutableHeaders setValue : mimeType forKey : @ "Content-Type" ] ;
[ self appendPartWithHeaders : mutableHeaders body : data ] ;
}
- ( void ) appendPartWithFormData : ( NSData * ) data
name : ( NSString * ) name
{
NSParameterAssert ( name ) ;
NSMutableDictionary * mutableHeaders = [ NSMutableDictionary dictionary ] ;
[ mutableHeaders setValue : [ NSString stringWithFormat : @ "form-data; name=\" % @ \ "" , name ] forKey : @ "Content-Disposition" ] ;
[ self appendPartWithHeaders : mutableHeaders body : data ] ;
}
- ( void ) appendPartWithHeaders : ( NSDictionary * ) headers
body : ( NSData * ) body
{
NSParameterAssert ( body ) ;
AFHTTPBodyPart * bodyPart = [ [ AFHTTPBodyPart alloc ] init ] ;
bodyPart . stringEncoding = self . stringEncoding ;
bodyPart . headers = headers ;
bodyPart . boundary = self . boundary ;
bodyPart . bodyContentLength = [ body length ] ;
bodyPart . body = body ;
[ 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 ;
}
// Reset the initial and final boundaries to ensure correct Content - Length
[ self . bodyStream setInitialAndFinalBoundaries ] ;
[ self . request setHTTPBodyStream : self . bodyStream ] ;
[ self . request setValue : [ NSString stringWithFormat : @ "multipart/form-data; boundary=%@" , self . boundary ] forHTTPHeaderField : @ "Content-Type" ] ;
[ self . request setValue : [ NSString stringWithFormat : @ "%llu" , [ self . bodyStream contentLength ] ] forHTTPHeaderField : @ "Content-Length" ] ;
return self . request ;
}
@ end
# pragma mark -
@ interface NSStream ( )
@ property ( readwrite ) NSStreamStatus streamStatus ;
@ property ( readwrite , copy ) NSError * streamError ;
@ end
@ interface AFMultipartBodyStream ( ) < NSCopying >
@ 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 ;
2017-03-09 20:10:44 -08:00
- ( instancetype ) initWithStringEncoding : ( NSStringEncoding ) encoding {
2015-09-18 15:02:15 -07:00
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 {
2017-03-09 20:10:44 -08:00
NSUInteger maxLength = MIN ( length , self . numberOfBytesInPacket ) - ( NSUInteger ) totalNumberOfBytesRead ;
2015-09-18 15:02:15 -07:00
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.0 f ) {
[ 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
2017-03-09 20:10:44 -08:00
- ( instancetype ) copyWithZone : ( NSZone * ) zone {
2015-09-18 15:02:15 -07:00
AFMultipartBodyStream * bodyStreamCopy = [ [ [ self class ] allocWithZone : zone ] initWithStringEncoding : self . stringEncoding ] ;
for ( AFHTTPBodyPart * bodyPart in self . HTTPBodyParts ) {
[ bodyStreamCopy appendHTTPBodyPart : [ bodyPart copy ] ] ;
}
[ bodyStreamCopy setInitialAndFinalBoundaries ] ;
return bodyStreamCopy ;
}
@ end
# pragma mark -
typedef enum {
AFEncapsulationBoundaryPhase = 1 ,
AFHeaderPhase = 2 ,
AFBodyPhase = 3 ,
AFFinalBoundaryPhase = 4 ,
} AFHTTPBodyPartReadPhase ;
@ interface AFHTTPBodyPart ( ) < NSCopying > {
AFHTTPBodyPartReadPhase _phase ;
NSInputStream * _inputStream ;
unsigned long long _phaseReadOffset ;
}
- ( BOOL ) transitionToNextPhase ;
- ( NSInteger ) readData : ( NSData * ) data
intoBuffer : ( uint8_t * ) buffer
maxLength : ( NSUInteger ) length ;
@ end
@ implementation AFHTTPBodyPart
2017-03-09 20:10:44 -08:00
- ( instancetype ) init {
2015-09-18 15:02:15 -07:00
self = [ super init ] ;
if ( ! self ) {
return nil ;
}
[ self transitionToNextPhase ] ;
return self ;
}
- ( void ) dealloc {
if ( _inputStream ) {
[ _inputStream close ] ;
_inputStream = nil ;
}
}
- ( NSInputStream * ) inputStream {
if ( ! _inputStream ) {
if ( [ self . body isKindOfClass : [ NSData class ] ] ) {
_inputStream = [ NSInputStream inputStreamWithData : self . body ] ;
} else if ( [ self . body isKindOfClass : [ NSURL class ] ] ) {
_inputStream = [ NSInputStream inputStreamWithURL : self . body ] ;
} else if ( [ self . body isKindOfClass : [ NSInputStream class ] ] ) {
_inputStream = self . body ;
} else {
_inputStream = [ NSInputStream inputStreamWithData : [ NSData data ] ] ;
}
}
return _inputStream ;
}
- ( NSString * ) stringForHeaders {
NSMutableString * headerString = [ NSMutableString string ] ;
for ( NSString * field in [ self . headers allKeys ] ) {
[ headerString appendString : [ NSString stringWithFormat : @ "%@: %@%@" , field , [ self . headers valueForKey : field ] , kAFMultipartFormCRLF ] ] ;
}
[ headerString appendString : kAFMultipartFormCRLF ] ;
return [ NSString stringWithString : headerString ] ;
}
- ( unsigned long long ) contentLength {
unsigned long long length = 0 ;
NSData * encapsulationBoundaryData = [ ( [ self hasInitialBoundary ] ? AFMultipartFormInitialBoundary ( self . boundary ) : AFMultipartFormEncapsulationBoundary ( self . boundary ) ) dataUsingEncoding : self . stringEncoding ] ;
length + = [ encapsulationBoundaryData length ] ;
NSData * headersData = [ [ self stringForHeaders ] dataUsingEncoding : self . stringEncoding ] ;
length + = [ headersData length ] ;
length + = _bodyContentLength ;
NSData * closingBoundaryData = ( [ self hasFinalBoundary ] ? [ AFMultipartFormFinalBoundary ( self . boundary ) dataUsingEncoding : self . stringEncoding ] : [ NSData data ] ) ;
length + = [ closingBoundaryData length ] ;
return length ;
}
- ( BOOL ) hasBytesAvailable {
// Allows ` read : maxLength : ` to be called again if ` AFMultipartFormFinalBoundary` doesn ' t fit into the available buffer
if ( _phase = = AFFinalBoundaryPhase ) {
return YES ;
}
switch ( self . inputStream . streamStatus ) {
case NSStreamStatusNotOpen :
case NSStreamStatusOpening :
case NSStreamStatusOpen :
case NSStreamStatusReading :
case NSStreamStatusWriting :
return YES ;
case NSStreamStatusAtEnd :
case NSStreamStatusClosed :
case NSStreamStatusError :
default :
return NO ;
}
}
- ( NSInteger ) read : ( uint8_t * ) buffer
maxLength : ( NSUInteger ) length
{
NSInteger totalNumberOfBytesRead = 0 ;
if ( _phase = = AFEncapsulationBoundaryPhase ) {
NSData * encapsulationBoundaryData = [ ( [ self hasInitialBoundary ] ? AFMultipartFormInitialBoundary ( self . boundary ) : AFMultipartFormEncapsulationBoundary ( self . boundary ) ) dataUsingEncoding : self . stringEncoding ] ;
totalNumberOfBytesRead + = [ self readData : encapsulationBoundaryData intoBuffer : & buffer [ totalNumberOfBytesRead ] maxLength : ( length - ( NSUInteger ) totalNumberOfBytesRead ) ] ;
}
if ( _phase = = AFHeaderPhase ) {
NSData * headersData = [ [ self stringForHeaders ] dataUsingEncoding : self . stringEncoding ] ;
totalNumberOfBytesRead + = [ self readData : headersData intoBuffer : & buffer [ totalNumberOfBytesRead ] maxLength : ( length - ( NSUInteger ) totalNumberOfBytesRead ) ] ;
}
if ( _phase = = AFBodyPhase ) {
NSInteger numberOfBytesRead = 0 ;
numberOfBytesRead = [ self . inputStream read : & buffer [ totalNumberOfBytesRead ] maxLength : ( length - ( NSUInteger ) totalNumberOfBytesRead ) ] ;
if ( numberOfBytesRead = = -1 ) {
return -1 ;
} else {
totalNumberOfBytesRead + = numberOfBytesRead ;
if ( [ self . inputStream streamStatus ] >= NSStreamStatusAtEnd ) {
[ self transitionToNextPhase ] ;
}
}
}
if ( _phase = = AFFinalBoundaryPhase ) {
NSData * closingBoundaryData = ( [ self hasFinalBoundary ] ? [ AFMultipartFormFinalBoundary ( self . boundary ) dataUsingEncoding : self . stringEncoding ] : [ NSData data ] ) ;
totalNumberOfBytesRead + = [ self readData : closingBoundaryData intoBuffer : & buffer [ totalNumberOfBytesRead ] maxLength : ( length - ( NSUInteger ) totalNumberOfBytesRead ) ] ;
}
return totalNumberOfBytesRead ;
}
- ( NSInteger ) readData : ( NSData * ) data
intoBuffer : ( uint8_t * ) buffer
maxLength : ( NSUInteger ) length
{
NSRange range = NSMakeRange ( ( NSUInteger ) _phaseReadOffset , MIN ( [ data length ] - ( ( NSUInteger ) _phaseReadOffset ) , length ) ) ;
[ data getBytes : buffer range : range ] ;
_phaseReadOffset + = range . length ;
if ( ( ( NSUInteger ) _phaseReadOffset ) >= [ data length ] ) {
[ self transitionToNextPhase ] ;
}
return ( NSInteger ) range . length ;
}
- ( BOOL ) transitionToNextPhase {
if ( ! [ [ NSThread currentThread ] isMainThread ] ) {
dispatch_sync ( dispatch_get _main _queue ( ) , ^ {
[ self transitionToNextPhase ] ;
} ) ;
return YES ;
}
switch ( _phase ) {
case AFEncapsulationBoundaryPhase :
_phase = AFHeaderPhase ;
break ;
case AFHeaderPhase :
[ self . inputStream scheduleInRunLoop : [ NSRunLoop currentRunLoop ] forMode : NSRunLoopCommonModes ] ;
[ self . inputStream open ] ;
_phase = AFBodyPhase ;
break ;
case AFBodyPhase :
[ self . inputStream close ] ;
_phase = AFFinalBoundaryPhase ;
break ;
case AFFinalBoundaryPhase :
default :
_phase = AFEncapsulationBoundaryPhase ;
break ;
}
_phaseReadOffset = 0 ;
return YES ;
}
# pragma mark - NSCopying
2017-03-09 20:10:44 -08:00
- ( instancetype ) copyWithZone : ( NSZone * ) zone {
2015-09-18 15:02:15 -07:00
AFHTTPBodyPart * bodyPart = [ [ [ self class ] allocWithZone : zone ] init ] ;
bodyPart . stringEncoding = self . stringEncoding ;
bodyPart . headers = self . headers ;
bodyPart . bodyContentLength = self . bodyContentLength ;
bodyPart . body = self . body ;
bodyPart . boundary = self . boundary ;
return bodyPart ;
}
@ end
# pragma mark -
@ implementation AFJSONRequestSerializer
+ ( instancetype ) serializer {
return [ self serializerWithWritingOptions : ( NSJSONWritingOptions ) 0 ] ;
}
+ ( instancetype ) serializerWithWritingOptions : ( NSJSONWritingOptions ) writingOptions
{
AFJSONRequestSerializer * serializer = [ [ self alloc ] init ] ;
serializer . writingOptions = writingOptions ;
return serializer ;
}
# pragma mark - AFURLRequestSerialization
- ( NSURLRequest * ) requestBySerializingRequest : ( NSURLRequest * ) request
withParameters : ( id ) parameters
error : ( NSError * __autoreleasing * ) error
{
NSParameterAssert ( request ) ;
if ( [ self . HTTPMethodsEncodingParametersInURI containsObject : [ [ request HTTPMethod ] uppercaseString ] ] ) {
return [ super requestBySerializingRequest : request withParameters : parameters error : error ] ;
}
NSMutableURLRequest * mutableRequest = [ request mutableCopy ] ;
[ self . HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock : ^ ( id field , id value , BOOL * __unused stop ) {
if ( ! [ request valueForHTTPHeaderField : field ] ) {
[ mutableRequest setValue : value forHTTPHeaderField : field ] ;
}
} ] ;
if ( parameters ) {
if ( ! [ mutableRequest valueForHTTPHeaderField : @ "Content-Type" ] ) {
[ mutableRequest setValue : @ "application/json" forHTTPHeaderField : @ "Content-Type" ] ;
}
2017-03-09 20:10:44 -08:00
if ( ! [ NSJSONSerialization isValidJSONObject : parameters ] ) {
if ( error ) {
NSDictionary * userInfo = @ { NSLocalizedFailureReasonErrorKey : NSLocalizedStringFromTable ( @ "The `parameters` argument is not valid JSON." , @ "AFNetworking" , nil ) } ;
* error = [ [ NSError alloc ] initWithDomain : AFURLRequestSerializationErrorDomain code : NSURLErrorCannotDecodeContentData userInfo : userInfo ] ;
}
return nil ;
}
NSData * jsonData = [ NSJSONSerialization dataWithJSONObject : parameters options : self . writingOptions error : error ] ;
if ( ! jsonData ) {
return nil ;
}
[ mutableRequest setHTTPBody : jsonData ] ;
2015-09-18 15:02:15 -07:00
}
return mutableRequest ;
}
# pragma mark - NSSecureCoding
2017-03-09 20:10:44 -08:00
- ( instancetype ) initWithCoder : ( NSCoder * ) decoder {
2015-09-18 15:02:15 -07:00
self = [ super initWithCoder : decoder ] ;
if ( ! self ) {
return nil ;
}
self . writingOptions = [ [ decoder decodeObjectOfClass : [ NSNumber class ] forKey : NSStringFromSelector ( @ selector ( writingOptions ) ) ] unsignedIntegerValue ] ;
return self ;
}
- ( void ) encodeWithCoder : ( NSCoder * ) coder {
[ super encodeWithCoder : coder ] ;
[ coder encodeInteger : self . writingOptions forKey : NSStringFromSelector ( @ selector ( writingOptions ) ) ] ;
}
# pragma mark - NSCopying
2017-03-09 20:10:44 -08:00
- ( instancetype ) copyWithZone : ( NSZone * ) zone {
2015-09-18 15:02:15 -07:00
AFJSONRequestSerializer * serializer = [ super copyWithZone : zone ] ;
serializer . writingOptions = self . writingOptions ;
return serializer ;
}
@ end
# pragma mark -
@ implementation AFPropertyListRequestSerializer
+ ( instancetype ) serializer {
return [ self serializerWithFormat : NSPropertyListXMLFormat_v1 _0 writeOptions : 0 ] ;
}
+ ( instancetype ) serializerWithFormat : ( NSPropertyListFormat ) format
writeOptions : ( NSPropertyListWriteOptions ) writeOptions
{
AFPropertyListRequestSerializer * serializer = [ [ self alloc ] init ] ;
serializer . format = format ;
serializer . writeOptions = writeOptions ;
return serializer ;
}
# pragma mark - AFURLRequestSerializer
- ( NSURLRequest * ) requestBySerializingRequest : ( NSURLRequest * ) request
withParameters : ( id ) parameters
error : ( NSError * __autoreleasing * ) error
{
NSParameterAssert ( request ) ;
if ( [ self . HTTPMethodsEncodingParametersInURI containsObject : [ [ request HTTPMethod ] uppercaseString ] ] ) {
return [ super requestBySerializingRequest : request withParameters : parameters error : error ] ;
}
NSMutableURLRequest * mutableRequest = [ request mutableCopy ] ;
[ self . HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock : ^ ( id field , id value , BOOL * __unused stop ) {
if ( ! [ request valueForHTTPHeaderField : field ] ) {
[ mutableRequest setValue : value forHTTPHeaderField : field ] ;
}
} ] ;
if ( parameters ) {
if ( ! [ mutableRequest valueForHTTPHeaderField : @ "Content-Type" ] ) {
[ mutableRequest setValue : @ "application/x-plist" forHTTPHeaderField : @ "Content-Type" ] ;
}
2017-03-09 20:10:44 -08:00
NSData * plistData = [ NSPropertyListSerialization dataWithPropertyList : parameters format : self . format options : self . writeOptions error : error ] ;
if ( ! plistData ) {
return nil ;
}
[ mutableRequest setHTTPBody : plistData ] ;
2015-09-18 15:02:15 -07:00
}
return mutableRequest ;
}
# pragma mark - NSSecureCoding
2017-03-09 20:10:44 -08:00
- ( instancetype ) initWithCoder : ( NSCoder * ) decoder {
2015-09-18 15:02:15 -07:00
self = [ super initWithCoder : decoder ] ;
if ( ! self ) {
return nil ;
}
2017-03-09 20:10:44 -08:00
self . format = ( NSPropertyListFormat ) [ [ decoder decodeObjectOfClass : [ NSNumber class ] forKey : NSStringFromSelector ( @ selector ( format ) ) ] unsignedIntegerValue ] ;
2015-09-18 15:02:15 -07:00
self . writeOptions = [ [ decoder decodeObjectOfClass : [ NSNumber class ] forKey : NSStringFromSelector ( @ selector ( writeOptions ) ) ] unsignedIntegerValue ] ;
return self ;
}
- ( void ) encodeWithCoder : ( NSCoder * ) coder {
[ super encodeWithCoder : coder ] ;
[ coder encodeInteger : self . format forKey : NSStringFromSelector ( @ selector ( format ) ) ] ;
[ coder encodeObject : @ ( self . writeOptions ) forKey : NSStringFromSelector ( @ selector ( writeOptions ) ) ] ;
}
# pragma mark - NSCopying
2017-03-09 20:10:44 -08:00
- ( instancetype ) copyWithZone : ( NSZone * ) zone {
2015-09-18 15:02:15 -07:00
AFPropertyListRequestSerializer * serializer = [ super copyWithZone : zone ] ;
serializer . format = self . format ;
serializer . writeOptions = self . writeOptions ;
return serializer ;
}
@ end