Receiving and responding HTTP messages using TCP sockets

Posted: (EET/GMT+2)

 

The HTTP protocol operates over TCP, and from a programming perspective, you can use network sockets for implementing the communications. I'm showing below how you can use Delphi to work with the HTTP protocol.

First, you need to open a socket in listening mode. The default HTTP port number is 80, but you can use any port you like. Since sockets can communicate in both directions, it is best to use the Delphi TThread class. Here is an example of opening a socket:

uses
  Classes, WinSock;
Const
  HTTPListenPort = 80;
...
Procedure TAcceptor.CreateListenSocket;
Var
  Name : TSockAddr;
  I    : Integer;

Begin
  Socket := WinSock.Socket(af_Inet,sock_Stream,IPProto_TCP);
  If (Socket = Invalid_Socket) Then Begin
    Msg := 'Acceptor: Can''t create socket: '+IntToStr(WSAGetLastError);
    Synchronize(DisplayMessage);
    Exit;
  End;
  With Name do Begin
    sin_Family := pf_Inet;
    sin_Port := htons(HTTPListenPort);
    I := htonl(InAddr_Any);
    sin_Addr := TInAddr(I);
  End;
  I := Bind(Socket,Name,SizeOf(Name));
  If (I = SOCKET_ERROR) Then Begin
    Msg := 'Acceptor: Can''t bind: '+IntToStr(WSAGetLastError);
    Synchronize(DisplayMessage);
    Exit;
  End;
  I := Listen(Socket,3);
  If (I = SOCKET_ERROR) Then Begin
    Msg := 'Acceptor: Can''t listen: '+IntToStr(WSAGetLastError);
    Synchronize(DisplayMessage);
    Exit;
  End;
  Msg := 'Acceptor: Waiting for connections...';
  Synchronize(DisplayMessage);
End;

The next step is to create a HTTP request processor. Again, this should be a custom descendant class of TThread. Here is a simple example:

procedure THTTPRequest.Execute;
Var
  Buf  : Array[0..512000] of Char; { HTTP data must be less than 500k }
  I    : Integer;
  Name : TSockAddr;
  S    : String;

begin
  Try
    I := Recv(Socket,Buf,SizeOf(Buf),0);
    If (I = SOCKET_ERROR) Then Begin
      Msg := 'Request: Can''t receive header: '+IntToStr(Socket)+' '+IntToStr(WSAGetLastError);
      Synchronize(DisplayMessage);
      Exit;
    End;
    S := 'Hello HTTP from Delphi!';
    I := Send(Socket,S[1],Length(S),0);
    If (I = SOCKET_ERROR) Then Begin
      Msg := 'Request: Can''t send: '+IntToStr(WSAGetLastError);
      Synchronize(DisplayMessage);
      Exit;
    End;
  Finally
    CloseSocket(Socket);
  End;
end;

If you put these two pieces of code together, you can respond to HTTP requests without any web server.

Remember that you need to initialize and shut Winsock down with WSAStartup and WSACleanup. Otherwise, you cannot create socket connections.