DocuSign.FileDownloader (DocuSign v2.2.3)

View Source

File download utilities for DocuSign documents and attachments.

This module provides functionality for downloading files from DocuSign APIs with automatic filename extraction from Content-Disposition headers, flexible file handling options, and support for multiple file formats.

Features

  • Automatic filename extraction from Content-Disposition headers
  • Configurable temporary file management
  • Multiple download strategies (to file, to memory, streaming)
  • Support for various file formats (PDF, HTML, images, etc.)
  • Filename sanitization and collision handling
  • Content-Type detection and validation

Usage

# Download to a temporary file
{:ok, path} = DocuSign.FileDownloader.download_to_temp(conn, url)

# Download to a specific path
{:ok, path} = DocuSign.FileDownloader.download_to_file(conn, url, "/path/to/file.pdf")

# Download to memory
{:ok, {content, filename, content_type}} = DocuSign.FileDownloader.download_to_memory(conn, url)

# Download with options
{:ok, result} = DocuSign.FileDownloader.download(conn, url, 
  strategy: :file,
  filename: "custom_name.pdf",
  temp_dir: "/custom/temp"
)

Configuration

You can configure the file downloader options:

config :docusign, :file_downloader,
  max_filename_length: 255,
  sanitize_filenames: true,
  allowed_content_types: ~w(application/pdf text/html image/png image/jpeg),
  track_temp_files: true

Summary

Functions

Cleans up tracked temporary files.

Downloads a file from the given URL using the DocuSign connection.

Downloads a file to a specific path.

Downloads a file to memory.

Downloads a file to a temporary location.

Generates a unique filename by appending a number if the file already exists.

Extracts filename from Content-Disposition header.

Sanitizes a filename by removing invalid characters and path components.

Types

download_options()

@type download_options() :: [
  strategy: download_strategy(),
  filename: String.t() | nil,
  temp_options: keyword() | nil,
  max_size: non_neg_integer() | nil,
  validate_content_type: boolean(),
  overwrite: boolean()
]

download_result()

@type download_result() ::
  {:ok, binary()}
  | {:ok, {binary(), String.t(), String.t()}}
  | {:ok, String.t()}
  | {:error, term()}

download_strategy()

@type download_strategy() :: :file | :memory | :temp | :stream

Functions

cleanup_temp_files()

@spec cleanup_temp_files() :: :ok

Cleans up tracked temporary files.

This function calls Temp.cleanup/0 to remove all tracked temporary files. Useful for manual cleanup before process exit.

Examples

DocuSign.FileDownloader.cleanup_temp_files()

download(conn, url, opts \\ [])

Downloads a file from the given URL using the DocuSign connection.

Options

  • :strategy - Download strategy (:file, :memory, :temp, :stream)
  • :filename - Custom filename (overrides Content-Disposition)
  • :temp_options - Options passed to Temp library for temporary files
  • :max_size - Maximum file size in bytes
  • :validate_content_type - Whether to validate content type
  • :overwrite - Whether to overwrite existing files

Returns

  • {:ok, content} when strategy is :memory
  • {:ok, {content, filename, content_type}} when strategy is :memory with metadata
  • {:ok, filepath} when strategy is :file or :temp
  • {:error, reason} on failure

Examples

# Download envelope document to temporary file
{:ok, temp_path} = DocuSign.FileDownloader.download(conn, 
  "/v2.1/accounts/123/envelopes/456/documents/1")

# Download with custom temp options
{:ok, path} = DocuSign.FileDownloader.download(conn, url,
  temp_options: [prefix: "contract", suffix: ".pdf"])

# Download to memory for processing
{:ok, {content, filename, content_type}} = DocuSign.FileDownloader.download(conn, url,
  strategy: :memory)

download_to_file(conn, url, filepath, opts \\ [])

@spec download_to_file(DocuSign.Connection.t(), String.t(), String.t(), keyword()) ::
  {:ok, String.t()} | {:error, term()}

Downloads a file to a specific path.

Returns {:ok, filepath} on success.

Examples

{:ok, path} = DocuSign.FileDownloader.download_to_file(conn, url, "/path/to/save/document.pdf")

download_to_memory(conn, url, opts \\ [])

@spec download_to_memory(DocuSign.Connection.t(), String.t(), keyword()) ::
  {:ok, {binary(), String.t(), String.t()}} | {:error, term()}

Downloads a file to memory.

Returns {:ok, {content, filename, content_type}} on success.

Examples

{:ok, {pdf_content, "document.pdf", "application/pdf"}} = 
  DocuSign.FileDownloader.download_to_memory(conn, url)

download_to_temp(conn, url, opts \\ [])

@spec download_to_temp(DocuSign.Connection.t(), String.t(), keyword()) ::
  {:ok, String.t()} | {:error, term()}

Downloads a file to a temporary location.

Returns {:ok, filepath} on success, where filepath is the path to the temporary file. The caller is responsible for cleaning up the temporary file.

Examples

{:ok, temp_path} = DocuSign.FileDownloader.download_to_temp(conn, url)
content = File.read!(temp_path)
File.rm!(temp_path)  # Clean up

ensure_unique_filename(filepath)

@spec ensure_unique_filename(String.t()) :: String.t()

Generates a unique filename by appending a number if the file already exists.

Examples

# If document.pdf exists, returns document_1.pdf
# If document_1.pdf also exists, returns document_2.pdf, etc.
DocuSign.FileDownloader.ensure_unique_filename("/path/to/document.pdf")

extract_filename_from_header(content_disposition)

@spec extract_filename_from_header(String.t()) ::
  {:ok, String.t()} | {:error, :no_filename}

Extracts filename from Content-Disposition header.

Examples

iex> DocuSign.FileDownloader.extract_filename_from_header("attachment; filename=document.pdf")
{:ok, "document.pdf"}

iex> DocuSign.FileDownloader.extract_filename_from_header("attachment; filename*=UTF-8''document%20name.pdf")
{:ok, "document name.pdf"}

iex> DocuSign.FileDownloader.extract_filename_from_header("attachment")
{:error, :no_filename}

sanitize_filename(filename)

@spec sanitize_filename(String.t()) :: String.t()

Sanitizes a filename by removing invalid characters and path components.

Examples

iex> DocuSign.FileDownloader.sanitize_filename("../../malicious.pdf")
"malicious.pdf"

iex> DocuSign.FileDownloader.sanitize_filename("file<>:"|?*.pdf")
"file.pdf"