hierynomus / hierynomus/sshj

Exception when using ReadAheadRemoteFileInputStream with S3 Upload

Open
#505 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
2.7k
Forks
620
Avg merge
3d 23h
Merged PRs (30d)
11

Description

I am working on a problem transferring a file via SFTP (using sshj 0.27.0) to Amazon S3. I'm encountering an Amazon SDK exception along the following lines:

`com.amazonaws.SdkClientException: Data read has a different length than the expected: dataLength=4221930; expectedLength=7105558; includeSkipped=false; in.getClass()=class com.amazonaws.internal.ReleasableInputStream; markedSupported=false; marked=0; resetSinceLastMarked=false; markCount=0; resetCount=`

This is a 7105558 byte file. Upon inspecting the state of the `ReadAheadRemoteFileInputStream` (which was initialized with `maxUnconfirmedReads` = 64) at the time this AWS SDK exception is thrown, I can see the following state:

- `unconfirmedReads` - a list of around 17+ items, and each is a STATUS packet (implying all data has been received)
- `unconfirmedReadOffsets` - a list of identical length, starting from an offset beyond the file size (as expected, I think)
- `requestOffset` - 9856068 (a value well beyond the file size)
- `responseOffset` - 4221930 (this is the same byte count that is reported in the error, which I assume is the number of bytes that have been loaded from the file and uploaded to S3 so far)

Further debugging shows that [this condition](https://github.com/hierynomus/sshj/blob/v0.27.0/src/main/java/net/schmizz/sshj/sftp/RemoteFile.java#L270) is being hit. But at that time, the `responseOffset` = 4221930 as well, so it seems as though the entire stream hasn't been read at the time the EOF triggers.

I have tried creating a simple standalone application that sends a file to S3, where this problem can be reproduced. This problem only happens if the content length for the S3 upload request is set. If left unset, the transfer doesn't fail, but the complete file does NOT end up in S3 (see switch in behavior below). It also only happens with the `ReadAheadRemoteFileInputStream` (if you change the code to use `RemoteFileInputStream` instead, the problem does not happen). That makes it hard for me to understand whether it's a bug in sshj or the S3 SDK.

- Install JDK 8 and Gradle if you don't already have them
- Obtain an AWS Access Key ID and Secret if you don't have them
- Clone [the repository](https://github.com/jeff303/sshj-s3-test)
- Prepare an SFTP server with a single large (5 MB+) file
- Update the `app.properties` file to fill in your own SFTP server info, file path, and S3 info
- Use `gradle run` command to run the sample application and reproduce the issue, as outlined below

```
gradle run
# the application will run, and should complete successfully

# set an environment variable that controls the contentLength setting for S3, and sets it to the same byte length retrieved by sshj
export SET_S3_CONTENT_LENGTH=true
# run it again
gradle run
# this time, the application will fail with an exception like the one above
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.