A little bit of a nit - when tracking progress you can ditch the mutex by using atomic integers for the download progress. Instead of using locks, your test for a chunk being done becomes something like "downloaded == chunk_size".
You also never call UpdateChunkProgress, FYI! The code is a little confusing to read because of that dead variable, at first I thought that chunks are never resumed. ProgressTracker and State/ChunkInfo do similar things, if I were in your shoes I'd make it so that there's clear ownership over where progress is actually tracked.
...I'd probably move State to be saved on the _start_ of the download, have it solely be responsible for tracking the arguments that the download was called with. Rename it to DownloadArguments, delete all the runtime state tracking, as it's already inferred by the downloader on start.