📄 iehttp3.pas
字号:
unit IEHTTP3;
{.$DEFINE TIE_USE_TNT} //enable this to use TTNTStringList instead of TWideStringList
//In Delphi 7, you will need to enable this to handle unicode responses
{.$define tie_debug}
// TIEHTTP
// WinInet HTTP/HTTPS component (supports GET/POST/multipart variables)
// Author: Kyriacos Michael ( to contact me please use the support url below )
// parts of the code were obtained from usenet.
// Base64 encoding/decoding by David Barton (davebarton@bigfoot.com)
// Support URL: http://www.myfxboard.com/tiehttp/
// Released: 1 Apr 2003
// Source code released: 28 Mar 2004
//
// This component was released as Freeware with source,
// after many requests from people wanting to extent it
// or simply have a look at it.
// You are free to use the source code for any kind of use, even commercial.
// You are not allowed to sell parts or the whole of the code.
// Please send any modifications of the code, or any additions
// back to the author.
//
// to do list:
// ------------------------------
// investigate InternetSetStatusCallback
// investigate InternetReadFile - > InternetReadFileEx + W
// upload progress
//
//change history
//
// 1.3.0.40 17may2004: blocking / non-blocking mode
// cancel requests
// request timeout
// 1.3.0.42 17may2004: fixed bug that avoids you to reuse the component after a timeout or a cancel request
// 1.3.0.46 14nov2005: fixed onpacketread in non-blocking mode
// added onTimer event and timerIntervalSeconds property
// 1.3.0.44 03sep2004: fixed some bugs in the timeout/onpacketread mechanism
// basic proxy authentication support
// request_header property e.g. if you want to set "Referer:"
// 1.3.0.47 18feb2006: added gzip decompression (iis) (i had only deflate)
// 1.5.0.48 02jan2007: supports Custom-Content-Length for aspx files
// 1.5.0.60 24apr2008: using xxxW() windows wide functions e.g. InternetOpenW
// 1.5.0.61 24apr2008: full unicode, ditched ansi char operations, pchar operations e.g. strcopy, strcat
// 1.5.0.62 24apr2008: automatic conversion from charset=utf-8, charset=utf-16, charset=us-ascii
// 1.5.0.65 30apr2008: twidestringlist: added option for d7 users to use the default TStringList (ansi) or the TTNTStringList (->DEFINE TIE_USE_TNT)
{$IFDEF VER80} unsupported {$ENDIF}
{$IFDEF VER90} {$DEFINE D7_AND_LOWER} {$ENDIF} // D2
{$IFDEF VER93} {$DEFINE D7_AND_LOWER} {$ENDIF} // CPPB 1
{$IFDEF VER100} {$DEFINE D7_AND_LOWER} {$ENDIF} // D3
{$IFDEF VER110} {$DEFINE D7_AND_LOWER} {$ENDIF} // CPPB 3
{$IFDEF VER120} {$DEFINE D7_AND_LOWER} {$ENDIF} // D4
{$IFDEF VER130} {$DEFINE D7_AND_LOWER} {$ENDIF} // D5
{$IFDEF VER140} {$DEFINE D7_AND_LOWER} {$ENDIF} // D6
{$IFDEF VER150} {$DEFINE D7_AND_LOWER} {$ENDIF} // D7
interface
uses
SysUtils, Classes, wininet, windows,
{$IFDEF D7_AND_LOWER}
//no widestrings in D5, D6 or D7
{$ELSE}
//D2005, D2006, D2007...
WideStrings,
{$ENDIF}
{$IFDEF TIE_USE_TNT}
tntclasses,
{$else}
tntlite, //allows MemoryStream and FileStream to load and save unicode files
{$endif}
WinInet_Ex, //must be after wininet; defines the wide version of TURLComponents
forms; //forms unit is necessary for application.processmessages (non blocking mode)
{$IFDEF D7_AND_LOWER} //D5, D6 or D7
type
{$IFDEF TIE_USE_TNT}
TWideStringList = TTNTStringList;
{$ELSE}
TWideStringList = TStringList; //fake TWideStringList
{$ENDIF}
{$ENDIF}
const
multipart_boundary = '-----------------------------7cf87224d2020a';
//type
// TRequestMethods = (rm_GET, rm_POST, rm_POST_multipart);
type
bytestring = ansistring;
type
TIEHTTP = class(TComponent)
private
extraHeaders : widestring;
hSession, hConnect, hFile : HInternet;
buffer: TByteArray; //TByteArray = array[0..32767] of Byte;
_lpSzExtraInfo_Bytes : ByteString;
is_ie6_and_below : boolean;
fTimeout : Integer; //value is in milliseconds
fTimerIntervalSeconds : Integer;
//ie_thread : TTimeout;
flag_request_to_stop : boolean;
flag_timeout_occured : boolean;
flag_cleanup_completed : boolean;
fBlockingMode: boolean;
last_packet_read_dt : TDateTime;
last_packet_processed_dt : TDateTime;
last_timer_procesed_dt : TDateTime;
timeout_datetime : tdatetime; //the calculated time to timeout
//procedure ReadUrl(hSession: HInternet; const UrlAddr: string; Dest: TStream);
procedure CrackURL; //step2 : uncompressed, no sl, will also perform crackurl
//procedure ProcessReadRequest; //step3 : actual reading
procedure SetGetStr(const Value: widestring);
procedure SetPostStr(const Value: widestring);
procedure SetRequestMethod(const Value: widestring);
procedure SetMultipart(value: boolean);
procedure SetURL(value: widestring);
procedure ConvertToMultiPart;
procedure ReadCookiesAndHeaders(hFile:HInternet);
procedure CalcTimeoutDatetime;
procedure SetTimeout(const Value: integer); //value is in milliseconds
procedure PrepareHeaders1;
procedure PrepareHeaders2;
procedure ReadResponse;
procedure SetBlockingMode(const Value: boolean);
procedure CleanUpConnectionMemory;
function GetErrorString(error_code: integer): widestring;
procedure AddHeader(s: widestring);
procedure SetTimeInterval(const Value: Integer);
protected
FpostStr : widestring;
FgetStr : widestring;
FRequestMethod : widestring;
FMultipartPOST : boolean;
FUrl: widestring;
FOnPacketRead: TNotifyEvent;
FOnTimer : TNotifyEvent;
public
//flag_WaitForSingleObject : boolean;
ie_thread : TThread; //ttimeout not known here
//ie_thread_ready : boolean;
ie_thread_finished : boolean;
//headers : string; //deprecated: see request_headers
error : integer;
error_msg : widestring;
http_agent_string : widestring;
result_sl : TWideStringList; //text response
sl : TWideStringList; //alias to result_sl
result_ms : TTNTMemoryStream; //binary response, tnt is to allow saving to unicode filename, nothing to do with content
//result_ms : TMemoryStream; //binary response
cookies : TWideStringlist;
request_headers : TWideStringList; //additional request headers, e.g.
response_headers : TWideStringList;
error_code : integer; //100: timeout
//101: canceled
working_status : integer;
bytes_read_total : integer;
event_handle : THandle;
content_type : widestring;
ContentSize : DWORD;
multipartVars : array of record f: widestring; v : widestring end; //v will be converted to utf8
multipartBinaryVars : array of record f: widestring; v : bytestring end;
aURLC2 : TURLComponents;
username : widestring;
password : widestring;
proxy_username : widestring;
proxy_password : widestring;
debug_total_packets : integer;
debug_total_packet_events : integer;
debug_total_timer_events : Integer;
unzip_method : ansichar; //G: iis Z: php
procedure ProcessReadRequest; //step3 : actual reading
procedure Execute; //step1 : execute default url
procedure ExecuteURL(url: widestring); //step1 : execute given url
constructor Create(AOwner: TComponent); override; //reintroduce;
destructor Destroy; override;
function GetStringPercentage: widestring; //example on how to read download status
procedure RequestCompleted;
procedure StopRequest(wait: boolean=false);
function GetProgress: single;
function GetProgressPercentage: single;
function CheckIEOnline: boolean;
function GetResponseHeaderValue(header_name: widestring): widestring;
function GetResponseHeaderIdx(header_name: widestring): integer;
procedure AddRequestHeader(header_name, value: widestring);
procedure DeleteRequestHeader(header_name: widestring);
function GetRequestHeaderIdx(header_name: widestring): integer;
function GetRequestHeaderValue(header_name: widestring): widestring;
function Canceled: boolean; //us-spelling
function FileToB64String(filename: widestring): bytestring;
published
property postStr : widestring read FPostStr write SetPostStr;
property getStr : widestring read FGetStr write SetGetStr;
property URL : widestring read FUrl write SetURL;
property Timeout : integer read fTimeout write SetTimeout;
property TimerIntervalSeconds : Integer read fTimerIntervalSeconds write SetTimeInterval;
property BlockingMode : boolean read fBlockingMode write SetBlockingMode;
//property username : string read FUsername write FUsername;
//property password : string read FPassword write FPassword;
//property content_type : string read Fcontent_type write Fcontent_type;
property RequestMethod : widestring read FRequestMethod write SetRequestMethod;
property MultipartPOST : boolean read FMultipartPOST write SetMultipart;
property OnPacketRead: TNotifyEvent read FOnPacketRead write FOnPacketRead;
property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
procedure AddMultipartVar(field: widestring; value: widestring);
procedure AddMultipartVarW(field: widestring; value: widestring);
procedure AddMultipartVarA(field: widestring; value: ansistring);
procedure AddMultipartVar_B64(field: widestring; value: bytestring);
procedure AddMultipartFile(field: widestring; filename: widestring);
procedure AddMultipartStream(field: widestring; ms: TMemoryStream);
//procedure AddMultipartVar_Compressed(field: string; value: string);
end;
procedure Register;
implementation
uses
{$IFDEF tie_debug} my_unit1, {$endif}
ZLib, iiehttp3_funcs, iehttp4_thread,
Dialogs, Controls; //for MessageDlg and mrOK;
procedure Register;
begin
RegisterComponents('Internet', [TIEHTTP]);
end;
{$IFDEF tie_debug}
procedure LogStr(s: widestring);
begin
AppendToFileLNA('c:\iehttp1.log', datetimetostr(now) + ' : ' + s);
end;
{$endif}
{ TIEHTTP }
constructor TIEHTTP.Create;
var
lStructSize : Cardinal;
wininet_receive_timeout : LongInt;
begin
inherited Create(AOwner);
setRequestMethod('GET');
multipartPOST := false;
result_sl := TWideStringList.Create;
sl := result_sl; //alias
result_ms := TTNTMemoryStream.Create;
result_ms.Position := 0;
response_headers := TWideStringList.create;
request_headers := TWideStringList.create;
request_headers.Add('Accept-Encoding: gzip, deflate');
cookies := tWideStringlist.create;
http_agent_string := 'tiehttp';
fBlockingMode := true; //if you will not be allowed to cancel requests
//except from other threads
fTimeout := 90; // timeout if no reply for X seconds between reads
// this will not affect a long connection as long
// as the delay between reads does not exceed X seconds
working_status := 0; //0: working=off, 1: working=on
lStructSize := sizeof(wininet_receive_timeout);
InternetQueryOptionW(nil, INTERNET_OPTION_RECEIVE_TIMEOUT, @wininet_receive_timeout, lStructSize );
//ie7 introduced a default receive timeout of 30seconds
//in ie6 and below the timeout was 0 (infinite)
is_ie6_and_below := wininet_receive_timeout <> 30000;
if not is_ie6_and_below then begin
wininet_receive_timeout := 0;
InternetSetOptionW(nil, INTERNET_OPTION_RECEIVE_TIMEOUT, @wininet_receive_timeout, sizeof(wininet_receive_timeout) );
end;
end;
destructor TIEHTTP.Destroy;
begin
result_sl.Free;
result_ms.free;
cookies.free;
response_headers.Free;
request_headers.free;
inherited Destroy;
end;
//==============================================================================
// sample: how to get download progress
//==============================================================================
function TIEHTTP.GetStringPercentage: widestring;
var
percent_done : widestring;
begin
if contentSize > 0 then
percent_done := format('%.0n%%', [ GetProgress*100 ] )
else
percent_done := '[]';
//example on how to read download status
result := format('Bytes Read: %.0n '#13'Total File Size: %.0n'#13'Status: %s done'
,[bytes_read_total*1.0,contentSize*1.0,percent_done] ) ;
end;
function TIEHTTP.GetProgress: single;
//percentage progress: 0.00 - 1.00
begin
if contentSize = 0 then begin
result := 0;
exit;
end;
result := (bytes_read_total/contentSize);
end;
function TIEHTTP.GetProgressPercentage: single;
//percentage progress: 0 - 100%
begin
result := GetProgress*100;
end;
procedure TIEHTTP.ProcessReadRequest;
//this is used from HTTPS -POST/GET
// HTTP -POST
// for HTTP/GET use geturl
var
dwFlags : DWord;
lpdwBufferLength: DWORD;
dwError : DWord;
var
context : DWORD;
var
dwBufLen : DWORD;
dwIndex : Cardinal;
//error_msg : string;
//wininet_receive_timeout : ULONG;
//lStructSize : cardinal;
ContentSize_custom : widestring;
begin
// Initialization, fall-through
hSession := nil;
hConnect := nil;
hFile := nil;
//size3_multipart := 0;
dwError := 0;
debug_total_packets := 0;
debug_total_packet_events := 0;
debug_total_timer_events := 0;
hSession := InternetOpenW(pwidechar(http_agent_string), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
try
if (hSession = nil) then begin
//raise exception.create('Could not open Internet');
error_msg := 'Could not open Internet';
exit;
end;
// Set options for the internet handle
//InternetSetOption(aHi, INTERNET_OPTION_CONNECT_TIMEOUT, @timeOutMS, sizeOf(timeOutMS));
//InternetSetOption(hI, INTERNET_OPTION_CONNECT_TIMEOUT,5*60*1000,0);
//session.SetOption(hI, INTERNET_OPTION_CONNECT_RETRIES,15,0);
//session.SetOption(hI, INTERNET_OPTION_DATA_SEND_TIMEOUT,5*60*1000,0);
//session.SetOption(hI, INTERNET_OPTION_RECEIVE_TIMEOUT,5*60*1000,0);
//in ie receive_timeout returns 30000 ms
//dwBufLen := sizeof(wininet_receive_timeout);
//InternetQueryOption(nil, INTERNET_OPTION_RECEIVE_TIMEOUT, @wininet_receive_timeout, dwBufLen);
//http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceinternet5/html/wce50lrfoptionflags.asp
//fix for ie7 beta2: get rid of "receive timeout" that is being set to 30 seconds
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -