Http Server in Ada

Here’s the translation of the HTTP server example from Go to Ada, formatted in Markdown suitable for Hugo:

Our HTTP server example demonstrates how to create a basic web server using Ada. We’ll use the GNAT implementation of Ada, which provides the GNAT.Sockets package for network programming.

with Ada.Text_IO;
with GNAT.Sockets;
with Ada.Strings.Unbounded;
with Ada.Containers.Indefinite_Hashed_Maps;
with Ada.Strings.Hash;

procedure HTTP_Server is
   use Ada.Text_IO;
   use GNAT.Sockets;
   use Ada.Strings.Unbounded;

   package String_Maps is new Ada.Containers.Indefinite_Hashed_Maps
     (Key_Type        => String,
      Element_Type    => Unbounded_String,
      Hash            => Ada.Strings.Hash,
      Equivalent_Keys => "=");

   procedure Hello (Socket : Socket_Type) is
   begin
      String'Write (Stream (Socket), "HTTP/1.1 200 OK" & ASCII.CR & ASCII.LF);
      String'Write (Stream (Socket), "Content-Type: text/plain" & ASCII.CR & ASCII.LF);
      String'Write (Stream (Socket), "" & ASCII.CR & ASCII.LF);
      String'Write (Stream (Socket), "hello" & ASCII.LF);
   end Hello;

   procedure Headers (Socket : Socket_Type; Request : String) is
      Headers : String_Maps.Map;
      Start   : Positive := Request'First;
      End_Pos : Natural;
   begin
      -- Parse headers (simplified)
      while Start < Request'Last loop
         End_Pos := Ada.Strings.Fixed.Index (Request (Start .. Request'Last), ASCII.LF & "");
         if End_Pos = 0 then
            End_Pos := Request'Last;
         else
            End_Pos := End_Pos - 1;
         end if;

         declare
            Line  : constant String := Request (Start .. End_Pos);
            Colon : constant Natural := Ada.Strings.Fixed.Index (Line, ":");
         begin
            if Colon /= 0 then
               Headers.Insert (Line (Line'First .. Colon - 1),
                               To_Unbounded_String (Line (Colon + 2 .. Line'Last)));
            end if;
         end;

         Start := End_Pos + 2;
      end loop;

      -- Write response
      String'Write (Stream (Socket), "HTTP/1.1 200 OK" & ASCII.CR & ASCII.LF);
      String'Write (Stream (Socket), "Content-Type: text/plain" & ASCII.CR & ASCII.LF);
      String'Write (Stream (Socket), "" & ASCII.CR & ASCII.LF);

      -- Echo headers
      for C in Headers.Iterate loop
         String'Write (Stream (Socket), 
            String_Maps.Key (C) & ": " & To_String (String_Maps.Element (C)) & ASCII.LF);
      end loop;
   end Headers;

   Server_Socket : Socket_Type;
   Client_Socket : Socket_Type;
   Address       : Sock_Addr_Type;
   Request       : String (1 .. 1024);
   Last          : Natural;

begin
   Address.Addr := Inet_Addr ("127.0.0.1");
   Address.Port := 8090;

   Create_Socket (Server_Socket);
   Set_Socket_Option (Server_Socket, Socket_Level, (Reuse_Address, True));
   Bind_Socket (Server_Socket, Address);
   Listen_Socket (Server_Socket);

   Put_Line ("Server started on port 8090");

   loop
      Accept_Socket (Server_Socket, Client_Socket, Address);

      String'Read (Stream (Client_Socket), Request, Last);

      if Ada.Strings.Fixed.Index (Request (1 .. Last), "/hello") /= 0 then
         Hello (Client_Socket);
      elsif Ada.Strings.Fixed.Index (Request (1 .. Last), "/headers") /= 0 then
         Headers (Client_Socket, Request (1 .. Last));
      else
         String'Write (Stream (Client_Socket), "HTTP/1.1 404 Not Found" & ASCII.CR & ASCII.LF);
      end if;

      Close_Socket (Client_Socket);
   end loop;
end HTTP_Server;

This Ada program creates a basic HTTP server that listens on port 8090. It defines two routes: “/hello” and “/headers”.

The Hello procedure is a simple handler that responds with “hello”.

The Headers procedure is more sophisticated. It parses the incoming HTTP headers and echoes them back in the response.

In the main procedure, we set up a server socket, bind it to the local address and port 8090, and then enter an infinite loop to accept incoming connections.

For each connection, we read the request, determine which handler to call based on the requested path, and then close the client socket.

To run the server:

  1. Save the code in a file named http_server.adb.
  2. Compile the code:
$ gnatmake http_server.adb
  1. Run the server:
$ ./http_server
Server started on port 8090

You can then access the server using curl or a web browser:

$ curl localhost:8090/hello
hello

This example demonstrates basic socket programming and HTTP handling in Ada. Note that for a production server, you’d want to add error handling, implement proper HTTP parsing, and possibly use a more robust web framework.