📄 idhttp.pas
字号:
unit IdHTTP;
{
Implementation of the HTTP protcol as specified in RFC 2616, 2109, 2965.
(See NOTE below for details of what is exactly implemented)
Author: Hadi Hariri (hadi@urusoft.com)
Copyright: (c) Chad Z. Hower and The Winshoes Working Group.
NOTE:
Initially only GET and POST will be supported. As time goes on more will
be added. For other developers, please add the date and what you have done
below.
Initials: Hadi Hariri - HH
Details of implementation
-------------------------
2001-Nov Nick Panteleeff
- Authentication and POST parameter extentsions
2001-Sept Doychin Bondzhev
- New internal design and new Authentication procedures.
- Bug fixes and new features in few other supporting components
2001-Jul-7 Doychin Bondzhev
- new property AllowCookie
- There is no more ExtraHeders property in Request/Response. Raw headers is used for that purpose.
2001-Jul-1 Doychin Bondzhev
- SSL support is up again - Thanks to Gregor
2001-Jun-17 Doychin Bondzhev
- New unit IdHTTPHeaderInfo.pas that contains the
TIdHeaderInfo(TIdEntytiHeaderInfo, TIdRequestHeaderInfo and TIdResponseHeaderInfo)
- Still in development and not verry well tested
By default when there is no authorization object associated with HTTP compoenet and there is user name and password
HTTP component creates and instance of TIdBasicAuthentication class. This behaivor is for both web server and proxy server
authorizations
2001-Apr-17 Doychin Bondzhev
- Added OnProxyAuthorization event. This event is called on 407 response from the HTTP Proxy.
- Added 2 new properties in TIdHeaderInfo
property AuthenticationScheme: TIdAuthenticationScheme - this property contains information for authentication scheme
requested by the web server
property ProxyAuthenticationScheme: TIdAuthenticationScheme - this property contains information for authentication scheme
requested by the proxy server
- Now the component authomaticly reconginizes the requested authorization scheme and it supports Basic like before and has been
extend to support Digest authorization
2001-Mar-31 Doychin Bondzhev
- If there is no CookieManager it does not support cookies.
2001-Feb-18 Doychin Bondzhev
- Added OnAuthorization event. This event is called on 401 response from the HTTP server.
This can be used to ask the user program to supply user name and password in order to acces
the requested resource
2001-Feb-02 Doychin Bondzhev
- Added Cookie support and relative paths on redirect
2000-Jul-25 Hadi Hariri
- Overloaded POst and moved clearing to disconect.
2000-June-22 Hadi Hariri
- Added Proxy support.
2000-June-10 Hadi Hariri
- Added Chunk-Encoding support and HTTP version number. Some additional
improvements.
2000-May-23 J. Peter Mugaas
-added redirect capability and supporting properties. Redirect is optional
and is set with HandleRedirects. Redirection is limited to RedirectMaximum
to prevent stack overflow due to recursion and to prevent redirects between
two places which would cause this to go on to infinity.
2000-May-22 J. Peter Mugaas
-adjusted code for servers which returned LF instead of EOL
-Headers are now retreived before an exception is raised. This
also facilitates server redirection where the server tells the client to
get a document from another location.
2000-May-01 Hadi Hariri
-Converted to Mercury
2000-May-01 Hadi Hariri
-Added PostFromStream and some clean up
2000-Apr-10 Hadi Hariri
-Re-done quite a few things and fixed GET bugs and finished POST method.
2000-Jan-13 MTL
-Moved to the New Palette Scheme
2000-Jan-08 MTL
-Cleaned up a few compiler hints during 7.038 build
1999-Dec-10 Hadi Hariri
-Started.
}
interface
uses
Classes,
IdException, IdAssignedNumbers, IdHeaderList, IdHTTPHeaderInfo, IdSSLOpenSSL,
IdTCPClient, IdURI, IdCookie, IdCookieManager, IdAuthentication , IdAuthenticationManager,
IdMultipartFormData;
type
// TO DOCUMENTATION TEAM
// ------------------------
// For internal use. No need of documentation
// hmConnect - Used to connect trought CERN proxy to SSL enabled sites.
TIdHTTPMethod = (hmHead, hmGet, hmPost, hmOptions, hmTrace, hmPut, hmDelete, hmConnect);
TIdHTTPWhatsNext = (wnGoToURL, wnJustExit, wnDontKnow, wnReadAndGo, wnAuthRequest);
TIdHTTPConnectionType = (ctNormal, ctSSL, ctProxy, ctSSLProxy);
// Protocol options
TIdHTTPOption = (hoInProcessAuth, hoKeepOrigProtocol, hoForceEncodeParams);
TIdHTTPOptions = set of TIdHTTPOption;
// Must be documented
TIdHTTPProtocolVersion = (pv1_0, pv1_1);
TIdHTTPOnRedirectEvent = procedure(Sender: TObject; var dest: string; var NumRedirect: Integer; var Handled: boolean; var VMethod: TIdHTTPMethod) of object;
TIdOnSelectAuthorization = procedure(Sender: TObject; var AuthenticationClass: TIdAuthenticationClass; AuthInfo: TIdHeaderList) of object;
TIdOnAuthorization = procedure(Sender: TObject; Authentication: TIdAuthentication; var Handled: boolean) of object;
// TIdProxyOnAuthorization = procedure(Sender: TObject; Authentication: TIdAuthentication; var Handled: boolean) of object;
const
Id_TIdHTTP_ProtocolVersion = pv1_1;
Id_TIdHTTP_RedirectMax = 15;
Id_TIdHTTP_HandleRedirects = False;
type
TIdCustomHTTP = class;
// TO DOCUMENTATION TEAM
// ------------------------
// The following classes are used internally and no need of documentation
// Only TIdHTTP must be documented
//
TIdHTTPResponse = class(TIdResponseHeaderInfo)
protected
FHTTP: TIdCustomHTTP;
FResponseCode: Integer;
FResponseText: string;
FKeepAlive: Boolean;
FContentStream: TStream;
FResponseVersion: TIdHTTPProtocolVersion;
//
function GetKeepAlive: Boolean;
function GetResponseCode: Integer;
public
constructor Create(AParent: TIdCustomHTTP); reintroduce; virtual;
property KeepAlive: Boolean read GetKeepAlive write FKeepAlive;
property ResponseText: string read FResponseText write FResponseText;
property ResponseCode: Integer read GetResponseCode write FResponseCode;
property ResponseVersion: TIdHTTPProtocolVersion read FResponseVersion write FResponseVersion;
property ContentStream: TStream read FContentStream write FContentStream;
end;
TIdHTTPRequest = class(TIdRequestHeaderInfo)
protected
FHTTP: TIdCustomHTTP;
FURL: string;
FMethod: TIdHTTPMethod;
FSourceStream: TStream;
FUseProxy: TIdHTTPConnectionType;
public
constructor Create(AHTTP: TIdCustomHTTP); reintroduce; virtual;
property URL: string read FURL write FURL;
property Method: TIdHTTPMethod read FMethod write FMethod;
property Source: TStream read FSourceStream write FSourceStream;
property UseProxy: TIdHTTPConnectionType read FUseProxy;
end;
TIdHTTPProtocol = class(TObject)
FHTTP: TIdCustomHTTP;
FRequest: TIdHTTPRequest;
FResponse: TIdHTTPResponse;
public
constructor Create(AConnection: TIdCustomHTTP);
destructor Destroy; override;
function ProcessResponse: TIdHTTPWhatsNext;
procedure BuildAndSendRequest(AURI: TIdURI);
procedure RetrieveHeaders;
property Request: TIdHTTPRequest read FRequest;
property Response: TIdHTTPResponse read FResponse;
end;
TIdCustomHTTP = class(TIdTCPClient)
protected
FCookieManager: TIdCookieManager;
FFreeOnDestroy: Boolean;
{Retries counter for WWW authorization}
FAuthRetries: Integer;
{Retries counter for proxy authorization}
FAuthProxyRetries: Integer;
{Max retries for authorization}
FMaxAuthRetries: Integer;
FAllowCookies: Boolean;
FAuthenticationManager: TIdAuthenticationManager;
FProtocolVersion: TIdHTTPProtocolVersion;
{this is an internal counter for redirercts}
FRedirectCount: Integer;
FRedirectMax: Integer;
FHandleRedirects: Boolean;
FOptions: TIdHTTPOptions;
FURI: TIdURI;
FHTTPProto: TIdHTTPProtocol;
FProxyParameters: TIdProxyConnectionInfo;
//
FOnRedirect: TIdHTTPOnRedirectEvent;
FOnSelectAuthorization: TIdOnSelectAuthorization;
FOnSelectProxyAuthorization: TIdOnSelectAuthorization;
FOnAuthorization: TIdOnAuthorization;
FOnProxyAuthorization: TIdOnAuthorization;
//
procedure SetHost(const Value: string); override;
procedure SetPort(const Value: integer); override;
procedure SetAuthenticationManager(const Value: TIdAuthenticationManager);
procedure SetCookieManager(ACookieManager: TIdCookieManager);
procedure SetAllowCookies(AValue: Boolean);
function GetResponseCode: Integer;
function GetResponseText: string;
function DoOnAuthorization(ARequest: TIdHTTPRequest; AResponse: TIdHTTPResponse): Boolean; virtual;
function DoOnProxyAuthorization(ARequest: TIdHTTPRequest; AResponse: TIdHTTPResponse): Boolean; virtual;
function DoOnRedirect(var Location: string; var VMethod: TIdHTTPMethod; RedirectCount: integer): boolean; virtual;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure ProcessCookies(ARequest: TIdHTTPRequest; AResponse: TIdHTTPResponse);
function SetHostAndPort: TIdHTTPConnectionType;
procedure SetCookies(AURL: TIdURI; ARequest: TIdHTTPRequest);
procedure ReadResult(AResponse: TIdHTTPResponse);
procedure PrepareRequest(ARequest: TIdHTTPRequest);
procedure ConnectToHost(ARequest: TIdHTTPRequest; AResponse: TIdHTTPResponse);
function GetResponseHeaders: TIdHTTPResponse;
function GetRequestHeaders: TIdHTTPRequest;
procedure SetRequestHeaders(const Value: TIdHTTPRequest);
procedure EncodeRequestParams(const AStrings: TStrings);
function SetRequestParams(const AStrings: TStrings): string;
procedure CheckAndConnect(AResponse: TIdHTTPResponse);
procedure DoOnDisconnected; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DoRequest(const AMethod: TIdHTTPMethod; AURL: string;
const ASource, AResponseContent: TStream); virtual;
procedure Options(AURL: string); overload;
procedure Get(AURL: string; const AResponseContent: TStream); overload;
function Get(AURL: string): string; overload;
procedure Trace(AURL: string; const AResponseContent: TStream); overload;
function Trace(AURL: string): string; overload;
procedure Head(AURL: string);
function Post(AURL: string; const ASource: TStrings): string; overload;
function Post(AURL: string; const ASource: TStream): string; overload;
function Post(AURL: string; const ASource: TIdMultiPartFormDataStream): string; overload;
procedure Post(AURL: string; const ASource: TStrings; const AResponseContent: TStream);
overload;
{Post data provided by a stream, this is for submitting data to a server}
procedure Post(AURL: string; const ASource, AResponseContent: TStream);
overload;
procedure Post(AURL: string; const ASource: TIdMultiPartFormDataStream; AResponseContent: TStream);
overload;
//
function Put(AURL: string; const ASource: TStream): string; overload;
procedure Put(AURL: string; const ASource, AResponseContent: TStream);
overload;
{This is the response code number such as 404 for File not Found}
property ResponseCode: Integer read GetResponseCode;
{This is the text of the message such as "404 File Not Found here Sorry"}
property ResponseText: string read GetResponseText;
property Response: TIdHTTPResponse read GetResponseHeaders;
{ This is the last processed URL }
property URL: TIdURI read FURI;
// Num retries for Authentication
property AuthRetries: Integer read FMaxAuthRetries write FMaxAuthRetries default 3;
property AllowCookies: Boolean read FAllowCookies write SetAllowCookies;
{Do we handle redirect requests or simply raise an exception and let the
developer deal with it}
property HandleRedirects: Boolean read FHandleRedirects write FHandleRedirects default Id_TIdHTTP_HandleRedirects;
property ProtocolVersion: TIdHTTPProtocolVersion read FProtocolVersion write FProtocolVersion default Id_TIdHTTP_ProtocolVersion;
{This is the maximum number of redirects we wish to handle, we limit this
to prevent stack overflow due to recursion. Recursion is safe ONLY if
prevented for continuing to infinity}
property RedirectMaximum: Integer read FRedirectMax write FRedirectMax default Id_TIdHTTP_RedirectMax;
property ProxyParams: TIdProxyConnectionInfo read FProxyParameters write FProxyParameters;
property Request: TIdHTTPRequest read GetRequestHeaders write SetRequestHeaders;
property HTTPOptions: TIdHTTPOptions read FOptions write FOptions;
// Fired when a rediretion is requested.
property OnRedirect: TIdHTTPOnRedirectEvent read FOnRedirect write FOnRedirect;
property OnSelectAuthorization: TIdOnSelectAuthorization read FOnSelectAuthorization write FOnSelectAuthorization;
property OnSelectProxyAuthorization: TIdOnSelectAuthorization read FOnSelectProxyAuthorization write FOnSelectProxyAuthorization;
property OnAuthorization: TIdOnAuthorization read FOnAuthorization write FOnAuthorization;
property OnProxyAuthorization: TIdOnAuthorization read FOnProxyAuthorization write FOnProxyAuthorization;
// Cookie stuff
property CookieManager: TIdCookieManager read FCookieManager write SetCookieManager;
//
property AuthenticationManager: TIdAuthenticationManager read FAuthenticationManager write SetAuthenticationManager;
end;
TIdHTTP = class(TIdCustomHTTP)
published
// Num retries for Authentication
property AuthRetries;
property AllowCookies;
{Do we handle redirect requests or simply raise an exception and let the
developer deal with it}
property HandleRedirects;
property ProtocolVersion;
{This is the maximum number of redirects we wish to handle, we limit this
to prevent stack overflow due to recursion. Recursion is safe ONLY if
prevented for continuing to infinity}
property RedirectMaximum;
property ProxyParams;
property Request;
property HTTPOptions;
// Fired when a rediretion is requested.
property OnRedirect;
property OnSelectAuthorization;
property OnSelectProxyAuthorization;
property OnAuthorization;
property OnProxyAuthorization;
property Host;
property Port default IdPORT_HTTP;
// Cookie stuff
property CookieManager;
//
// property AuthenticationManager: TIdAuthenticationManager read FAuthenticationManager write SetAuthenticationManager;
end;
EIdUnknownProtocol = class(EIdException);
EIdHTTPProtocolException = class(EIdProtocolReplyError)
protected
FErrorMessage: string;
public
constructor CreateError(const anErrCode: Integer; const asReplyMessage: string;
const asErrorMessage: string); reintroduce; virtual;
property ErrorMessage: string read FErrorMessage;
end;
implementation
uses
SysUtils,
IdGlobal, IdComponent, IdCoderMIME, IdTCPConnection, IdResourceStrings;
const
ProtocolVersionString: array[TIdHTTPProtocolVersion] of string = ('1.0', '1.1');
{ EIdHTTPProtocolException }
constructor EIdHTTPProtocolException.CreateError(const anErrCode: Integer;
const asReplyMessage: string; const asErrorMessage: string);
begin
inherited CreateError(anErrCode, asReplyMessage);
FErrorMessage := asErrorMessage;
end;
{ TIdHTTP }
constructor TIdCustomHTTP.Create(AOwner: TComponent);
begin
FURI := TIdURI.Create('');
inherited Create(AOwner);
Port := IdPORT_HTTP;
FAuthRetries := 0;
FAuthProxyRetries := 0;
FMaxAuthRetries := 3;
AllowCookies := true;
FFreeOnDestroy := false;
FOptions := [hoForceEncodeParams];
FRedirectMax := Id_TIdHTTP_RedirectMax;
FHandleRedirects := Id_TIdHTTP_HandleRedirects;
//
FProtocolVersion := Id_TIdHTTP_ProtocolVersion;
FHTTPProto := TIdHTTPProtocol.Create(self);
FProxyParameters := TIdProxyConnectionInfo.Create;
FProxyParameters.Clear;
end;
destructor TIdCustomHTTP.Destroy;
begin
FreeAndNil(FHTTPProto);
FreeAndNil(FURI);
FreeAndNil(FProxyParameters);
{if FFreeOnDestroy then
begin
FreeAndNil(FCookieManager);
end;}
inherited Destroy;
end;
procedure TIdCustomHTTP.Options(AURL: string);
begin
DoRequest(hmOptions, AURL, nil, nil);
end;
procedure TIdCustomHTTP.Get(AURL: string; const AResponseContent: TStream);
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -