github tonikelope/megabasterd v8.56
MegaBasterd 8.56

5 hours ago

TL;DR

  • Fixes intermittent SSLHandshakeException: Received fatal alert: handshake_failure while uploading file thumbnails. The file itself uploaded fine — the failure happened in the post-upload thumbnail step (MegaAPI.uploadThumbnails), so the symptom was a finished upload with a silently missing thumbnail and a GRAVE stack trace in the DEBUG LOG. No file or queue data was ever lost.

  • Root cause: the thumbnail upload was the only hop in the entire upload pipeline that forced TLS. The file-data request ({"a":"u"}) asks MEGA for a plain-HTTP gfs… storage URL and the chunk uploaders stream over HTTP. The thumbnail/attribute request ({"a":"ufa"}) was hardcoded with "ssl":1, which makes MEGA hand back an HTTPS gfs… URL. The handshake_failure alert is sent by the storage node, not the JVM — some gfs upload nodes intermittently reject the offered TLS handshake, even though the API endpoint (api.mega…) negotiates HTTPS without issue. So only the thumbnail leg failed.

  • Fix part 1 — drop "ssl":1 from the ufa request. The thumbnail bytes are already AES-CBC encrypted with the file key (_encThumbAttr) before they are sent, exactly like the file chunks, so plain HTTP is no less secure than the transport the file data already uses. This removes the only TLS handshake in the upload path and eliminates the failure mode at the source.

  • Fix part 2 — retry with exponential backoff. Each thumbnail leg is now wrapped in a retry loop (MAX_THUMBNAIL_UPLOAD_RETRIES = 5, reusing MiscTools.getWaitTimeExpBackOff) so a transient network/IOException no longer drops the thumbnail on the first hiccup. The connection is reopened cleanly on every attempt, the loop bails early if the upload is stopped, and IOException (which SSLHandshakeException extends) is caught defensively in case MEGA ever changes the endpoint behaviour again.

What was wrong

uploadThumbnails built its attribute-upload request as:

[{"a":"ufa", "s":..., "ssl":1}, {"a":"ufa", "s":..., "ssl":1}]

MEGA returns a p upload URL per attribute. With "ssl":1 that URL is https://gfs…, so con.getOutputStream() triggers a TLS handshake against the storage node. When the node answered with a fatal handshake_failure alert, the exception propagated out of the per-URL loop, was swallowed by the method's outer catch (Exception), and the method returned "" — the file stayed uploaded but with no thumbnail, leaving only this in the log:

GRAVE: ... javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at ...MegaAPI.uploadThumbnails(MegaAPI.java:1213)
    at ...Upload.run(Upload.java:1005)

The file-data path never hit this because initUploadFile sends {"a":"u","s":...} with no ssl flag and uploads chunks over plain HTTP.

What changes

MegaAPI.uploadThumbnails:

  • The ufa request no longer carries "ssl":1, so the thumbnail uploads over HTTP just like the file chunks (data is still AES-CBC encrypted end-to-end).
  • Each of the two attribute legs (thumbnail 0 and preview 1) now runs inside a retry loop bounded by the new MegaAPI.MAX_THUMBNAIL_UPLOAD_RETRIES = 5 constant, with exponential backoff between attempts and a fresh HttpURLConnection per try. The loop stops early when upload.isStopped().

If all retries are exhausted the behaviour is unchanged from before — the file remains correctly uploaded, only the thumbnail is skipped — but now the DEBUG LOG shows an explicit WARNING per retry instead of a single silent GRAVE.

Other

  • Version bumped to 8.56 in pom.xml and MainPanel.VERSION.
  • No changes to the file-data transfer path, the resume queue, the account-login flow, the MEGA error-popup machinery, the SmartProxy machinery, the post-finish hooks, or any i18n bundle.
  • Note left for a future pass: the thumbnail connection still does not route through the configured HTTP/SmartProxy (it opens a direct connection), unlike the API and chunk paths. Out of scope for this fix.

Don't miss a new megabasterd release

NewReleases is sending notifications on new releases.