class LittleGhost::Providers::HTTPTransport
HTTPTransport gives provider clients a shared, bounded streaming HTTP layer. It applies cancellation, deadlines, timeouts, and response-size limits while yielding response chunks as they arrive.
Security and trust
HTTPS is required by default. Enabling allow_insecure_http can expose API keys and model content in transit; use it only with a trusted local development endpoint.
Constants
- DEFAULT_MAX_RESPONSE_BYTES
-
Default upper bound for a complete provider response (50 MiB).
Public Class Methods
# File lib/little_ghost/providers/http_transport.rb, line 56 def initialize( base_url:, open_timeout:, read_timeout:, allow_insecure_http: false, max_response_bytes: DEFAULT_MAX_RESPONSE_BYTES, max_error_body_bytes: DEFAULT_MAX_ERROR_BODY_BYTES ) @base_url = URI(base_url.end_with?("/") ? base_url : "#{base_url}/") unless %w[http https].include?(@base_url.scheme) && @base_url.host raise ConfigurationError, "Provider base_url must be an HTTP(S) URL" end if @base_url.scheme == "http" && !allow_insecure_http raise ConfigurationError, "Provider base_url must use HTTPS unless allow_insecure_http is enabled" end @open_timeout = open_timeout @read_timeout = read_timeout @max_response_bytes = positive_integer(max_response_bytes, :max_response_bytes) @max_error_body_bytes = positive_integer(max_error_body_bytes, :max_error_body_bytes) end
Configures base_url with connection, read, and response size limits.
Public Instance Methods
# File lib/little_ghost/providers/http_transport.rb, line 82 def stream(path:, headers:, body:, cancellation_token:, deadline: nil) return enum_for(__method__, path:, headers:, body:, cancellation_token:, deadline:) unless block_given? stream = Support::InterruptibleStream.new(cancellation_token:, deadline:) do |emit| uri = URI.join(@base_url.to_s, path.sub(%r{\A/}, "")) request = Net::HTTP::Post.new(uri) headers.each { |name, value| request[name] = value } request.body = body http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = uri.scheme == "https" http.open_timeout = remaining_timeout(deadline, @open_timeout) http.read_timeout = remaining_timeout(deadline, @read_timeout) http.write_timeout = remaining_timeout(deadline, @read_timeout) http.request(request) do |response| unless response.is_a?(Net::HTTPSuccess) response_body = read_limited(response, @max_error_body_bytes) raise HTTPError.new( "Provider request failed with HTTP #{response.code}", status: response.code.to_i, body: response_body ) end bytes_read = 0 response.read_body do |chunk| bytes_read += chunk.bytesize raise ProtocolError, "Provider response exceeded #{@max_response_bytes} bytes" if bytes_read > @max_response_bytes emit.call(chunk) end end rescue *TRANSIENT_NETWORK_ERRORS => error raise HTTPError, "Provider request failed (#{error.class})" end stream.each { |chunk| yield chunk } end
Posts body and yields response chunks until completion.
Cancellation and deadline interrupt the request. Without a block, this method returns an Enumerator.