lazarus/tools/jsonviewer/frarest.pp

560 lines
13 KiB
ObjectPascal

unit frarest;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, StdCtrls, Buttons, ActnList, ComCtrls, frmAuthentication, fphttpclient, SynEdit,
SynHighlighterJScript;
type
{ TRestFrame }
TRestRequest = Procedure (Sender : TObject; Stream : TStream) of object;
{ TRequestData }
TRequestData = Class(TCollectionItem)
private
FContent: UTF8String;
FHeaders: TStrings;
FMethod: String;
FName: UTF8String;
FURL: String;
procedure SetHeaders(AValue: TStrings);
Public
Constructor Create(aCollection : TCollection); override;
Destructor Destroy; override;
Procedure Assign(Source : TPersistent); override;
Property Name : UTF8String Read FName Write FName;
Property Method : String Read FMethod Write FMethod;
Property URL : String Read FURL Write FURL;
Property Headers : TStrings Read FHeaders Write SetHeaders;
Property Content : UTF8String Read FContent Write FContent;
end;
{ TRequestDataList }
TRequestDataList = Class(TCollection)
private
FOnChanged : TNotifyEvent;
function GetD(aIndex : Integer): TRequestData;
procedure SetD(aIndex : Integer; AValue: TRequestData);
Protected
procedure Update(Item: TCollectionItem); override;
Public
Function AddRequest(aName : UTF8String) : TRequestData;
Property Requests[aIndex : Integer] : TRequestData Read GetD Write SetD; default;
end;
TRestFrame = class(TFrame)
AAddHeader: TAction;
AAuthentication: TAction;
AAddToFavourites: TAction;
ASend: TAction;
ADeleteHeader: TAction;
AEditHeader: TAction;
ALRest: TActionList;
Button1: TButton;
CBMethod: TComboBox;
CBURL: TComboBox;
CBUseCurrentTabContent: TCheckBox;
ILRest: TImageList;
LHTTPStatus: TLabel;
LBHeaders: TListBox;
LBResponseHeaders: TListBox;
PCRest: TPageControl;
SBAdd: TSpeedButton;
SBDelete: TSpeedButton;
SBEdit: TSpeedButton;
SERequestContent: TSynEdit;
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
SynContent: TSynJScriptSyn;
TSResult: TTabSheet;
TSRequestContent: TTabSheet;
TSHeaders: TTabSheet;
procedure AAddHeaderExecute(Sender: TObject);
procedure AAddToFavouritesExecute(Sender: TObject);
procedure AAddToFavouritesUpdate(Sender: TObject);
procedure AAuthenticationExecute(Sender: TObject);
procedure ADeleteHeaderExecute(Sender: TObject);
procedure ADeleteHeaderUpdate(Sender: TObject);
procedure AEditHeaderExecute(Sender: TObject);
procedure AEditHeaderUpdate(Sender: TObject);
procedure ASendExecute(Sender: TObject);
procedure ASendUpdate(Sender: TObject);
procedure CBURLKeyPress(Sender: TObject; var Key: char);
private
FFavourites: TRequestDataList;
FOnContentReceived: TRestRequest;
FOnSendContent: TRestRequest;
function GetOnFavouritesChanged: TNotifyEvent;
function GetRequestData: TStream;
function GetURL: String;
procedure GetUserNamePassword(out aUserName, aPassword: String);
procedure SetFavourites(AValue: TRequestDataList);
procedure SetOnFavouritesChanged(AValue: TNotifyEvent);
procedure SetUserNamePassword(const aUserName, aPassword: String);
procedure ShowResult(H: TFPHTTPClient; Resp: TStream);
public
Constructor Create(aOwner : TComponent); override;
Destructor Destroy; override;
Procedure ExecuteRequest;
Function HaveFavouriteData: Boolean;
Function AddToFavourites(Const AName : String; AddContent : Boolean) : TRequestData;
Function AddToFavourites : TRequestData;
Procedure ApplyFavourite(aFavourite : TRequestData);
Procedure LoadFavourites(Const FileName : String);
Procedure SaveFavourites(Const FileName : String);
Property OnFavouritesChanged : TNotifyEvent Read GetOnFavouritesChanged Write SetOnFavouritesChanged;
Property Favourites : TRequestDataList Read FFavourites Write SetFavourites;
Property OnSendContent: TRestRequest Read FOnSendContent Write FOnSendContent;
Property OnContentReceived: TRestRequest Read FOnContentReceived Write FOnContentReceived;
end;
implementation
uses base64,dialogs, uriparser, frmheader, strutils, frmaddtofavourite, jsonconf;
Const
SAuthorization = 'Authorization';
SBasic = 'Basic';
{$R *.lfm}
{ TRequestData }
procedure TRequestData.SetHeaders(AValue: TStrings);
begin
if FHeaders=AValue then Exit;
FHeaders.Assign(aValue);
end;
constructor TRequestData.Create(aCollection: TCollection);
begin
inherited Create(aCollection);
FHeaders:=TStringList.Create;
FHeaders.NameValueSeparator:=':';
end;
destructor TRequestData.Destroy;
begin
FreeAndNil(Fheaders);
inherited Destroy;
end;
procedure TRequestData.Assign(Source: TPersistent);
Var
RD : TRequestData;
begin
if (Source is TRequestData) then
begin
RD:=Source as TRequestData;
FName:=RD.Name;
FContent:=RD.Content;
FHeaders:=RD.Headers;
FMethod:=RD.Method;
FURL:=RD.URL;
end
else
inherited Assign(Source);
end;
{ TRequestDataList }
function TRequestDataList.GetD(aIndex : Integer): TRequestData;
begin
Result:=Items[aIndex] as TRequestData;
end;
procedure TRequestDataList.SetD(aIndex : Integer; AValue: TRequestData);
begin
Items[aIndex]:=AValue;
end;
procedure TRequestDataList.Update(Item: TCollectionItem);
begin
inherited Update(Item);
If Assigned(FOnChanged) then
FOnChanged(Self);
end;
function TRequestDataList.AddRequest(aName: UTF8String): TRequestData;
begin
Result:=Add as TRequestData;
Result.Name:=AName;
end;
{ TRestFrame }
procedure TRestFrame.ASendUpdate(Sender: TObject);
begin
(Sender as TAction).Enabled:=(CBURL.Text<>'') and (CBMethod.Text<>'');
end;
procedure TRestFrame.CBURLKeyPress(Sender: TObject; var Key: char);
begin
if Key=#13 then
ExecuteRequest;
end;
Function TRestFrame.GetURL : String;
Var
URI : TURI;
begin
URI:=ParseURI(CBURL.Text,'http',80,False);
if URI.Port=80 then
URI.Port:=0;
Result:=EncodeURI(URI);
end;
Function TRestFrame.GetRequestData : TStream;
var
Req : TStream;
begin
Req:=Nil;
if CBUseCurrentTabContent.Checked then
begin
Req:=TMemoryStream.Create;
if Assigned(OnSendContent) then
OnSendContent(Self,Req);
end
else if (Trim(SERequestContent.Text)<>'') then
begin
Req:=TMemoryStream.Create;
SERequestContent.Lines.SaveToStream(Req);
end;
if Assigned(Req) then
Req.Position:=0;
Result:=Req;
end;
function TRestFrame.GetOnFavouritesChanged: TNotifyEvent;
begin
Result:=FFavourites.FOnChanged;
end;
procedure TRestFrame.ShowResult(H : TFPHTTPClient; Resp : TStream);
begin
TSResult.TabVisible:=True;
PCRest.ActivePage:=TSResult;
LBResponseHeaders.Items:=H.ResponseHeaders;
With H do
if ResponseStatusCode=0 then
LHTTPStatus.Caption:='HTTP request failed'
else
LHTTPStatus.Caption:=Format('HTTP %s %d %s',[ServerHTTPVersion,ResponseStatusCode,ResponseStatusText]);
if Assigned(OnContentReceived) and (Resp.Size>0) then
OnContentReceived(Self,Resp);
end;
constructor TRestFrame.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
// For some reason this is not kept ?
LBHeaders.Items.NameValueSeparator:=':';
FFavourites:=TRequestDataList.Create(TRequestData);
end;
destructor TRestFrame.Destroy;
begin
FreeAndNil(FFavourites);
inherited Destroy;
end;
procedure TRestFrame.ExecuteRequest;
Var
H : TFPHTTPClient;
S : String;
Req,Resp : TStream;
begin
Resp:=nil;
Req:=nil;
H:=TFPHTTPClient.Create(Self);
try
For S in LBHeaders.Items do
H.RequestHeaders.Add(S);
if Not SameText(CBMethod.Text,'GET') then
Req:=GetRequestData;
H.RequestBody:=Req;
Resp:=TMemoryStream.Create;
try
H.HTTPMethod(CBMethod.Text,GetURL,Resp,[]);
except
on E : Exception do
ShowMessage(Format('Request failed with error %s : %s',[E.ClassName,E.Message]));
end;
ShowResult(H,Resp);
finally
Req.Free;
Resp.Free;
H.Free;
end;
end;
function TRestFrame.AddToFavourites(const AName: String; AddContent: Boolean): TRequestData;
Var
R : TRequestData;
S : TStringStream;
begin
FFavourites.BeginUpdate;
try
R:=FFavourites.AddRequest(aName);
R.Method:=CBMethod.Text;
R.Headers:=LBHeaders.Items;
R.URL:=CBURL.Text;
if AddContent then
if Not (CBUseCurrentTabContent.Checked and Assigned(OnSendContent)) then
R.Content:=SERequestContent.Text
else
begin
S:=TStringStream.Create('',CP_UTF8);
try
OnSendContent(Self,S);
R.Content:=S.DataString;
finally
S.Free;
end;
end;
Result:=R;
finally
FFavourites.EndUpdate;
end;
end;
procedure TRestFrame.ApplyFavourite(aFavourite: TRequestData);
begin
CBMethod.Text:=aFavourite.Method;
LBHeaders.Items:=aFavourite.Headers;
CBURL.Text:=aFavourite.URL;
if aFavourite.Content<>'' then
begin
CBUseCurrentTabContent.Checked:=False;
SERequestContent.Text:=aFavourite.Content;
end;
end;
procedure TRestFrame.LoadFavourites(const FileName: String);
Var
C : TJSONConfig;
I,aCount : Integer;
N : UTF8String;
begin
C:=Nil;
FFavourites.BeginUpdate;
try
FFavourites.Clear;
C:=TJSONConfig.Create(Self);
C.Filename:=FileName;
C.OpenKey('/Favourites',True);
aCount:=C.GetValue('Count',0);
For I:=1 to aCount do
begin
C.OpenKey(Format('/Favourites/Favourite%d',[I]),True);
N:=C.GetValue('Name','');
With FFavourites.AddRequest(N) do
begin
Method:=C.GetValue('Method','GET');
URL:=C.GetValue('Url','');
C.GetValue('Headers',Headers,'');
end;
end;
finally
FFavourites.EndUpdate;
C.Free;
end;
end;
procedure TRestFrame.SaveFavourites(const FileName: String);
Var
C : TJSONConfig;
I : Integer;
begin
C:=TJSONConfig.Create(Self);
try
C.Filename:=FileName;
C.OpenKey('/Favourites',True);
C.SetValue('Count',FFavourites.Count);
For I:=0 to FFavourites.Count-1 do
begin
C.OpenKey(Format('/Favourites/Favourite%d',[I+1]),True);
With FFavourites[i] do
begin
C.SetValue('Name',FFavourites[i].Name);
C.SetValue('Method',FFavourites[i].Method);
C.SetValue('Url',FFavourites[i].URL);
C.SetValue('Headers',FFavourites[i].Headers);
end;
end;
C.Flush;
finally
C.Free;
end;
end;
procedure TRestFrame.ASendExecute(Sender: TObject);
begin
ExecuteRequest;
end;
procedure TRestFrame.AAddHeaderExecute(Sender: TObject);
begin
LBHeaders.Items.NameValueSeparator:=':';
With THeaderForm.Create(Self) do
try
if ShowModal=mrOK then
if (HeaderValue<>'') then
LBHeaders.Items.Values[HeaderName]:=' '+HeaderValue
else
LBHeaders.Items.Add(HeaderName+': ');
finally
Free;
end;
end;
function TRestFrame.AddToFavourites: TRequestData;
begin
Result:=nil;
With TSaveRequestDataForm.Create(Self) do
try
if ShowModal=mrOK then
Result:=AddToFavourites(RequestName,SaveContent);
Finally
Free;
end;
end;
procedure TRestFrame.AAddToFavouritesExecute(Sender: TObject);
begin
AddToFavourites;
end;
Function TRestFrame.HaveFavouriteData : Boolean;
begin
Result:=(CBURL.Text<>'') and (CBMethod.Text<>'');
end;
procedure TRestFrame.AAddToFavouritesUpdate(Sender: TObject);
begin
(Sender as TAction).Enabled:=HaveFavouriteData;
end;
procedure TRestFrame.GetUserNamePassword(Out aUserName,aPassword : String);
Var
A : String;
begin
aUserName:='';
aPassword:='';
A:=Trim(LBHeaders.Items.Values[SAuthorization]);
if Not SameText(ExtractWord(1,A,[' ']),SBasic) then exit;
A:=ExtractWord(2,A,[' ']);
if A='' then exit;
A:=DecodeStringBase64(A);
aUserName:=ExtractWord(1,A,[':']);
aPassword:=ExtractWord(2,A,[':']);
end;
procedure TRestFrame.SetFavourites(AValue: TRequestDataList);
begin
if FFavourites=AValue then Exit;
FFavourites.Assign(AValue);
end;
procedure TRestFrame.SetOnFavouritesChanged(AValue: TNotifyEvent);
begin
if GetOnFavouritesChanged=AValue then Exit;
FFavourites.FOnChanged:=AValue;
end;
procedure TRestFrame.SetUserNamePassword(Const aUserName,aPassword : String);
Var
A : String;
begin
A:=EncodeStringBase64(aUserName+':'+aPassword);
LBHeaders.Items.Values[SAuthorization]:=SBasic+' '+A;
end;
procedure TRestFrame.AAuthenticationExecute(Sender: TObject);
Var
UN, PW : String;
begin
LBHeaders.Items.NameValueSeparator:=':';
GetUserNamePassword(UN,PW);
With TAuthenticationForm.Create(Self) do
try
Username:=UN;
Password:=PW;
If ShowModal=mrOK then
SetUserNamePassword(UserName,Password);
finally
Free;
end;
end;
procedure TRestFrame.ADeleteHeaderExecute(Sender: TObject);
begin
With LBHeaders do
if (ItemIndex<>-1) then
Items.Delete(ItemIndex);
end;
procedure TRestFrame.ADeleteHeaderUpdate(Sender: TObject);
begin
(Sender as TAction).Enabled:=(LBHeaders.ItemIndex<>-1);
end;
procedure TRestFrame.AEditHeaderExecute(Sender: TObject);
Var
idx : Integer;
begin
LBHeaders.Items.NameValueSeparator:=':';
idx:=LBHeaders.ItemIndex;
With THeaderForm.Create(Self) do
try
HeaderName:=LBHeaders.Items.Names[idx];
HeaderValue:=LBHeaders.Items.ValueFromIndex[idx];
if (ShowModal=mrOK) then
if (HeaderValue<>'') then
LBHeaders.Items[idx]:=HeaderName+': '+HeaderValue
else
LBHeaders.Items[idx]:=HeaderName+':';
finally
Free;
end;
end;
procedure TRestFrame.AEditHeaderUpdate(Sender: TObject);
begin
(Sender as TAction).Enabled:=(LBHeaders.ItemIndex<>-1);
end;
end.