Skip to content

Commit b9de2e3

Browse files
committed
Supports requests using multipart/form-data
1 parent 04f9446 commit b9de2e3

File tree

1 file changed

+137
-11
lines changed

1 file changed

+137
-11
lines changed

src/RestClient.pas

Lines changed: 137 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,34 @@ TResource = class
230230
{$ENDIF}
231231
end;
232232

233+
{$IFDEF SUPPORTS_GENERICS}
234+
TMultiPartFormAttachment = class
235+
private
236+
FFileName: string;
237+
FMimeType: string;
238+
FContent: TStringStream;
239+
public
240+
constructor Create(MimeType, FileName: string); overload;
241+
constructor Create(Source: TStream; MimeType, FileName: string); overload;
242+
constructor Create(FilePath, MimeType, FileName: string); overload;
243+
destructor Destroy; override;
244+
property Content: TStringStream read FContent write FContent;
245+
property MimeType: string read FMimeType write FMimeType;
246+
property FileName: string read FFileName write FFileName;
247+
end;
248+
249+
TMultiPartFormData = class
250+
private
251+
FBoundary: string;
252+
FContentType: string;
253+
procedure AddFieldContent(Field: TRttiField; var Content: TStringList);
254+
public
255+
constructor Create;
256+
function ContentAsString: string;
257+
property ContentType: string read FContentType;
258+
end;
259+
{$ENDIF}
260+
233261
implementation
234262

235263
uses StrUtils, Math,
@@ -896,21 +924,29 @@ procedure TResource.GetAsDataSet(ADataSet: TDataSet);
896924

897925
procedure TResource.SetContent(entity: TObject);
898926
var
899-
vJson: string;
927+
vRawContent: string;
900928
vStream: TStringStream;
929+
vMultipartFormData: TMultipartFormData;
901930
begin
902931
FContent.Clear;
903-
if Assigned(entity) then
932+
if not Assigned(entity) then
933+
Exit;
934+
935+
if entity is TMultipartFormData then
904936
begin
905-
vJson := TJsonUtil.Marshal(Entity);
906-
907-
vStream := TStringStream.Create(vJson);
908-
try
909-
vStream.Position := 0;
910-
FContent.CopyFrom(vStream, vStream.Size);
911-
finally
912-
vStream.Free;
913-
end;
937+
vMultipartFormData := TMultipartFormData(entity);
938+
vRawContent := vMultipartFormData.ContentAsString;
939+
ContentType(vMultipartFormData.ContentType);
940+
end
941+
else
942+
vRawContent := TJsonUtil.Marshal(Entity);
943+
944+
vStream := TStringStream.Create(vRawContent);
945+
try
946+
vStream.Position := 0;
947+
FContent.CopyFrom(vStream, vStream.Size);
948+
finally
949+
vStream.Free;
914950
end;
915951
end;
916952

@@ -1016,4 +1052,94 @@ class function TJsonListAdapter.NewFrom(AList: TList; AItemClass: TClass): IJson
10161052
Result := TJsonListAdapter.Create(AList, AItemClass);
10171053
end;
10181054

1055+
{ TMultiPartFormData }
1056+
1057+
{$IFDEF SUPPORTS_GENERICS}
1058+
procedure TMultiPartFormData.AddFieldContent(Field: TRttiField; var Content: TStringList);
1059+
const
1060+
FmtTextContent = 'Content-Disposition: form-data; name="%s"'+ sLineBreak+sLineBreak +'%s';
1061+
FmtFileContent = 'Content-Disposition: form-data; name="%s"; filename="%s"'+ sLineBreak +'Content-Type: %s'+ sLineBreak+sLineBreak+ '%s';
1062+
var
1063+
Attachment: TMultiPartFormAttachment;
1064+
begin
1065+
if Field.FieldType.TypeKind in [tkString, tkUString, tkWChar, tkLString, tkWString, tkInteger, tkChar, tkWChar] then
1066+
begin
1067+
Content.Add(Format(FmtTextContent, [Field.Name, Field.GetValue(Self).AsString]));
1068+
Exit;
1069+
end;
1070+
1071+
if Field.FieldType.Name.Equals(TMultiPartFormAttachment.ClassName) then
1072+
begin
1073+
Attachment := Field.GetValue(Self).AsType<TMultiPartFormAttachment>;
1074+
Content.Add(Format(FmtFileContent, [Field.Name, Attachment.FileName, Attachment.MimeType, Attachment.Content.DataString]));
1075+
end;
1076+
end;
1077+
1078+
function TMultiPartFormData.ContentAsString: string;
1079+
var
1080+
vField: TRttiField;
1081+
vContent: TStringList;
1082+
vBoundary: string;
1083+
vRttiContext: TRttiContext;
1084+
vRttiType: TRttiType;
1085+
begin
1086+
vBoundary := '--' + FBoundary;
1087+
1088+
vContent := TStringList.Create;
1089+
try
1090+
vContent.Add(vBoundary);
1091+
1092+
vRttiContext := TRttiContext.Create;
1093+
vRttiType := vRttiContext.GetType(Self.ClassType);
1094+
for vField in vRttiType.GetDeclaredFields do
1095+
begin
1096+
AddFieldContent(vField, vContent);
1097+
vContent.Add(vBoundary);
1098+
end;
1099+
1100+
vContent.Strings[Pred(vContent.Count)] := vBoundary + '--';
1101+
Result := vContent.Text;
1102+
finally
1103+
vContent.Free;
1104+
end;
1105+
end;
1106+
1107+
constructor TMultiPartFormData.Create;
1108+
const
1109+
FmtBoundary = 'boundary--%s';
1110+
FmtContentType = 'multipart/form-data; boundary=%s';
1111+
var
1112+
vGUID: TGUID;
1113+
begin
1114+
CreateGUID(vGUID);
1115+
FBoundary := Format(FmtBoundary, [GUIDToString(vGUID)]);
1116+
FContentType := Format(FmtContentType, [FBoundary]);
1117+
end;
1118+
1119+
constructor TMultiPartFormAttachment.Create(Source: TStream; MimeType, FileName: string);
1120+
begin
1121+
Create(MimeType, FileName);
1122+
FContent.LoadFromStream(Source);
1123+
end;
1124+
1125+
constructor TMultiPartFormAttachment.Create(FilePath, MimeType, FileName: string);
1126+
begin
1127+
Create(MimeType, FileName);
1128+
FContent.LoadFromFile(FilePath);
1129+
end;
1130+
1131+
constructor TMultiPartFormAttachment.Create(MimeType, FileName: string);
1132+
begin
1133+
FContent := TStringStream.Create;
1134+
FMimeType := MimeType;
1135+
FFileName := FileName;
1136+
end;
1137+
1138+
destructor TMultiPartFormAttachment.Destroy;
1139+
begin
1140+
FContent.Free;
1141+
inherited;
1142+
end;
1143+
{$ENDIF}
1144+
10191145
end.

0 commit comments

Comments
 (0)