View Issue Details

IDProjectCategoryView StatusLast Update
0027558FPCFCLpublic2015-03-07 17:13
ReporterAndrewHAssigned ToMichael Van Canneyt 
PrioritynormalSeverityminorReproducibilityhave not tried
Status resolvedResolutionfixed 
Product Version3.1.1Product Build 
Target Version4.0.0Fixed in Version3.1.1 
Summary0027558: [PATCH] TFPCustomHTTPClient.FileFormPost add possiblilty to include formdata and file in same POST request
DescriptionAdded procedure StreamFormPost and overloaded FileFormPost to allow adding Formdata when sending a file.

Before you could send formdata (name=value pairs) or a file (field-name filename)
Now you can do both with FileFormPost or StreamFormPost in the same POST request
TagsNo tags attached.
Fixed in Revision30123
FPCOldBugId0
FPCTarget
Attached Files
  • fcl-web-form-and-stream.diff (3,531 bytes)
    Index: packages/fcl-web/src/base/fphttpclient.pp
    ===================================================================
    --- packages/fcl-web/src/base/fphttpclient.pp	(revision 30024)
    +++ packages/fcl-web/src/base/fphttpclient.pp	(working copy)
    @@ -202,6 +202,12 @@
         Class function SimpleFormPost(const URL: string; FormData : TStrings): String;
         // Post a file
         Procedure FileFormPost(const AURL, AFieldName, AFileName: string; const Response: TStream);
    +    // Post form with a file
    +    Procedure FileFormPost(const AURL: string; FormData: TStrings; AFieldName, AFileName: string; const Response: TStream);
    +    // Post a stream
    +    Procedure StreamFormPost(const AURL, AFieldName, AFileName: string; const AStream: TStream; const Response: TStream);
    +    // Post form with a stream
    +    Procedure StreamFormPost(const AURL: string; FormData: TStrings; const AFieldName, AFileName: string; const AStream: TStream; const Response: TStream);
         // Simple form of Posting a file
         Class Procedure SimpleFileFormPost(const AURL, AFieldName, AFileName: string; const Response: TStream);
       Protected
    @@ -420,7 +426,7 @@
         Result:=Result+'?'+URI.Params;
     end;
     
    -Function TFPCustomHTTPClient.GetSocketHandler(Const UseSSL : Boolean) : TSocketHandler;
    +function TFPCustomHTTPClient.GetSocketHandler(const UseSSL: Boolean): TSocketHandler;
     
     begin
       Result:=Nil;
    @@ -1708,25 +1714,56 @@
     
     procedure TFPCustomHTTPClient.FileFormPost(const AURL, AFieldName,
       AFileName: string; const Response: TStream);
    +begin
    +  FileFormPost(AURL, nil, AFieldName, AFileName, Response);
    +end;
     
    +procedure TFPCustomHTTPClient.FileFormPost(const AURL: string;
    +  FormData: TStrings; AFieldName, AFileName: string; const Response: TStream);
    +var
    +  F: TFileStream;
    +begin
    +  F:=TFileStream.Create(AFileName,fmOpenRead or fmShareDenyWrite);
    +  StreamFormPost(AURL, FormData, AFieldName, ExtractFileName(AFileName), F, Response);
    +  F.Free;
    +end;
    +
    +procedure TFPCustomHTTPClient.StreamFormPost(const AURL, AFieldName,
    +  AFileName: string; const AStream: TStream; const Response: TStream);
    +begin
    +  StreamFormPost(AURL, nil, AFieldName, AFileName, AStream, Response);
    +end;
    +
    +procedure TFPCustomHTTPClient.StreamFormPost(const AURL: string;
    +  FormData: TStrings; const AFieldName, AFileName: string;
    +  const AStream: TStream; const Response: TStream);
     Var
       S, Sep : string;
       SS : TStringStream;
    -  F : TFileStream;
    +  I: Integer;
    +  N,V: String;
     begin
       Sep:=Format('%.8x_multipart_boundary',[Random($ffffff)]);
       AddHeader('Content-Type','multipart/form-data; boundary='+Sep);
    +  SS:=TStringStream.Create('');
    +  if FormData <> nil then
    +    for I := 0 to FormData.Count -1 do
    +    begin
    +      // not url encoded
    +      FormData.GetNameValue(I,N,V);
    +      S :='--'+Sep+CRLF;
    +      S:=S+Format('Content-Disposition: form-data; name="%s"'+CRLF+CRLF+'%s'+CRLF,[N, V]);
    +      SS.WriteBuffer(S[1],Length(S));
    +    end;
       S:='--'+Sep+CRLF;
       s:=s+Format('Content-Disposition: form-data; name="%s"; filename="%s"'+CRLF,[AFieldName,ExtractFileName(AFileName)]);
       s:=s+'Content-Type: application/octet-string'+CRLF+CRLF;
    -  SS:=TStringStream.Create(s);
    +  SS.WriteBuffer(S[1],Length(S));
       try
    -    SS.Seek(0,soFromEnd);
    -    F:=TFileStream.Create(AFileName,fmOpenRead or fmShareDenyWrite);
         try
    -      SS.CopyFrom(F,F.Size);
    +      AStream.Seek(0, soFromBeginning);
    +      SS.CopyFrom(AStream,AStream.Size);
         finally
    -      F.Free;
         end;
         S:=CRLF+'--'+Sep+'--'+CRLF;
         SS.WriteBuffer(S[1],Length(S));
    

Activities

AndrewH

2015-02-27 20:58

developer  

fcl-web-form-and-stream.diff (3,531 bytes)
Index: packages/fcl-web/src/base/fphttpclient.pp
===================================================================
--- packages/fcl-web/src/base/fphttpclient.pp	(revision 30024)
+++ packages/fcl-web/src/base/fphttpclient.pp	(working copy)
@@ -202,6 +202,12 @@
     Class function SimpleFormPost(const URL: string; FormData : TStrings): String;
     // Post a file
     Procedure FileFormPost(const AURL, AFieldName, AFileName: string; const Response: TStream);
+    // Post form with a file
+    Procedure FileFormPost(const AURL: string; FormData: TStrings; AFieldName, AFileName: string; const Response: TStream);
+    // Post a stream
+    Procedure StreamFormPost(const AURL, AFieldName, AFileName: string; const AStream: TStream; const Response: TStream);
+    // Post form with a stream
+    Procedure StreamFormPost(const AURL: string; FormData: TStrings; const AFieldName, AFileName: string; const AStream: TStream; const Response: TStream);
     // Simple form of Posting a file
     Class Procedure SimpleFileFormPost(const AURL, AFieldName, AFileName: string; const Response: TStream);
   Protected
@@ -420,7 +426,7 @@
     Result:=Result+'?'+URI.Params;
 end;
 
-Function TFPCustomHTTPClient.GetSocketHandler(Const UseSSL : Boolean) : TSocketHandler;
+function TFPCustomHTTPClient.GetSocketHandler(const UseSSL: Boolean): TSocketHandler;
 
 begin
   Result:=Nil;
@@ -1708,25 +1714,56 @@
 
 procedure TFPCustomHTTPClient.FileFormPost(const AURL, AFieldName,
   AFileName: string; const Response: TStream);
+begin
+  FileFormPost(AURL, nil, AFieldName, AFileName, Response);
+end;
 
+procedure TFPCustomHTTPClient.FileFormPost(const AURL: string;
+  FormData: TStrings; AFieldName, AFileName: string; const Response: TStream);
+var
+  F: TFileStream;
+begin
+  F:=TFileStream.Create(AFileName,fmOpenRead or fmShareDenyWrite);
+  StreamFormPost(AURL, FormData, AFieldName, ExtractFileName(AFileName), F, Response);
+  F.Free;
+end;
+
+procedure TFPCustomHTTPClient.StreamFormPost(const AURL, AFieldName,
+  AFileName: string; const AStream: TStream; const Response: TStream);
+begin
+  StreamFormPost(AURL, nil, AFieldName, AFileName, AStream, Response);
+end;
+
+procedure TFPCustomHTTPClient.StreamFormPost(const AURL: string;
+  FormData: TStrings; const AFieldName, AFileName: string;
+  const AStream: TStream; const Response: TStream);
 Var
   S, Sep : string;
   SS : TStringStream;
-  F : TFileStream;
+  I: Integer;
+  N,V: String;
 begin
   Sep:=Format('%.8x_multipart_boundary',[Random($ffffff)]);
   AddHeader('Content-Type','multipart/form-data; boundary='+Sep);
+  SS:=TStringStream.Create('');
+  if FormData <> nil then
+    for I := 0 to FormData.Count -1 do
+    begin
+      // not url encoded
+      FormData.GetNameValue(I,N,V);
+      S :='--'+Sep+CRLF;
+      S:=S+Format('Content-Disposition: form-data; name="%s"'+CRLF+CRLF+'%s'+CRLF,[N, V]);
+      SS.WriteBuffer(S[1],Length(S));
+    end;
   S:='--'+Sep+CRLF;
   s:=s+Format('Content-Disposition: form-data; name="%s"; filename="%s"'+CRLF,[AFieldName,ExtractFileName(AFileName)]);
   s:=s+'Content-Type: application/octet-string'+CRLF+CRLF;
-  SS:=TStringStream.Create(s);
+  SS.WriteBuffer(S[1],Length(S));
   try
-    SS.Seek(0,soFromEnd);
-    F:=TFileStream.Create(AFileName,fmOpenRead or fmShareDenyWrite);
     try
-      SS.CopyFrom(F,F.Size);
+      AStream.Seek(0, soFromBeginning);
+      SS.CopyFrom(AStream,AStream.Size);
     finally
-      F.Free;
     end;
     S:=CRLF+'--'+Sep+'--'+CRLF;
     SS.WriteBuffer(S[1],Length(S));

Michael Van Canneyt

2015-03-07 17:13

administrator   ~0081704

Your patch contained 2 potential memory leaks, fixed those and then applied the patch. Thanks for implementing it !

Issue History

Date Modified Username Field Change
2015-02-27 20:58 AndrewH New Issue
2015-02-27 20:58 AndrewH File Added: fcl-web-form-and-stream.diff
2015-02-27 20:59 AndrewH Description Updated View Revisions
2015-02-27 21:23 Jonas Maebe Assigned To => Michael Van Canneyt
2015-02-27 21:23 Jonas Maebe Status new => assigned
2015-03-07 17:13 Michael Van Canneyt Fixed in Revision => 30123
2015-03-07 17:13 Michael Van Canneyt Note Added: 0081704
2015-03-07 17:13 Michael Van Canneyt Status assigned => resolved
2015-03-07 17:13 Michael Van Canneyt Fixed in Version => 3.1.1
2015-03-07 17:13 Michael Van Canneyt Resolution open => fixed
2015-03-07 17:13 Michael Van Canneyt Target Version => 4.0.0