mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-06 07:58:07 +02:00
560 lines
13 KiB
ObjectPascal
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.
|
|
|