{
    This file is part of the Web Service Toolkit
    Copyright (c) 2006 by Inoussa OUEDRAOGO

    This file is provide under modified LGPL licence
    ( the files COPYING.modifiedLGPL and COPYING.LGPL).


    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
}

{$INCLUDE wst_global.inc}
{$IFDEF FPC}
  //{$UNDEF INDY_9}
  //{$DEFINE INDY_10}
{$ELSE}
  //{$UNDEF INDY_10}
  //{$DEFINE INDY_9}
{$ENDIF}

unit indy_http_server;

interface

uses
  Classes, SysUtils,
  IdCustomHTTPServer,
  IdHTTPServer,
{$IFDEF INDY_10}
  IdContext,
{$ENDIF}
{$IFDEF INDY_9}
  IdTCPServer,
{$ENDIF}
  IdSocketHandle,
  server_listener;

{$INCLUDE wst.inc}
{$INCLUDE wst_delphi.inc}
  
type

  { TwstIndyHttpListener }

  TwstIndyHttpListener = class(TwstListener)
  private
    FHTTPServerObject: TIdHTTPServer;
    FRootAddress : string;
  private
    procedure ProcessWSDLRequest(
          {$IFDEF INDY_10}
          AContext        : TIdContext;
          {$ENDIF}
          ARequestInfo    : TIdHTTPRequestInfo;
          AResponseInfo   : TIdHTTPResponseInfo;
      var APath           : string
    );
    procedure ProcessServiceRequest(
          {$IFDEF INDY_10}
          AContext        : TIdContext;
          {$ENDIF}
          ARequestInfo    : TIdHTTPRequestInfo;
          AResponseInfo   : TIdHTTPResponseInfo;
      var APath           : string
    );
  private
    procedure Handler_CommandGet(
    {$IFDEF INDY_10}
      AContext        : TIdContext;
    {$ENDIF}
    {$IFDEF INDY_9}
      AThread: TIdPeerThread;
    {$ENDIF}
      ARequestInfo    : TIdHTTPRequestInfo;
      AResponseInfo   : TIdHTTPResponseInfo
    );
  public
    constructor Create(
      const AServerIpAddress   : string  = '127.0.0.1';
      const AListningPort      : Integer = 8000;
      const ADefaultClientPort : Integer = 25000;
      const AServerSoftware    : string  = 'Web Service Toolkit Application'
    );
    destructor Destroy(); override;
    class function GetDescription() : string;override;
    procedure Start();override;
    procedure Stop();override;
  end;


implementation
uses
{$IFNDEF FPC}
     ActiveX,
  {$IFDEF INDY_9}
     wst_indy9_utils,
  {$ENDIF}
{$ENDIF}
     base_service_intf,
     server_service_intf, server_service_imputils,
     metadata_wsdl;

function ExtractNextPathElement(var AFullPath : string):string;
var
  i : SizeInt;
begin
  Result := '';
  if ( Length(AFullPath) > 0 ) then begin
    while ( Length(AFullPath) > 0 ) and ( AFullPath[1] = sSEPARATOR ) do begin
      Delete(AFullPath,1,1);
    end;
    i := Pos(sSEPARATOR,AFullPath);
    if ( i < 1 ) then begin
      Result := AFullPath;
      AFullPath := '';
    end else begin
      Result := Copy(AFullPath,1,Pred(i));
      Delete(AFullPath,1,i);
    end;
  end;
end;

{ TwstIndyHttpListener }

procedure TwstIndyHttpListener.ProcessWSDLRequest(
      {$IFDEF INDY_10}
      AContext        : TIdContext;
      {$ENDIF}
      ARequestInfo    : TIdHTTPRequestInfo;
      AResponseInfo   : TIdHTTPResponseInfo;
  var APath           : string
);
var
  locRepName, strBuff : string;
  i : Integer;
begin
  locRepName := ExtractNextPathElement(APath);
  if AnsiSameText(sWSDL,locRepName) then
    locRepName := ExtractNextPathElement(APath);
  strBuff := GenerateWSDL(locRepName,FRootAddress);
  i := Length(strBuff);
  if ( i > 0 ) then begin
    AResponseInfo.ContentType := 'text/xml';
    if not Assigned(AResponseInfo.ContentStream) then
      AResponseInfo.ContentStream := TMemoryStream.Create();
    AResponseInfo.ContentStream.Write(strBuff[1],i);
    Exit;
  end;
  AResponseInfo.ContentText := GenerateWSDLHtmlTable();
  AResponseInfo.ContentType := 'text/html';
end;

procedure TwstIndyHttpListener.ProcessServiceRequest(
      {$IFDEF INDY_10}
      AContext        : TIdContext;
      {$ENDIF}
      ARequestInfo    : TIdHTTPRequestInfo;
      AResponseInfo   : TIdHTTPResponseInfo;
  var APath           : string
);
var
  trgt,ctntyp, frmt : string;
  rqst : IRequestBuffer;
  inStream : {$IFDEF FPC}TMemoryStream{$ELSE}TStringStream{$ENDIF};
begin
  trgt := ExtractNextPathElement(APath);
  if AnsiSameText(sWSDL,trgt) then begin
    ProcessWSDLRequest({$IFDEF INDY_10}AContext,{$ENDIF}ARequestInfo,AResponseInfo,APath);
    Exit;
  end;
  inStream := nil;
  try
    try
      inStream := {$IFDEF FPC}TMemoryStream.Create();{$ELSE}TStringStream.Create(ARequestInfo.FormParams);{$ENDIF}
      AResponseInfo.ContentStream := TMemoryStream.Create();

      ctntyp := ARequestInfo.ContentType;
    {$IFDEF FPC}
      inStream.CopyFrom(ARequestInfo.PostStream,0);
    {$ENDIF}
      inStream.Position := 0;
      AResponseInfo.ContentType := ctntyp;
      frmt := Trim(ARequestInfo.Params.Values['format']);
      rqst := TRequestBuffer.Create(trgt,ctntyp,inStream,AResponseInfo.ContentStream,frmt);
      HandleServiceRequest(rqst);
    finally
      inStream.Free();
    end;
  except
    on e : Exception do begin
      NotifyMessage('ProcessData()>> Exception = '+e.Message);
      raise;
    end;
  end;
end;

procedure TwstIndyHttpListener.Handler_CommandGet(
  {$IFDEF INDY_10}
    AContext        : TIdContext;
  {$ENDIF}
  {$IFDEF INDY_9}
    AThread: TIdPeerThread;
  {$ENDIF}
  ARequestInfo   : TIdHTTPRequestInfo;
  AResponseInfo  : TIdHTTPResponseInfo
);
var
{$IFDEF WST_DBG}
  s : string;
{$ENDIF}
  locPath, locPathPart : string;
  j : SizeInt;
begin
{$IFDEF WST_DBG}
  if Assigned(ARequestInfo.PostStream) and ( ARequestInfo.PostStream.Size > 0 ) then begin
    j := ARequestInfo.PostStream.Size;
    SetLength(s,j);
    ARequestInfo.PostStream.Read(s[1],j);
    NotifyMessage('----------- QUERY ----------------------');
    Display(s);
  end;
{$ENDIF}
  locPath := ARequestInfo.Document;
  locPathPart := ExtractNextPathElement(locPath);
  if AnsiSameText(sSERVICES_PREFIXE,locPathPart)  then begin
    ProcessServiceRequest({$IFDEF INDY_10}AContext,{$ENDIF}ARequestInfo,AResponseInfo,locPath);
  {$IFDEF WST_DBG}
    if Assigned(AResponseInfo.ContentStream) and ( AResponseInfo.ContentStream.Size > 0 ) then begin
      j := AResponseInfo.ContentStream.Size;
      SetLength(s,j);
      AResponseInfo.ContentStream.Position := 0;
      AResponseInfo.ContentStream.Read(s[1],j);
      Display('--------- RESPONSE ------------------------');
      Display(s);
    end;
  {$ENDIF}
    Exit;
  end;

  ProcessWSDLRequest({$IFDEF INDY_10}AContext,{$ENDIF}ARequestInfo,AResponseInfo,locPath);
end;

constructor TwstIndyHttpListener.Create(
      const AServerIpAddress   : string;
      const AListningPort      : Integer;
      const ADefaultClientPort : Integer;
      const AServerSoftware    : string
);
var
  b : TIdSocketHandle;
begin
  inherited Create();
  FHTTPServerObject := TIdHTTPServer.Create({$IFDEF INDY_9}nil{$ENDIF});
{$IFDEF INDY_9}
  FHTTPServerObject.ThreadClass := TwstIndy9Thread;
{$ENDIF}
  b := FHTTPServerObject.Bindings.Add();
  b.IP := AServerIpAddress;
  b.port := AListningPort;
  FRootAddress := Format('http://%s:%d/',[AServerIpAddress,AListningPort]);

  FHTTPServerObject.DefaultPort := ADefaultClientPort;
  FHTTPServerObject.ServerSoftware := AServerSoftware;
  //FHTTPServerObject.Active := True;
  FHTTPServerObject.OnCommandGet := {$IFDEF FPC}@{$ENDIF}Handler_CommandGet;
end;

destructor TwstIndyHttpListener.Destroy();
begin
  if ( FHTTPServerObject <> nil ) then
    Stop();
  FreeAndNil(FHTTPServerObject);
  inherited Destroy();
end;

procedure TwstIndyHttpListener.Start();
begin
  if not FHTTPServerObject.Active then
    FHTTPServerObject.Active := True;
end;

procedure TwstIndyHttpListener.Stop();
begin
  if FHTTPServerObject.Active then
    FHTTPServerObject.Active := False;
end;

class function TwstIndyHttpListener.GetDescription: string;
begin
  Result := 'WST Indy HTTP Listener';
end;

initialization


end.
