Skip to content

Conversation

@bajrangCoder
Copy link
Member

@bajrangCoder bajrangCoder commented Jan 13, 2026

  • Improve hashCode() to produce 48-char hex (192-bit) output using FNV-1a inspired multi-pass algorithm
  • SFTP: Use "wt" mode in openOutputStream() to truncate before write
  • FTP: Explicitly delete cache file before writing new content
  • FTP: Refactor to try-with-resources for proper stream handling

Fixes #1436 , #1470 , #1740 , #1735

- Improve hashCode() to produce 48-char hex (192-bit) output using
  FNV-1a inspired multi-pass algorithm
- SFTP: Use "wt" mode in openOutputStream() to truncate before write
- FTP: Explicitly delete cache file before writing new content
- FTP: Refactor to try-with-resources for proper stream handling

Fixes Acode-Foundation#1436 , Acode-Foundation#1470 , Acode-Foundation#1740
@greptile-apps
Copy link

greptile-apps bot commented Jan 13, 2026

Greptile Overview

Greptile Summary

This PR addresses mixed content issues in FTP/SFTP cached files through three main changes:

Hash Algorithm Enhancement

The hashCode() function was upgraded from a simple 32-bit hash to a 192-bit (48-character hex) FNV-1a inspired multi-pass algorithm. This dramatically reduces hash collision probability for cache file naming. However, the empty string case returns "0" (1 char) instead of the full 48-char format, creating an inconsistency. Note that this change invalidates all existing cached files since the hash format has changed.

SFTP Cache Truncation

The SFTP plugin now uses "wt" mode when opening the output stream (contentResolver.openOutputStream(fileUri, "wt")), which properly truncates the file before writing. This follows existing patterns in the codebase (sdcard plugin uses "rwt" and "wa" modes) and cleanly prevents stale content from remaining in cached files.

FTP Resource Management & Cache Clearing

The FTP plugin was refactored to use try-with-resources for proper stream handling in both downloadFile() and uploadFile() methods. Additionally, the code now explicitly deletes existing cache files before downloading. However, there's a critical issue: when retrieveFileStream() or storeFileStream() returns null, the methods return early without calling completePendingCommand(), which is required by Apache Commons Net FTP to complete the transaction. This can leave the FTP connection in an inconsistent state.

Confidence Score: 2/5

  • This PR has critical FTP connection state management issues that could cause subsequent operations to fail or hang
  • The score reflects significant issues found: (1) FTP methods skip completePendingCommand() on null stream returns, violating Apache Commons Net requirements and potentially leaving connections in inconsistent states; (2) hashCode empty string handling is inconsistent with the stated 48-char format; (3) unchecked delete() return value could hide failures. The SFTP changes are solid, but the FTP implementation needs fixes before merging.
  • Pay close attention to src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java - the completePendingCommand() issue needs resolution to prevent FTP connection problems

Important Files Changed

File Analysis

Filename Score Overview
src/utils/polyfill.js 3/5 Upgraded hashCode from 32-bit to 192-bit FNV-1a inspired algorithm with 6 passes, but has inconsistent empty string handling that returns "0" instead of 48-char format
src/plugins/sftp/src/com/foxdebug/sftp/Sftp.java 5/5 Added "wt" mode to openOutputStream for proper truncation before write, cleanly prevents stale content - follows existing patterns in codebase
src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java 2/5 Refactored to try-with-resources and added cache file deletion, but early returns skip completePendingCommand() causing potential FTP connection state issues

Sequence Diagram

sequenceDiagram
    participant User
    participant JS as JavaScript (FTP/SFTP)
    participant Hash as String.hashCode()
    participant Java as FTP/SFTP Plugin
    participant Cache as Cache Storage
    participant Remote as FTP/SFTP Server

    User->>JS: Open remote file
    JS->>Hash: Generate cache filename from URL
    Note over Hash: OLD: 32-bit hash<br/>NEW: 192-bit (48-char hex)
    Hash-->>JS: Cache filename
    
    alt FTP Download
        JS->>Java: downloadFile(remoteFile, cacheFile)
        Java->>Cache: Delete existing cache file
        Java->>Remote: retrieveFileStream(path)
        Remote-->>Java: InputStream
        Java->>Java: NEW: try-with-resources<br/>opens FileOutputStream
        Java->>Cache: Write to cache file
        Java->>Remote: completePendingCommand()
        Java-->>JS: Success
    else SFTP Download
        JS->>Java: getFile(remoteFile, cacheFile)
        Java->>Remote: getInputStream(filename)
        Remote-->>Java: InputStream
        Java->>Cache: NEW: openOutputStream(uri, "wt")<br/>truncates before write
        Java->>Cache: Write to cache file
        Java-->>JS: Success
    end
    
    JS-->>User: Display file content from cache
Loading

greptile-apps[bot]

This comment was marked as resolved.

@greptile-apps

This comment was marked as resolved.

@bajrangCoder bajrangCoder added the CI: RUN ON-DEMAND PREVIEW RELEASES Triggers an on-demand preview build for this pull request via CI workflow. label Jan 13, 2026
@github-actions github-actions bot removed the CI: RUN ON-DEMAND PREVIEW RELEASES Triggers an on-demand preview build for this pull request via CI workflow. label Jan 13, 2026
@github-actions

This comment has been minimized.

@github-actions
Copy link

Preview Release for this, has been built.

Click here to view that github actions build

@bajrangCoder
Copy link
Member Author

Apk is available , test it out and let me know

@RohitKushvaha01

This comment was marked as resolved.

@RohitKushvaha01 RohitKushvaha01 marked this pull request as draft January 13, 2026 09:49
@bajrangCoder bajrangCoder marked this pull request as ready for review January 13, 2026 12:17
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +606 to +613
if (inputStream == null) {
Log.d(
"FTP",
"FTPClient (" + ftpId + ") path: " + path + " - not found"
);
callback.error("File not found.");
return;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When inputStream is null, the method returns early without calling ftp.completePendingCommand(). According to Apache Commons Net FTP documentation, completePendingCommand() must be called after using streaming methods like retrieveFileStream() to complete the FTP transaction, even if the stream is null.

Without calling completePendingCommand(), the FTP connection may be left in an inconsistent state, potentially causing subsequent FTP operations to fail or hang.

Consider checking for null before entering the try-with-resources block, or calling completePendingCommand() in a finally block to ensure it always executes.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java
Line: 606:613

Comment:
When `inputStream` is null, the method returns early without calling `ftp.completePendingCommand()`. According to Apache Commons Net FTP documentation, `completePendingCommand()` must be called after using streaming methods like `retrieveFileStream()` to complete the FTP transaction, even if the stream is null.

Without calling `completePendingCommand()`, the FTP connection may be left in an inconsistent state, potentially causing subsequent FTP operations to fail or hang.

Consider checking for null before entering the try-with-resources block, or calling `completePendingCommand()` in a finally block to ensure it always executes.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +692 to +695
if (outputStream == null) {
callback.error("File not found.");
return;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When outputStream is null, the method returns early without calling ftp.completePendingCommand(). According to Apache Commons Net FTP documentation, completePendingCommand() must be called after using streaming methods like storeFileStream() to complete the FTP transaction.

Without calling completePendingCommand(), the FTP connection may be left in an inconsistent state, potentially causing subsequent FTP operations to fail or hang.

Consider checking for null before entering the try-with-resources block, or ensuring completePendingCommand() is called in a finally block.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java
Line: 692:695

Comment:
When `outputStream` is null, the method returns early without calling `ftp.completePendingCommand()`. According to Apache Commons Net FTP documentation, `completePendingCommand()` must be called after using streaming methods like `storeFileStream()` to complete the FTP transaction.

Without calling `completePendingCommand()`, the FTP connection may be left in an inconsistent state, potentially causing subsequent FTP operations to fail or hang.

Consider checking for null before entering the try-with-resources block, or ensuring `completePendingCommand()` is called in a finally block.

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Caching Causing File Mixing

2 participants