Compare commits
6 Commits
Author | SHA1 | Date |
---|---|---|
Andreas Schneider | 4742af20fe | |
Andreas Schneider | 282ae6fa28 | |
Andreas Schneider | 7cc7705b29 | |
Andreas Schneider | 8e820eb2f3 | |
Andreas Schneider | e576805e84 | |
Andreas Schneider | b260f184f8 |
16
README.md
16
README.md
|
@ -113,6 +113,22 @@ Once the first none-empty line is unrecognized (no command found), the parser wi
|
|||
: Sets authentication for the HTTP proxy.
|
||||
Same syntax as `BasicAuth`.
|
||||
|
||||
`Generate <variablename> <generator>`
|
||||
: Sets a variable with a generated value.
|
||||
Possible generators:
|
||||
|
||||
* `UUID`
|
||||
* `unixtime` (a unix timestamp)
|
||||
* `localtime` (a formatted time)
|
||||
* `isodatetime` (Date and Time according to ISO8601)
|
||||
* `isodate` (Date according to ISO8601)
|
||||
* `isotime` (Time according to ISO8601)
|
||||
|
||||
`Expect <expectation type>=<expecation>`
|
||||
: Checks expectations after the request.
|
||||
* `Status=<statuscode>`: checks, if the status code matches
|
||||
If an expectation fails, the application exists with code 5.
|
||||
|
||||
`Call <URL>`
|
||||
: This prepares the actual call by providing the URL to be called.
|
||||
Variables in the form of `@<variablename>` are replaced accordingly.
|
||||
|
|
|
@ -56,6 +56,7 @@ type
|
|||
FFormFields: TStrings;
|
||||
FFilters: TFilterList;
|
||||
FBeautify: Boolean;
|
||||
FExpectations: TStringList;
|
||||
FURL: String;
|
||||
FMethod: String;
|
||||
//Main
|
||||
|
@ -69,11 +70,14 @@ type
|
|||
procedure CmdFormField(AData: String);
|
||||
procedure CmdProxy(AData: String);
|
||||
procedure CmdProxyAuth(AData: String);
|
||||
procedure CmdGenerate(AData: String);
|
||||
procedure CmdExpect(AData: String);
|
||||
procedure ProcessCall(AURL: String);
|
||||
//Helper
|
||||
procedure WriteHelp;
|
||||
procedure ListTemplates;
|
||||
procedure WriteContent;
|
||||
procedure CheckExpectations;
|
||||
public
|
||||
constructor Create; overload;
|
||||
destructor Destroy; override;
|
||||
|
@ -83,7 +87,7 @@ implementation
|
|||
|
||||
uses
|
||||
strutils, crt, UCRTHelper, fpjson, DOM, XMLRead, XMLWrite, vinfo,
|
||||
IdCompressorZLib, IdHeaderList, IdGlobalProtocols;
|
||||
IdCompressorZLib, IdHeaderList, IdGlobalProtocols, xmlxsdparser;
|
||||
|
||||
type
|
||||
TContentType = (ctOther, ctJSON, ctXML);
|
||||
|
@ -165,8 +169,8 @@ begin
|
|||
|
||||
if FileExists(ParamStr(ParamCount)) then
|
||||
begin
|
||||
AssignFile(data, ParamStr(1));
|
||||
FTemplateName := ExtractFileName(ParamStr(1));
|
||||
AssignFile(data, ParamStr(ParamCount));
|
||||
FTemplateName := ExtractFileName(ParamStr(ParamCount));
|
||||
if AnsiEndsStr('.rest', FTemplateName) then
|
||||
FTemplateName := Copy(FTemplateName, 1, Length(FTemplateName) - 5);
|
||||
end else
|
||||
|
@ -267,6 +271,16 @@ begin
|
|||
Result := True;
|
||||
CmdProxy(Copy(ALine, 10, Length(ALine)));
|
||||
end else
|
||||
if AnsiStartsStr('Generate ', ALine) then
|
||||
begin
|
||||
Result := True;
|
||||
CmdGenerate(Copy(ALine, 10, Length(ALine)));
|
||||
end else
|
||||
if AnsiStartsStr('Expect ', ALine) then
|
||||
begin
|
||||
Result := True;
|
||||
CmdExpect(Copy(ALine, 8, Length(ALine)));
|
||||
end else
|
||||
if AnsiStartsStr('Call ', ALine) then
|
||||
begin
|
||||
Result := True;
|
||||
|
@ -289,17 +303,25 @@ begin
|
|||
|
||||
AName := Copy(AName, 2, Length(AName));
|
||||
|
||||
if mode = pmNormal then
|
||||
//Check if the variable has been set on the commandline; we do not
|
||||
//have to ask the user then.
|
||||
if HasOption('var:' + AName) then
|
||||
begin
|
||||
default := FSessionIni.ReadString(FTemplateName, AName, '');
|
||||
value := Prompt(AName, default);
|
||||
value := GetOptionValue('var:' + AName);
|
||||
end else
|
||||
begin
|
||||
value := Prompt(AName, mode);
|
||||
end;
|
||||
if mode = pmNormal then
|
||||
begin
|
||||
default := FSessionIni.ReadString(FTemplateName, AName, '');
|
||||
value := Prompt(AName, default);
|
||||
end else
|
||||
begin
|
||||
value := Prompt(AName, mode);
|
||||
end;
|
||||
|
||||
if value = '' then
|
||||
Halt(3); //Cancelled
|
||||
if value = '' then
|
||||
Halt(3); //Cancelled
|
||||
end;
|
||||
|
||||
FParser.Fields.Add(AName, value);
|
||||
|
||||
|
@ -331,6 +353,10 @@ var
|
|||
separator: Char;
|
||||
i: Integer;
|
||||
begin
|
||||
FParser.Content := AData;
|
||||
FParser.Replace;
|
||||
AData := FParser.Content;
|
||||
|
||||
separator := AData[1];
|
||||
i := 2;
|
||||
while (i < Length(AData)) and (AData[i] <> separator) do
|
||||
|
@ -379,19 +405,60 @@ begin
|
|||
FHttp.ProxyParams.ProxyPassword := Copy(AData, i + 1, Length(AData));
|
||||
end;
|
||||
|
||||
procedure TRestemplateApplication.CmdGenerate(AData: String);
|
||||
var
|
||||
i: Integer;
|
||||
varName, generator: String;
|
||||
guid: TGuid;
|
||||
begin
|
||||
i := 1;
|
||||
while (i < Length(AData)) and (AData[i] <> ' ') do
|
||||
Inc(i);
|
||||
|
||||
varName := Copy(AData, 1, i - 1);
|
||||
generator := LowerCase(Copy(AData, i + 1, Length(AData)));
|
||||
|
||||
case generator of
|
||||
'uuid':
|
||||
begin
|
||||
CreateGUID(guid);
|
||||
FParser.Fields.Add(varName, Copy(GUIDToString(guid), 2, 36));
|
||||
end;
|
||||
'unixtime': FParser.Fields.Add(varName, IntToStr(DateTimeToUnix(Now)));
|
||||
'localtime': FParser.Fields.Add(varName, DateTimeToStr(Now));
|
||||
'isodatetime': FParser.Fields.Add(varName, xsdFormatDateTime(Now, nil));
|
||||
'isodate': FParser.Fields.Add(varName, xsdFormatDate(Now));
|
||||
'isotime': FParser.Fields.Add(varName, xsdFormatTime(Now));
|
||||
else
|
||||
raise Exception.Create('Unknown generator: ' + generator);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TRestemplateApplication.CmdExpect(AData: String);
|
||||
begin
|
||||
FExpectations.Add(AData);
|
||||
end;
|
||||
|
||||
procedure TRestemplateApplication.ProcessCall(AURL: String);
|
||||
var
|
||||
s: String;
|
||||
s, httpMethod: String;
|
||||
request, response: TStream;
|
||||
jsonParser: TJSONParser;
|
||||
jsonData: TJSONData;
|
||||
contentType: TContentType;
|
||||
xmlDoc: TXMLDocument;
|
||||
begin
|
||||
httpMethod := Trim(FMethod);
|
||||
if httpMethod = '' then
|
||||
if (FContent.Count > 0) or (FFormFields.Count > 0) then
|
||||
httpMethod := 'POST'
|
||||
else
|
||||
httpMethod := 'GET';
|
||||
|
||||
FParser.Content := AURL;
|
||||
FParser.Replace;
|
||||
AURL := FParser.Content;
|
||||
writeln('Calling ', AURL);
|
||||
writeln(httpMethod, ' ', AURL);
|
||||
|
||||
response := TMemoryStream.Create;
|
||||
request := nil;
|
||||
|
@ -407,18 +474,24 @@ begin
|
|||
FContent.SaveToStream(request);
|
||||
end;
|
||||
|
||||
if HasOption('showrequest') then
|
||||
begin
|
||||
//TODO Handle URL-Encoded FormFields here!
|
||||
writeln;
|
||||
writeln('Request:');
|
||||
for s in FContent do
|
||||
writeln(' ', s);
|
||||
end;
|
||||
|
||||
try
|
||||
FRequest.Prepare;
|
||||
FHttp.Request := FRequest;
|
||||
FHttp.HTTPOptions := FHttp.HTTPOptions + [hoNoProtocolErrorException];
|
||||
|
||||
// Workaround for CustomHeaders not being assigned :-/
|
||||
FHttp.Request.CustomHeaders.AddStrings(FRequest.CustomHeaders);
|
||||
|
||||
if SameText('POST', FMethod) and (FFormFields.Count > 0) then
|
||||
if SameText('POST', httpMethod) and (FFormFields.Count > 0) then
|
||||
FHttp.Post(AURL, FFormFields, response)
|
||||
else
|
||||
FHttp.Perform(FMethod, AURL, request, response);
|
||||
FHttp.Perform(httpMethod, AURL, request, response);
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
|
@ -468,6 +541,18 @@ begin
|
|||
|
||||
response.Free;
|
||||
request.Free;
|
||||
|
||||
try
|
||||
CheckExpectations;
|
||||
except
|
||||
on e: Exception do
|
||||
begin
|
||||
writeln;
|
||||
writeln('Expections failed:');
|
||||
writeln(e.Message);
|
||||
ExitCode := 5;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TRestemplateApplication.WriteHelp;
|
||||
|
@ -485,6 +570,8 @@ begin
|
|||
Writeln('Options:');
|
||||
Writeln(' -l --list');
|
||||
Writeln(' Print a list of known templates.');
|
||||
Writeln(' --var:<variableName>=<value>');
|
||||
Writeln(' Sets the variable <variableName> to <value>.');
|
||||
Writeln(' -h --help');
|
||||
Writeln(' Print this help screen.');
|
||||
end;
|
||||
|
@ -562,6 +649,26 @@ begin
|
|||
highlights.Free;
|
||||
end;
|
||||
|
||||
procedure TRestemplateApplication.CheckExpectations;
|
||||
var
|
||||
i: Integer;
|
||||
expectType, expectation: String;
|
||||
begin
|
||||
for i := 0 to FExpectations.Count - 1 do
|
||||
begin
|
||||
expectType := LowerCase(FExpectations.Names[i]);
|
||||
expectation := FExpectations.ValueFromIndex[i];
|
||||
|
||||
case expectType of
|
||||
'status':
|
||||
if FHttp.ResponseCode <> StrToInt(expectation) then
|
||||
raise Exception.Create(Format('Status code unexpected! %d <> %s', [FHttp.ResponseCode, expectation]));
|
||||
else
|
||||
raise Exception.Create('Invalid expectation: ' + FExpectations[i]);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TRestemplateApplication.Create;
|
||||
begin
|
||||
inherited Create(nil);
|
||||
|
@ -578,6 +685,7 @@ begin
|
|||
FRequest.RawHeaders.AddValue('User-Agent', 'Mozilla/4.0 (compatible; restemplate ' + VersionInfo.GetProductVersionString + ')');
|
||||
FFilters := TFilterList.Create;
|
||||
FParser := TJTemplateParser.Create;
|
||||
FExpectations := TStringList.Create;
|
||||
end;
|
||||
|
||||
destructor TRestemplateApplication.Destroy;
|
||||
|
@ -589,6 +697,7 @@ begin
|
|||
//TODO Owned? FRequest.Free;
|
||||
FFilters.Free;
|
||||
FParser.Free;
|
||||
FExpectations.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
|
|
|
@ -336,6 +336,7 @@ begin
|
|||
begin
|
||||
LDest := TIdEntityHeaderInfo(Destination);
|
||||
LDest.FRawHeaders.Assign(FRawHeaders);
|
||||
LDest.FCustomHeaders.Assign(FCustomHeaders);
|
||||
LDest.FCacheControl := FCacheControl;
|
||||
LDest.FCharSet := FCharSet;
|
||||
LDest.FContentDisposition := FContentDisposition;
|
||||
|
@ -966,9 +967,9 @@ begin
|
|||
// TODO: omitted intentionally?
|
||||
// LDest.FHost := FHost;
|
||||
// LDest.FProxyConnection := FProxyConnection;
|
||||
end else begin
|
||||
inherited AssignTo(Destination);
|
||||
end;
|
||||
|
||||
inherited AssignTo(Destination);
|
||||
end;
|
||||
|
||||
procedure TIdRequestHeaderInfo.Clear;
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
<VersionInfo>
|
||||
<UseVersionInfo Value="True"/>
|
||||
<MinorVersionNr Value="6"/>
|
||||
<StringTable LegalCopyright="Andreas Schneider" ProductName="restemplate" ProductVersion="0.6.0"/>
|
||||
<RevisionNr Value="2"/>
|
||||
<StringTable LegalCopyright="Andreas Schneider" ProductName="restemplate" ProductVersion="0.6.2"/>
|
||||
</VersionInfo>
|
||||
<MacroValues Count="1">
|
||||
<Macro1 Name="LCLWidgetType" Value="nogui"/>
|
||||
|
|
Loading…
Reference in New Issue