338 lines
8.7 KiB
Plaintext
338 lines
8.7 KiB
Plaintext
{
|
|
$Project$
|
|
$Workfile$
|
|
$Revision$
|
|
$DateUTC$
|
|
$Id$
|
|
|
|
This file is part of the Indy (Internet Direct) project, and is offered
|
|
under the dual-licensing agreement described on the Indy website.
|
|
(http://www.indyproject.org/)
|
|
|
|
Copyright:
|
|
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
|
|
}
|
|
{
|
|
$Log$
|
|
}
|
|
{
|
|
Rev 1.5 2004.10.27 9:17:46 AM czhower
|
|
For TIdStrings
|
|
|
|
Rev 1.4 7/28/04 11:43:32 PM RLebeau
|
|
Bug fix for CleanupCookieList()
|
|
|
|
Rev 1.3 2004.02.03 5:45:02 PM czhower
|
|
Name changes
|
|
|
|
Rev 1.2 1/22/2004 7:10:02 AM JPMugaas
|
|
Tried to fix AnsiSameText depreciation.
|
|
|
|
Rev 1.1 2004.01.21 1:04:54 PM czhower
|
|
InitComponenet
|
|
|
|
Rev 1.0 11/14/2002 02:16:26 PM JPMugaas
|
|
|
|
2001-Mar-31 Doychin Bondzhev
|
|
- Added new method AddCookie2 that is called when we have Set-Cookie2 as response
|
|
- The common code in AddCookie and AddCookie2 is now in DoAdd
|
|
|
|
2001-Mar-24 Doychin Bondzhev
|
|
- Added OnNewCookie event
|
|
This event is called for every new cookie. Can be used to ask the user program
|
|
do we have to store this cookie in the cookie collection
|
|
- Added new method AddCookie
|
|
This calls the OnNewCookie event and if the result is true it adds the new cookie
|
|
in the collection
|
|
}
|
|
|
|
unit IdCookieManager;
|
|
|
|
{
|
|
Implementation of the HTTP State Management Mechanism as specified in RFC 6265.
|
|
|
|
Author: Remy Lebeau (remy@lebeausoftware.org)
|
|
Copyright: (c) Chad Z. Hower and The Indy Team.
|
|
}
|
|
|
|
interface
|
|
|
|
{$i IdCompilerDefines.inc}
|
|
|
|
uses
|
|
Classes,
|
|
IdBaseComponent,
|
|
IdCookie,
|
|
IdHeaderList,
|
|
IdURI;
|
|
|
|
Type
|
|
TOnNewCookieEvent = procedure(ASender: TObject; ACookie: TIdCookie; var VAccept: Boolean) of object;
|
|
|
|
TOnCookieManagerEvent = procedure(ASender: TObject; ACookieCollection: TIdCookies) of object;
|
|
TOnCookieCreateEvent = TOnCookieManagerEvent;
|
|
TOnCookieDestroyEvent = TOnCookieManagerEvent;
|
|
|
|
TIdCookieManager = class(TIdBaseComponent)
|
|
protected
|
|
FOnCreate: TOnCookieCreateEvent;
|
|
FOnDestroy: TOnCookieDestroyEvent;
|
|
FOnNewCookie: TOnNewCookieEvent;
|
|
FCookieCollection: TIdCookies;
|
|
|
|
procedure CleanupCookieList;
|
|
procedure DoOnCreate; virtual;
|
|
procedure DoOnDestroy; virtual;
|
|
function DoOnNewCookie(ACookie: TIdCookie): Boolean; virtual;
|
|
procedure InitComponent; override;
|
|
public
|
|
destructor Destroy; override;
|
|
//
|
|
procedure AddServerCookie(const ACookie: String; AURL: TIdURI);
|
|
procedure AddServerCookies(const ACookies: TStrings; AURL: TIdURI);
|
|
|
|
procedure AddCookies(ASource: TIdCookieManager);
|
|
procedure CopyCookie(ACookie: TIdCookie);
|
|
//
|
|
procedure GenerateClientCookies(AURL: TIdURI; SecureOnly: Boolean;
|
|
Headers: TIdHeaderList);
|
|
//
|
|
property CookieCollection: TIdCookies read FCookieCollection;
|
|
published
|
|
property OnCreate: TOnCookieCreateEvent read FOnCreate write FOnCreate;
|
|
property OnDestroy: TOnCookieDestroyEvent read FOnDestroy write FOnDestroy;
|
|
property OnNewCookie: TOnNewCookieEvent read FOnNewCookie write FOnNewCookie;
|
|
end;
|
|
|
|
//procedure SplitCookies(const ACookie: String; ACookies: TStrings);
|
|
|
|
implementation
|
|
|
|
uses
|
|
{$IFDEF HAS_UNIT_Generics_Defaults}
|
|
System.Generics.Defaults,
|
|
{$ENDIF}
|
|
IdAssignedNumbers, IdException, IdGlobal, IdGlobalProtocols, SysUtils;
|
|
|
|
{ TIdCookieManager }
|
|
|
|
destructor TIdCookieManager.Destroy;
|
|
begin
|
|
CleanupCookieList;
|
|
DoOnDestroy;
|
|
FreeAndNil(FCookieCollection);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function SortCookiesFunc({$IFDEF HAS_GENERICS_TList}const {$ENDIF}Item1, Item2: TIdCookie): Integer;
|
|
begin
|
|
// using the algorithm defined in RFC 6265 section 5.4
|
|
|
|
if Item1 = Item2 then
|
|
begin
|
|
Result := 0;
|
|
end
|
|
else if Length(Item2.Path) > Length(Item1.Path) then
|
|
begin
|
|
Result := 1;
|
|
end
|
|
else if Length(Item1.Path) = Length(Item2.Path) then
|
|
begin
|
|
if Item2.CreatedAt < Item1.CreatedAt then begin
|
|
Result := 1;
|
|
end else begin
|
|
Result := -1;
|
|
end;
|
|
end else
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
end;
|
|
|
|
procedure TIdCookieManager.GenerateClientCookies(AURL: TIdURI; SecureOnly: Boolean;
|
|
Headers: TIdHeaderList);
|
|
var
|
|
I: Integer;
|
|
LCookieList: TIdCookieList;
|
|
LResultList: TIdCookieList;
|
|
LCookie: TIdCookie;
|
|
LCookiesToSend: String;
|
|
LNow: TDateTime;
|
|
begin
|
|
// check for expired cookies first...
|
|
CleanupCookieList;
|
|
|
|
LCookieList := CookieCollection.LockCookieList(caRead);
|
|
try
|
|
if LCookieList.Count > 0 then begin
|
|
LResultList := TIdCookieList.Create;
|
|
try
|
|
// Search for cookies for this domain and URI
|
|
for I := 0 to LCookieList.Count-1 do begin
|
|
LCookie := LCookieList[I];
|
|
if LCookie.IsAllowed(AURL, SecureOnly) then begin
|
|
LResultList.Add(LCookie);
|
|
end;
|
|
end;
|
|
|
|
if LResultList.Count > 0 then begin
|
|
if LResultList.Count > 1 then begin
|
|
LResultList.Sort(
|
|
{$IFDEF HAS_GENERICS_TList}
|
|
TComparer<TIdCookie>.Construct(SortCookiesFunc)
|
|
{$ELSE}
|
|
TListSortCompare(@SortCookiesFunc)
|
|
{$ENDIF}
|
|
);
|
|
end;
|
|
|
|
LNow := Now;
|
|
for I := 0 to LResultList.Count-1 do begin
|
|
LResultList[I].LastAccessed := LNow;
|
|
end;
|
|
|
|
LCookiesToSend := LResultList[0].ClientCookie;
|
|
for I := 1 to LResultList.Count-1 do begin
|
|
LCookiesToSend := LCookiesToSend + '; ' + LResultList[I].ClientCookie; {Do not Localize}
|
|
end;
|
|
|
|
Headers.AddValue('Cookie', LCookiesToSend); {Do not Localize}
|
|
end;
|
|
finally
|
|
LResultList.Free;
|
|
end;
|
|
end;
|
|
finally
|
|
CookieCollection.UnlockCookieList(caRead);
|
|
end;
|
|
end;
|
|
|
|
procedure TIdCookieManager.AddServerCookie(const ACookie: String; AURL: TIdURI);
|
|
var
|
|
LCookie: TIdCookie;
|
|
begin
|
|
// TODO: use TIdCookies.AddServerCookie() after adding
|
|
// a way for it to query the manager for rejections...
|
|
//
|
|
//FCookieCollection.AddServerCookie(ACookie, AURI);
|
|
|
|
LCookie := FCookieCollection.Add;
|
|
try
|
|
if LCookie.ParseServerCookie(ACookie, AURL) then
|
|
begin
|
|
if DoOnNewCookie(LCookie) then
|
|
begin
|
|
if FCookieCollection.AddCookie(LCookie, AURL) then begin
|
|
LCookie := nil;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
if LCookie <> nil then
|
|
begin
|
|
LCookie.Collection := nil;
|
|
LCookie.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TIdCookieManager.AddCookies(ASource: TIdCookieManager);
|
|
begin
|
|
if (ASource <> nil) and (ASource <> Self) then begin
|
|
FCookieCollection.AddCookies(ASource.CookieCollection);
|
|
end;
|
|
end;
|
|
|
|
procedure TIdCookieManager.AddServerCookies(const ACookies: TStrings; AURL: TIdURI);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to ACookies.Count-1 do begin
|
|
AddServerCookie(ACookies[I], AURL);
|
|
end;
|
|
end;
|
|
|
|
procedure TIdCookieManager.CopyCookie(ACookie: TIdCookie);
|
|
var
|
|
LCookie: TIdCookie;
|
|
begin
|
|
LCookie := TIdCookieClass(ACookie.ClassType).Create(FCookieCollection);
|
|
try
|
|
LCookie.Assign(ACookie);
|
|
if LCookie.Domain <> '' then
|
|
begin
|
|
if DoOnNewCookie(LCookie) then
|
|
begin
|
|
if FCookieCollection.AddCookie(LCookie, nil) then begin
|
|
LCookie := nil;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
if LCookie <> nil then
|
|
begin
|
|
LCookie.Collection := nil;
|
|
LCookie.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TIdCookieManager.DoOnNewCookie(ACookie: TIdCookie): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnNewCookie) then begin
|
|
OnNewCookie(Self, ACookie, Result);
|
|
end;
|
|
end;
|
|
|
|
procedure TIdCookieManager.DoOnCreate;
|
|
begin
|
|
if Assigned(FOnCreate) then begin
|
|
OnCreate(Self, FCookieCollection);
|
|
end;
|
|
end;
|
|
|
|
procedure TIdCookieManager.DoOnDestroy;
|
|
begin
|
|
if Assigned(FOnDestroy) then
|
|
begin
|
|
OnDestroy(Self, FCookieCollection);
|
|
end;
|
|
end;
|
|
|
|
procedure TIdCookieManager.CleanupCookieList;
|
|
var
|
|
i: Integer;
|
|
LCookieList: TIdCookieList;
|
|
LCookie: TIdCookie;
|
|
begin
|
|
LCookieList := FCookieCollection.LockCookieList(caReadWrite);
|
|
try
|
|
for i := LCookieList.Count-1 downto 0 do
|
|
begin
|
|
LCookie := LCookieList[i];
|
|
if LCookie.IsExpired then
|
|
begin
|
|
// The Cookie has expired. It has to be removed from the collection
|
|
LCookieList.Delete(i);
|
|
// must set the Collection to nil or the cookie will try to remove
|
|
// itself from the cookie collection and deadlock
|
|
LCookie.Collection := nil;
|
|
LCookie.Free;
|
|
end;
|
|
end;
|
|
finally
|
|
FCookieCollection.UnlockCookieList(caReadWrite);
|
|
end;
|
|
end;
|
|
|
|
procedure TIdCookieManager.InitComponent;
|
|
begin
|
|
inherited InitComponent;
|
|
FCookieCollection := TIdCookies.Create(Self);
|
|
DoOnCreate;
|
|
end;
|
|
|
|
end.
|