Class: LittleGhost::Providers::HTTPTransport
- Inherits:
-
Object
- Object
- LittleGhost::Providers::HTTPTransport
- Defined in:
- lib/little_ghost/providers/http_transport.rb
Overview
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.
Constant Summary collapse
- DEFAULT_MAX_RESPONSE_BYTES =
Default upper bound for a complete provider response (50 MiB).
50 * 1024 * 1024
- DEFAULT_MAX_ERROR_BODY_BYTES =
:nodoc:
4 * 1024
- TRANSIENT_NETWORK_ERRORS =
[ Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout, EOFError, SocketError, SystemCallError, IOError, OpenSSL::SSL::SSLError, Net::ProtocolError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError ].freeze
Instance Method Summary collapse
-
#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) ⇒ HTTPTransport
constructor
Configures
base_urlwith connection, read, and response size limits. -
#stream(path:, headers:, body:, cancellation_token:, deadline: nil) ⇒ Object
Posts
bodyand yields response chunks until completion.
Constructor Details
#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) ⇒ HTTPTransport
Configures base_url with connection, read, and response
size limits.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# 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 |
Instance Method Details
#stream(path:, headers:, body:, cancellation_token:, deadline: nil) ⇒ Object
Posts body and yields response chunks until completion.
Cancellation and deadline interrupt the request. Without a block, this
method returns an Enumerator.
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# 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 |