httpsend.pas - int64 support and improvements (by Pepak)
InputStream and OutputStream properties for direct HTTP upload/download to any TStream git-svn-id: https://svn.code.sf.net/p/synalist/code/trunk@227 7c85be65-684b-0410-a082-b2ed4fbef004
This commit is contained in:
parent
8f9d5b6aad
commit
56710f0ab4
90
httpsend.pas
90
httpsend.pas
@ -1,5 +1,5 @@
|
||||
{==============================================================================|
|
||||
| Project : Ararat Synapse | 003.012.010 |
|
||||
| Project : Ararat Synapse | 003.013.000 |
|
||||
|==============================================================================|
|
||||
| Content: HTTP client |
|
||||
|==============================================================================|
|
||||
@ -34,6 +34,7 @@
|
||||
|==============================================================================|
|
||||
| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
|
||||
| Portions created by Lukas Gebauer are Copyright (c) 1999-2021. |
|
||||
| Portions created by Pepak are Copyright (c) 2020-2021. |
|
||||
| All Rights Reserved. |
|
||||
|==============================================================================|
|
||||
| Contributor(s): |
|
||||
@ -101,18 +102,21 @@ type
|
||||
FResultString: string;
|
||||
FUserAgent: string;
|
||||
FCookies: TStringList;
|
||||
FDownloadSize: integer;
|
||||
FUploadSize: integer;
|
||||
FRangeStart: integer;
|
||||
FRangeEnd: integer;
|
||||
FDownloadSize: int64;
|
||||
FUploadSize: int64;
|
||||
FRangeStart: int64;
|
||||
FRangeEnd: int64;
|
||||
FAddPortNumberToHost: Boolean;
|
||||
FInputStream, FOutputStream: TStream;
|
||||
function ReadUnknown: Boolean; virtual;
|
||||
function ReadIdentity(Size: Integer): Boolean; virtual;
|
||||
function ReadIdentity(Size: int64): Boolean; virtual;
|
||||
function ReadChunked: Boolean; virtual;
|
||||
procedure ParseCookies;
|
||||
function PrepareHeaders: AnsiString;
|
||||
function InternalDoConnect(needssl: Boolean): Boolean;
|
||||
function InternalConnect(needssl: Boolean): Boolean;
|
||||
function InputDocument: TStream;
|
||||
function OutputDocument: TStream;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
@ -158,13 +162,13 @@ type
|
||||
|
||||
{:If you need to download only part of a requested document, specify here
|
||||
the position of subpart begin. If 0, the full document is requested.}
|
||||
property RangeStart: integer read FRangeStart Write FRangeStart;
|
||||
property RangeStart: int64 read FRangeStart Write FRangeStart;
|
||||
|
||||
{:If you need to download only part of a requested document, specify here
|
||||
the position of subpart end. If 0, the document from rangeStart to end of
|
||||
document is requested.
|
||||
(Useful for resuming broken downloads, for example.)}
|
||||
property RangeEnd: integer read FRangeEnd Write FRangeEnd;
|
||||
property RangeEnd: int64 read FRangeEnd Write FRangeEnd;
|
||||
|
||||
{:Mime type of sending data. Default is: 'text/html'.}
|
||||
property MimeType: string read FMimeType Write FMimeType;
|
||||
@ -209,12 +213,12 @@ type
|
||||
{:if this value is not 0, then data download is pending. In this case you
|
||||
have here the total size of downloaded data. Useful for drawing download
|
||||
progressbar from OnStatus event.}
|
||||
property DownloadSize: integer read FDownloadSize;
|
||||
property DownloadSize: int64 read FDownloadSize;
|
||||
|
||||
{:if this value is not 0, then data upload is pending. In this case you have
|
||||
here the total size of uploaded data. Useful for drawing upload progressbar
|
||||
from OnStatus event.}
|
||||
property UploadSize: integer read FUploadSize;
|
||||
property UploadSize: int64 read FUploadSize;
|
||||
|
||||
{:Socket object used for TCP/IP operation.
|
||||
Good for setting OnStatus hook, etc.}
|
||||
@ -223,6 +227,12 @@ type
|
||||
{:Allows to switch off port number in 'Host:' HTTP header. By default @TRUE.
|
||||
Some buggy servers do not like port informations in this header.}
|
||||
property AddPortNumberToHost: Boolean read FAddPortNumberToHost write FAddPortNumberToHost;
|
||||
public
|
||||
{:for direct sending from any TStream. Defalut nil = use Document property instead.}
|
||||
property InputStream: TStream read FInputStream write FInputStream;
|
||||
|
||||
{:for direct dovnloading into any TStream. Defalut nil = use Document property instead.}
|
||||
property OutputStream: TStream read FOutputStream write FOutputStream;
|
||||
end;
|
||||
|
||||
{:A very useful function, and example of use can be found in the THTTPSend
|
||||
@ -296,6 +306,8 @@ begin
|
||||
FUploadSize := 0;
|
||||
FAddPortNumberToHost := true;
|
||||
FKeepAliveTimeout := 300;
|
||||
FInputStream := nil;
|
||||
FOutputStream := nil;
|
||||
Clear;
|
||||
end;
|
||||
|
||||
@ -308,11 +320,29 @@ begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function THTTPSend.InputDocument: TStream;
|
||||
begin
|
||||
if InputStream <> nil then
|
||||
Result := InputStream
|
||||
else
|
||||
Result := Document;
|
||||
end;
|
||||
|
||||
function THTTPSend.OutputDocument: TStream;
|
||||
begin
|
||||
if OutputStream <> nil then
|
||||
Result := OutputStream
|
||||
else
|
||||
Result := Document;
|
||||
end;
|
||||
|
||||
procedure THTTPSend.Clear;
|
||||
begin
|
||||
FRangeStart := 0;
|
||||
FRangeEnd := 0;
|
||||
FDocument.Clear;
|
||||
InputDocument.Size := 0;
|
||||
OutputDocument.Size := 0;
|
||||
FHeaders.Clear;
|
||||
FMimeType := 'text/html';
|
||||
end;
|
||||
@ -383,7 +413,7 @@ var
|
||||
status100: Boolean;
|
||||
status100error: string;
|
||||
ToClose: Boolean;
|
||||
Size: Integer;
|
||||
Size: int64;
|
||||
Prot, User, Pass, Host, Port, Path, Para, URI: string;
|
||||
s, su: AnsiString;
|
||||
HttpTunnel: Boolean;
|
||||
@ -400,7 +430,7 @@ begin
|
||||
FDownloadSize := 0;
|
||||
FUploadSize := 0;
|
||||
|
||||
URI := ParseURL(URL, Prot, User, Pass, Host, Port, Path, Para);
|
||||
URI := ParseURL(trim(URL), Prot, User, Pass, Host, Port, Path, Para);
|
||||
User := DecodeURL(user);
|
||||
Pass := DecodeURL(pass);
|
||||
if User = '' then
|
||||
@ -425,14 +455,14 @@ begin
|
||||
FSock.HTTPTunnelPass := '';
|
||||
end;
|
||||
UsingProxy := (FProxyHost <> '') and not(HttpTunnel);
|
||||
Sending := FDocument.Size > 0;
|
||||
Sending := InputDocument.Size > 0;
|
||||
{Headers for Sending data}
|
||||
status100 := FStatus100 and Sending and (FProtocol = '1.1');
|
||||
if status100 then
|
||||
FHeaders.Insert(0, 'Expect: 100-continue');
|
||||
if Sending then
|
||||
begin
|
||||
FHeaders.Insert(0, 'Content-Length: ' + IntToStr(FDocument.Size));
|
||||
FHeaders.Insert(0, 'Content-Length: ' + IntToStr(InputDocument.Size));
|
||||
if FMimeType <> '' then
|
||||
FHeaders.Insert(0, 'Content-Type: ' + FMimeType);
|
||||
end;
|
||||
@ -514,7 +544,7 @@ begin
|
||||
end;
|
||||
|
||||
{ reading Status }
|
||||
FDocument.Position := 0;
|
||||
InputDocument.Position := 0;
|
||||
Status100Error := '';
|
||||
if status100 then
|
||||
begin
|
||||
@ -538,23 +568,23 @@ begin
|
||||
begin
|
||||
{ we can upload content }
|
||||
Status100Error := '';
|
||||
FUploadSize := FDocument.Size;
|
||||
FSock.SendBuffer(FDocument.Memory, FDocument.Size);
|
||||
FUploadSize := InputDocument.Size;
|
||||
FSock.SendStreamRaw(InputDocument);
|
||||
end;
|
||||
end
|
||||
else
|
||||
{ upload content }
|
||||
if sending then
|
||||
begin
|
||||
if FDocument.Size >= c64k then
|
||||
if InputDocument.Size >= c64k then
|
||||
begin
|
||||
FSock.SendString(PrepareHeaders);
|
||||
FUploadSize := FDocument.Size;
|
||||
FSock.SendBuffer(FDocument.Memory, FDocument.Size);
|
||||
FUploadSize := InputDocument.Size;
|
||||
FSock.SendStreamRaw(InputDocument);
|
||||
end
|
||||
else
|
||||
begin
|
||||
s := PrepareHeaders + ReadStrFromStream(FDocument, FDocument.Size);
|
||||
s := PrepareHeaders + ReadStrFromStream(InputDocument, InputDocument.Size);
|
||||
FUploadSize := Length(s);
|
||||
FSock.SendString(s);
|
||||
end;
|
||||
@ -590,7 +620,7 @@ begin
|
||||
begin
|
||||
{ old HTTP 0.9 and some buggy servers not send result }
|
||||
s := s + CRLF;
|
||||
WriteStrToStream(FDocument, s);
|
||||
WriteStrToStream(OutputDocument, s);
|
||||
FResultCode := 0;
|
||||
end;
|
||||
until (FSock.LastError <> 0) or (FResultCode <> 100);
|
||||
@ -618,7 +648,7 @@ begin
|
||||
su := UpperCase(s);
|
||||
if Pos('CONTENT-LENGTH:', su) = 1 then
|
||||
begin
|
||||
Size := StrToIntDef(Trim(SeparateRight(s, ':')), -1);
|
||||
Size := StrToInt64Def(Trim(SeparateRight(s, ':')), -1);
|
||||
if (Size <> -1) and (FTransferEncoding = TE_UNKNOWN) then
|
||||
FTransferEncoding := TE_IDENTITY;
|
||||
end;
|
||||
@ -671,7 +701,7 @@ begin
|
||||
Result := ReadChunked;
|
||||
end;
|
||||
|
||||
FDocument.Position := 0;
|
||||
OutputDocument.Position := 0;
|
||||
if ToClose then
|
||||
begin
|
||||
FSock.CloseSocket;
|
||||
@ -689,7 +719,7 @@ begin
|
||||
repeat
|
||||
s := FSock.RecvPacket(FTimeout);
|
||||
if FSock.LastError = 0 then
|
||||
WriteStrToStream(FDocument, s);
|
||||
WriteStrToStream(OutputDocument, s);
|
||||
until FSock.LastError <> 0;
|
||||
if FSock.LastError = WSAECONNRESET then
|
||||
begin
|
||||
@ -698,13 +728,13 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function THTTPSend.ReadIdentity(Size: Integer): Boolean;
|
||||
function THTTPSend.ReadIdentity(Size: int64): Boolean;
|
||||
begin
|
||||
if Size > 0 then
|
||||
begin
|
||||
FDownloadSize := Size;
|
||||
FSock.RecvStreamSize(FDocument, FTimeout, Size);
|
||||
FDocument.Position := FDocument.Size;
|
||||
FSock.RecvStreamSize(OutputDocument, FTimeout, Size);
|
||||
OutputDocument.Position := OutputDocument.Size;
|
||||
Result := FSock.LastError = 0;
|
||||
end
|
||||
else
|
||||
@ -714,7 +744,7 @@ end;
|
||||
function THTTPSend.ReadChunked: Boolean;
|
||||
var
|
||||
s: ansistring;
|
||||
Size: Integer;
|
||||
Size: int64;
|
||||
begin
|
||||
repeat
|
||||
repeat
|
||||
@ -724,7 +754,7 @@ begin
|
||||
Break;
|
||||
s := Trim(SeparateLeft(s, ' '));
|
||||
s := Trim(SeparateLeft(s, ';'));
|
||||
Size := StrToIntDef('$' + s, 0);
|
||||
Size := StrToInt64Def('$' + s, 0);
|
||||
if Size = 0 then
|
||||
Break;
|
||||
if not ReadIdentity(Size) then
|
||||
|
Loading…
Reference in New Issue
Block a user