@@ -19,23 +19,35 @@ internal extension FTPFileProvider {
19
19
completionHandler ( nil , error)
20
20
return
21
21
}
22
- afterSend ? ( error)
23
22
24
- if task. state == . suspended {
25
- task. resume ( )
23
+ self . readData ( on: task, minLength: minLength, maxLength: 4096 , timeout: timeout, afterSend: afterSend, completionHandler: completionHandler)
24
+ }
25
+ }
26
+
27
+ func readData( on task: FileProviderStreamTask ,
28
+ minLength: Int = 4 , maxLength: Int = 4096 , timeout: TimeInterval ,
29
+ afterSend: ( ( _ error: Error ? ) -> Void ) ? = nil ,
30
+ completionHandler: @escaping ( _ response: String ? , _ error: Error ? ) -> Void ) {
31
+ task. readData ( ofMinLength: minLength, maxLength: maxLength, timeout: timeout) { ( data, eof, error) in
32
+ if let error = error {
33
+ completionHandler ( nil , error)
34
+ return
26
35
}
27
36
28
- task. readData ( ofMinLength: minLength, maxLength: 4096 , timeout: timeout) { ( data, eof, error) in
29
- if let error = error {
30
- completionHandler ( nil , error)
37
+ if let data = data, let response = String ( data: data, encoding: . utf8) {
38
+ let lines = response. components ( separatedBy: " \n " ) . compactMap { $0. isEmpty ? nil : $0. trimmingCharacters ( in: . whitespacesAndNewlines) }
39
+ if let last = lines. last, last. hasPrefix ( " 1 " ) {
40
+ // 1XX: Need to wait for some other response
41
+ let timeout = self . session. configuration. timeoutIntervalForResource
42
+ self . readData ( on: task, minLength: minLength, maxLength: maxLength, timeout: timeout, afterSend: afterSend, completionHandler: completionHandler)
43
+
44
+ // Call afterSend
45
+ afterSend ? ( error)
31
46
return
32
47
}
33
-
34
- if let data = data, let response = String ( data: data, encoding: . utf8) {
35
- completionHandler ( response. trimmingCharacters ( in: . whitespacesAndNewlines) , nil )
36
- } else {
37
- completionHandler ( nil , URLError ( . cannotParseResponse, url: self . url ( of: " " ) ) )
38
- }
48
+ completionHandler ( response. trimmingCharacters ( in: . whitespacesAndNewlines) , nil )
49
+ } else {
50
+ completionHandler ( nil , URLError ( . cannotParseResponse, url: self . url ( of: " " ) ) )
39
51
}
40
52
}
41
53
}
@@ -323,14 +335,28 @@ internal extension FTPFileProvider {
323
335
let success_lock = NSLock ( )
324
336
var success = false
325
337
let command = useMLST ? " MLSD \( path) " : " LIST \( path) "
326
- self . execute ( command: command, on: task, afterSend: { error in
327
- let timeout = self . session. configuration. timeoutIntervalForRequest
328
- var finalData = Data ( )
329
- var eof = false
330
- let error_lock = NSLock ( )
331
- var error : Error ?
332
-
338
+ self . execute ( command: command, on: task) { ( response, error) in
333
339
do {
340
+ if let error = error {
341
+ throw error
342
+ }
343
+
344
+ guard let response = response else {
345
+ throw URLError ( . cannotParseResponse, url: self . url ( of: path) )
346
+ }
347
+
348
+ if response. hasPrefix ( " 500 " ) && useMLST {
349
+ dataTask. cancel ( )
350
+ self . supportsRFC3659 = false
351
+ throw URLError ( . unsupportedURL, url: self . url ( of: path) )
352
+ }
353
+
354
+ let timeout = self . session. configuration. timeoutIntervalForRequest
355
+ var finalData = Data ( )
356
+ var eof = false
357
+ let error_lock = NSLock ( )
358
+ var error : Error ?
359
+
334
360
while !eof {
335
361
let group = DispatchGroup ( )
336
362
group. enter ( )
@@ -361,34 +387,16 @@ internal extension FTPFileProvider {
361
387
}
362
388
}
363
389
364
- guard let response = String ( data: finalData, encoding: . utf8) else {
390
+ guard let dataResponse = String ( data: finalData, encoding: . utf8) else {
365
391
throw URLError ( . badServerResponse, url: self . url ( of: path) )
366
392
}
367
393
368
- let contents : [ String ] = response . components ( separatedBy: " \n " )
394
+ let contents : [ String ] = dataResponse . components ( separatedBy: " \n " )
369
395
. compactMap ( { $0. trimmingCharacters ( in: . whitespacesAndNewlines) } )
370
396
success_lock. try ( )
371
397
success = true
372
398
success_lock. unlock ( )
373
399
completionHandler ( contents, nil )
374
- } catch {
375
- completionHandler ( [ ] , error)
376
- }
377
- } ) { ( response, error) in
378
- do {
379
- if let error = error {
380
- throw error
381
- }
382
-
383
- guard let response = response else {
384
- throw URLError ( . cannotParseResponse, url: self . url ( of: path) )
385
- }
386
-
387
- if response. hasPrefix ( " 500 " ) && useMLST {
388
- dataTask. cancel ( )
389
- self . supportsRFC3659 = false
390
- throw URLError ( . unsupportedURL, url: self . url ( of: path) )
391
- }
392
400
393
401
success_lock. try ( )
394
402
if !success && !( response. hasPrefix ( " 25 " ) || response. hasPrefix ( " 15 " ) ) {
@@ -480,7 +488,7 @@ internal extension FTPFileProvider {
480
488
}
481
489
482
490
// Send retreive command
483
- self . execute ( command: " TYPE I " + " \r \n " + " REST \( position) " + " \r \n " + " RETR \( filePath) " , on: task, afterSend : { error in
491
+ self . execute ( command: " TYPE I " + " \r \n " + " REST \( position) " + " \r \n " + " RETR \( filePath) " , on: task) { ( response , error) in
484
492
// starting passive task
485
493
onTask ? ( dataTask)
486
494
@@ -549,7 +557,7 @@ internal extension FTPFileProvider {
549
557
}
550
558
551
559
completionHandler ? ( nil )
552
- } ) { ( response , error ) in
560
+
553
561
do {
554
562
if let error = error {
555
563
throw error
@@ -695,6 +703,20 @@ internal extension FTPFileProvider {
695
703
}
696
704
let success_lock = NSLock ( )
697
705
var success = false
706
+
707
+ let completed_lock = NSLock ( )
708
+ var completed = false
709
+ func completionOnce( completion: ( ) -> ( ) ) {
710
+ completed_lock. lock ( )
711
+ guard !completed else {
712
+ completed_lock. unlock ( )
713
+ return
714
+ }
715
+ completion ( )
716
+ completed = true
717
+ completed_lock. unlock ( )
718
+ }
719
+
698
720
self . execute ( command: " STOR \( filePath) " , on: task, afterSend: { error in
699
721
onTask ? ( dataTask)
700
722
@@ -708,14 +730,20 @@ internal extension FTPFileProvider {
708
730
stream. open ( )
709
731
710
732
repeat {
733
+ guard !completed else {
734
+ return
735
+ }
736
+
711
737
lock. lock ( )
712
738
var subdata = Data . init ( count: chunkSize)
713
739
let count = subdata. withUnsafeMutableBytes { buffer in
714
740
stream. read ( buffer, maxLength: chunkSize)
715
741
}
716
742
if count < 0 {
717
743
lock. unlock ( )
718
- completionHandler ( stream. streamError ?? URLError ( . requestBodyStreamExhausted, url: self . url ( of: filePath) ) )
744
+ completionOnce {
745
+ completionHandler ( stream. streamError ?? URLError ( . requestBodyStreamExhausted, url: self . url ( of: filePath) ) )
746
+ }
719
747
return
720
748
}
721
749
subdata. count = count
@@ -741,15 +769,20 @@ internal extension FTPFileProvider {
741
769
let waitResult = group. wait ( timeout: . now( ) + timeout)
742
770
743
771
lock. lock ( )
772
+
744
773
if let error = error {
745
774
lock. unlock ( )
746
- completionHandler ( error)
775
+ completionOnce {
776
+ completionHandler ( error)
777
+ }
747
778
return
748
779
}
749
780
750
781
if waitResult == . timedOut {
751
782
lock. unlock ( )
752
- completionHandler ( URLError ( . timedOut, url: self . url ( of: filePath) ) )
783
+ completionOnce {
784
+ completionHandler ( URLError ( . timedOut, url: self . url ( of: filePath) ) )
785
+ }
753
786
return
754
787
}
755
788
lock. unlock ( )
@@ -758,15 +791,14 @@ internal extension FTPFileProvider {
758
791
success_lock. lock ( )
759
792
success = true
760
793
success_lock. unlock ( )
761
- completionHandler ( nil )
762
- } ) { ( response, error) in
763
- success_lock. lock ( )
764
- guard success else {
765
- success_lock. unlock ( )
766
- return
767
- }
768
- success_lock. unlock ( )
769
794
795
+ if self . securedDataConnection {
796
+ dataTask. stopSecureConnection ( )
797
+ }
798
+ // TOFIX: Close read/write stream for receive a FTP response from the server
799
+ dataTask. closeRead ( )
800
+ dataTask. closeWrite ( )
801
+ } ) { ( response, error) in
770
802
do {
771
803
if let error = error {
772
804
throw error
@@ -776,11 +808,38 @@ internal extension FTPFileProvider {
776
808
throw URLError ( . cannotParseResponse, url: self . url ( of: filePath) )
777
809
}
778
810
779
- if !( response. hasPrefix ( " 1 " ) || response. hasPrefix ( " 2 " ) ) {
780
- throw FileProviderFTPError ( message: response)
811
+ let lines = response. components ( separatedBy: " \n " ) . compactMap { $0. isEmpty ? nil : $0. trimmingCharacters ( in: . whitespacesAndNewlines) }
812
+ if lines. count > 0 {
813
+ for line in lines {
814
+ if !( line. hasPrefix ( " 1 " ) || line. hasPrefix ( " 2 " ) ) {
815
+ // FTP Error Response
816
+ throw FileProviderFTPError ( message: response)
817
+ }
818
+ }
819
+ }
820
+
821
+ success_lock. lock ( )
822
+ if success, let last = lines. last, last. hasPrefix ( " 2 " ) {
823
+ success_lock. unlock ( )
824
+ // File successfully transferred.
825
+ completionOnce {
826
+ completionHandler ( nil )
827
+ }
828
+ return
829
+ } else {
830
+ success_lock. unlock ( )
831
+ throw URLError ( . cannotCreateFile, url: self . url ( of: filePath) )
781
832
}
782
833
} catch {
783
- completionHandler ( error)
834
+ success_lock. lock ( )
835
+ if !success {
836
+ dataTask. cancel ( )
837
+ }
838
+ success_lock. unlock ( )
839
+
840
+ completionOnce {
841
+ completionHandler ( error)
842
+ }
784
843
}
785
844
}
786
845
}
0 commit comments