Skip to content

v2.1.0 - Resumable downloads, multipart uploads, progress and cancel callbacks

Choose a tag to compare

@github-actions github-actions released this 05 Oct 18:15
· 5 commits to main since this release

MATLAB Versions Tested

webprogress.download can continue an interrupted download, and webprogress.upload can send one part of a file and show a multipart upload in one display. Both can report progress to a function you supply and stop when it asks them to. Existing code keeps working, with two changes to read under Changed: a transfer that receives no data for 60 seconds now stops with an error, and the Cancel button of the progress dialog raises an error that a try/catch block can handle.

Added

  • webprogress.download(...,Resume=true) keeps the part of the file received so far in FILENAME.part when a download fails or is interrupted, and a later call with Resume=true asks the server for the rest only. The entity tag and length of the file are kept in FILENAME.part.json, so the URL may change between calls, as a presigned URL does. When the file has changed on the server, the server cannot send a range, or it gives the file no strong ETag, the download starts from the beginning. A folder target raises webprogress:download:FolderTargetNotResumable. Two MATLAB sessions must not resume the same FILENAME: they write the same partial file and corrupt it (#25).
  • webprogress.upload accepts Offset and NumBytes to send one byte range of a file, with its length in Content-Length. Every request reads the range from its start, so a part can be sent again after a failure or a redirect. A range outside the file, including an Offset at the end of the file, raises webprogress:upload:RangeOutsideFile; NumBytes=0 raises MATLAB:validators:mustBePositive; a file that shrinks during the upload raises webprogress:upload:FileChanged (#26).
  • webprogress.MultipartProgressMonitor(TOTALBYTES) shows one progress display for a file uploaded in several requests. Pass it to each part with webprogress.upload(...,ProgressMonitor=MONITOR); a part the server accepts is added to CompletedBytes, a part that fails is not, and close(monitor) closes the display or prints the completion message. CompletedBytes=N at construction starts a monitor at the bytes a server already accepted, to continue an upload after a cancel (#26, #33).
  • ProgressFcn on webprogress.download, webprogress.upload and both monitor classes is called with a struct of ActionName, TransferredBytes and TotalBytes, at most once per UpdateInterval and once more when the transfer is done. DisplayMode="None" turns the built-in display off, so the progress can be shown in an app of your own (#27).
  • CancelRequestedFcn on the same functions and classes is called before a transfer and at most once per UpdateInterval while it runs, and stops the transfer when it returns true. webprogress.download and webprogress.upload then raise webprogress:download:Cancelled or webprogress:upload:Cancelled; upload raises it also when called with outputs. A cancelled download saves no file, and with Resume=true keeps its partial file (#27).
  • DataTimeout=SECONDS on webprogress.download and webprogress.upload sets how long a transfer may receive no data before it stops with webprogress:download:TransferStalled or webprogress:upload:TransferStalled; Inf waits without limit (#31).
  • webprogress.FileTransferProgressMonitor accepts StartBytes, the bytes of the file transferred before this transfer, which count toward the progress but not toward the remaining-time estimate (#25).

Changed

  • A transfer that receives no data for 60 seconds, the default DataTimeout, raises TransferStalled, where v2.0.0 waited without limit. Pass DataTimeout=Inf to keep waiting (#31).
  • The Cancel button of the progress dialog raises webprogress:download:Cancelled or webprogress:upload:Cancelled at the next progress report, which a try/catch block can handle. In v2.0.0 it stopped the call the way Ctrl+C does, past every catch block. A cancel acts at the next progress report, so a transfer that has stopped receiving data ends through DataTimeout instead (#27).

Fixed

  • An upload whose server replies with a body, as Dropbox does with JSON, is described as an upload to the end. In v2.0.0 the display switched to the reply, and the completion message described a download of 0 MB. The reply's bytes no longer replace the uploaded byte count in the display, the completion message or the reports to ProgressFcn (#27).

Documentation

  • The README shows how to drive a display of your own with ProgressFcn, DisplayMode="None" and CancelRequestedFcn (#27).

Internal

  • AGENTS.md records that the resume, multipart, callback and timeout layers were reviewed for structure, naming and tests rather than for HTTP semantics, and lists the behaviour of the MATLAB HTTP stack that was established by probing it (#33).
  • The test suite grows to 154 tests in nine classes. The local test server honours byte ranges and ETags, can truncate, delay, redirect and stall a transfer, echoes uploaded bodies, and lists the requests it received. DownloadResumeTest, UploadRangeTest and ProgressCallbackTest are new (#25, #26, #27, #31).
  • captureOutput and listFiles are shared from tests/helpers instead of copied into each test class (#30).
  • The short-download progress tests get a body that lasts longer than the monitor's first-call interval, so they no longer fail when the body arrives within 10 ms (#29).
  • A test lists open files with fopen('all') before R2024a, where openedFiles does not exist (#35).
All merged pull requests

What's Changed

  • test: delay the body in the short download progress tests by @ehennestad in #29
  • feat: resume an interrupted download with Resume=true by @ehennestad in #25
  • feat: upload a byte range of a file and show parts in one display by @ehennestad in #26
  • feat: report progress to a callback and cancel a transfer on request by @ehennestad in #27
  • test: share captureOutput and listFiles between the test classes by @ehennestad in #30
  • feat: stop a transfer that receives no data for DataTimeout seconds by @ehennestad in #31
  • feat: start a MultipartProgressMonitor at the bytes already accepted by @ehennestad in #33
  • test: list open files with fopen('all') before R2024a by @ehennestad in #35

Full Changelog: v2.0.0...v2.1.0