mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-13 23:59:10 +02:00
* Parse the ContentType according to rfc1341
git-svn-id: trunk@49360 -
This commit is contained in:
parent
6db4ab5012
commit
20039e3b77
@ -363,6 +363,7 @@ type
|
|||||||
// Variables
|
// Variables
|
||||||
Class Function GetVariableHeaderName(AVariable : THTTPVariableType) : String;
|
Class Function GetVariableHeaderName(AVariable : THTTPVariableType) : String;
|
||||||
Function GetHTTPVariable(AVariable : THTTPVariableType) : String;
|
Function GetHTTPVariable(AVariable : THTTPVariableType) : String;
|
||||||
|
Class Function ParseContentType(const AContentType: String; Parameters: TStrings) : String;
|
||||||
// Get/Set custom headers.
|
// Get/Set custom headers.
|
||||||
Function GetCustomHeader(const Name: String) : String; virtual;
|
Function GetCustomHeader(const Name: String) : String; virtual;
|
||||||
Procedure SetCustomHeader(const Name, Value: String); virtual;
|
Procedure SetCustomHeader(const Name, Value: String); virtual;
|
||||||
@ -1395,6 +1396,125 @@ begin
|
|||||||
Result:=FVariables[AVariable];
|
Result:=FVariables[AVariable];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
TParseState =
|
||||||
|
(psStart, psContentType, psSearchParam, psParam, psSearchParamEqual, psSearchParamValue, psParamValueQuoted, psParamValue);
|
||||||
|
|
||||||
|
Class Function THTTPHeader.ParseContentType(const AContentType: String; Parameters: TStrings): String;
|
||||||
|
var
|
||||||
|
len: Integer;
|
||||||
|
ind: Integer;
|
||||||
|
state: TParseState;
|
||||||
|
start: Integer;
|
||||||
|
paramname: string;
|
||||||
|
paramvalue: string;
|
||||||
|
begin
|
||||||
|
// See rfc1341, Content-Type
|
||||||
|
Result := '';
|
||||||
|
len := Length(AContentType);
|
||||||
|
if len=0 then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
ind := 1;
|
||||||
|
state := psStart;
|
||||||
|
while ind <= len do
|
||||||
|
begin
|
||||||
|
case state of
|
||||||
|
psStart:
|
||||||
|
begin
|
||||||
|
if not (AContentType[ind] in [' ']) then
|
||||||
|
begin
|
||||||
|
state := psContentType;
|
||||||
|
start := ind;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
psContentType:
|
||||||
|
begin
|
||||||
|
if (AContentType[ind] in [' ', ';']) then
|
||||||
|
begin
|
||||||
|
Result := Copy(AContentType, start, ind-start);
|
||||||
|
if not Assigned(Parameters) then
|
||||||
|
Exit;
|
||||||
|
state := psSearchParam;
|
||||||
|
end;
|
||||||
|
if (ind = len) then
|
||||||
|
begin
|
||||||
|
Result := Copy(AContentType, start, ind-start+1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
psSearchParam:
|
||||||
|
begin
|
||||||
|
if not (AContentType[ind] in [' ', ';']) then
|
||||||
|
begin
|
||||||
|
state := psParam;
|
||||||
|
start := ind;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
psParam:
|
||||||
|
begin
|
||||||
|
if (AContentType[ind] in [' ', '=']) then
|
||||||
|
begin
|
||||||
|
paramname := Copy(AContentType, start, ind-start);
|
||||||
|
if AContentType[ind] = '=' then
|
||||||
|
state := psSearchParamValue
|
||||||
|
else
|
||||||
|
state := psSearchParamEqual
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
psSearchParamEqual:
|
||||||
|
begin
|
||||||
|
if (AContentType[ind] = '=') then
|
||||||
|
state := psSearchParamValue;
|
||||||
|
end;
|
||||||
|
psSearchParamValue:
|
||||||
|
begin
|
||||||
|
if (AContentType[ind] = '"') then
|
||||||
|
begin
|
||||||
|
state := psParamValueQuoted;
|
||||||
|
start := ind +1;
|
||||||
|
end
|
||||||
|
else if (AContentType[ind] <> ' ') then
|
||||||
|
begin
|
||||||
|
state := psParamValue;
|
||||||
|
start := ind;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
psParamValue:
|
||||||
|
begin
|
||||||
|
if (AContentType[ind] in [' ', ';']) then
|
||||||
|
begin
|
||||||
|
paramvalue := Copy(AContentType, start, ind-start);
|
||||||
|
Parameters.Values[paramname] := paramvalue;
|
||||||
|
|
||||||
|
state := psSearchParam;
|
||||||
|
end
|
||||||
|
else if (ind = len) then
|
||||||
|
begin
|
||||||
|
paramvalue := Copy(AContentType, start, ind-start+1);
|
||||||
|
Parameters.Values[paramname] := paramvalue;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
psParamValueQuoted:
|
||||||
|
begin
|
||||||
|
if AContentType[ind] = '"' then
|
||||||
|
begin
|
||||||
|
paramvalue := Copy(AContentType, start, ind-start);
|
||||||
|
Parameters.Values[paramname] := paramvalue;
|
||||||
|
|
||||||
|
state := psSearchParam;
|
||||||
|
end
|
||||||
|
else if (ind = len) then
|
||||||
|
begin
|
||||||
|
paramvalue := Copy(AContentType, start, ind-start+1);
|
||||||
|
Parameters.Values[paramname] := paramvalue;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
inc(ind);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function THTTPHeader.GetHTTPVariable(AIndex: Integer): String;
|
function THTTPHeader.GetHTTPVariable(AIndex: Integer): String;
|
||||||
begin
|
begin
|
||||||
if (AIndex>=0) and (AIndex<=Ord(High(THTTPVariableType))) then
|
if (AIndex>=0) and (AIndex<=Ord(High(THTTPVariableType))) then
|
||||||
@ -2385,10 +2505,10 @@ function TRequest.DerriveStreamingContentType(): TStreamingContentType;
|
|||||||
var
|
var
|
||||||
CT: string;
|
CT: string;
|
||||||
begin
|
begin
|
||||||
CT:=ContentType;
|
CT:=Uppercase(ParseContentType(ContentType, nil));
|
||||||
if Pos('MULTIPART/FORM-DATA',Uppercase(CT))<>0 then
|
if CT='MULTIPART/FORM-DATA' then
|
||||||
Result := sctMultipart
|
Result := sctMultipart
|
||||||
else if Pos('APPLICATION/X-WWW-FORM-URLENCODED',Uppercase(CT))<>0 then
|
else if CT='APPLICATION/X-WWW-FORM-URLENCODED' then
|
||||||
Result := sctFormUrlEncoded
|
Result := sctFormUrlEncoded
|
||||||
else
|
else
|
||||||
Result := sctUnknown
|
Result := sctUnknown
|
||||||
@ -2397,20 +2517,19 @@ end;
|
|||||||
procedure TRequest.ProcessStreamingMultiPart(const State: TContentStreamingState; const Buf; const Size: Integer);
|
procedure TRequest.ProcessStreamingMultiPart(const State: TContentStreamingState; const Buf; const Size: Integer);
|
||||||
Var
|
Var
|
||||||
ST: TStrings;
|
ST: TStrings;
|
||||||
S, CT, B: String;
|
S: String;
|
||||||
I: Integer;
|
|
||||||
begin
|
begin
|
||||||
{$ifdef CGIDEBUG} SendMethodEnter('ProcessStreamingMultiPart');{$endif CGIDEBUG}
|
{$ifdef CGIDEBUG} SendMethodEnter('ProcessStreamingMultiPart');{$endif CGIDEBUG}
|
||||||
if State=cssStart then
|
if State=cssStart then
|
||||||
begin
|
begin
|
||||||
CT := ContentType;
|
ST := TStringList.Create;
|
||||||
i:=Pos('=',CT);
|
try
|
||||||
B:=Copy(CT,I+1,Length(CT)-I);
|
ParseContentType(ContentType, ST);
|
||||||
I:=Length(B);
|
FMimeItems := CreateMimeItems;
|
||||||
If (I>0) and (B[1]='"') then
|
FMimeItems.Boundary := ST.Values['boundary'];
|
||||||
B:=Copy(B,2,I-2);
|
finally
|
||||||
FMimeItems := CreateMimeItems;
|
ST.Free;
|
||||||
FMimeItems.Boundary := B;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if FKeepFullContents or not FMimeItems.SupportsStreamingProcessing then
|
if FKeepFullContents or not FMimeItems.SupportsStreamingProcessing then
|
||||||
|
@ -253,6 +253,105 @@ Small
|
|||||||
<hashTree/>
|
<hashTree/>
|
||||||
</hashTree>
|
</hashTree>
|
||||||
</hashTree>
|
</hashTree>
|
||||||
|
<GenericController guiclass="LogicControllerGui" testclass="GenericController" testname="Post small file (rfc1341)" enabled="true"/>
|
||||||
|
<hashTree>
|
||||||
|
<HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true">
|
||||||
|
<collectionProp name="HeaderManager.headers">
|
||||||
|
<elementProp name="" elementType="Header">
|
||||||
|
<stringProp name="Header.name">Content-Type</stringProp>
|
||||||
|
<stringProp name="Header.value">multipart/form-data; boundary="------------------------e6d533842bd07008"; type=Text/HTML</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
</collectionProp>
|
||||||
|
</HeaderManager>
|
||||||
|
<hashTree/>
|
||||||
|
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post small file - test rfc1341 content type " enabled="true">
|
||||||
|
<boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
|
||||||
|
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
|
||||||
|
<collectionProp name="Arguments.arguments">
|
||||||
|
<elementProp name="" elementType="HTTPArgument">
|
||||||
|
<boolProp name="HTTPArgument.always_encode">false</boolProp>
|
||||||
|
<stringProp name="Argument.value">--------------------------e6d533842bd07008
|
||||||
|
Content-Disposition: form-data; name="upload"; filename="UploadFileSmall.txt"
|
||||||
|
Content-Type: text/plain
|
||||||
|

|
||||||
|
Small
|
||||||
|

|
||||||
|
--------------------------e6d533842bd07008--</stringProp>
|
||||||
|
<stringProp name="Argument.metadata">=</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
</collectionProp>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="HTTPSampler.domain"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.port"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.protocol"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.path"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.method">POST</stringProp>
|
||||||
|
<boolProp name="HTTPSampler.follow_redirects">false</boolProp>
|
||||||
|
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||||
|
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
|
||||||
|
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
|
||||||
|
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
|
</HTTPSamplerProxy>
|
||||||
|
<hashTree>
|
||||||
|
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
|
||||||
|
<stringProp name="JSON_PATH">$.files[0].size</stringProp>
|
||||||
|
<stringProp name="EXPECTED_VALUE">7</stringProp>
|
||||||
|
<boolProp name="JSONVALIDATION">true</boolProp>
|
||||||
|
<boolProp name="EXPECT_NULL">false</boolProp>
|
||||||
|
<boolProp name="INVERT">false</boolProp>
|
||||||
|
<boolProp name="ISREGEX">false</boolProp>
|
||||||
|
</JSONPathAssertion>
|
||||||
|
<hashTree/>
|
||||||
|
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
|
||||||
|
<stringProp name="JSON_PATH">$.files[0].sha1</stringProp>
|
||||||
|
<stringProp name="EXPECTED_VALUE">d9ce7590765717c47c737add2ac11e0665eabbea</stringProp>
|
||||||
|
<boolProp name="JSONVALIDATION">true</boolProp>
|
||||||
|
<boolProp name="EXPECT_NULL">false</boolProp>
|
||||||
|
<boolProp name="INVERT">false</boolProp>
|
||||||
|
<boolProp name="ISREGEX">false</boolProp>
|
||||||
|
</JSONPathAssertion>
|
||||||
|
<hashTree/>
|
||||||
|
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
|
||||||
|
<stringProp name="JSON_PATH">$.files[0].contentType</stringProp>
|
||||||
|
<stringProp name="EXPECTED_VALUE">text/plain</stringProp>
|
||||||
|
<boolProp name="JSONVALIDATION">true</boolProp>
|
||||||
|
<boolProp name="EXPECT_NULL">false</boolProp>
|
||||||
|
<boolProp name="INVERT">false</boolProp>
|
||||||
|
<boolProp name="ISREGEX">false</boolProp>
|
||||||
|
</JSONPathAssertion>
|
||||||
|
<hashTree/>
|
||||||
|
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
|
||||||
|
<stringProp name="JSON_PATH">$.files[0].fieldname</stringProp>
|
||||||
|
<stringProp name="EXPECTED_VALUE">upload</stringProp>
|
||||||
|
<boolProp name="JSONVALIDATION">true</boolProp>
|
||||||
|
<boolProp name="EXPECT_NULL">false</boolProp>
|
||||||
|
<boolProp name="INVERT">false</boolProp>
|
||||||
|
<boolProp name="ISREGEX">false</boolProp>
|
||||||
|
</JSONPathAssertion>
|
||||||
|
<hashTree/>
|
||||||
|
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
|
||||||
|
<stringProp name="JSON_PATH">$.files[0].filename</stringProp>
|
||||||
|
<stringProp name="EXPECTED_VALUE">UploadFileSmall.txt</stringProp>
|
||||||
|
<boolProp name="JSONVALIDATION">true</boolProp>
|
||||||
|
<boolProp name="EXPECT_NULL">false</boolProp>
|
||||||
|
<boolProp name="INVERT">false</boolProp>
|
||||||
|
<boolProp name="ISREGEX">false</boolProp>
|
||||||
|
</JSONPathAssertion>
|
||||||
|
<hashTree/>
|
||||||
|
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Assertion" enabled="true">
|
||||||
|
<stringProp name="JSON_PATH">$.content.raw</stringProp>
|
||||||
|
<stringProp name="EXPECTED_VALUE"></stringProp>
|
||||||
|
<boolProp name="JSONVALIDATION">true</boolProp>
|
||||||
|
<boolProp name="EXPECT_NULL">false</boolProp>
|
||||||
|
<boolProp name="INVERT">false</boolProp>
|
||||||
|
<boolProp name="ISREGEX">false</boolProp>
|
||||||
|
</JSONPathAssertion>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
</hashTree>
|
||||||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post UploadFile1.txt" enabled="true">
|
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Post UploadFile1.txt" enabled="true">
|
||||||
<elementProp name="HTTPsampler.Files" elementType="HTTPFileArgs">
|
<elementProp name="HTTPsampler.Files" elementType="HTTPFileArgs">
|
||||||
<collectionProp name="HTTPFileArgs.files">
|
<collectionProp name="HTTPFileArgs.files">
|
||||||
|
Loading…
Reference in New Issue
Block a user