diff --git a/app/logical/downloads/file.rb b/app/logical/downloads/file.rb index 28372e8be..68d8faafd 100644 --- a/app/logical/downloads/file.rb +++ b/app/logical/downloads/file.rb @@ -36,7 +36,7 @@ module Downloads url, headers, @data = before_download(@source, @data) ::File.open(@file_path, "wb") do |out| - http_get_streaming(url, headers) do |response| + http_get_streaming(uncached_url(url, headers), headers) do |response| out.write(response) end end @@ -133,5 +133,27 @@ module Downloads src end end + + private + + # Prevent Cloudflare from potentially mangling the image. See issue #3528. + def uncached_url(url, headers = {}) + url = Addressable::URI.parse(url) + + if is_cloudflare?(url, headers) + url.query_values = (url.query_values || {}).merge(danbooru_no_cache: SecureRandom.uuid) + end + + url + end + + def is_cloudflare?(url, headers = {}) + Cache.get("is_cloudflare:#{url.origin}", 4.hours) do + res = HTTParty.head(url, { headers: headers }.deep_merge(Danbooru.config.httparty_options)) + raise Error.new("HTTP error code: #{res.code} #{res.message}") unless res.success? + + res.key?("CF-Ray") + end + end end end diff --git a/test/unit/downloads/art_station_test.rb b/test/unit/downloads/art_station_test.rb index a7db904d5..077007b8d 100644 --- a/test/unit/downloads/art_station_test.rb +++ b/test/unit/downloads/art_station_test.rb @@ -28,6 +28,13 @@ module Downloads end end + context "a download for an ArtStation image hosted on CloudFlare" do + should "return the original file, not the polished file" do + @source = "https://cdnb.artstation.com/p/assets/images/images/003/716/071/large/aoi-ogata-hate-city.jpg?1476754974" + assert_downloaded(517_706, @source) # polished size: 502_052 + end + end + context "a download for a https://$artist.artstation.com/projects/$id page" do setup do @source = "https://dantewontdie.artstation.com/projects/YZK5q"