program client;
{$mode objfpc}{$H+}
uses
Classes,
IdHTTP,
IdURI,
Interfaces,
Math,
MD5,
pl_indy,
SysUtils;
function HttpGet(const AUrl: String): String;
begin
with TIdHTTP.Create(nil) do begin
try
Result := Get(AUrl);
finally
Free;
end;
end;
end;
function HttpGetMD5(const AUrl: String): String;
begin
Result := HttpGet(AUrl + '?cmd=md5');
end;
function HttpJoinFiles(const AUrl: String; const AFileNames: String): String;
begin
Result := HttpGet(AUrl + '?cmd=join&files=' + AFileNames);
end;
function HttpDelete(const AUrl: String): String;
begin
with TIdHTTP.Create(nil) do begin
try
Result := Delete(AUrl);
finally
Free;
end;
end;
end;
function StreamCopyChunk(const ADst: TMemoryStream; const ASrc: TStream; const AChunkSize: Integer): Integer;
begin
ADst.Clear;
Result := Min(AChunkSize, ASrc.Size - ASrc.Position);
if Result > 0 then begin
ADst.CopyFrom(ASrc, Result);
ADst.Position := 0;
end;
end;
function MemoryStreamGetMD5(const AStream: TMemoryStream): String;
var
LPointer: Pointer;
begin
LPointer := AStream.Memory;
Result := MD5Print(MD5Buffer(LPointer^, AStream.Size));
end;
procedure StreamHttpPut(const AStream: TStream; const AUrl: String);
begin
with TIdHTTP.Create(nil) do begin
try
AStream.Position := 0;
Put(AUrl, AStream);
finally
Free;
end;
end;
end;
procedure StreamHttpPutWithErrorCheck(const AStream: TMemoryStream; const AUrl: String; ATryCount: Integer);
begin
while ATryCount > 0 do begin
StreamHttpPut(AStream, AUrl);
if HttpGetMD5(AUrl) = MemoryStreamGetMD5(AStream) then begin
Exit;
end;
Dec(ATryCount);
end;
raise Exception.Create('Chunk MD5 Check Failed');
end;
procedure SendFile(const AURI: TIdURI; const AStream: TStream; const AChunkSize: Integer);
var
LIndex: Integer;
LRemotePath: String;
LMemoryStream: TMemoryStream;
begin
LRemotePath := AURI.Protocol + '://' + AURI.Host + AURI.Path;
LMemoryStream := TMemoryStream.Create;
try
with TStringList.Create do begin
try
repeat
if StreamCopyChunk(LMemoryStream, AStream, AChunkSize) > 0 then begin
Add(Format('__temp%d', [Count]));
StreamHttpPutWithErrorCheck(LMemoryStream, LRemotePath + Strings[Count - 1], 5);
end;
until AStream.Position = AStream.Size;
HttpJoinFiles(LRemotePath + AURI.Document, CommaText);
for LIndex := 0 to Count - 1 do begin
HttpDelete(LRemotePath + Strings[LIndex]);
end;
finally
Free;
end;
end;
finally
FreeAndNil(LMemoryStream);
end;
end;
procedure SendFile(const AURI: TIdURI; const AFileName: TFileName; const AChunkSize: Integer);
var
LStream: TStream;
begin
LStream := TFileStream.Create(AFileName, fmOpenRead);
try
SendFile(AURI, LStream, AChunkSize);
finally
FreeAndNil(LStream);
end;
if HttpGetMD5(AURI.URI) <> MD5Print(MD5File(AFileName)) then begin
raise Exception.Create('Final MD5 Check Failed');
end;
end;
procedure SendFile(const ADst: String; const AFileName: TFileName; const AChunkSize: Integer);
var
LURI: TIdURI;
begin
LURI := TIdURI.Create(ADst);
try
SendFile(LURI, AFileName, AChunkSize);
finally
FreeAndNil(LURI);
end;
end;
begin
try
SendFile('http://127.0.0.1/result.mp4', 'E:\New Movies\Inland Empire (2006).mp4', $1000000);
except
on E: Exception do WriteLn(E.Message);
end;
WriteLn('DONE');
ReadLn;
end.