Compose HTTP reads with Flyology operations.

Start bounded request-head and body operations before the owner task waits. Use one Flyology completion set to wait for HTTP, timers, gates, connection work, and cancellation sources.

OPERATIONS 01

Choose synchronous or composable calls.

When one task can wait for each protocol step in sequence, use the ordinary synchronous procedures. When one owner task must wait for an HTTP read and other Flyology operations, use the completion-set overloads in Flyology.HTTP.Server.

Synchronous
Call Read_Request_Head, Accept_Body, or Read_Body as a normal procedure. The call returns its result or raises its error directly.
Composable
Supply a completion set to the corresponding provider overload. The root constructor starts immediately and returns a typed limited operation.

A composable call does not create a helper task, callback thread, or task stack. The HTTP state machine advances in bounded steps when the completion-set owner drives it.

OPERATIONS 02

Use an operation-capable connection adapter.

An HTTP operation requires a transport that implements Operation_Transport. The supplied Flyology.HTTP.Server.Connections adapter provides that capability for a high-level Flyology connection.

borrow an established Flyology connection
package HTTP renames Flyology.HTTP.Server;
package HTTP_Connections renames Flyology.HTTP.Server.Connections;

--  Channel is an established, caller-owned Flyology.IO.Connections.Connection.
Transport : aliased HTTP_Connections.Connection_Transport (Channel'Access);
Client    : aliased HTTP.Connection (Transport'Access);

Connections.Connection_Transport borrows the Flyology connection. The Flyology connection must outlive the adapter. The adapter must outlive the Server.Connection and its operations.

The adapter continues to work after you upgrade the high-level Flyology connection to TLS. Before you start the first HTTP operation, finish the Flyology.IO.Connections.TLS.Upgrade operation. The HTTP operation then uses the current plaintext or TLS transport through the same connection capability.

OPERATIONS 03

Start, wait, and finish every operation.

The Server.Read_Request_Head constructor starts one Read_Request_Head_Operation. The example also starts a timer and adds a gate that observes both root operations.

compose one request head with a timer
declare
   --  Two root operations plus one gate require three slots.
   Set : aliased Flyology.Operations.Completion_Set (3);

   Head : aliased HTTP.Read_Request_Head_Operation :=
     HTTP.Read_Request_Head
       (Set      => Set'Access,
        Item     => Client'Access,
        Timeout  => 5.0,
        Max_Body => 8 * 1_024 * 1_024);

   Alarm : aliased Flyology.IO.Timers.Timer_Operation :=
     Flyology.IO.Timers.Sleep_For (Set'Access, 0.050);

   Both : Flyology.Operations.Gate_Operation :=
     Flyology.Operations.Wait_All
       (Set'Access,
        [Flyology.Operations.Reference (Head),
         Flyology.Operations.Reference (Alarm)]);

   Matched : Flyology.Operations.Completion_Batch (Set.Capacity);
   Request : HTTP.Request;
   Closed  : Boolean;
begin
   Flyology.Operations.Wait_All (Set);
   Flyology.Operations.Finish (Both, Matched);
   Flyology.IO.Timers.Finish (Alarm);
   HTTP.Finish (Head, Request, Closed);

   if not Closed then
      Put_Line (HTTP.Target (Request));
   end if;
end;

Each root operation uses one completion-set slot. A gate uses another slot. The HTTP operation uses only one slot. Its transport capability does not use a completion-set slot.

Call the request-head overload of Server.Finish to consume the terminal result and get a Request. A clean close between requests sets Closed and returns an empty request. After Finish returns with Closed = False, the Target accessor is valid.

For a retained child, declare the operation with its completion set, then call the same-name procedure with Operation last. After typed Finish, release the child before restarting it. This is the same provider-centric initiation convention used by Flyology core.

OPERATIONS 04

Accept and stream the request body in order.

After the head finishes, call Server.Accept_Body. Its Accept_Body_Operation sends 100 Continue when the parsed request requires it. Otherwise, the operation can complete immediately.

Then start Server.Read_Body repeatedly. Each Read_Body_Operation fills one caller-owned buffer and reports whether framing and trailers are complete.

accept and stream one body
declare
   Set      : aliased Flyology.Operations.Completion_Set (1);
   Data     : aliased Ada.Streams.Stream_Element_Array (1 .. 4_096);
   Last     : Ada.Streams.Stream_Element_Offset;
   Finished : Boolean := False;
begin
   declare
      Acceptance : HTTP.Accept_Body_Operation :=
        HTTP.Accept_Body (Set'Access, Client'Access);
   begin
      Flyology.Operations.Wait_All (Set);
      HTTP.Finish (Acceptance);
   end;

   while not Finished loop
      declare
         Read : HTTP.Read_Body_Operation :=
           HTTP.Read_Body (Set'Access, Client'Access, Data'Access);
      begin
         Flyology.Operations.Wait_All (Set);
         HTTP.Finish (Read, Last, Finished);
         if Last >= Data'First then
            Consume (Data (Data'First .. Last));
         end if;
      end;
   end loop;
end;

The complete-request deadline starts with the request head. Repeated body reads do not restart it. When the header and complete request need different absolute budgets, use the distinct-timeout request-head overload.

OPERATIONS 05

Choose the completion rule explicitly.

Wait_Some
Returns a new terminal batch after at least one operation completes.
Wait_At_Least
Returns after a requested number of new terminal results, or when the set first becomes quiescent.
Wait_All
Waits until no operation remains pending. Failures and cancellations also count as terminal results.
Wait_For_Success
Returns after one new success, or when success becomes impossible.
Wait_For_Successes
Returns after the requested success count, or when that count becomes impossible.

Function overloads of these waits construct first-class gates from fixed references to operations in one set. A gate observes its members. If you cancel the gate, Flyology does not cancel its members. See the Flyology guide for counted waits, completion batches, outcome inspection, and nested gate examples.

OPERATIONS 06

Cancel, drain, and finish.

Cancellation makes an active operation terminal only after the transport releases its borrowed state. After cancellation, call the typed HTTP Finish. This call consumes the terminal result and raises Flyology.Operations.Operation_Cancelled.

consume an explicitly cancelled request head
if Flyology.Operations.Is_Active (Head) then
   Flyology.Operations.Cancel (Head);
end if;

begin
   HTTP.Finish (Head, Request, Closed);
exception
   when Flyology.Operations.Operation_Cancelled =>
      null;
end;

The operation also retains timeout, malformed-input, body-limit, and transport failures until typed Finish. A wait reports terminal completion. It does not consume the provider-specific result. Only when scheduling policy must distinguish success, failure, and cancellation, inspect the generic outcome before Finish.

At scope finalization, Flyology cancels unfinished operations and releases their transport capabilities. When the application must observe a result or error, cancel the operation and call its typed Finish explicitly.

OPERATIONS 07

Keep every borrowed value alive until Finish.

  • The completion set must outlive all operations and gates that use it.
  • The HTTP connection, its connection adapter, and the underlying Flyology connection must outlive each HTTP operation.
  • A cancellation token supplied to a constructor must outlive that operation.
  • A body-read buffer remains borrowed until typed Finish, even after the operation becomes terminal.
  • Use one owner task for a completion set and its operations.
  • Keep protocol steps sequential on one HTTP connection. Use distinct HTTP connections for simultaneous request-head operations.

A terminal operation releases its connection lease before Finish. Queued high-level connection work can then continue while the operation retains the result. The operation retains the parsed request or body status until typed Finish consumes it.

OPERATIONS 08

Use operations only for supported work.

  • Composable constructors support low-level HTTP/1.x request heads, body acceptance, and decoded body reads.
  • Response writes remain synchronous.
  • The pooled Client exposes its own complete-exchange operations. Routed server exchanges, HTTP/2 and HTTP/3 server streams, SSE, and WebSocket APIs do not expose these low-level HTTP/1.x operation types.
  • The direct Server.TLS.Connection_Transport implements the synchronous transport interface only. A composable constructor rejects it with Program_Error.
  • For TLS composition, upgrade a high-level Flyology connection and retain the operation-capable Server.Connections.Connection_Transport adapter.

The composable API does not replace the synchronous API. Existing synchronous procedures keep their signatures and exception behavior.