From b0124c4fb0fea355eb8e94a7a154858aa4d361fc Mon Sep 17 00:00:00 2001 From: Danny Weinberg Date: Fri, 1 Feb 2019 14:22:36 -0800 Subject: [PATCH] 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 ``` --- Library/Homebrew/test/cask/cmd/info_spec.rb | 28 +++++++++++++++++++++ Library/Homebrew/utils/curl.rb | 18 ++++++++++--- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/Library/Homebrew/test/cask/cmd/info_spec.rb b/Library/Homebrew/test/cask/cmd/info_spec.rb index 1685b22483..ae5ad215ef 100644 --- a/Library/Homebrew/test/cask/cmd/info_spec.rb +++ b/Library/Homebrew/test/cask/cmd/info_spec.rb @@ -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 diff --git a/Library/Homebrew/utils/curl.rb b/Library/Homebrew/utils/curl.rb index 5b0c5a66db..bcc47d4394 100644 --- a/Library/Homebrew/utils/curl.rb +++ b/Library/Homebrew/utils/curl.rb @@ -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