lib/down.rb in down-2.3.5 vs lib/down.rb in down-2.3.6
- old
+ new
@@ -1,6 +1,7 @@
require "down/version"
+require "down/chunked_io"
require "open-uri"
require "net/http"
require "tempfile"
require "fileutils"
@@ -79,10 +80,11 @@
def stream(url, options = {})
warn "Down.stream is deprecated and will be removed in Down 3. Use Down.open instead."
io = open(url, options)
io.each_chunk { |chunk| yield chunk, io.size }
+ io.close
end
def open(url, options = {})
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
@@ -111,15 +113,16 @@
end
end
end
response = request.resume
- content_length = Integer(response["Content-Length"]) if response["Content-Length"]
- chunks = response.to_enum(:read_body)
- close_connection = -> { request.resume }
- ChunkedIO.new(size: content_length, chunks: chunks, on_close: close_connection)
+ ChunkedIO.new(
+ chunks: response.enum_for(:read_body),
+ size: response["Content-Length"] && response["Content-Length"].to_i,
+ on_close: -> { request.resume },
+ )
end
def copy_to_tempfile(basename, io)
tempfile = Tempfile.new(["down", File.extname(basename)], binmode: true)
if io.is_a?(OpenURI::Meta) && io.is_a?(Tempfile)
@@ -132,88 +135,23 @@
end
tempfile.open
tempfile
end
- class ChunkedIO
- attr_reader :tempfile
-
- def initialize(options)
- @size = options.fetch(:size)
- @chunks = options.fetch(:chunks)
- @on_close = options.fetch(:on_close, ->{})
- @tempfile = Tempfile.new("down", binmode: true)
+ module DownloadedFile
+ def original_filename
+ filename_from_content_disposition || filename_from_uri
end
- def size
- @size
- end
-
- def read(length = nil, outbuf = nil)
- download_chunk until enough_downloaded?(length) || download_finished?
- @tempfile.read(length, outbuf)
- end
-
- def each_chunk
- return enum_for(__method__) if !block_given?
- yield download_chunk until download_finished?
- end
-
- def eof?
- @tempfile.eof? && download_finished?
- end
-
- def rewind
- @tempfile.rewind
- end
-
- def close
- terminate_download
- @tempfile.close!
- end
-
private
- def download_chunk
- chunk = @chunks.next
- write(chunk)
- begin
- @chunks.peek
- rescue StopIteration
- terminate_download
- end
- chunk
+ def filename_from_content_disposition
+ meta["content-disposition"].to_s[/filename="([^"]+)"/, 1]
end
- def enough_downloaded?(length)
- length && (@tempfile.pos + length <= @tempfile.size)
- end
-
- def download_finished?
- !@on_close
- end
-
- def terminate_download
- if @on_close
- @on_close.call
- @on_close = nil
- end
- end
-
- def write(chunk)
- current_pos = @tempfile.pos
- @tempfile.pos = @tempfile.size
- @tempfile.write(chunk)
- @tempfile.pos = current_pos
- end
- end
-
- module DownloadedFile
- def original_filename
+ def filename_from_uri
path = base_uri.path
- unless path.empty? || path == "/"
- filename = path.split("/").last
- CGI.unescape(filename)
- end
+ filename = path.split("/").last
+ CGI.unescape(filename) if filename
end
end
end