Cask handle already downloaded file

The current logic for curl_download tries to restart any existing
partial download, but this fails for some servers when the file is
already fully downloaded, returning a status code 416. This updates the
function to check for the file being already downloaded and if so bails
early.

The following command used to fail when run more than once but now works
as expected:
```
brew cask info https://raw.githubusercontent.com/homebrew/homebrew-cask/master/Casks/docker.rb
```
This commit is contained in:
Danny Weinberg 2019-02-01 14:22:36 -08:00
parent 1920eecb71
commit b0124c4fb0
2 changed files with 42 additions and 4 deletions

View File

@ -136,4 +136,32 @@ describe Cask::Cmd::Info, :cask do
Caffeine.app (App)
EOS
end
it "can run be run with a url twice" do
expect {
described_class.run("https://raw.githubusercontent.com/Homebrew/homebrew-cask" \
"/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb")
described_class.run("https://raw.githubusercontent.com/Homebrew/homebrew-cask" \
"/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb")
}.to output(<<~EOS).to_stdout
==> Downloading https://raw.githubusercontent.com/Homebrew/homebrew-cask/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb.
docker: 2.0.0.2-ce-mac81,30215 (auto_updates)
https://www.docker.com/community-edition
Not installed
==> Names
Docker Community Edition
Docker CE
==> Artifacts
Docker.app (App)
==> Downloading https://raw.githubusercontent.com/Homebrew/homebrew-cask/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb.
docker: 2.0.0.2-ce-mac81,30215 (auto_updates)
https://www.docker.com/community-edition
Not installed
==> Names
Docker Community Edition
Docker CE
==> Artifacts
Docker.app (App)
EOS
end
end

View File

@ -51,10 +51,20 @@ def curl_download(*args, to: nil, **options)
destination = Pathname(to)
destination.dirname.mkpath
continue_at = if destination.exist? &&
curl_output("--location", "--range", "0-1",
"--write-out", "%{http_code}",
"--output", "/dev/null", *args, **options).stdout.to_i == 206 # Partial Content
range_stdout = curl_output("--location", "--range", "0-1",
"--dump-header", "-",
"--write-out", "%{http_code}",
"--output", "/dev/null", *args, **options).stdout
headers, _, http_status = range_stdout.partition("\r\n\r\n")
supports_partial_download = http_status.to_i == 206 # Partial Content
if supports_partial_download &&
destination.exist? &&
destination.size == %r{^.*Content-Range: bytes \d+-\d+/(\d+)\r\n.*$}m.match(headers)[1].to_i
return # We've already downloaded all the bytes
end
continue_at = if destination.exist? && supports_partial_download
"-"
else
0