|
@@ -136,11 +136,13 @@ type
|
|
Function IndexOfCookie(AName : String) : Integer;
|
|
Function IndexOfCookie(AName : String) : Integer;
|
|
property Items[Index: Integer]: TCookie read GetCookie write SetCookie; default;
|
|
property Items[Index: Integer]: TCookie read GetCookie write SetCookie; default;
|
|
end;
|
|
end;
|
|
|
|
+
|
|
{ TUploadedFile }
|
|
{ TUploadedFile }
|
|
|
|
|
|
TUploadedFile = Class(TCollectionItem)
|
|
TUploadedFile = Class(TCollectionItem)
|
|
Private
|
|
Private
|
|
FContentType: String;
|
|
FContentType: String;
|
|
|
|
+ FDescription: String;
|
|
FDisposition: String;
|
|
FDisposition: String;
|
|
FFieldName: String;
|
|
FFieldName: String;
|
|
FFileName: String;
|
|
FFileName: String;
|
|
@@ -148,6 +150,7 @@ type
|
|
FSize: Int64;
|
|
FSize: Int64;
|
|
FStream : TStream;
|
|
FStream : TStream;
|
|
Protected
|
|
Protected
|
|
|
|
+ Procedure DeleteTempUploadedFile; virtual;
|
|
function GetStream: TStream; virtual;
|
|
function GetStream: TStream; virtual;
|
|
Public
|
|
Public
|
|
Destructor Destroy; override;
|
|
Destructor Destroy; override;
|
|
@@ -158,20 +161,66 @@ type
|
|
Property ContentType : String Read FContentType Write FContentType;
|
|
Property ContentType : String Read FContentType Write FContentType;
|
|
Property Disposition : String Read FDisposition Write FDisposition;
|
|
Property Disposition : String Read FDisposition Write FDisposition;
|
|
Property LocalFileName : String Read FLocalFileName Write FLocalFileName;
|
|
Property LocalFileName : String Read FLocalFileName Write FLocalFileName;
|
|
|
|
+ Property Description : String Read FDescription Write FDescription;
|
|
end;
|
|
end;
|
|
-
|
|
|
|
|
|
+ TUploadedFileClass = Class of TUploadedFile;
|
|
|
|
+
|
|
{ TUploadedFiles }
|
|
{ TUploadedFiles }
|
|
|
|
|
|
TUploadedFiles = Class(TCollection)
|
|
TUploadedFiles = Class(TCollection)
|
|
private
|
|
private
|
|
|
|
+ FRequest : TRequest; // May be nil
|
|
function GetFile(Index : Integer): TUploadedFile;
|
|
function GetFile(Index : Integer): TUploadedFile;
|
|
procedure SetFile(Index : Integer; const AValue: TUploadedFile);
|
|
procedure SetFile(Index : Integer; const AValue: TUploadedFile);
|
|
|
|
+ Protected
|
|
|
|
+ Function GetTempUploadFileName(Const AName, AFileName : String; ASize : Int64): String;
|
|
|
|
+ Procedure DeleteTempUploadedFiles; virtual;
|
|
public
|
|
public
|
|
Function IndexOfFile(AName : String) : Integer;
|
|
Function IndexOfFile(AName : String) : Integer;
|
|
Function FileByName(AName : String) : TUploadedFile;
|
|
Function FileByName(AName : String) : TUploadedFile;
|
|
Function FindFile(AName : String) : TUploadedFile;
|
|
Function FindFile(AName : String) : TUploadedFile;
|
|
Property Files[Index : Integer] : TUploadedFile read GetFile Write SetFile; default;
|
|
Property Files[Index : Integer] : TUploadedFile read GetFile Write SetFile; default;
|
|
end;
|
|
end;
|
|
|
|
+ TUploadedFilesClass = Class of TUploadedFiles;
|
|
|
|
+
|
|
|
|
+ { TMimeItem }
|
|
|
|
+ // Used to decode multipart encoded content
|
|
|
|
+
|
|
|
|
+ TMimeItem = Class(TCollectionItem)
|
|
|
|
+ private
|
|
|
|
+ protected
|
|
|
|
+ Function CreateUploadedFile(Files : TUploadedFiles) : TUploadedFile; virtual;
|
|
|
|
+ Function ProcessHeader(Const AHeader,AValue : String) : Boolean; virtual;
|
|
|
|
+ procedure SaveToFile(const AFileName: String); virtual;
|
|
|
|
+ function GetIsFile: Boolean; virtual;
|
|
|
|
+ // These must be implemented in descendents;
|
|
|
|
+ function GetDataSize: Int64; virtual; abstract;
|
|
|
|
+ function GetHeader(AIndex: Integer): String; virtual; abstract;
|
|
|
|
+ Procedure SetHeader(AIndex: Integer; Const AValue: String); virtual; abstract;
|
|
|
|
+ Public
|
|
|
|
+ Procedure Process(Stream : TStream); virtual; abstract;
|
|
|
|
+ Property Data : String index 0 Read GetHeader Write SetHeader;
|
|
|
|
+ Property Name : String index 1 Read GetHeader Write SetHeader;
|
|
|
|
+ Property Disposition : String index 2 Read GetHeader Write SetHeader;
|
|
|
|
+ Property FileName : String index 3 Read GetHeader Write SetHeader;
|
|
|
|
+ Property ContentType : String index 4 Read GetHeader Write SetHeader;
|
|
|
|
+ Property Description : String index 5 Read GetHeader Write SetHeader;
|
|
|
|
+ Property IsFile : Boolean Read GetIsFile;
|
|
|
|
+ Property DataSize : Int64 Read GetDataSize;
|
|
|
|
+ end;
|
|
|
|
+ TMimeItemClass = Class of TMimeItem;
|
|
|
|
+ { TMimeItems }
|
|
|
|
+
|
|
|
|
+ TMimeItems = Class(TCollection)
|
|
|
|
+ private
|
|
|
|
+ function GetP(AIndex : Integer): TMimeItem;
|
|
|
|
+ Protected
|
|
|
|
+ Procedure CreateUploadFiles(Files : TUploadedFiles; Vars : TStrings); virtual;
|
|
|
|
+ procedure FormSplit(var Cnt: String; boundary: String); virtual;
|
|
|
|
+ Public
|
|
|
|
+ Property Parts[AIndex : Integer] : TMimeItem Read GetP; default;
|
|
|
|
+ end;
|
|
|
|
+ TMimeItemsClass = Class of TMimeItems;
|
|
|
|
|
|
{ THTTPHeader }
|
|
{ THTTPHeader }
|
|
|
|
|
|
@@ -286,6 +335,8 @@ type
|
|
Protected
|
|
Protected
|
|
FContentRead : Boolean;
|
|
FContentRead : Boolean;
|
|
FContent : String;
|
|
FContent : String;
|
|
|
|
+ Function CreateUploadedFiles : TUploadedFiles; virtual;
|
|
|
|
+ Function CreateMimeItems : TMimeItems; virtual;
|
|
procedure HandleUnknownEncoding(Const AContentType : String;Stream : TStream); virtual;
|
|
procedure HandleUnknownEncoding(Const AContentType : String;Stream : TStream); virtual;
|
|
procedure ParseFirstHeaderLine(const line: String);override;
|
|
procedure ParseFirstHeaderLine(const line: String);override;
|
|
procedure ReadContent; virtual;
|
|
procedure ReadContent; virtual;
|
|
@@ -295,7 +346,7 @@ type
|
|
Procedure ProcessQueryString(Const FQueryString : String; SL:TStrings); virtual;
|
|
Procedure ProcessQueryString(Const FQueryString : String; SL:TStrings); virtual;
|
|
procedure ProcessURLEncoded(Stream : TStream;SL:TStrings); virtual;
|
|
procedure ProcessURLEncoded(Stream : TStream;SL:TStrings); virtual;
|
|
Function RequestUploadDir : String; virtual;
|
|
Function RequestUploadDir : String; virtual;
|
|
- Function GetTempUploadFileName(Const AName, AFileName : String; ASize : Int64) : String; virtual;
|
|
|
|
|
|
+ Function GetTempUploadFileName(Const AName, AFileName : String; ASize : Int64) : String; virtual;
|
|
Procedure DeleteTempUploadedFiles; virtual;
|
|
Procedure DeleteTempUploadedFiles; virtual;
|
|
Procedure InitRequestVars; virtual;
|
|
Procedure InitRequestVars; virtual;
|
|
Procedure InitPostVars; virtual;
|
|
Procedure InitPostVars; virtual;
|
|
@@ -417,6 +468,13 @@ Function HTTPDecode(const AStr: String): String;
|
|
Function HTTPEncode(const AStr: String): String;
|
|
Function HTTPEncode(const AStr: String): String;
|
|
Function IncludeHTTPPathDelimiter(const AStr: String): String;
|
|
Function IncludeHTTPPathDelimiter(const AStr: String): String;
|
|
|
|
|
|
|
|
+Var
|
|
|
|
+ // Default classes used when instantiating the collections.
|
|
|
|
+ UploadedFilesClass : TUploadedFilesClass = TUploadedFiles;
|
|
|
|
+ UploadedFileClass : TUploadedFileClass = TUploadedFile;
|
|
|
|
+ MimeItemsClass : TMimeItemsClass = TMimeItems;
|
|
|
|
+ MimeItemClass : TMimeItemClass = nil;
|
|
|
|
+
|
|
implementation
|
|
implementation
|
|
|
|
|
|
uses
|
|
uses
|
|
@@ -556,6 +614,127 @@ begin
|
|
Result:=Result+'/';
|
|
Result:=Result+'/';
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+{ -------------------------------------------------------------------
|
|
|
|
+ THTTPMimeItem, default used by TRequest to process Multipart-encoded data.
|
|
|
|
+ -------------------------------------------------------------------}
|
|
|
|
+
|
|
|
|
+Type
|
|
|
|
+ { THTTPMimeItem }
|
|
|
|
+
|
|
|
|
+ THTTPMimeItem = Class(TMimeItem)
|
|
|
|
+ private
|
|
|
|
+ FData : Array[0..5] of string;
|
|
|
|
+ protected
|
|
|
|
+ Procedure SetHeader(AIndex: Integer; Const AValue: String); override;
|
|
|
|
+ function GetDataSize: Int64; override;
|
|
|
|
+ function GetHeader(AIndex: Integer): String; override;
|
|
|
|
+ function GetIsFile: Boolean; override;
|
|
|
|
+ public
|
|
|
|
+ Procedure Process(Stream : TStream); override;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+procedure THTTPMimeItem.SetHeader(AIndex: Integer; const AValue: String);
|
|
|
|
+begin
|
|
|
|
+ FData[AIndex]:=Avalue;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function THTTPMimeItem.GetDataSize: int64;
|
|
|
|
+begin
|
|
|
|
+ Result:=Length(Data);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function THTTPMimeItem.GetHeader(AIndex: Integer): String;
|
|
|
|
+begin
|
|
|
|
+ Result:=FData[AIndex];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function THTTPMimeItem.GetIsFile: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:=inherited GetIsFile;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure THTTPMimeItem.Process(Stream: TStream);
|
|
|
|
+
|
|
|
|
+ Function GetLine(Var S : String) : String;
|
|
|
|
+
|
|
|
|
+ Var
|
|
|
|
+ P : Integer;
|
|
|
|
+
|
|
|
|
+ begin
|
|
|
|
+ P:=Pos(#13#10,S);
|
|
|
|
+ If (P<>0) then
|
|
|
|
+ begin
|
|
|
|
+ Result:=Copy(S,1,P-1);
|
|
|
|
+ Delete(S,1,P+1);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ Function GetWord(Var S : String) : String;
|
|
|
|
+
|
|
|
|
+ Var
|
|
|
|
+ I,len : Integer;
|
|
|
|
+ Quoted : Boolean;
|
|
|
|
+ C : Char;
|
|
|
|
+
|
|
|
|
+ begin
|
|
|
|
+ len:=length(S);
|
|
|
|
+ quoted:=false;
|
|
|
|
+ Result:='';
|
|
|
|
+ for i:=1 to len do
|
|
|
|
+ Begin
|
|
|
|
+ c:=S[i];
|
|
|
|
+ if (c='"') then
|
|
|
|
+ Quoted:=Not Quoted
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ if not (c in [' ','=',';',':']) or Quoted then
|
|
|
|
+ Result:=Result+C;
|
|
|
|
+ if (c in [';',':','=']) and (not quoted) then
|
|
|
|
+ begin
|
|
|
|
+ Delete(S,1,I);
|
|
|
|
+ Exit;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ S:='';
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ Line : String;
|
|
|
|
+ len : integer;
|
|
|
|
+ S : string;
|
|
|
|
+ D : String;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ {$ifdef CGIDEBUG}SendMethodEnter('THTTPMimeItem.Process');{$ENDIF}
|
|
|
|
+ If Stream is TStringStream then
|
|
|
|
+ D:=TStringStream(Stream).Datastring
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ SetLength(D,Stream.Size);
|
|
|
|
+ Stream.ReadBuffer(D[1],Stream.Size);
|
|
|
|
+ end;
|
|
|
|
+ Line:=GetLine(D);
|
|
|
|
+ While (Line<>'') do
|
|
|
|
+ begin
|
|
|
|
+ {$ifdef CGIDEBUG}SendDebug('Process data line: '+line);{$ENDIF}
|
|
|
|
+ S:=GetWord(Line);
|
|
|
|
+ While (S<>'') do
|
|
|
|
+ begin
|
|
|
|
+ ProcessHeader(lowercase(S),GetWord(Line));
|
|
|
|
+ S:=GetWord(Line);
|
|
|
|
+ end;
|
|
|
|
+ Line:=GetLine(D);
|
|
|
|
+ end;
|
|
|
|
+ // Now Data contains the rest of the data, plus a CR/LF. Strip the CR/LF
|
|
|
|
+ Len:=Length(D);
|
|
|
|
+ If (len>2) then
|
|
|
|
+ Data:=Copy(D,1,Len-2)
|
|
|
|
+ else
|
|
|
|
+ Data:='';
|
|
|
|
+ {$ifdef CGIDEBUG}SendMethodExit('THTTPMimeItem.Process');{$ENDIF}
|
|
|
|
+end;
|
|
|
|
|
|
{ ---------------------------------------------------------------------
|
|
{ ---------------------------------------------------------------------
|
|
THTTPHeader
|
|
THTTPHeader
|
|
@@ -812,101 +991,127 @@ begin
|
|
SetFieldValue(i,AValue);
|
|
SetFieldValue(i,AValue);
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ -------------------------------------------------------------------
|
|
|
|
- TFormItem, used by TRequest to process Multipart-encoded data.
|
|
|
|
- -------------------------------------------------------------------}
|
|
|
|
-
|
|
|
|
-Type
|
|
|
|
- TFormItem = Class(TObject)
|
|
|
|
- Disposition : String;
|
|
|
|
- Name : String;
|
|
|
|
- IsFile : Boolean;
|
|
|
|
- FileName : String;
|
|
|
|
- ContentType : String;
|
|
|
|
- DLen : Integer;
|
|
|
|
- Data : String;
|
|
|
|
- Procedure Process;
|
|
|
|
- end;
|
|
|
|
|
|
+{ ---------------------------------------------------------------------
|
|
|
|
+ TMimeItems
|
|
|
|
+ ---------------------------------------------------------------------}
|
|
|
|
|
|
-Procedure TFormItem.Process;
|
|
|
|
|
|
+function TMimeItems.GetP(AIndex : Integer): TMimeItem;
|
|
|
|
+begin
|
|
|
|
+ Result:=TMimeItem(Items[Aindex]);
|
|
|
|
+end;
|
|
|
|
|
|
- Function GetLine(Var S : String) : String;
|
|
|
|
|
|
+procedure TMimeItems.CreateUploadFiles(Files: TUploadedFiles; Vars : TStrings);
|
|
|
|
|
|
- Var
|
|
|
|
- P : Integer;
|
|
|
|
|
|
+Var
|
|
|
|
+ I,j : Integer;
|
|
|
|
+ P : TMimeItem;
|
|
|
|
+ LFN,Name,Value : String;
|
|
|
|
+ U : TUploadedFile;
|
|
|
|
|
|
- begin
|
|
|
|
- P:=Pos(#13#10,S);
|
|
|
|
- If (P<>0) then
|
|
|
|
|
|
+begin
|
|
|
|
+ For I:=Count-1 downto 0 do
|
|
|
|
+ begin
|
|
|
|
+ P:=GetP(i);
|
|
|
|
+ If (P.Name='') then
|
|
|
|
+ P.Name:='DummyFileItem'+IntToStr(i);
|
|
|
|
+ //Raise Exception.CreateFmt('Invalid multipart encoding: %s',[FI.Data]);
|
|
|
|
+{$ifdef CGIDEBUG}
|
|
|
|
+ With P Do
|
|
begin
|
|
begin
|
|
- Result:=Copy(S,1,P-1);
|
|
|
|
- Delete(S,1,P+1);
|
|
|
|
|
|
+ SendSeparator;
|
|
|
|
+ SendDebug ('PMP item Name : '+Name);
|
|
|
|
+ SendDebug ('PMP item Disposition : '+Disposition);
|
|
|
|
+ SendDebug ('PMP item FileName : '+FileName);
|
|
|
|
+ SendBoolean('PMP item IsFile : ',IsFile);
|
|
|
|
+ SendDebug ('PMP item ContentType : '+ContentType);
|
|
|
|
+ SendDebug ('PMP item Description : '+Description);
|
|
|
|
+ SendInteger('PMP item DLen : ',Datasize);
|
|
|
|
+ SendDebug ('PMP item Data : '+Data);
|
|
|
|
+ end;
|
|
|
|
+{$endif CGIDEBUG}
|
|
|
|
+ Name:=P.Name;
|
|
|
|
+ If Not P.IsFile Then
|
|
|
|
+ Value:=P.Data
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ Value:=P.FileName;
|
|
|
|
+ P.CreateUploadedFile(Files);
|
|
end;
|
|
end;
|
|
|
|
+ Vars.Add(Name+'='+Value)
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TMimeItem.GetIsFile: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:=(FileName<>'');
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TMimeItem.ProcessHeader(const AHeader, AValue: String): Boolean;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ Result:=True;
|
|
|
|
+ Case AHeader of
|
|
|
|
+ 'content-disposition' : Disposition:=Avalue;
|
|
|
|
+ 'name': Name:=Avalue;
|
|
|
|
+ 'filename' : FileName:=AValue;
|
|
|
|
+ 'content-description' : description:=AValue;
|
|
|
|
+ 'content-type' : ContentType:=AValue;
|
|
|
|
+ else
|
|
|
|
+ Result:=False;
|
|
end;
|
|
end;
|
|
|
|
+end;
|
|
|
|
|
|
- Function GetWord(Var S : String) : String;
|
|
|
|
|
|
+Procedure TMimeItem.SaveToFile(Const AFileName: String);
|
|
|
|
|
|
- Var
|
|
|
|
- I,len : Integer;
|
|
|
|
- Quoted : Boolean;
|
|
|
|
- C : Char;
|
|
|
|
|
|
+Var
|
|
|
|
+ D : String;
|
|
|
|
+ F : TFileStream;
|
|
|
|
|
|
- begin
|
|
|
|
- len:=length(S);
|
|
|
|
- quoted:=false;
|
|
|
|
- Result:='';
|
|
|
|
- for i:=1 to len do
|
|
|
|
- Begin
|
|
|
|
- c:=S[i];
|
|
|
|
- if (c='"') then
|
|
|
|
- Quoted:=Not Quoted
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- if not (c in [' ','=',';',':']) or Quoted then
|
|
|
|
- Result:=Result+C;
|
|
|
|
- if (c in [';',':','=']) and (not quoted) then
|
|
|
|
- begin
|
|
|
|
- Delete(S,1,I);
|
|
|
|
- Exit;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- S:='';
|
|
|
|
|
|
+begin
|
|
|
|
+ F:=TFileStream.Create(AFileName,fmCreate);
|
|
|
|
+ Try
|
|
|
|
+ D:=Data;
|
|
|
|
+ F.Write(D[1],DataSize);
|
|
|
|
+ finally
|
|
|
|
+ F.Free;
|
|
end;
|
|
end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TMimeItem.CreateUploadedFile(Files: TUploadedFiles): TUploadedFile;
|
|
|
|
|
|
Var
|
|
Var
|
|
- Line : String;
|
|
|
|
- len : integer;
|
|
|
|
- S : string;
|
|
|
|
|
|
+ J : Int64;
|
|
|
|
+ D,LFN : String;
|
|
|
|
|
|
begin
|
|
begin
|
|
- Line:=GetLine(Data);
|
|
|
|
- While (Line<>'') do
|
|
|
|
|
|
+ Result:=Nil;
|
|
|
|
+ D:=Data;
|
|
|
|
+ J:=DataSize;
|
|
|
|
+ if (J=0){zero lenght file} or
|
|
|
|
+ ((J=2)and (D=#13#10)){empty files come as a simple empty line} then
|
|
|
|
+ LFN:='' //No tmp file will be created for empty files
|
|
|
|
+ else
|
|
begin
|
|
begin
|
|
- S:=GetWord(Line);
|
|
|
|
- While (S<>'') do
|
|
|
|
- begin
|
|
|
|
- If CompareText(S,'Content-Disposition')=0 then
|
|
|
|
- Disposition:=GetWord(Line)
|
|
|
|
- else if CompareText(S,'name')=0 Then
|
|
|
|
- Name:=GetWord(Line)
|
|
|
|
- else if CompareText(S,'filename')=0 then
|
|
|
|
- begin
|
|
|
|
- FileName:=GetWord(Line);
|
|
|
|
- isFile:=True;
|
|
|
|
- end
|
|
|
|
- else if CompareText(S,'Content-Type')=0 then
|
|
|
|
- ContentType:=GetWord(Line);
|
|
|
|
- S:=GetWord(Line);
|
|
|
|
- end;
|
|
|
|
- Line:=GetLine(Data);
|
|
|
|
|
|
+ LFN:=Files.GetTempUploadFileName(Name,FileName,J);
|
|
|
|
+ SaveToFile(LFN);
|
|
end;
|
|
end;
|
|
- // Now Data contains the rest of the data, plus a CR/LF. Strip the CR/LF
|
|
|
|
- Len:=Length(Data);
|
|
|
|
- If (len>2) then
|
|
|
|
- Data:=Copy(Data,1,Len-2);
|
|
|
|
|
|
+ if (LFN<>'') then
|
|
|
|
+ begin
|
|
|
|
+ Result:=Files.Add as TUploadedFile;
|
|
|
|
+ with Result do
|
|
|
|
+ begin
|
|
|
|
+ FieldName:=Self.Name;
|
|
|
|
+ FileName:=Self.FileName;
|
|
|
|
+ ContentType:=Self.ContentType;
|
|
|
|
+ Disposition:=Self.Disposition;
|
|
|
|
+ Size:=Self.Datasize;
|
|
|
|
+ LocalFileName:=LFN;
|
|
|
|
+ Description:=Self.Description;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+
|
|
{
|
|
{
|
|
This needs MASSIVE improvements for large files.
|
|
This needs MASSIVE improvements for large files.
|
|
Best would be to do this directly from the input stream
|
|
Best would be to do this directly from the input stream
|
|
@@ -914,34 +1119,41 @@ end;
|
|
certain size is reached.)
|
|
certain size is reached.)
|
|
}
|
|
}
|
|
|
|
|
|
-procedure FormSplit(var Cnt : String; boundary: String; List : TList);
|
|
|
|
|
|
+procedure TMimeItems.FormSplit(var Cnt : String; boundary: String);
|
|
|
|
|
|
// Splits the form into items
|
|
// Splits the form into items
|
|
var
|
|
var
|
|
Sep : string;
|
|
Sep : string;
|
|
Clen,slen, p:longint;
|
|
Clen,slen, p:longint;
|
|
- FI : TFormItem;
|
|
|
|
|
|
+ FI : TMimeItem;
|
|
|
|
+ S : TStringStream;
|
|
|
|
|
|
begin
|
|
begin
|
|
|
|
+ {$ifdef CGIDEBUG}SendMethodEnter('TMimeItems.FormSplit');{$ENDIF}
|
|
Sep:='--'+boundary+#13+#10;
|
|
Sep:='--'+boundary+#13+#10;
|
|
Slen:=length(Sep);
|
|
Slen:=length(Sep);
|
|
CLen:=Pos('--'+Boundary+'--',Cnt);
|
|
CLen:=Pos('--'+Boundary+'--',Cnt);
|
|
// Cut last marker
|
|
// Cut last marker
|
|
Cnt:=Copy(Cnt,1,Clen-1);
|
|
Cnt:=Copy(Cnt,1,Clen-1);
|
|
// Cut first marker
|
|
// Cut first marker
|
|
- Delete(Cnt,1,Slen);
|
|
|
|
|
|
+ system.Delete(Cnt,1,Slen);
|
|
Clen:=Length(Cnt);
|
|
Clen:=Length(Cnt);
|
|
While Clen>0 do
|
|
While Clen>0 do
|
|
begin
|
|
begin
|
|
- Fi:=TFormItem.Create;
|
|
|
|
- List.Add(Fi);
|
|
|
|
P:=pos(Sep,Cnt);
|
|
P:=pos(Sep,Cnt);
|
|
If (P=0) then
|
|
If (P=0) then
|
|
P:=CLen+1;
|
|
P:=CLen+1;
|
|
- FI.Data:=Copy(Cnt,1,P-1);
|
|
|
|
- delete(Cnt,1,P+SLen-1);
|
|
|
|
|
|
+ S:=TStringStream.Create(Copy(Cnt,1,P-1));
|
|
|
|
+ try
|
|
|
|
+ FI:=Add as TMimeItem;
|
|
|
|
+ FI.Process(S)
|
|
|
|
+ finally
|
|
|
|
+ S.Free;
|
|
|
|
+ end;
|
|
|
|
+ system.delete(Cnt,1,P+SLen-1);
|
|
CLen:=Length(Cnt);
|
|
CLen:=Length(Cnt);
|
|
end;
|
|
end;
|
|
|
|
+ {$ifdef CGIDEBUG}SendMethodExit('TMimeItems.FormSplit');{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
|
|
{ -------------------------------------------------------------------
|
|
{ -------------------------------------------------------------------
|
|
@@ -952,13 +1164,45 @@ constructor TRequest.create;
|
|
begin
|
|
begin
|
|
inherited create;
|
|
inherited create;
|
|
FHandleGetOnPost:=True;
|
|
FHandleGetOnPost:=True;
|
|
- FFiles:=TUploadedFiles.Create(TUPloadedFile);
|
|
|
|
|
|
+ FFiles:=CreateUploadedFiles;
|
|
|
|
+ FFiles.FRequest:=Self;
|
|
FLocalPathPrefix:='-';
|
|
FLocalPathPrefix:='-';
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+Function TRequest.CreateUploadedFiles : TUploadedFiles;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ CC : TUploadedFilesClass;
|
|
|
|
+ CI : TUploadedFileClass;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ CC:=UploadedFilesClass;
|
|
|
|
+ CI:=UploadedFileClass;
|
|
|
|
+ if (CC=Nil) then
|
|
|
|
+ CC:=TUploadedFiles;
|
|
|
|
+ if (CI=Nil) then
|
|
|
|
+ CI:=TUploadedFile;
|
|
|
|
+ Result:=CC.Create(CI);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TRequest.CreateMimeItems: TMimeItems;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ CC : TMimeItemsClass;
|
|
|
|
+ CI : TMimeItemClass;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ CC:=MimeItemsClass;
|
|
|
|
+ CI:=MimeItemClass;
|
|
|
|
+ if (CC=Nil) then
|
|
|
|
+ CC:=TMimeItems;
|
|
|
|
+ if (CI=Nil) then
|
|
|
|
+ CI:=TMimeItem;
|
|
|
|
+ Result:=CC.Create(CI);
|
|
|
|
+end;
|
|
|
|
+
|
|
destructor TRequest.destroy;
|
|
destructor TRequest.destroy;
|
|
begin
|
|
begin
|
|
- DeleteTempUploadedFiles;
|
|
|
|
FreeAndNil(FFiles);
|
|
FreeAndNil(FFiles);
|
|
inherited destroy;
|
|
inherited destroy;
|
|
end;
|
|
end;
|
|
@@ -1206,17 +1450,8 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
Procedure TRequest.DeleteTempUploadedFiles;
|
|
Procedure TRequest.DeleteTempUploadedFiles;
|
|
-var
|
|
|
|
- i: Integer;
|
|
|
|
- s: String;
|
|
|
|
begin
|
|
begin
|
|
- //delete all temporary uploaded files created for this request if there is any
|
|
|
|
- i := FFiles.Count;
|
|
|
|
- if i > 0 then for i := i - 1 downto 0 do
|
|
|
|
- begin
|
|
|
|
- s := FFiles[i].LocalFileName;
|
|
|
|
- if FileExists(s) then DeleteFile(s);
|
|
|
|
- end;
|
|
|
|
|
|
+ FFiles.DeleteTempUploadedFiles;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TRequest.InitRequestVars;
|
|
procedure TRequest.InitRequestVars;
|
|
@@ -1306,11 +1541,11 @@ end;
|
|
Procedure TRequest.ProcessMultiPart(Stream : TStream; Const Boundary : String; SL:TStrings);
|
|
Procedure TRequest.ProcessMultiPart(Stream : TStream; Const Boundary : String; SL:TStrings);
|
|
|
|
|
|
Var
|
|
Var
|
|
- L : TList;
|
|
|
|
|
|
+ L : TMimeItems;
|
|
B : String;
|
|
B : String;
|
|
I,J : Integer;
|
|
I,J : Integer;
|
|
S,FF,key, Value : String;
|
|
S,FF,key, Value : String;
|
|
- FI : TFormItem;
|
|
|
|
|
|
+ FI : TMimeItem;
|
|
F : TStream;
|
|
F : TStream;
|
|
|
|
|
|
begin
|
|
begin
|
|
@@ -1320,78 +1555,26 @@ begin
|
|
I:=Length(B);
|
|
I:=Length(B);
|
|
If (I>0) and (B[1]='"') then
|
|
If (I>0) and (B[1]='"') then
|
|
B:=Copy(B,2,I-2);
|
|
B:=Copy(B,2,I-2);
|
|
- L:=TList.Create;
|
|
|
|
|
|
+ L:=CreateMimeItems;
|
|
Try
|
|
Try
|
|
- SetLength(S,Stream.Size);
|
|
|
|
- If Length(S)>0 then
|
|
|
|
- if Stream is TCustomMemoryStream then
|
|
|
|
- // Faster.
|
|
|
|
- Move(TCustomMemoryStream(Stream).Memory^,S[1],Length(S))
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- Stream.Read(S[1],Length(S));
|
|
|
|
- Stream.Position:=0;
|
|
|
|
- end;
|
|
|
|
- FormSplit(S,B,L);
|
|
|
|
- For I:=L.Count-1 downto 0 do
|
|
|
|
|
|
+ if Stream is TStringStream then
|
|
|
|
+ S:=TStringStream(Stream).DataString
|
|
|
|
+ else
|
|
begin
|
|
begin
|
|
- FI:=TFormItem(L[i]);
|
|
|
|
- FI.Process;
|
|
|
|
- If (FI.Name='') then
|
|
|
|
- Fi.Name:='DummyFileItem'+IntToStr(i);
|
|
|
|
- //Raise Exception.CreateFmt('Invalid multipart encoding: %s',[FI.Data]);
|
|
|
|
-{$ifdef CGIDEBUG}
|
|
|
|
- With FI Do
|
|
|
|
- begin
|
|
|
|
- SendSeparator;
|
|
|
|
- SendDebug ('PMP item Name : '+Name);
|
|
|
|
- SendDebug ('PMP item Disposition : '+Disposition);
|
|
|
|
- SendDebug ('PMP item FileName : '+FileName);
|
|
|
|
- SendBoolean('PMP item IsFile : ',IsFile);
|
|
|
|
- SendDebug ('PMP item ContentType : '+ContentType);
|
|
|
|
- SendInteger('PMP item DLen : ',DLen);
|
|
|
|
- SendDebug ('PMP item Data : '+Data);
|
|
|
|
- end;
|
|
|
|
-{$endif CGIDEBUG}
|
|
|
|
- Key:=FI.Name;
|
|
|
|
- If Not FI.IsFile Then
|
|
|
|
- Value:=FI.Data
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- Value:=FI.FileName;
|
|
|
|
- J := Length(FI.Data);
|
|
|
|
- if (J=0){zero lenght file} or
|
|
|
|
- ((J=2)and(FI.Data=#13#10)){empty files come as a simple empty line} then
|
|
|
|
- FF:='' //No tmp file will be created for empty files
|
|
|
|
|
|
+ SetLength(S,Stream.Size);
|
|
|
|
+ If Length(S)>0 then
|
|
|
|
+ if Stream is TCustomMemoryStream then
|
|
|
|
+ // Faster.
|
|
|
|
+ Move(TCustomMemoryStream(Stream).Memory^,S[1],Length(S))
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
- FI.DLen:=J;
|
|
|
|
- FF:=GetTempUploadFileName(FI.name,FI.FileName,J);
|
|
|
|
- F:=TFileStream.Create(FF,fmCreate);
|
|
|
|
- Try
|
|
|
|
- F.Write(FI.Data[1],J);
|
|
|
|
- finally
|
|
|
|
- F.Free;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- if (Value <> '') or (FI.DLen > 0)then{only non zero length files or files with non empty names will be considered}
|
|
|
|
- With Files.Add as TUploadedFile do
|
|
|
|
- begin
|
|
|
|
- FieldName:=FI.Name;
|
|
|
|
- FileName:=FI.FileName;
|
|
|
|
- ContentType:=FI.ContentType;
|
|
|
|
- Disposition:=FI.Disposition;
|
|
|
|
- Size:=FI.DLen;
|
|
|
|
- LocalFileName:=FF;
|
|
|
|
|
|
+ Stream.Read(S[1],Length(S));
|
|
|
|
+ Stream.Position:=0;
|
|
end;
|
|
end;
|
|
- end;
|
|
|
|
- FI.Free;
|
|
|
|
- L[i]:=Nil;
|
|
|
|
- SL.Add(Key+'='+Value)
|
|
|
|
end;
|
|
end;
|
|
|
|
+ L.FormSplit(S,B);
|
|
|
|
+ L.CreateUploadFiles(Files,SL);
|
|
Finally
|
|
Finally
|
|
- For I:=0 to L.Count-1 do
|
|
|
|
- TObject(L[i]).Free;
|
|
|
|
L.Free;
|
|
L.Free;
|
|
end;
|
|
end;
|
|
{$ifdef CGIDEBUG} SendMethodExit('ProcessMultiPart');{$endif CGIDEBUG}
|
|
{$ifdef CGIDEBUG} SendMethodExit('ProcessMultiPart');{$endif CGIDEBUG}
|
|
@@ -1425,6 +1608,15 @@ begin
|
|
Items[Index]:=AValue;
|
|
Items[Index]:=AValue;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TUploadedFiles.GetTempUploadFileName(const AName, AFileName: String;
|
|
|
|
+ ASize: Int64): String;
|
|
|
|
+begin
|
|
|
|
+ If Assigned(FRequest) then
|
|
|
|
+ Result:=FRequest.GetTempUploadFileName(AName,AFileName,ASize)
|
|
|
|
+ else
|
|
|
|
+ Result:=GetTempFileName;
|
|
|
|
+end;
|
|
|
|
+
|
|
function TUploadedFiles.IndexOfFile(AName: String): Integer;
|
|
function TUploadedFiles.IndexOfFile(AName: String): Integer;
|
|
|
|
|
|
begin
|
|
begin
|
|
@@ -1455,10 +1647,32 @@ begin
|
|
Result:=Files[I];
|
|
Result:=Files[I];
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+Procedure TUPloadedFiles.DeleteTempUploadedFiles;
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ i: Integer;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ //delete all temporary uploaded files created for this request if there are any
|
|
|
|
+ for i := Count-1 downto 0 do
|
|
|
|
+ Files[i].DeleteTempUploadedFile;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+
|
|
{ ---------------------------------------------------------------------
|
|
{ ---------------------------------------------------------------------
|
|
TUploadedFile
|
|
TUploadedFile
|
|
---------------------------------------------------------------------}
|
|
---------------------------------------------------------------------}
|
|
|
|
|
|
|
|
+procedure TUploadedFile.DeleteTempUploadedFile;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ s: String;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if (LocalFileName<>'') and FileExists(LocalFileName) then
|
|
|
|
+ DeleteFile(LocalFileName);
|
|
|
|
+end;
|
|
|
|
+
|
|
function TUploadedFile.GetStream: TStream;
|
|
function TUploadedFile.GetStream: TStream;
|
|
begin
|
|
begin
|
|
If (FStream=Nil) then
|
|
If (FStream=Nil) then
|
|
@@ -1660,8 +1874,9 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
-{ TCookie }
|
|
|
|
-
|
|
|
|
|
|
+{ ---------------------------------------------------------------------
|
|
|
|
+ TCookie
|
|
|
|
+ ---------------------------------------------------------------------}
|
|
|
|
|
|
function TCookie.GetAsString: string;
|
|
function TCookie.GetAsString: string;
|
|
|
|
|
|
@@ -1729,7 +1944,9 @@ begin
|
|
FExpires := EncodeDate(1970, 1, 1);
|
|
FExpires := EncodeDate(1970, 1, 1);
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TCookieCollection }
|
|
|
|
|
|
+{ ---------------------------------------------------------------------
|
|
|
|
+ TCookies
|
|
|
|
+ ---------------------------------------------------------------------}
|
|
|
|
|
|
function TCookies.GetCookie(Index: Integer): TCookie;
|
|
function TCookies.GetCookie(Index: Integer): TCookie;
|
|
begin
|
|
begin
|
|
@@ -1775,8 +1992,9 @@ begin
|
|
Dec(Result);
|
|
Dec(Result);
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TCustomSession }
|
|
|
|
-
|
|
|
|
|
|
+{ ---------------------------------------------------------------------
|
|
|
|
+ TCustomSession
|
|
|
|
+ ---------------------------------------------------------------------}
|
|
|
|
|
|
procedure TCustomSession.SetSessionCookie(const AValue: String);
|
|
procedure TCustomSession.SetSessionCookie(const AValue: String);
|
|
begin
|
|
begin
|
|
@@ -1816,5 +2034,6 @@ begin
|
|
// Do nothing
|
|
// Do nothing
|
|
end;
|
|
end;
|
|
|
|
|
|
-
|
|
|
|
|
|
+initialization
|
|
|
|
+ MimeItemClass:=THTTPMimeItem;
|
|
end.
|
|
end.
|