@ -700,72 +700,86 @@ public enum OnionRequestAPI: OnionRequestAPIType {
do {
let data : Data = try AESGCM . decrypt ( responseData , with : destinationSymmetricKey )
// T h e d a t a w i l l b e i n t h e f o r m o f ` l 1 2 3 : j s o n e ` o r ` l 1 2 3 : j s o n 4 5 6 : b o d y e ` s o w e n e e d t o b r e a k t h e d a t a i n t o
// p a r t s t o p r o p e r l y p r o c e s s i t
guard let responseString : String = String ( data : data , encoding : . ascii ) , responseString . starts ( with : " l " ) else {
return seal . reject ( HTTP . Error . invalidResponse )
}
let stringParts : [ String . SubSequence ] = responseString . split ( separator : " : " )
guard stringParts . count > 1 , let infoLength : Int = Int ( stringParts [ 0 ] . suffix ( from : stringParts [ 0 ] . index ( stringParts [ 0 ] . startIndex , offsetBy : 1 ) ) ) else {
return seal . reject ( HTTP . Error . invalidResponse )
}
let infoStringStartIndex : String . Index = responseString . index ( responseString . startIndex , offsetBy : " l \( infoLength ) : " . count )
let infoStringEndIndex : String . Index = responseString . index ( infoStringStartIndex , offsetBy : infoLength )
let infoString : String = String ( responseString [ infoStringStartIndex . . < infoStringEndIndex ] )
guard let infoStringData : Data = infoString . data ( using : . utf8 ) , let responseInfo : ResponseInfo = try ? JSONDecoder ( ) . decode ( ResponseInfo . self , from : infoStringData ) else {
// P r o c e s s t h e b e n c o d e d r e s p o n s e
guard let processedResponse : ( info : ResponseInfo , body : Data ? ) = process ( bencodedData : data ) else {
return seal . reject ( HTTP . Error . invalidResponse )
}
// C u s t o m h a n d l e a c l o c k o u t o f s y n c e r r o r ( v 4 r e t u r n s ' 4 2 5 ' b u t i n c l u d e d t h e ' 4 0 6 ' j u s t i n c a s e )
guard responseInfo . code != 406 && responseInfo . code != 425 else {
// C u s t o m h a n d l e a c l o c k o u t o f s y n c e r r o r ( v 4 r e t u r n s ' 4 2 5 ' b u t i n c l u d e d t h e ' 4 0 6 '
// j u s t i n c a s e )
guard processedResponse . info . code != 406 && processedResponse . info . code != 425 else {
SNLog ( " The user's clock is out of sync with the service node network. " )
return seal . reject ( SnodeAPIError . clockOutOfSync )
}
guard responseI nfo. code != 401 else { // S i g n a t u r e v e r i f i c a t i o n f a i l e d
guard processedResponse . info . code != 401 else { // S i g n a t u r e v e r i f i c a t i o n f a i l e d
SNLog ( " Failed to verify the signature. " )
return seal . reject ( SnodeAPIError . signatureVerificationFailed )
}
// H a n d l e e r r o r s t a t u s c o d e s
guard 200. . . 299 ~= responseI nfo. code else {
guard 200. . . 299 ~= processedResponse. i nfo. code else {
return seal . reject (
OnionRequestAPIError . httpRequestFailedAtDestination (
statusCode : UInt ( responseI nfo. code ) ,
statusCode : UInt ( processedResponse. i nfo. code ) ,
data : data ,
destination : destination
)
)
}
// I f t h e r e i s n o d a t a i n t h e r e s p o n s e t h e n j u s t r e t u r n t h e R e s p o n s e I n f o
guard responseString . count > " l \( infoLength ) \( infoString ) e " . count else {
return seal . fulfill ( ( responseInfo , nil ) )
}
// E x t r a c t t h e r e s p o n s e d a t a a s w e l l
let dataString : String = String ( responseString . suffix ( from : infoStringEndIndex ) )
let dataStringParts : [ String . SubSequence ] = dataString . split ( separator : " : " )
guard dataStringParts . count > 1 , let finalDataLength : Int = Int ( dataStringParts [ 0 ] ) , let suffixData : Data = " e " . data ( using : . utf8 ) else {
return seal . reject ( HTTP . Error . invalidResponse )
}
let dataBytes : Array < UInt8 > = Array ( data )
let dataEndIndex : Int = ( dataBytes . count - suffixData . count )
let dataStartIndex : Int = ( dataEndIndex - finalDataLength )
let finalDataBytes : ArraySlice < UInt8 > = dataBytes [ dataStartIndex . . < dataEndIndex ]
let finalData : Data = Data ( finalDataBytes )
return seal . fulfill ( ( responseInfo , finalData ) )
return seal . fulfill ( processedResponse )
}
catch {
return seal . reject ( error )
}
}
}
public static func process ( bencodedData data : Data ) -> ( info : ResponseInfo , body : Data ? ) ? {
// T h e d a t a w i l l b e i n t h e f o r m o f ` l 1 2 3 : j s o n e ` o r ` l 1 2 3 : j s o n 4 5 6 : b o d y e ` s o w e n e e d t o b r e a k t h e d a t a
// i n t o p a r t s t o p r o p e r l y p r o c e s s i t
guard let responseString : String = String ( data : data , encoding : . ascii ) , responseString . starts ( with : " l " ) else {
return nil
}
let stringParts : [ String . SubSequence ] = responseString . split ( separator : " : " )
guard stringParts . count > 1 , let infoLength : Int = Int ( stringParts [ 0 ] . suffix ( from : stringParts [ 0 ] . index ( stringParts [ 0 ] . startIndex , offsetBy : 1 ) ) ) else {
return nil
}
let infoStringStartIndex : String . Index = responseString . index ( responseString . startIndex , offsetBy : " l \( infoLength ) : " . count )
let infoStringEndIndex : String . Index = responseString . index ( infoStringStartIndex , offsetBy : infoLength )
let infoString : String = String ( responseString [ infoStringStartIndex . . < infoStringEndIndex ] )
guard let infoStringData : Data = infoString . data ( using : . utf8 ) , let responseInfo : ResponseInfo = try ? JSONDecoder ( ) . decode ( ResponseInfo . self , from : infoStringData ) else {
return nil
}
// C u s t o m h a n d l e a c l o c k o u t o f s y n c e r r o r ( v 4 r e t u r n s ' 4 2 5 ' b u t i n c l u d e d t h e ' 4 0 6 ' j u s t i n c a s e )
guard responseInfo . code != 406 && responseInfo . code != 425 else { return nil }
guard responseInfo . code != 401 else { return nil }
// I f t h e r e i s n o d a t a i n t h e r e s p o n s e t h e n j u s t r e t u r n t h e R e s p o n s e I n f o
guard responseString . count > " l \( infoLength ) \( infoString ) e " . count else {
return ( responseInfo , nil )
}
// E x t r a c t t h e r e s p o n s e d a t a a s w e l l
let dataString : String = String ( responseString . suffix ( from : infoStringEndIndex ) )
let dataStringParts : [ String . SubSequence ] = dataString . split ( separator : " : " )
guard dataStringParts . count > 1 , let finalDataLength : Int = Int ( dataStringParts [ 0 ] ) , let suffixData : Data = " e " . data ( using : . utf8 ) else {
return nil
}
let dataBytes : Array < UInt8 > = Array ( data )
let dataEndIndex : Int = ( dataBytes . count - suffixData . count )
let dataStartIndex : Int = ( dataEndIndex - finalDataLength )
let finalDataBytes : ArraySlice < UInt8 > = dataBytes [ dataStartIndex . . < dataEndIndex ]
let finalData : Data = Data ( finalDataBytes )
return ( responseInfo , finalData )
}
}