TermUI.Backend.InputBuffer (TermUI v1.0.0)
View SourceShared input buffer management for terminal backends.
This module provides secure input buffer handling with:
- Size limits to prevent memory exhaustion
- Rate-limited logging to prevent log flooding
- Consistent behavior across backends
Security
The input buffer protects against memory exhaustion attacks where malformed input streams send unterminated escape sequences. Without protection, the buffer would grow indefinitely.
Buffer Size Limits
- Maximum buffer size: 1024 bytes
- Keep size on truncation: 256 bytes
The 256-byte keep size preserves potential partial escape sequences (typical sequences are 8-20 bytes, max CSI is ~100 bytes).
Rate-Limited Logging
Buffer overflow warnings are rate-limited to prevent log flooding attacks. Maximum one warning every 5 seconds per backend instance.
Usage
Backends should use this module instead of implementing their own buffer management:
# In your backend module
alias TermUI.Backend.InputBuffer
# Appending data
new_buffer = InputBuffer.append(state.input_buffer, data)
# Applying limit (returns {buffer, overflow_occurred?})
{limited_buffer, overflowed} = InputBuffer.apply_limit(new_buffer)
# Or use the combined function that handles state
new_state = InputBuffer.append_with_limit(state, data, :input_buffer)
Summary
Functions
Appends data to a buffer and returns the new buffer.
Appends data to a state's buffer field with limit protection.
Applies the buffer size limit, truncating if necessary.
Clears the rate limit state (useful for testing).
Returns the number of bytes kept when truncating.
Returns the maximum buffer size allowed.
Functions
Appends data to a buffer and returns the new buffer.
This is a simple append without limit checking. Use apply_limit/2
or append_with_limit/4 for protected appending.
Parameters
buffer- The existing buffer (binary)data- Data to append (binary)
Returns
The combined buffer.
Examples
iex> TermUI.Backend.InputBuffer.append("hello", " world")
"hello world"
Appends data to a state's buffer field with limit protection.
This is a convenience function that:
- Appends data to the specified buffer field
- Applies the size limit
- Returns the updated state
Parameters
state- Map or struct containing the bufferdata- Data to append (binary)field- The field name containing the buffer (atom)opts- Options passed toapply_limit/2
Returns
The updated state with the new buffer value.
Examples
iex> state = %{input_buffer: "partial"}
iex> new_state = TermUI.Backend.InputBuffer.append_with_limit(state, "[A", :input_buffer)
iex> new_state.input_buffer
"partial[A"
Applies the buffer size limit, truncating if necessary.
If the buffer exceeds the maximum size, it is truncated to keep only the most recent bytes (to preserve potential partial escape sequences).
Parameters
buffer- The buffer to check (binary)opts- Options::source- Identifier for rate-limited logging (default::unknown):log- Whether to log overflow (default:true)
Returns
Tuple of {limited_buffer, overflowed?}.
Examples
iex> {buffer, false} = TermUI.Backend.InputBuffer.apply_limit("short")
iex> buffer
"short"
iex> long = String.duplicate("x", 2000)
iex> {buffer, true} = TermUI.Backend.InputBuffer.apply_limit(long, source: :test)
iex> byte_size(buffer)
256
@spec clear_rate_limits() :: :ok
Clears the rate limit state (useful for testing).
Examples
iex> TermUI.Backend.InputBuffer.clear_rate_limits()
:ok
@spec keep_size() :: pos_integer()
Returns the number of bytes kept when truncating.
Examples
iex> TermUI.Backend.InputBuffer.keep_size()
256
@spec max_size() :: pos_integer()
Returns the maximum buffer size allowed.
Examples
iex> TermUI.Backend.InputBuffer.max_size()
1024