down

repository·master·Indexed 22 days ago

https://github.com/janko/down

A Ruby utility for streaming, flexible, and safe downloading of remote files. It supports multiple HTTP backends (Down::NetHttp, Down::Http, and Down::Httpx) and provides tools for handling large files via :max_size limits and streaming IO through Down::ChunkedIO. Key features include support for basic authentication in URLs, download progress monitoring, and a comprehensive exception hierarchy under Down::Error.

Tokens
9.8K
Snippets
39
Records
46
Agent score
76%

What's inside down

  1. Configure caching and rewinding in Down::ChunkedIO

    master

    By default, Down::ChunkedIO caches downloaded content into a Tempfile so that you can #rewind the stream and re-read data.

    If you want to reduce disk usage and IO calls and do not need to rewind, you can disable caching by passing rewindable: false to Down.open.

    # Default behavior (rewindable)
    remote_file = Down.open("http://example.com/image.jpg")
    remote_file.read(1*1024*1024)
    remote_file.rewind
    remote_file.read(1*1024*1024) # reads from cache
    
    # Disable caching
    Down.open("http://example.com/image.jpg", rewindable: false)
  2. Configure and use different Down backends

    master

    Down supports multiple backends for downloading files. You can use a backend directly by calling its class methods, or set a backend globally for the Down module.

    Available backends:

    • Down::NetHttp (default)
    • Down::Http (requires http gem)
    • Down::Httpx (requires httpx gem)

    To set a backend globally, use Down.backend :backend_name.

    require "down"
    
    # Set the backend globally
    Down.backend :http
    
    # Use the global Down methods
    Down.download("...")
    Down.open("...")
    
    # OR use a backend directly
    require "down/http"
    Down::Http.download("...")
  3. Handle authentication in Down::NetHttp

    master

    Down supports basic authentication in two ways:

    1. In the URL: Include credentials directly in the remote URL (e.g., https://user:pass@example.com/file.zip).
    2. Via Proxy: If using a :proxy option, provide a URL containing credentials (e.g., proxy: "http://user:pass@proxy.example.com:8080").

    Note: When following redirects, Down::NetHttp will not leak credentials to the new location unless auth_on_redirect: true is explicitly passed in the options.

  4. Use the Down::Http backend

    master

    The Down::Http backend uses the http.rb gem. It is optimized for low memory usage (up to 10x less than Net::HTTP) and supports persistent connections and global timeouts.

    Installation:

    gem "down", "~> 5.0"
    gem "http", "~> 5.0"

    Usage: Options are passed to HTTP::Client#request. It is recommended to use the chainable builder API when using Down::Http.open to configure the client.

    require "down/http"
    
    # Download to a Tempfile
    tempfile = Down::Http.download("http://nature.com/forest.jpg")
    
    # Open as an IO object
    io = Down::Http.open("http://nature.com/forest.jpg")
    
    # Using the builder API for configuration
    Down::Http.open("http://example.org/image.jpg") do |client|
      client.timeout(connect: 3, read: 3)
    end
  5. Specify a download destination or customize Tempfile

    master

    You can control where files are saved or how the temporary files are named using the following options in Down.download:

    • :destination: Specifies a specific path on disk. Note that when using this, Down.download returns nil instead of a Tempfile.
    • :extension: Overrides the file extension of the returned Tempfile.
    • :tempfile_name: Overrides the default prefix used for the Tempfile name.
    # Download to a specific path
    Down.download("http://example.com/image.jpg", destination: "/path/to/destination")
    
    # Override extension
    tempfile = Down.download("http://example.com/some/file", extension: "txt")
    
    # Override tempfile prefix
    tempfile = Down.download("http://example.com/image.jpg", tempfile_name: "custom-prefix")
  6. Create a custom Down::ChunkedIO

    master

    The Down::ChunkedIO class can wrap any streaming source by providing an Enumerator that yields chunks. This is useful for wrapping non-HTTP streams (like MongoDB GridFS) into a standard IO-like interface.

    Supported initialization options:

    • :chunks: An Enumerator that yields chunks of content.
    • :size: The known size of the file (used by #size).
    • :on_close: A proc called when streaming finishes or the IO is closed.
    • :data: Custom data to store (returned by #data).
    • :rewindable: Whether to cache retrieved data into a file (defaults to true).
    • :encoding: Force content to be returned in a specific encoding (defaults to Encoding::BINARY).
    require "down/chunked_io"
    
    # Example: Wrapping a MongoDB GridFS stream
    mongo = Mongo::Client.new(...)
    bucket = mongo.database.fs
    
    content_length = bucket.find(_id: id).first[:length]
    stream = bucket.open_download_stream(id)
    
    io = Down::ChunkedIO.new(
      size: content_length,
      chunks: stream.enum_for(:each),
      on_close: -> { stream.close },
    )
  7. Download a remote file with Down.download

    master

    The Down.download method downloads a remote file into a Tempfile. The returned Tempfile includes additional metadata extracted from the HTTP response, such as content_type, original_filename, and charset.

    require "down"
    
    tempfile = Down.download("http://example.com/nature.jpg")
    tempfile.content_type      #=> "text/plain"
    tempfile.original_filename #=> "document.txt"
    tempfile.charset           #=> "utf-8"
  8. Yield chunks as they are downloaded

    master

    To process data in chunks without any disk caching (regardless of the :rewindable setting), use the #each_chunk method on a Down::ChunkedIO object.

    remote_file = Down.open("http://example.com/image.jpg")
    remote_file.each_chunk { |chunk| ... }
    remote_file.close
  9. Handle Basic Authentication in URLs

    master

    Down.download and Down.open automatically detect and apply HTTP basic authentication if the credentials are provided within the URL.

    Down.download("http://user:password@example.org")
    Down.open("http://user:password@example.org")
  10. Limit download size with :max_size

    master

    To protect your server from large files, use the :max_size option. Down will terminate the download as soon as it receives a Content-Length header exceeding the limit, or as soon as the downloaded content surpasses the limit if the header is missing. If the limit is exceeded, a Down::TooLarge error is raised.

    Down.download("http://example.com/image.jpg", max_size: 5 * 1024 * 1024) # 5 MB
    # Raises Down::TooLarge if file exceeds 5MB
  11. Monitor download progress

    master

    Use :content_length_proc and :progress_proc to track download status:

    • :content_length_proc: A proc called with the Content-Length value once received.
    • :progress_proc: A proc called with the current filesize whenever a new chunk is downloaded.
    Down.download "http://example.com/movie.mp4",
      content_length_proc: -> (content_length) { ... },
      progress_proc:       -> (progress)       { ... }