2010/01/01
Adaで超いい加減HTTPサーバ
Adaのタスクはもっと評価されいい、のかな?
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Maps; use Ada.Strings.Maps;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Streams;
with Ada.Streams.Stream_IO;
with GNAT.Sockets;
with Ada.Integer_Text_IO;
use Ada.Integer_Text_IO;
procedure Run_Server is
package GS renames GNAT.Sockets;
CRLF: constant String := ASCII.CR & ASCII.LF;
task type HTTP_Request is
entry Process(Client_Socket: in GS.Socket_Type);
end;
task body HTTP_Request is
Client: GS.Socket_Type;
Connection: GS.Stream_Access;
function Read return String is
Request_Error: exception;
Offset: Ada.Streams.Stream_Element_Count;
Buffer: Ada.Streams.Stream_Element_Array(1..1024);
Result: Unbounded_String := To_Unbounded_String("");
begin
loop
GS.Receive_Socket(Client, Buffer, Offset);
if Natural(Offset) = 0 then
Put_Line("EOF");
raise Request_Error;
end if;
for i in 1..Offset loop
Result := Result & Character'Val(Buffer(i));
end loop;
exit when Tail(Result, 4) = CRLF & CRLF;
end loop;
return To_String(Result);
end;
function Parse_URL(Headers: String) return String is
first: Positive;
last: Natural;
begin
Find_Token(Headers, To_Set(" "), Ada.Strings.Outside, first, last);
Find_Token(Headers(last+1..Headers'Last), To_Set(" "), Ada.Strings.Outside, first, last);
declare
Url: String := Headers(first+1..last);
begin
if Url = "" or else Url(Url'Last) = '/' then
Url := Url & "index.html";
end if;
return Url;
end;
end;
procedure Write(Url: String) is
package ASS_IO renames Ada.Streams.Stream_IO;
File: ASS_IO.File_Type;
begin
ASS_IO.Open(File, ASS_IO.In_File, Url);
declare
File_Stream: ASS_IO.Stream_Access;
Offset: Ada.Streams.Stream_Element_Count;
File_Buffer: Ada.Streams.Stream_Element_Array(1..1024);
begin
String'Write(Connection, "HTTP/1.0 200 OK" & CRLF & CRLF);
File_Stream := ASS_IO.Stream(File);
loop
Ada.Streams.Read(File_Stream.all, File_Buffer, Offset);
exit when Natural(Offset) = 0;
Connection.Write(File_Buffer(1..Offset));
end loop;
ASS_IO.Close(File);
exception
when others => ASS_IO.Close(File);
end;
Put_Line("done");
end;
begin
accept Process(Client_Socket: in GS.Socket_Type) do
Client := Client_Socket;
end Process;
Connection := GS.Stream(Client);
declare
Headers: String := Read;
Url: String := Parse_URL(Headers);
begin
Write(Url);
end;
GS.Close_Socket(Client);
exception
when others =>
GS.Close_Socket(Client);
end;
type HTTP_Request_Access is access HTTP_Request;
Server: GS.Socket_Type;
Server_Address: GS.Sock_Addr_Type;
Client: GS.Socket_Type;
Client_Address: GS.Sock_Addr_Type;
begin
GS.Initialize;
GS.Create_Socket(Server);
Server_Address.Addr := GS.Inet_Addr("127.0.0.1");
Server_Address.Port := 1972;
GS.Bind_Socket(Server, Server_Address);
GS.Listen_Socket(Server);
loop
GS.Accept_Socket(Server, Client, Client_Address);
Put_Line("Request came");
declare
req: HTTP_Request_Access := new HTTP_Request;
begin
req.Process(Client);
end;
end loop;
end;
Goのgoroutine、Adaのタスクと来たら次はScalaのアクターで書くとどうなるのか、是非見てみたいですね。
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/uchida/ada8d853044304452a06e1bhttp30b530fc/tbping