@@ -113,18 +113,66 @@ function createNSRequest(url: string): NSMutableURLRequest {
113113
114114class HttpsResponseLegacy implements IHttpsResponseLegacy {
115115 // private callback?: com.nativescript.https.OkhttpResponse.OkHttpResponseAsyncCallback;
116+ private tempFilePath ?: string ;
117+
116118 constructor (
117119 private data : NSDictionary < string , any > & NSData & NSArray < any > ,
118120 public contentLength ,
119- private url : string
120- ) { }
121+ private url : string ,
122+ tempFilePath ?: string
123+ ) {
124+ this . tempFilePath = tempFilePath ;
125+ }
126+
127+ // Helper to ensure data is loaded from temp file if needed
128+ private ensureDataLoaded ( ) : boolean {
129+ // If we have data already, we're good
130+ if ( this . data ) {
131+ return true ;
132+ }
133+
134+ // If we have a temp file, load it into memory
135+ if ( this . tempFilePath ) {
136+ try {
137+ this . data = NSData . dataWithContentsOfFile ( this . tempFilePath ) as any ;
138+ return this . data != null ;
139+ } catch ( e ) {
140+ console . error ( 'Failed to load data from temp file:' , e ) ;
141+ return false ;
142+ }
143+ }
144+
145+ return false ;
146+ }
147+
148+ // Helper to get temp file path or create from data
149+ private getTempFilePath ( ) : string | null {
150+ if ( this . tempFilePath ) {
151+ return this . tempFilePath ;
152+ }
153+
154+ // If we have data but no temp file, create a temp file
155+ if ( this . data && this . data instanceof NSData ) {
156+ const tempDir = NSTemporaryDirectory ( ) ;
157+ const tempFileName = NSUUID . UUID ( ) . UUIDString ;
158+ const tempPath = tempDir + tempFileName ;
159+ const success = this . data . writeToFileAtomically ( tempPath , true ) ;
160+ if ( success ) {
161+ this . tempFilePath = tempPath ;
162+ return tempPath ;
163+ }
164+ }
165+
166+ return null ;
167+ }
168+
121169 toArrayBufferAsync ( ) : Promise < ArrayBuffer > {
122170 throw new Error ( 'Method not implemented.' ) ;
123171 }
124172
125173 arrayBuffer : ArrayBuffer ;
126174 toArrayBuffer ( ) {
127- if ( ! this . data ) {
175+ if ( ! this . ensureDataLoaded ( ) ) {
128176 return null ;
129177 }
130178 if ( this . arrayBuffer ) {
@@ -139,7 +187,7 @@ class HttpsResponseLegacy implements IHttpsResponseLegacy {
139187 }
140188 stringResponse : string ;
141189 toString ( encoding ?: any ) {
142- if ( ! this . data ) {
190+ if ( ! this . ensureDataLoaded ( ) ) {
143191 return null ;
144192 }
145193 if ( this . stringResponse ) {
@@ -168,7 +216,7 @@ class HttpsResponseLegacy implements IHttpsResponseLegacy {
168216 }
169217 jsonResponse : any ;
170218 toJSON < T > ( encoding ?: any ) {
171- if ( ! this . data ) {
219+ if ( ! this . ensureDataLoaded ( ) ) {
172220 return null ;
173221 }
174222 if ( this . jsonResponse ) {
@@ -192,7 +240,7 @@ class HttpsResponseLegacy implements IHttpsResponseLegacy {
192240 }
193241 imageSource : ImageSource ;
194242 async toImage ( ) : Promise < ImageSource > {
195- if ( ! this . data ) {
243+ if ( ! this . ensureDataLoaded ( ) ) {
196244 return Promise . resolve ( null ) ;
197245 }
198246 if ( this . imageSource ) {
@@ -212,30 +260,58 @@ class HttpsResponseLegacy implements IHttpsResponseLegacy {
212260 }
213261 file : File ;
214262 async toFile ( destinationFilePath ?: string ) : Promise < File > {
215- if ( ! this . data ) {
216- return Promise . resolve ( null ) ;
217- }
218263 if ( this . file ) {
219264 return Promise . resolve ( this . file ) ;
220265 }
266+
221267 const r = await new Promise < File > ( ( resolve , reject ) => {
222268 if ( ! destinationFilePath ) {
223269 destinationFilePath = getFilenameFromUrl ( this . url ) ;
224270 }
225- if ( this . data instanceof NSData ) {
226- // ensure destination path exists by creating any missing parent directories
271+
272+ // If we have a temp file, move it to destination (efficient, no memory copy)
273+ if ( this . tempFilePath ) {
274+ try {
275+ const fileManager = NSFileManager . defaultManager ;
276+ const destURL = NSURL . fileURLWithPath ( destinationFilePath ) ;
277+ const tempURL = NSURL . fileURLWithPath ( this . tempFilePath ) ;
278+
279+ // Create parent directory if needed
280+ const parentDir = destURL . URLByDeletingLastPathComponent ;
281+ fileManager . createDirectoryAtURLWithIntermediateDirectoriesAttributesError ( parentDir , true , null ) ;
282+
283+ // Remove destination if it exists
284+ if ( fileManager . fileExistsAtPath ( destinationFilePath ) ) {
285+ fileManager . removeItemAtPathError ( destinationFilePath ) ;
286+ }
287+
288+ // Move temp file to destination
289+ const success = fileManager . moveItemAtURLToURLError ( tempURL , destURL ) ;
290+ if ( success ) {
291+ // Clear temp path since file has been moved
292+ this . tempFilePath = null ;
293+ resolve ( File . fromPath ( destinationFilePath ) ) ;
294+ } else {
295+ reject ( new Error ( `Failed to move temp file to: ${ destinationFilePath } ` ) ) ;
296+ }
297+ } catch ( e ) {
298+ reject ( new Error ( `Cannot save file with path: ${ destinationFilePath } . ${ e } ` ) ) ;
299+ }
300+ }
301+ // Fallback: if we have data in memory, write it
302+ else if ( this . ensureDataLoaded ( ) && this . data instanceof NSData ) {
227303 const file = File . fromPath ( destinationFilePath ) ;
228-
229304 const result = this . data . writeToFileAtomically ( destinationFilePath , true ) ;
230305 if ( result ) {
231306 resolve ( file ) ;
232307 } else {
233308 reject ( new Error ( `Cannot save file with path: ${ destinationFilePath } .` ) ) ;
234309 }
235310 } else {
236- reject ( new Error ( `Cannot save file with path : ${ destinationFilePath } .` ) ) ;
311+ reject ( new Error ( `No data available to save to file : ${ destinationFilePath } .` ) ) ;
237312 }
238313 } ) ;
314+
239315 this . file = r ;
240316 return r ;
241317 }
@@ -549,8 +625,63 @@ export function createRequest(opts: HttpsRequestOptions, useLegacy: boolean = tr
549625 } else if ( typeof opts . content === 'string' ) {
550626 dict = NSJSONSerialization . JSONObjectWithDataOptionsError ( NSString . stringWithString ( opts . content ) . dataUsingEncoding ( NSUTF8StringEncoding ) , 0 as any ) ;
551627 }
552- task = manager . request ( opts . method , opts . url , dict , headers , progress , progress , success , failure ) ;
553- task . resume ( ) ;
628+
629+ // For GET requests, use streaming download to temp file (memory efficient)
630+ if ( opts . method === 'GET' ) {
631+ const downloadTask = manager . downloadToTemp (
632+ opts . method ,
633+ opts . url ,
634+ dict ,
635+ headers ,
636+ progress ,
637+ ( response : NSURLResponse , tempFilePath : string , error : NSError ) => {
638+ clearRunningRequest ( ) ;
639+ if ( error ) {
640+ // Convert download task to data task for failure handling
641+ const dataTask = ( task as any ) as NSURLSessionDataTask ;
642+ failure ( dataTask , error ) ;
643+ return ;
644+ }
645+
646+ const httpResponse = response as NSHTTPURLResponse ;
647+ const contentLength = httpResponse ?. expectedContentLength || 0 ;
648+
649+ // Create response with temp file path (no data loaded in memory yet)
650+ const content = useLegacy
651+ ? new HttpsResponseLegacy ( null , contentLength , opts . url , tempFilePath )
652+ : tempFilePath ;
653+
654+ let getHeaders = ( ) => ( { } ) ;
655+ const sendi = {
656+ content,
657+ contentLength,
658+ get headers ( ) {
659+ return getHeaders ( ) ;
660+ }
661+ } as any as HttpsResponse ;
662+
663+ if ( ! Utils . isNullOrUndefined ( httpResponse ) ) {
664+ sendi . statusCode = httpResponse . statusCode ;
665+ getHeaders = function ( ) {
666+ const dict = httpResponse . allHeaderFields ;
667+ if ( dict ) {
668+ const headers = { } ;
669+ dict . enumerateKeysAndObjectsUsingBlock ( ( k , v ) => ( headers [ k ] = v ) ) ;
670+ return headers ;
671+ }
672+ return null ;
673+ } ;
674+ }
675+ resolve ( sendi ) ;
676+ }
677+ ) ;
678+
679+ task = downloadTask as any ;
680+ } else {
681+ // For non-GET requests, use regular request (loads into memory)
682+ task = manager . request ( opts . method , opts . url , dict , headers , progress , progress , success , failure ) ;
683+ task . resume ( ) ;
684+ }
554685 }
555686 if ( task && tag ) {
556687 runningRequests [ tag ] = task ;
0 commit comments