← All compilation units

Flyology.HTTP.Client

Description

Provides an origin-bound synchronous HTTP client with bounded connection pooling. Lightweight callers suspend on Flyology I/O; native callers block only their pthread. HTTP/1.1 is the initial protocol engine, while the request/response API does not expose connection ownership.

Add_Header

procedure Add_Header
  (Item : in out Request; Name : String; Value : String)

Append one end-to-end request field. Framing, connection, upgrade, and Expect fields are client-controlled and rejected here.

Parameters
Item

Request to change

Name

Field name

Value

Field value

Raised exceptions
Constraint_Error

Name, Value, or a client-controlled field is invalid

Flyology

.HTTP.Headers.Headers_Too_Large Request field storage is exhausted

Add_Trailer

procedure Add_Trailer
  (Item : in out Request; Name : String; Value : String)

Append one request trailer field. The client generates the Trailer declaration and sends retained trailer values after an unknown-length chunked source finishes. Trailers are rejected for retained or known-length bodies. Known fields affecting framing, routing, authentication, request semantics, or payload interpretation are prohibited, and repeated names are rejected. The caller must know that the field definition permits use in trailers.

Parameters
Item

Request to change

Name

Trailer field name

Value

Trailer field value retained by Item

Raised exceptions
Constraint_Error

Name is prohibited or repeated in request trailers, or Name or Value has invalid HTTP field syntax

Flyology

.HTTP.Headers.Headers_Too_Large Trailer storage is exhausted

Body_Complete

function Body_Complete (Item : Response) return Boolean

Report whether body framing is complete and no connection lease remains.

Parameters
Item

Response to inspect

Return value

True after complete body consumption

Raised exceptions
Program_Error

Item is not initialized by Execute

Body_Length

type Body_Length is private;

Known or unknown streaming request body length. Unknown bodies use the active protocol's streaming framing; HTTP/1.1 uses chunked coding.

Body_Size

subtype Body_Size is Long_Long_Integer range 0 .. Long_Long_Integer'Last;

Maximum representable request body byte count.

Client

type Client (Capacity : Positive := 4) is limited private;

Origin-bound client. Capacity is the maximum number of open plus connecting transports. Configure must complete before concurrent use. Finalize requests shutdown and closes transports. Execute's aliased controlling parameter lets Ada accessibility reject a response that would escape Item's lifetime. Internal retention also protects cleanup during abort and finalization races.

Record fields
Capacity

Maximum open plus connecting transport count

Client_Closed

Client_Closed : exception;

Raised after client shutdown rejects a request or interrupts pool admission.

Client_Diagnostics

type Client_Diagnostics is record
   Transport_Capacity : Positive;
   Pending_Transports : Natural;
   Active_Exchanges    : Natural;
   Reusable_Transports : Natural;
   Closing_Transports  : Natural;
   Admission_Waiters   : Natural;
   Transports_Created  : Natural;
   Transport_Reuses    : Natural;
   Transports_Closed   : Natural;
   Stale_Retries       : Natural;
   Admission_Timeouts  : Natural;
end record;

Coherent client counters. Exchange and transport counts are separate so a later multiplexed protocol can report several exchanges on one transport without changing this record's meaning.

Record fields
Transport_Capacity

Configured transport slot bound

Pending_Transports

Transports being established

Active_Exchanges

Requests that own protocol exchanges

Reusable_Transports

Established transports eligible for reuse

Closing_Transports

Transports being closed outside the pool lock

Admission_Waiters

Requests waiting for exchange capacity

Transports_Created

Successfully established transports

Transport_Reuses

Exchanges assigned an existing transport

Transports_Closed

Transports removed from the client

Stale_Retries

Idempotent exchanges retried once after an existing transport failed before producing response bytes

Admission_Timeouts

Pool waits whose request deadline expired

Configure

procedure Configure
  (Item         : in out Client;
   Origin_Value : Origin;
   Pool         : Pool_Configuration := Default_Pool_Configuration)

Bind a new client to one origin and immutable pool policy. The call does no DNS, socket, TLS, task, or event-loop work. Reconfiguration and an HTTPS origin without a retained TLS backend is rejected.

Parameters
Item

Unconfigured client

Origin_Value

Normalized origin

Pool

Pool retention policy

Raised exceptions
Program_Error

Item is configured or arguments are invalid

Configure

procedure Configure
  (Item         : in out Client;
   Origin_Value : Origin;
   Backend      : not null access Flyology.IO.TLS.Provider'Class;
   Pool         : Pool_Configuration := Default_Pool_Configuration)

Bind a new client to one origin using an explicit TLS provider. The client retains independently owned provider state, so Backend may be finalized after Configure returns. This overload is required for HTTPS and accepted for HTTP so callers may share configuration code.

Parameters
Item

Unconfigured client

Origin_Value

Normalized origin

Backend

Initialized TLS provider retained by Item

Pool

Pool retention policy

Raised exceptions
Program_Error

Item is configured or arguments are invalid

Flyology

.IO.TLS.TLS_Error Backend cannot be retained

Connection_Error

Connection_Error : exception;

Raised when the origin cannot be resolved or every resolved address fails before an HTTP exchange starts.

Declared_Length

function Declared_Length
  (Item : Request_Body_Source) return Body_Length

Return the source's stable framing length. Known lengths generate Content-Length; Unknown_Length selects the protocol's streaming framing.

Parameters
Item

Source to inspect before its first read

Return value

Known byte count or Unknown_Length

Default_Pool_Configuration

Default_Pool_Configuration : constant Pool_Configuration := (others => <>);

Default conservative pool policy.

Default_Same_Origin_Redirects

Default_Same_Origin_Redirects : constant Redirect_Configuration :=
  (Mode => Follow_Same_Origin, Maximum_Hops => 5);

Opt-in policy that follows at most five same-origin redirects.

Diagnostics

function Diagnostics (Item : Client) return Client_Diagnostics

Return coherent exchange and transport diagnostics without starting I/O.

Parameters
Item

Client to inspect

Return value

Current and cumulative counters

Execute

function Execute
  (Item    : aliased in out Client;
   Value   : Request;
   Source  : in out Request_Body_Source'Class;
   Timeout : Duration := 30.0;
   Token   : access Flyology.Cancellation.Token := null) return Response

Execute one request while pulling its body from Source. The source's Declared_Length controls protocol framing. Source is not retained and is replayed only when it implements Rewindable_Request_Body_Source and the ordinary idempotent stale-transport retry conditions hold. Its exceptions propagate after the leased transport is discarded.

Parameters
Item

Shared configured client that outlives the result

Value

Request metadata; a retained body is rejected

Source

Request body producer used only during this call

Timeout

Whole-exchange deadline interval

Token

Optional cancellation source

Return value

Response head with a streaming response body lease

Raised exceptions
Client_Closed

Client is stopping

Connection_Error

Resolution or all address attempts fail

Constraint_Error

Request metadata is unsupported or already contains a retained body

Request_Body_Error

Source violates its progress contract or ends before a known length is complete

Protocol_Error

Response framing is malformed or unsupported

Response_Too_Large

Response head exceeds its bound

Redirect_Error

An enabled redirect cannot be followed safely

Flyology

.IO.Timeout_Error Whole-exchange deadline expires

.IO.Device_Error Established transport I/O fails

.IO.Sockets.Socket_Error Socket transmission fails

.IO.TLS.TLS_Error TLS setup or transmission fails

.Cancellation.Operation_Cancelled Token is requested

Execute

function Execute
  (Item    : aliased in out Client;
   Value   : Request;
   Timeout : Duration := 30.0;
   Token   : access Flyology.Cancellation.Token := null) return Response

Execute one request. One monotonic Timeout starts before pool admission and covers admission, DNS, all address attempts, TLS, request send, the response head, and later body reads. Negative is unlimited and zero is immediate. Token is borrowed only until the final response head is returned; body reads receive their own optional cancellation token.

Parameters
Item

Shared configured client that outlives the result

Value

Request to execute

Timeout

Whole-exchange deadline interval

Token

Optional cancellation source An idempotent request assigned a reused transport is retried once when that transport fails before any response byte is received. Retained bodies can be replayed directly; streamed bodies are eligible only when Source implements Rewindable_Request_Body_Source. The retry remains inside the original deadline. Non-idempotent requests are never retried.

Return value

Response head with a streaming body lease

Raised exceptions
Client_Closed

Client is stopping

Connection_Error

Resolution or all address attempts fail

Constraint_Error

Request fields, target, or method-body combination is unsupported; CONNECT is not implemented

Protocol_Error

Response framing is malformed or unsupported

Response_Too_Large

Response head exceeds its bound

Redirect_Error

An enabled redirect cannot be followed safely

Flyology

.IO.Timeout_Error Whole-exchange deadline expires

.IO.Device_Error Established transport I/O fails

.IO.Sockets.Socket_Error Socket transmission fails

.IO.TLS.TLS_Error TLS setup or transmission fails

.Cancellation.Operation_Cancelled Token is requested

Header

function Header
  (Item : Response; Name : String; Occurrence : Positive := 1)
   return String

Return one physical response field occurrence.

Parameters
Item

Response to inspect

Name

Field name

Occurrence

One-based occurrence

Return value

Field value or empty when absent

Raised exceptions
Program_Error

Item is not initialized by Execute

Header_Count

function Header_Count (Item : Response) return Natural

Return the number of physical response fields.

Parameters
Item

Response to inspect

Return value

Field count

Raised exceptions
Program_Error

Item is not initialized by Execute

Header_Count

function Header_Count (Item : Response; Name : String) return Natural

Count physical response fields with a case-insensitive name.

Parameters
Item

Response to inspect

Name

Field name

Return value

Physical occurrence count

Raised exceptions
Program_Error

Item is not initialized by Execute

Header_Name

function Header_Name (Item : Response; Index : Positive) return String

Return one response field name by wire order.

Parameters
Item

Response to inspect

Index

One-based physical field index

Return value

Preserved field name

Raised exceptions
Program_Error

Item is not initialized by Execute

Constraint_Error

Index exceeds Header_Count

Header_Value

function Header_Value (Item : Response; Index : Positive) return String

Return one response field value by wire order.

Parameters
Item

Response to inspect

Index

One-based physical field index

Return value

Preserved field value

Raised exceptions
Program_Error

Item is not initialized by Execute

Constraint_Error

Index exceeds Header_Count

Known_Length

function Known_Length (Bytes : Body_Size) return Body_Length

Construct a known streaming request body length.

Parameters
Bytes

Exact number of source bytes to transmit

Return value

Known body length

Negotiated_Protocol

function Negotiated_Protocol (Item : Response) return Protocol

Return the negotiated protocol.

Parameters
Item

Response to inspect

Return value

HTTP_1_1_Protocol in the initial implementation

Raised exceptions
Program_Error

Item is not initialized by Execute

No_Redirects

No_Redirects : constant Redirect_Configuration := (others => <>);

Default policy: return redirect responses without following them.

Pool_Configuration

type Pool_Configuration is record
   Max_Idle                   : Natural := 1;
   Idle_Timeout               : Duration := 30.0;
   Max_Connection_Age         : Duration := 300.0;
   Max_Requests_Per_Connection : Natural := 0;
end record;

Pool reuse and retention policy. Capacity remains the Client discriminant and bounds open plus connecting slots.

Record fields
Max_Idle

Maximum reusable connections retained, capped by client capacity; zero disables reuse without disabling concurrent requests

Idle_Timeout

Seconds an unused connection may remain reusable; negative disables the age check

Max_Connection_Age

Total reusable lifetime in seconds; negative disables the age check

Max_Requests_Per_Connection

Total requests before rotation; zero disables request-count rotation

Prune_Idle

procedure Prune_Idle (Item : in out Client)

Close every currently idle connection. Active leases are unaffected.

Parameters
Item

Configured client

Read

procedure Read
  (Item     : in out Request_Body_Source;
   Data     : out Ada.Streams.Stream_Element_Array;
   Last     : out Ada.Streams.Stream_Element_Offset;
   Finished : out Boolean;
   Timeout  : Duration;
   Token    : access Flyology.Cancellation.Token)

Produce the next request body bytes.

Parameters
Item

Source state to advance

Data

Client-owned destination buffer

Last

Last produced byte, or Data'First - 1

Finished

Whether the source has no bytes after this call

Timeout

Remaining whole-exchange deadline interval

Token

Optional cancellation source from Execute

Read_All

function Read_All
  (Item    : in out Response;
   Maximum : Natural := 1_024 * 1_024;
   Token   : access Flyology.Cancellation.Token := null)
   return Flyology.Bytes.Unbounded_Bytes

Read the complete remaining body into owned storage under the original deadline. Maximum bounds decoded bytes retained by this convenience operation.

Parameters
Item

Active response

Maximum

Maximum decoded bytes

Token

Optional cancellation source borrowed for this call

Return value

Complete retained body

Raised exceptions
Program_Error

Item is not initialized by Execute

Response_Too_Large

Maximum would be exceeded

Client_Closed

Client shutdown interrupts the exchange

Protocol_Error

Response body framing is malformed

Flyology

.IO.Timeout_Error Whole-exchange deadline expires

.IO.Device_Error Established transport I/O fails

.IO.Sockets.Socket_Error Socket reception fails

.IO.TLS.TLS_Error TLS reception fails

.Cancellation.Operation_Cancelled Token is requested

Read_Body

procedure Read_Body
  (Item     : in out Response;
   Data     : out Ada.Streams.Stream_Element_Array;
   Last     : out Ada.Streams.Stream_Element_Offset;
   Finished : out Boolean;
   Token    : access Flyology.Cancellation.Token := null)

Stream decoded response representation bytes. Fixed-length and chunked framing are removed. Last is Data'First - 1 when no bytes are produced. Finished becomes true only after complete framing; that transition releases or closes the underlying connection. The Execute deadline and token remain authoritative and are never restarted.

Parameters
Item

Active response

Data

Caller-owned destination

Last

Last decoded byte, or Data'First - 1

Finished

Whether response framing is complete

Token

Optional cancellation source borrowed for this call

Raised exceptions
Program_Error

Item is not initialized by Execute

Client_Closed

Client shutdown interrupts the exchange

Protocol_Error

Response body framing is malformed

Flyology

.IO.Timeout_Error Whole-exchange deadline expires

.IO.Device_Error Established transport I/O fails

.IO.Sockets.Socket_Error Socket reception fails

.IO.TLS.TLS_Error TLS reception fails

.Cancellation.Operation_Cancelled Token is requested

Reason_Phrase

function Reason_Phrase (Item : Response) return String

Return the final response reason phrase. HTTP/2 and later protocols may return an empty string because they do not carry one.

Parameters
Item

Response to inspect

Return value

Preserved HTTP/1.x reason phrase after its status separator

Raised exceptions
Program_Error

Item is not initialized by Execute

Redirect_Configuration

type Redirect_Configuration is record
   Mode          : Redirect_Mode := Return_Redirects;
   Maximum_Hops  : Redirect_Limit := 5;
end record;

Per-request redirect policy.

Record fields
Mode

Whether redirects are returned or followed within the origin

Maximum_Hops

Maximum redirects followed before Redirect_Error

Redirect_Error

Redirect_Error : exception;

Raised when an enabled redirect cannot be followed safely because its target is invalid, repeats a prior target, exceeds the configured hop limit, or requires replaying a one-shot request source.

Redirect_Limit

subtype Redirect_Limit is Natural range 0 .. 20;

Supported bound for automatically followed redirect hops.

Redirect_Mode

type Redirect_Mode is (Return_Redirects, Follow_Same_Origin);

Automatic redirect behavior. Returning redirects is the default and preserves the response exactly as received. Same-origin following never sends a request to a different scheme, host, or port.

Enumeration literals
Return_Redirects

Return every redirect response to the caller

Follow_Same_Origin

Follow eligible redirects within the client origin

Request

type Request is private;

Mutable request value. Bodies are retained as owned bytes so request transmission remains valid across task suspension.

Request_Body_Error

Request_Body_Error : exception;

Raised when a streaming request body violates the progress contract or does not finish on exactly its positive declared length.

Request_Body_Source

type Request_Body_Source is limited interface;

Pull source for a streaming request body. Execute queries Declared_Length once, calls Read serially, and never retains the source after returning. The declared length must remain stable during Execute. Implementations must honor the remaining whole-exchange timeout and cancellation token when they perform blocking work. A call must either produce at least one byte or set Finished. Last is Data'First - 1 when no bytes are produced.

Response

type Response is limited private;

Limited response owning one exchange lease until its body is consumed. Reading the complete body returns a reusable connection to the pool. Finalizing an incomplete response closes it without draining.

Response_Too_Large

Response_Too_Large : exception;

Raised when retained response metadata or a Read_All body exceeds its bound.

Rewind

procedure Rewind
  (Item : in out Rewindable_Request_Body_Source)

Restore a rewindable source to its initial byte before one safe retry.

Parameters
Item

Source whose exact initial sequence is restored

Rewindable_Request_Body_Source

type Rewindable_Request_Body_Source is
  limited interface and Request_Body_Source;

Request source that can reproduce exactly the same byte sequence after a failed transport attempt. Rewind must be nonblocking and restore the initial cursor without changing Declared_Length. Execute calls it only after discarding a failed reused transport and only when the method is idempotent and no response byte was received.

Set_Body

procedure Set_Body
  (Item : in out Request; Value : Ada.Streams.Stream_Element_Array)

Replace the request body from contiguous bytes.

Parameters
Item

Request to change

Value

Request representation bytes

Set_Body

procedure Set_Body (Item : in out Request; Value : String)

Replace the request body using a one-to-one byte mapping.

Parameters
Item

Request to change

Value

Request representation bytes

Set_Expect_Continue

procedure Set_Expect_Continue
  (Item         : in out Request;
   Enabled      : Boolean := True;
   Wait_Timeout : Duration := 1.0)

Enable or disable the Expect: 100-continue handshake. When enabled for a nonempty retained or streaming body, Execute sends the request head first and waits up to Wait_Timeout for 100 Continue or a final response. A positive wait expiry with no partial response sends the body; a negative value waits within the whole exchange deadline and zero sends immediately after the head. A final response suppresses body reads and transmission. A 417 final response received before body transmission is retried once on a fresh transport without the expectation, within the same deadline and shared automatic-retry budget. The whole exchange deadline is never extended.

Parameters
Item

Request to change

Enabled

Whether to generate Expect: 100-continue

Wait_Timeout

Maximum continue-specific wait in seconds

Set_Method

procedure Set_Method (Item : in out Request; Value : Method)

Replace the request method.

Parameters
Item

Request to change

Value

Validated method

Set_Redirects

procedure Set_Redirects
  (Item : in out Request; Value : Redirect_Configuration)

Replace the request's automatic redirect policy. One monotonic Execute deadline covers every hop and every intermediate response-body drain. Cross-origin redirects are always returned to the caller.

Parameters
Item

Request to change

Value

Redirect mode and hop bound

Set_Target

procedure Set_Target (Item : in out Request; Value : String)

Replace the origin-form request target. Asterisk-form is retained for OPTIONS and validated when Execute observes the complete Request. Absolute-form, authority-form, fragments, non-ASCII bytes, spaces, control characters, and targets over 8 KiB are rejected.

Parameters
Item

Request to change

Value

Origin-form target

Raised exceptions
Constraint_Error

Value is not a supported request target

Shutdown

procedure Shutdown (Item : in out Client; Timeout : Duration := 5.0)

Terminally reject admission, cancel admitted transport operations, close idle connections, and wait up to Timeout for leases and connecting slots to drain. A timeout leaves Item stopping and may be retried.

Parameters
Item

Client to stop

Timeout

Drain deadline interval; negative waits indefinitely

Raised exceptions
Flyology

.IO.Timeout_Error Active leases do not drain

Status

function Status (Item : Response) return Status_Code

Return the final response status.

Parameters
Item

Response to inspect

Return value

Three-digit status

Raised exceptions
Program_Error

Item is not initialized by Execute

Trailer

function Trailer
  (Item : Response; Name : String; Occurrence : Positive := 1)
   return String

Return one completed chunked trailer occurrence.

Parameters
Item

Response whose body has completed

Name

Trailer name

Occurrence

One-based occurrence

Return value

Trailer value or empty when absent

Raised exceptions
Program_Error

Item is uninitialized or its body is incomplete

Trailer_Count

function Trailer_Count (Item : Response) return Natural

Return the number of physical trailer fields available after body completion.

Parameters
Item

Response to inspect

Return value

Trailer field count

Raised exceptions
Program_Error

Item is uninitialized or its body is incomplete

Trailer_Count

function Trailer_Count (Item : Response; Name : String) return Natural

Count completed chunked trailer fields with a case-insensitive name.

Parameters
Item

Response whose body has completed

Name

Trailer name

Return value

Physical occurrence count

Raised exceptions
Program_Error

Item is uninitialized or its body is incomplete

Trailer_Name

function Trailer_Name (Item : Response; Index : Positive) return String

Return one trailer field name by wire order.

Parameters
Item

Response to inspect

Index

One-based physical field index

Return value

Preserved trailer name

Raised exceptions
Program_Error

Item is uninitialized or its body is incomplete

Constraint_Error

Index exceeds Trailer_Count

Trailer_Value

function Trailer_Value (Item : Response; Index : Positive) return String

Return one trailer field value by wire order.

Parameters
Item

Response to inspect

Index

One-based physical field index

Return value

Preserved trailer value

Raised exceptions
Program_Error

Item is uninitialized or its body is incomplete

Constraint_Error

Index exceeds Trailer_Count

Unknown_Length

Unknown_Length : constant Body_Length;

Unknown streaming request body length.