在FlashGet中没问题,而NetAnts却不行?Why(150分)

  • 主题发起人 主题发起人 freeforever
  • 开始时间 开始时间
F

freeforever

Unregistered / Unconfirmed
GUEST, unregistred user!
我在使用ics控件中Thttpcli的demo程序时发现它不能下载Chinaren校友录的班级
相册中的图片,后改用NetAnts尝试下载,未遂,仅收到err_403.html文件,转而用FlashGet
却无此问题,成功得到图片.问题在何处?解决方法如何?请讲清原理及主要依据?
相关信息如下:
NetAnts:
2001/08/16 01:43:50 Resolve host address ...
2001/08/16 01:43:50 Host address resolved
2001/08/16 01:43:50 Connect to host (album.chinaren.com:80) ...
2001/08/16 01:43:50 Connect to host successfully
2001/08/16 01:43:50 GET /album/77/22505.jpg HTTP/1.1
2001/08/16 01:43:50 Host: album.chinaren.com
2001/08/16 01:43:50 Accept: */*
2001/08/16 01:43:50 User-Agent: NetAnts/1.23
2001/08/16 01:43:50 Pragma: no-cache
2001/08/16 01:43:50 Cache-Control: no-cache
2001/08/16 01:43:50 Connection: close
2001/08/16 01:43:50 Cookie: CHINARENUSER=************; OWP=Y //****为已做修改
2001/08/16 01:43:50 HTTP/1.1 302 Found
2001/08/16 01:43:50 Date: Tue, 14 Aug 2001 17:22:37 GMT
2001/08/16 01:43:50 Server: Apache/1.3.12 (Unix) PHP/4.0.4pl1
2001/08/16 01:43:50 Location: http://errmsg.chinaren.com/err_403.html
2001/08/16 01:43:50 Connection: close
2001/08/16 01:43:50 Transfer-Encoding: chunked
2001/08/16 01:43:50 Content-Type: text/html; charset=iso-8859-1
2001/08/16 01:43:50 Redirect link to other site
2001/08/16 01:43:50 Resolve host address ...
2001/08/16 01:43:50 Host address resolved
2001/08/16 01:43:50 Connect to host (errmsg.chinaren.com:80) ...
2001/08/16 01:43:50 Connect to host successfully
2001/08/16 01:43:50 GET /err_403.html HTTP/1.1
2001/08/16 01:43:50 Host: errmsg.chinaren.com
2001/08/16 01:43:50 Accept: */*
2001/08/16 01:43:50 User-Agent: NetAnts/1.23
2001/08/16 01:43:50 Pragma: no-cache
2001/08/16 01:43:50 Cache-Control: no-cache
2001/08/16 01:43:50 Connection: close
2001/08/16 01:43:50 Cookie: CHINARENUSER=************; OWP=Y //****为已做修改
2001/08/16 01:43:51 HTTP/1.1 200 OK
2001/08/16 01:43:51 Date: Tue, 14 Aug 2001 17:22:52 GMT
2001/08/16 01:43:51 Server: Apache/1.3.9 (Unix) PHP/4.0RC1
2001/08/16 01:43:51 Vary: Host
2001/08/16 01:43:51 Last-Modified: Sun, 30 Jan 2000 09:23:42 GMT
2001/08/16 01:43:51 ETag: "39479-1ce2-3894031e"
2001/08/16 01:43:51 Accept-Ranges: bytes
2001/08/16 01:43:51 Content-Length: 7394
2001/08/16 01:43:51 Connection: close
2001/08/16 01:43:51 Content-Type: text/html
2001/08/16 01:43:51 Receiving data...
2001/08/16 01:43:51 No block left, ant finish
FlashGets:
Thu Aug 16 01:47:34 2001 正在连接 album.chinaren.com:80
Thu Aug 16 01:47:34 2001 正在连接 album.chinaren.com [IP=211.155.249.170:80]
Thu Aug 16 01:47:34 2001 已连接.
Thu Aug 16 01:47:34 2001 GET /album/77/22505.jpg HTTP/1.1
Thu Aug 16 01:47:34 2001 HOST: album.chinaren.com
Thu Aug 16 01:47:34 2001 ACCEPT: */*
Thu Aug 16 01:47:34 2001 Referer: http://album.chinaren.com/album/77
Thu Aug 16 01:47:34 2001 Cookie: CHINARENUSER=************; OWP=Y //****为已做修改
Thu Aug 16 01:47:34 2001 User-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)
Thu Aug 16 01:47:34 2001 Pragma: no-cache
Thu Aug 16 01:47:34 2001 Cache-Control: no-cache
Thu Aug 16 01:47:34 2001 Connection: close
Thu Aug 16 01:47:35 2001 HTTP/1.1 200 OK
Thu Aug 16 01:47:35 2001 Date: Tue, 14 Aug 2001 17:26:22 GMT
Thu Aug 16 01:47:35 2001 Server: Apache/1.3.12 (Unix) PHP/4.0.4pl1
Thu Aug 16 01:47:35 2001 Cache-Control: max-age=31536000
Thu Aug 16 01:47:35 2001 Expires: Wed, 14 Aug 2002 17:26:22 GMT
Thu Aug 16 01:47:35 2001 Last-Modified: Sun, 22 Jul 2001 08:42:59 GMT
Thu Aug 16 01:47:35 2001 ETag: "13b91e4-916b-3b5a9213"
Thu Aug 16 01:47:35 2001 Accept-Ranges: bytes
Thu Aug 16 01:47:35 2001 Content-Length: 37227
Thu Aug 16 01:47:35 2001 Connection: close
Thu Aug 16 01:47:35 2001 Content-Type: image/jpeg
Thu Aug 16 01:47:35 2001 开始接受数据!
Thu Aug 16 01:47:39 2001 关闭
//各位测试时,请使用这个连接即可:
http://album.chinaren.com/album/77/22505.jpg
 
仔细看一下上面的内容,并使用IE 试图打开
http://album.chinaren.com/album/77/22505.jpg
结果是该地址禁止访问,这里可以知道使用了Cookie 缓冲,
但是NETANS并不支持Cookie ,而FlashGets是支持的,在它
的设置里明确有是否允许使用Cookie 的选项。
 
另外你试一试把 NetAnts 的协议 设置成
User-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)
看看,因为我没有办法实验,要不就是NetAnts 不支持,:)。
 
但是,NetAnts中的信息表明其已经使用了cookie.(即在“参数设置”-"高级"-
"使用浏览器的cookie"),相关信息也可在问题中的NetAnts内容中得到。
此外,我将"用户代理"设为“Mozilla/4.0 (compatible; MSIE 5.0; Windows 98)”后,
重试,未遂.
另外,这里提一句,在ics的自带demo中已经为"Mozilla/3.0 (compatible)"
了。
希望更好的解释,谢谢.
 
netants应该是将http://album.chinaren.com/album/77/22505.jpg重定向到err_403.html

“使用浏览器的cookie”是如何实现,我的意思是如何用程序实现?
 
是不是所用的协议不同呀!
 
>>netmoles
{*******************************************************}
{ }
{ Borland Delphi Run-time Library }
{ Win32 Internet API Interface Unit }
{ }
{ Copyright (c) 1985-1999, Microsoft Corporation }
{ }
{ Translator: Inprise Corporation }
{ }
{*******************************************************}
{ Cookie APIs }

function InternetSetCookieA(lpszUrl, lpszCookieName,
lpszCookieData: PAnsiChar): BOOL; stdcall;
{$EXTERNALSYM InternetSetCookieA}
function InternetSetCookieW(lpszUrl, lpszCookieName,
lpszCookieData: PWideChar): BOOL; stdcall;
{$EXTERNALSYM InternetSetCookieW}
function InternetSetCookie(lpszUrl, lpszCookieName,
lpszCookieData: PChar): BOOL; stdcall;
{$EXTERNALSYM InternetSetCookie}

function InternetGetCookieA(lpszUrl, lpszCookieName,
lpszCookieData: PAnsiChar; var lpdwSize: DWORD): BOOL; stdcall;
{$EXTERNALSYM InternetGetCookieA}
function InternetGetCookieW(lpszUrl, lpszCookieName,
lpszCookieData: PWideChar; var lpdwSize: DWORD): BOOL; stdcall;
{$EXTERNALSYM InternetGetCookieW}
function InternetGetCookie(lpszUrl, lpszCookieName,
lpszCookieData: PChar; var lpdwSize: DWORD): BOOL; stdcall;
{$EXTERNALSYM InternetGetCookie}

{*******************************************************}
{ }
{ Borland Delphi Visual Component Library }
{ Web server application components }
{ }
{ Copyright (c) 1997,99 Inprise Corporation }
{ }
{*******************************************************}

unit HTTPApp;

interface

uses SyncObjs, SysUtils, Classes, Forms, Masks, Contnrs;

const
sDateFormat = '"%s", dd "%s" yyyy hh:mm:ss';

MAX_STRINGS = 12;
MAX_INTEGERS = 1;
MAX_DATETIMES = 3;

type
TMethodType = (mtAny, mtGet, mtPut, mtPost, mtHead);

{ Forward declaration }

TWebResponse = class;

{ TWebRequest }

TWebRequest = class(TObject)
private
FMethodType: TMethodType;
FContentFields,
FCookieFields,
FQueryFields: TStrings;
function GetContentFields: TStrings;
function GetCookieFields: TStrings;
function GetQueryFields: TStrings;
protected
function GetStringVariable(Index: Integer): string; virtual; abstract;
function GetDateVariable(Index: Integer): TDateTime; virtual; abstract;
function GetIntegerVariable(Index: Integer): Integer; virtual; abstract;
public
constructor Create;
destructor Destroy; override;
// Read count bytes from client
function ReadClient(var Buffer; Count: Integer): Integer; virtual; abstract;
// Read count characters as a string from client
function ReadString(Count: Integer): string; virtual; abstract;
// Translate a relative URI to a local absolute path
function TranslateURI(const URI: string): string; virtual; abstract;
// Write count bytes back to client
function WriteClient(var Buffer; Count: Integer): Integer; virtual; abstract;
// Write string contents back to client
function WriteString(const AString: string): Boolean; virtual; abstract;
// Utility to extract fields from a given string buffer
procedure ExtractFields(Separators, WhiteSpace: TSysCharSet;
Content: PChar; Strings: TStrings);
// Fills the given string list with the content fields as the result
// of a POST method
procedure ExtractContentFields(Strings: TStrings);
// Fills the given string list with values from the cookie header field
procedure ExtractCookieFields(Strings: TStrings);
// Fills the given TStrings with the values from the Query data
// (ie: data following the "?" in the URL)
procedure ExtractQueryFields(Strings: TStrings);
// Read an arbitrary HTTP/Server Field not lists here
function GetFieldByName(const Name: string): string; virtual; abstract;
// The request method as an enumeration
property MethodType: TMethodType read FMethodType;
// Field lists
property ContentFields: TStrings read GetContentFields;
property CookieFields: TStrings read GetCookieFields;
property QueryFields: TStrings read GetQueryFields;
// HTTP header Fields
property Method: string index 0 read GetStringVariable;
property ProtocolVersion: string index 1 read GetStringVariable;
property URL: string index 2 read GetStringVariable;
property Query: string index 3 read GetStringVariable;
property PathInfo: string index 4 read GetStringVariable;
property PathTranslated: string index 5 read GetStringVariable;
property Authorization: string index 28 read GetStringVariable;
property CacheControl: string index 6 read GetStringVariable;
property Cookie: string index 27 read GetStringVariable;
property Date: TDateTime index 7 read GetDateVariable;
property Accept: string index 8 read GetStringVariable;
property From: string index 9 read GetStringVariable;
property Host: string index 10 read GetStringVariable;
property IfModifiedSince: TDateTime index 11 read GetDateVariable;
property Referer: string index 12 read GetStringVariable;
property UserAgent: string index 13 read GetStringVariable;
property ContentEncoding: string index 14 read GetStringVariable;
property ContentType: string index 15 read GetStringVariable;
property ContentLength: Integer index 16 read GetIntegerVariable;
property ContentVersion: string index 17 read GetStringVariable;
property Content: string index 25 read GetStringVariable;
property Connection: string index 26 read GetStringVariable;
property DerivedFrom: string index 18 read GetStringVariable;
property Expires: TDateTime index 19 read GetDateVariable;
property Title: string index 20 read GetStringVariable;
property RemoteAddr: string index 21 read GetStringVariable;
property RemoteHost: string index 22 read GetStringVariable;
property ScriptName: string index 23 read GetStringVariable;
property ServerPort: Integer index 24 read GetIntegerVariable;
end;

{ TCookie }

TCookie = class(TCollectionItem)
private
FName: string;
FValue: string;
FPath: string;
FDomain: string;
FExpires: TDateTime;
FSecure: Boolean;
protected
function GetHeaderValue: string;
public
constructor Create(Collection: TCollection); override;
procedure AssignTo(Dest: TPersistent); override;
property Name: string read FName write FName;
property Value: string read FValue write FValue;
property Domain: string read FDomain write FDomain;
property Path: string read FPath write FPath;
property Expires: TDateTime read FExpires write FExpires;
property Secure: Boolean read FSecure write FSecure;
property HeaderValue: string read GetHeaderValue;
end;

{ TCookieCollection }

TCookieCollection = class(TCollection)
private
FWebResponse: TWebResponse;
protected
function GetCookie(Index: Integer): TCookie;
procedure SetCookie(Index: Integer; Cookie: TCookie);
public
constructor Create(WebResponse: TWebResponse; ItemClass: TCollectionItemClass);
function Add: TCookie;
property WebResponse: TWebResponse read FWebResponse;
property Items[Index: Integer]: TCookie read GetCookie write SetCookie; default;
end;

{ TWebResponse }

TWebResponse = class(TObject)
private
FContentStream: TStream;
FCustomHeaders: TStrings;
FCookies: TCookieCollection;
procedure SetCustomHeaders(Value: TStrings);
protected
FHTTPRequest: TWebRequest;
procedure AddCustomHeaders(var Headers: string);
function GetStringVariable(Index: Integer): string; virtual; abstract;
procedure SetStringVariable(Index: Integer; const Value: string); virtual; abstract;
function GetDateVariable(Index: Integer): TDateTime; virtual; abstract;
procedure SetDateVariable(Index: Integer; const Value: TDateTime); virtual; abstract;
function GetIntegerVariable(Index: Integer): Integer; virtual; abstract;
procedure SetIntegerVariable(Index: Integer; Value: Integer); virtual; abstract;
function GetContent: string; virtual; abstract;
procedure SetContent(const Value: string); virtual; abstract;
procedure SetContentStream(Value: TStream); virtual;
function GetStatusCode: Integer; virtual; abstract;
procedure SetStatusCode(Value: Integer); virtual; abstract;
function GetLogMessage: string; virtual; abstract;
procedure SetLogMessage(const Value: string); virtual; abstract;
public
constructor Create(HTTPRequest: TWebRequest);
destructor Destroy; override;
function GetCustomHeader(const Name: string): String;
procedure SendResponse; virtual; abstract;
procedure SendRedirect(const URI: string); virtual; abstract;
procedure SendStream(AStream: TStream); virtual; abstract;
function Sent: Boolean; virtual;
procedure SetCookieField(Values: TStrings; const ADomain, APath: string;
AExpires: TDateTime; ASecure: Boolean);
procedure SetCustomHeader(const Name, Value: string);
property Cookies: TCookieCollection read FCookies;
property HTTPRequest: TWebRequest read FHTTPRequest;
property Version: string index 0 read GetStringVariable write SetStringVariable;
property ReasonString: string index 1 read GetStringVariable write SetStringVariable;
property Server: string index 2 read GetStringVariable write SetStringVariable;
property WWWAuthenticate: string index 3 read GetStringVariable write SetStringVariable;
property Realm: string index 4 read GetStringVariable write SetStringVariable;
property Allow: string index 5 read GetStringVariable write SetStringVariable;
property Location: string index 6 read GetStringVariable write SetStringVariable;
property ContentEncoding: string index 7 read GetStringVariable write SetStringVariable;
property ContentType: string index 8 read GetStringVariable write SetStringVariable;
property ContentVersion: string index 9 read GetStringVariable write SetStringVariable;
property DerivedFrom: string index 10 read GetStringVariable write SetStringVariable;
property Title: string index 11 read GetStringVariable write SetStringVariable;

property StatusCode: Integer read GetStatusCode write SetStatusCode;
property ContentLength: Integer index 0 read GetIntegerVariable write SetIntegerVariable;

property Date: TDateTime index 0 read GetDateVariable write SetDateVariable;
property Expires: TDateTime index 1 read GetDateVariable write SetDateVariable;
property LastModified: TDateTime index 2 read GetDateVariable write SetDateVariable;

property Content: string read GetContent write SetContent;
property ContentStream: TStream read FContentStream write SetContentStream;

property LogMessage: string read GetLogMessage write SetLogMessage;

property CustomHeaders: TStrings read FCustomHeaders write SetCustomHeaders;
end;

{ TWebDispatcherEditor }

TCustomWebDispatcher = class;
TCustomContentProducer = class;

{ THTMLTagAttributes }

THTMLAlign = (haDefault, haLeft, haRight, haCenter);
THTMLVAlign = (haVDefault, haTop, haMiddle, haBottom, haBaseline);
THTMLBgColor = type string;

THTMLTagAttributes = class(TPersistent)
private
FProducer: TCustomContentProducer;
FCustom: string;
FOnChange: TNotifyEvent;
procedure SetCustom(const Value: string);
protected
procedure Changed;
public
constructor Create(Producer: TCustomContentProducer);
procedure RestoreDefaults; virtual;
property Producer: TCustomContentProducer read FProducer;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
published
property Custom: string read FCustom write SetCustom;
end;

THTMLTableAttributes = class(THTMLTagAttributes)
private
FAlign: THTMLAlign;
FBorder: Integer;
FBgColor: THTMLBgColor;
FCellSpacing: Integer;
FCellPadding: Integer;
FWidth: Integer;
procedure SetAlign(Value: THTMLAlign);
procedure SetBorder(Value: Integer);
procedure SetBGColor(Value: THTMLBgColor);
procedure SetCellSpacing(Value: Integer);
procedure SetCellPadding(Value: Integer);
procedure SetWidth(Value: Integer);
protected
procedure AssignTo(Dest: TPersistent); override;
public
constructor Create(Producer: TCustomContentProducer);
procedure RestoreDefaults; override;
published
property Align: THTMLAlign read FAlign write SetAlign default haDefault;
property BgColor: THTMLBgColor read FBgColor write SetBgColor;
property Border: Integer read FBorder write SetBorder default -1;
property CellSpacing: Integer read FCellSpacing write SetCellSpacing default -1;
property CellPadding: Integer read FCellPadding write SetCellPAdding default -1;
property Width: Integer read FWidth write SetWidth default 100;
end;

THTMLTableElementAttributes = class(THTMLTagAttributes)
private
FAlign: THTMLAlign;
FBgColor: THTMLBgColor;
FVAlign: THTMLVAlign;
procedure SetAlign(Value: THTMLAlign);
procedure SetBGColor(Value: THTMLBgColor);
procedure SetVAlign(Value: THTMLVAlign);
protected
procedure AssignTo(Dest: TPersistent); override;
public
procedure RestoreDefaults; override;
published
property Align: THTMLAlign read FAlign write SetAlign default haDefault;
property BgColor: THTMLBgColor read FBgColor write SetBgColor;
property VAlign: THTMLVAlign read FVAlign write SetVAlign default haVDefault;
end;

THTMLTableHeaderAttributes = class(THTMLTableElementAttributes)
private
FCaption: string;
procedure SetCaption(Value: string);
protected
procedure AssignTo(Dest: TPersistent); override;
public
procedure RestoreDefaults; override;
published
property Caption: string read FCaption write SetCaption;
end;

THTMLTableRowAttributes = class(THTMLTableElementAttributes);
THTMLTableCellAttributes = class(THTMLTableElementAttributes);

{ TCustomContentProducer }

TCustomContentProducer = class(TComponent)
private
FDispatcher: TCustomWebDispatcher;
protected
procedure SetDispatcher(Value: TCustomWebDispatcher); virtual;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
function Content: string; virtual;
function ContentFromStream(Stream: TStream): string; virtual;
function ContentFromString(const S: string): string; virtual;
published
property Dispatcher: TCustomWebDispatcher read FDispatcher
write SetDispatcher stored False;
end;

{ TCustomHTTPPageProducer }

TCustomPageProducer = class(TCustomContentProducer)
private
FHTMLFile: TFileName;
FHTMLDoc: TStrings;
FStripParamQuotes: Boolean;
procedure SetHTMLFile(const Value: TFileName);
procedure SetHTMLDoc(Value: TStrings);
protected
function HandleTag(const TagString: string; TagParams: TStrings): string; virtual;
property HTMLDoc: TStrings read FHTMLDoc write SetHTMLDoc;
property HTMLFile: TFileName read FHTMLFile write SetHTMLFile;
property StripParamQuotes: Boolean read FStripParamQuotes write FStripParamQuotes default True;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function Content: string; override;
function ContentFromStream(Stream: TStream): string; override;
function ContentFromString(const S: string): string; override;
end;

{ TPageProducer }

TTag = (tgCustom, tgLink, tgImage, tgTable, tgImageMap, tgObject, tgEmbed);

THTMLTagEvent = procedure (Sender: TObject; Tag: TTag; const TagString: string;
TagParams: TStrings; var ReplaceText: string) of object;

TPageProducer = class(TCustomPageProducer)
private
FOnHTMLTag: THTMLTagEvent;
protected
function HandleTag(const TagString: string; TagParams: TStrings): string; override;
procedure DoTagEvent(Tag: TTag; const TagString: string; TagParams: TStrings;
var ReplaceText: string); dynamic;
published
property HTMLDoc;
property HTMLFile;
property StripParamQuotes;
property OnHTMLTag: THTMLTagEvent read FOnHTMLTag write FOnHTMLTag;
end;

{ TWebActionItem }

THTTPMethodEvent = procedure (Sender: TObject; Request: TWebRequest;
Response: TWebResponse; var Handled: Boolean) of object;

TWebActionItem = class(TCollectionItem)
private
FOnAction: THTTPMethodEvent;
FPathInfo: string;
FMethodType: TMethodType;
FDefault: Boolean;
FEnabled: Boolean;
FMaskPathInfo: string;
FMask: TMask;
FName: string;
FProducer: TCustomContentProducer;
function DispatchAction(Request: TWebRequest; Response: TWebResponse;
DoDefault: Boolean): Boolean;
procedure SetDefault(Value: Boolean);
procedure SetEnabled(Value: Boolean);
procedure SetMethodType(Value: TMethodType);
procedure SetOnAction(Value: THTTPMethodEvent);
procedure SetPathInfo(const Value: string);
procedure SetProducer(const Value: TCustomContentProducer);
function GetMask: TMask;
function ProducerPathInfo: string;
protected
function GetDisplayName: string; override;
procedure SetDisplayName(const Value: string); override;
function GetPathInfo: string;
public
constructor Create(Collection: TCollection); override;
destructor Destroy; override;
procedure AssignTo(Dest: TPersistent); override;
published
property Default: Boolean read FDefault write SetDefault default False;
property Enabled: Boolean read FEnabled write SetEnabled default True;
property MethodType: TMethodType read FMethodType write SetMethodType default mtAny;
property Name: string read GetDisplayName write SetDisplayName;
property PathInfo: string read GetPathInfo write SetPathInfo;
property Producer: TCustomContentProducer read FProducer write SetProducer;
property OnAction: THTTPMethodEvent read FOnAction write SetOnAction;
end;

{ TWebActionItems }

TWebActionItems = class(TCollection)
private
FWebDispatcher: TCustomWebDispatcher;
function GetActionItem(Index: Integer): TWebActionItem;
procedure SetActionItem(Index: Integer; Value: TWebActionItem);
protected
function GetAttrCount: Integer; override;
function GetAttr(Index: Integer): string; override;
function GetItemAttr(Index, ItemIndex: Integer): string; override;
function GetOwner: TPersistent; override;
procedure SetItemName(Item: TCollectionItem); override;
procedure Update(Item: TCollectionItem); override;
public
constructor Create(WebDispatcher: TCustomWebDispatcher;
ItemClass: TCollectionItemClass);
function Add: TWebActionItem;
property WebDispatcher: TCustomWebDispatcher read FWebDispatcher;
property Items[Index: Integer]: TWebActionItem read GetActionItem
write SetActionItem; default;
end;

{ IWebDispatch }

IWebDispatch = interface
['{F358F272-DB6D-11D2-AA3F-00A024C11562}']
function DispatchEnabled: Boolean;
function DispatchMethodType: TMethodType;
function DispatchRequest(Sender: TObject; Request: TWebRequest; Response: TWebResponse): Boolean;
function DispatchMask: TMask;
function DispatchSubItems: IInterfaceList;
property Enabled: Boolean read DispatchEnabled;
property MethodType: TMethodType read DispatchMethodType;
property Mask: TMask read DispatchMask;
property SubItems: IInterfaceList read DispatchSubItems;
end;

{ TCustomWebDispatcher }

TCustomWebDispatcher = class(TDataModule)
private
FRequest: TWebRequest;
FResponse: TWebResponse;
FActions: TWebActionItems;
FBeforeDispatch: THTTPMethodEvent;
FAfterDispatch: THTTPMethodEvent;
FDispatchList: TComponentList;
function GetAction(Index: Integer): TWebActionItem;
procedure SetActions(Value: TWebActionItems);
protected
function DoAfterDispatch(Request: TWebRequest; Response: TWebResponse): Boolean;
function DoBeforeDispatch(Request: TWebRequest; Response: TWebResponse): Boolean;
function DispatchAction(Request: TWebRequest;
Response: TWebResponse): Boolean;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
property BeforeDispatch: THTTPMethodEvent read FBeforeDispatch write FBeforeDispatch;
property AfterDispatch: THTTPMethodEvent read FAfterDispatch write FAfterDispatch;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function ActionByName(const AName: string): TWebActionItem;
property Actions: TWebActionItems read FActions write SetActions;
property Action[Index: Integer]: TWebActionItem read GetAction;
property Request: TWebRequest read FRequest;
property Response: TWebResponse read FResponse;
end;

{ TWebDispatcher }

TWebDispatcher = class(TCustomWebDispatcher)
published
property Actions;
property BeforeDispatch;
property AfterDispatch;
end;

{ TWebModule }

TWebModule = class(TCustomWebDispatcher)
public
constructor Create(AOwner: TComponent); override;
published
property Actions;
property BeforeDispatch;
property AfterDispatch;
end;

const
HTMLAlign: array[THTMLAlign] of string =
('',
' Align="Left"',
' Align="Right"',
' Align="Center"');
HTMLVAlign: array[THTMLVAlign] of string =
('',
' VAlign="Top"',
' VAlign="Middle"',
' VAlign="Bottom"',
' VAlign="Basline"');

function DosPathToUnixPath(const Path: string): string;
function HTTPDecode(const AStr: String): string;
function HTTPEncode(const AStr: String): string;
function ParseDate(const DateStr: string): TDateTime;
procedure ExtractHTTPFields(Separators, WhiteSpace: TSysCharSet; Content: PChar;
Strings: TStrings; StripQuotes: Boolean = False);
procedure ExtractHeaderFields(Separators, WhiteSpace: TSysCharSet; Content: PChar;
Strings: TStrings; Decode: Boolean; StripQuotes: Boolean = False);
function StatusString(StatusCode: Integer): string;
function UnixPathToDosPath(const Path: string): string;
function MonthStr(DateTime: TDateTime): string;
function DayOfWeekStr(DateTime: TDateTime): string;

implementation

uses Windows, CopyPrsr, WebConst;

{ TWebRequest }

constructor TWebRequest.Create;
begin
inherited Create;
if CompareText(Method, 'GET') = 0 then
FMethodType := mtGet
else if CompareText(Method, 'PUT') = 0 then
FMethodType := mtPut
else if CompareText(Method, 'POST') = 0 then
FMethodType := mtPost
else if CompareText(Method, 'HEAD') = 0 then
FMethodType := mtHead;
end;

destructor TWebRequest.Destroy;
begin
FContentFields.Free;
FCookieFields.Free;
FQueryFields.Free;
inherited Destroy;
end;

procedure TWebRequest.ExtractFields(Separators, WhiteSpace: TSysCharSet;
Content: PChar; Strings: TStrings);
begin
ExtractHTTPFields(Separators, WhiteSpace, Content, Strings);
end;

procedure TWebRequest.ExtractContentFields(Strings: TStrings);
var
ContentStr: string;
begin
if ContentLength > 0 then
begin
ContentStr := Content;
if Length(ContentStr) < ContentLength then
ContentStr := ContentStr + ReadString(ContentLength - Length(ContentStr));
ExtractFields(['&'], [], PChar(ContentStr), Strings);
end;
end;

procedure TWebRequest.ExtractCookieFields(Strings: TStrings);
var
CookieStr: string;
begin
CookieStr := Cookie;
ExtractHeaderFields([';'], [' '], PChar(CookieStr), Strings, False);
end;

procedure TWebRequest.ExtractQueryFields(Strings: TStrings);
var
ContentStr: string;
begin
ContentStr := Query;
ExtractFields(['&'], [], PChar(ContentStr), Strings);
end;

function TWebRequest.GetContentFields: TStrings;
begin
if FContentFields = nil then
begin
FContentFields := TStringList.Create;
ExtractContentFields(FContentFields);
end;
Result := FContentFields;
end;

function TWebRequest.GetCookieFields: TStrings;
begin
if FCookieFields = nil then
begin
FCookieFields := TStringList.Create;
ExtractCookieFields(FCookieFields);
end;
Result := FCookieFields;
end;

function TWebRequest.GetQueryFields: TStrings;
begin
if FQueryFields = nil then
begin
FQueryFields := TStringList.Create;
ExtractQueryFields(FQueryFields);
end;
Result := FQueryFields;
end;

{ TCookie }

constructor TCookie.Create(Collection: TCollection);
begin
inherited Create(Collection);
FExpires := -1;
end;

procedure TCookie.AssignTo(Dest: TPersistent);
begin
if Dest is TCookie then
with TCookie(Dest) do
begin
Name := Self.FName;
Value := Self.FValue;
Domain := Self.FDomain;
Path := Self.FPath;
Expires := Self.FExpires;
Secure := Self.FSecure;
end else inherited AssignTo(Dest);
end;

function TCookie.GetHeaderValue: string;
begin
Result := Format('%s=%s; ', [FName, FValue]);
if Domain <> '' then
Result := Result + Format('domain=%s; ', [Domain]);
if Path <> '' then
Result := Result + Format('path=%s; ', [Path]);
if Expires > -1 then
Result := Result +
Format(FormatDateTime('"expires="' + sDateFormat + ' "GMT; "', Expires),
[DayOfWeekStr(Expires), MonthStr(Expires)]);
if Secure then Result := Result + 'secure';
if Copy(Result, Length(Result) - 2, MaxInt) = '; ' then
SetLength(Result, Length(Result) - 2);
end;

{ TCookieCollection }

constructor TCookieCollection.Create(WebResponse: TWebResponse; ItemClass: TCollectionItemClass);
begin
inherited Create(ItemClass);
FWebResponse := WebResponse;
end;

function TCookieCollection.Add: TCookie;
begin
Result := TCookie(inherited Add);
end;

function TCookieCollection.GetCookie(Index: Integer): TCookie;
begin
Result := TCookie(inherited Items[Index]);
end;

procedure TCookieCollection.SetCookie(Index: Integer; Cookie: TCookie);
begin
Items[Index].Assign(Cookie);
end;

{ TWebResponse }

constructor TWebResponse.Create(HTTPRequest: TWebRequest);
begin
inherited Create;
FHTTPRequest := HTTPRequest;
FCustomHeaders := TStringList.Create;
FCookies := TCookieCollection.Create(Self, TCookie);
end;

destructor TWebResponse.Destroy;
begin
FContentStream.Free;
FCustomHeaders.Free;
FCookies.Free;
inherited Destroy;
end;

procedure TWebResponse.AddCustomHeaders(var Headers: string);
var
I: Integer;
Name, Value: string;
begin
for I := 0 to FCustomHeaders.Count - 1 do
begin
Name := FCustomHeaders.Names;
Value := FCustomHeaders.values[Name];
Headers := Headers + Name + ': ' + Value + #13#10;
end;
end;

function TWebResponse.GetCustomHeader(const Name: string): string;
begin
Result := FCustomHeaders.Values[Name];
end;

function TWebResponse.Sent: Boolean;
begin
Result := False;
end;

procedure TWebResponse.SetContentStream(Value: TStream);
begin
if Value <> FContentStream then
begin
FContentStream.Free;
FContentStream := Value;
if FContentStream <> nil then
ContentLength := FContentStream.Size
else ContentLength := Length(Content);
end;
end;

procedure TWebResponse.SetCookieField(Values: TStrings; const ADomain,
APath: string; AExpires: TDateTime; ASecure: Boolean);
var
I: Integer;
begin
for I := 0 to Values.Count - 1 do
with Cookies.Add do
begin
Name := Values.Names;
Value := Values.Values[Values.Names];
Domain := ADomain;
Path := APath;
Expires := AExpires;
Secure := ASecure;
end;
end;

procedure TWebResponse.SetCustomHeader(const Name, Value: string);
begin
FCustomHeaders.Values[Name] := Value;
end;

procedure TWebResponse.SetCustomHeaders(Value: TStrings);
begin
FCustomHeaders.Assign(Value);
end;

{ THTMLTagAttributes }

constructor THTMLTagAttributes.Create(Producer: TCustomContentProducer);
begin
inherited Create;
FProducer := Producer;
end;

procedure THTMLTagAttributes.Changed;
begin
if Assigned(FOnChange) then FOnChange(Self);
end;

procedure THTMLTagAttributes.RestoreDefaults;
begin
FCustom := '';
Changed;
end;

procedure THTMLTagAttributes.SetCustom(const Value: string);
begin
if Value <> FCustom then
begin
FCustom := Value;
Changed;
end;
end;

{ THTMLTableAttributes }

constructor THTMLTableAttributes.Create(Producer: TCustomContentProducer);
begin
inherited Create(Producer);
FWidth := 100;
FBorder := -1;
FCellPadding := -1;
FCellSpacing := -1;
end;

procedure THTMLTableAttributes.AssignTo(Dest: TPersistent);
begin
if Dest is THTMLTableAttributes then
with THTMLTableAttributes(Dest) do
begin
FWidth := Self.FWidth;
FAlign := Self.FAlign;
FBorder := Self.FBorder;
FBgColor := Self.FBgColor;
FCellSpacing := Self.FCellSpacing;
FCellPadding := Self.FCellPadding;
Changed;
end else inherited AssignTo(Dest);
end;

procedure THTMLTableAttributes.RestoreDefaults;
begin
FCustom := '';
FAlign := haDefault;
FWidth := 100;
FBorder := -1;
FCellPadding := -1;
FCellSpacing := -1;
Changed;
end;

procedure THTMLTableAttributes.SetAlign(Value: THTMLAlign);
begin
if Value <> FAlign then
begin
FAlign := Value;
Changed;
end;
end;

procedure THTMLTableAttributes.SetBorder(Value: Integer);
begin
if Value <> FBorder then
begin
FBorder := Value;
Changed;
end;
end;

procedure THTMLTableAttributes.SetBGColor(Value: THTMLBgColor);
begin
if Value <> FBgColor then
begin
FBgColor := Value;
Changed;
end;
end;

procedure THTMLTableAttributes.SetCellSpacing(Value: Integer);
begin
if Value <> FCellSpacing then
begin
FCellSpacing := Value;
Changed;
end;
end;

procedure THTMLTableAttributes.SetCellPadding(Value: Integer);
begin
if Value <> FCellPadding then
begin
FCellPadding := Value;
Changed;
end;
end;

procedure THTMLTableAttributes.SetWidth(Value: Integer);
begin
if Value <> FWidth then
begin
FWidth := Value;
Changed;
end;
end;

{ THTMLTableElementAttributes }

procedure THTMLTableElementAttributes.AssignTo(Dest: TPersistent);
begin
if Dest is THTMLTableElementAttributes then
with THTMLTableElementAttributes(Dest) do
begin
FAlign := Self.FAlign;
FVAlign := Self.FVAlign;
FBgColor := Self.FBgColor;
Changed;
end else inherited AssignTo(Dest);
end;

procedure THTMLTableElementAttributes.RestoreDefaults;
begin
FCustom := '';
FAlign := haDefault;
FVAlign := haVDefault;
FBgColor := '';
Changed;
end;

procedure THTMLTableElementAttributes.SetAlign(Value: THTMLAlign);
begin
if Value <> FAlign then
begin
FAlign := Value;
Changed;
end;
end;

procedure THTMLTableElementAttributes.SetBGColor(Value: THTMLBgColor);
begin
if Value <> FBgColor then
begin
FBgColor := Value;
Changed;
end;
end;

procedure THTMLTableElementAttributes.SetVAlign(Value: THTMLVAlign);
begin
if Value <> FVAlign then
begin
FVAlign := Value;
Changed;
end;
end;

{ THTMLTableHeaderAttributes }

procedure THTMLTableHeaderAttributes.AssignTo(Dest: TPersistent);
begin
if Dest is THTMLTableHeaderAttributes then
with THTMLTableHeaderAttributes(Dest) do
begin
FAlign := Self.FAlign;
FVAlign := Self.FVAlign;
FBgColor := Self.FBgColor;
FCaption := Self.FCaption;
Changed;
end else inherited AssignTo(Dest);
end;

procedure THTMLTableHeaderAttributes.RestoreDefaults;
begin
FCustom := '';
FAlign := haDefault;
FVAlign := haVDefault;
FBgColor := '';
FCaption := '';
Changed;
end;

procedure THTMLTableHeaderAttributes.SetCaption(Value: string);
begin
if AnsiCompareStr(Value, FCaption) <> 0 then
begin
FCaption := Value;
Changed;
end;
end;

{ TCustomHTMLProducer }

procedure TCustomContentProducer.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = FDispatcher) then
FDispatcher := nil;
end;

procedure TCustomContentProducer.SetDispatcher(Value: TCustomWebDispatcher);
begin
if FDispatcher <> Value then
begin
if Value <> nil then Value.FreeNotification(Self);
FDispatcher := Value;
end;
end;

function TCustomContentProducer.Content: string;
begin
Result := '';
end;

function TCustomContentProducer.ContentFromStream(Stream: TStream): string;
begin
Result := Content;
end;

function TCustomContentProducer.ContentFromString(const S: string): string;
begin
Result := Content;
end;

{ TCustomPageProducer }

constructor TCustomPageProducer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
RPR;
FStripParamQuotes := True;
FHTMLDoc := TStringList.Create;
end;

destructor TCustomPageProducer.Destroy;
begin
FHTMLDoc.Free;
inherited Destroy;
end;

function TCustomPageProducer.Content: string;
var
InStream: TStream;
begin
Result := '';
if FHTMLFile <> '' then
InStream := TFileStream.Create(FHTMLFile, fmOpenRead + fmShareDenyWrite)
else InStream := TStringStream.Create(FHTMLDoc.Text);
if InStream <> nil then
try
Result := ContentFromStream(InStream);
finally
InStream.Free;
end;
end;

function TCustomPageProducer.ContentFromStream(Stream: TStream): string;
var
Parser: TCopyParser;
OutStream: TStringStream;
ParamStr, ReplaceStr, TokenStr: string;
ParamList: TStringList;
begin
OutStream := TStringStream.Create('');
try
Parser := TCopyParser.Create(Stream, OutStream);
with Parser do
try
while True do
begin
while not (Token in [toEof, '<']) do
begin
CopyTokenToOutput;
SkipToken(True);
end;
if Token = toEOF then Break;
if Token = '<' then
begin
if SkipToken(False) = '#' then
begin
SkipToken(False);
TokenStr := TokenString;
ParamStr := TrimLeft(TrimRight(SkipToToken('>')));
ParamList := TStringList.Create;
try
ExtractHTTPFields([' '], [' '], PChar(ParamStr), ParamList, FStripParamQuotes);
ReplaceStr := HandleTag(TokenStr, ParamList);
OutStream.WriteString(ReplaceStr);
finally
ParamList.Free;
end;
SkipToken(True);
end else
begin
OutStream.WriteString('<');
CopyTokenToOutput;
SkipToken(True);
end;
end;
end;
finally
Parser.Free;
end;
Result := OutStream.DataString;
finally
OutStream.Free;
end;
end;

function TCustomPageProducer.ContentFromString(const S: string): string;
var
InStream: TStream;
begin
InStream := TStringStream.Create(S);
try
Result := ContentFromStream(InStream);
finally
InStream.Free;
end;
end;

function TCustomPageProducer.HandleTag(const TagString: string; TagParams: TStrings): string;
begin
Result := Format('<#%s>', [TagString]);
end;

procedure TCustomPageProducer.SetHTMLFile(const Value: TFileName);
begin
if CompareText(FHTMLFile, Value) <> 0 then
begin
FHTMLDoc.Clear;
FHTMLFile := Value;
end;
end;

procedure TCustomPageProducer.SetHTMLDoc(Value: TStrings);
begin
FHTMLDoc.Assign(Value);
FHTMLFile := '';
end;

{ TPageProducer }

var
TagSymbols: array[TTag] of string =
('', 'LINK', 'IMAGE', 'TABLE', 'IMAGEMAP', 'OBJECT', 'EMBED');

function TPageProducer.HandleTag(const TagString: string; TagParams: TStrings): string;
var
Tag: TTag;
begin
Tag := High(TTag);
while Tag >= Low(TTag) do
begin
if (Tag = tgCustom) or (CompareText(TagSymbols[Tag], TagString) = 0) then Break;
Dec(Tag);
end;
Result := '';
DoTagEvent(Tag, TagString, TagParams, Result);
end;

procedure TPageProducer.DoTagEvent(Tag: TTag; const TagString: string;
TagParams: TStrings; var ReplaceText: string);
begin
if Assigned(FOnHTMLTag) then
FOnHTMLTag(Self, Tag, TagString, TagParams, ReplaceText);
end;

{ TWebActionItem }

constructor TWebActionItem.Create(Collection: TCollection);
begin
inherited Create(Collection);
FEnabled := True;
end;

destructor TWebActionItem.Destroy;
begin
FMask.Free;
inherited Destroy;
end;

procedure TWebActionItem.AssignTo(Dest: TPersistent);
begin
if Dest is TWebActionItem then
begin
if Assigned(Collection) then Collection.BeginUpdate;
try
with TWebActionItem(Dest) do
begin
Default := Self.Default;
PathInfo := Self.PathInfo;
Enabled := Self.Enabled;
MethodType := Self.MethodType;
end;
finally
if Assigned(Collection) then Collection.EndUpdate;
end;
end else inherited AssignTo(Dest);
end;

function TWebActionItem.DispatchAction(Request: TWebRequest; Response: TWebResponse;
DoDefault: Boolean): Boolean;
begin
Result := False;
if (FDefault and DoDefault) or (FEnabled and ((FMethodType = mtAny) or
(FMethodType = Request.MethodType)) and
GetMask.Matches(Request.PathInfo)) then
begin
if Assigned(FProducer) then
begin
Result := True;
Response.Content := FProducer.Content;
end;
if Assigned(FOnAction) then
begin
Result := True;
FOnAction(Self, Request, Response, Result);
end
end;
end;

function TWebActionItem.GetDisplayName: string;
begin
Result := FName;
end;

procedure TWebActionItem.SetDefault(Value: Boolean);
var
I: Integer;
Action: TWebActionItem;
begin
if Value <> FDefault then
begin
if Value and (Collection <> nil) then
for I := 0 to Collection.Count - 1 do
begin
Action := TWebActionItems(Collection).Items;
if (Action <> Self) and (Action is TWebActionItem) then
Action.Default := False;
end;
FDefault := Value;
Changed(False);
end;
end;

procedure TWebActionItem.SetEnabled(Value: Boolean);
begin
if Value <> FEnabled then
begin
FEnabled := Value;
Changed(False);
end;
end;

procedure TWebActionItem.SetMethodType(Value: TMethodType);
begin
if Value <> FMethodType then
begin
FMethodType := Value;
Changed(False);
end;
end;

procedure TWebActionItem.SetDisplayName(const Value: string);
var
I: Integer;
Action: TWebActionItem;
begin
if AnsiCompareText(Value, FName) <> 0 then
begin
if Collection <> nil then
for I := 0 to Collection.Count - 1 do
begin
Action := TWebActionItems(Collection).Items;
if (Action <> Self) and (Action is TWebActionItem) and
(AnsiCompareText(Value, Action.Name) = 0) then
raise Exception.Create(sDuplicateActionName);
end;
FName := Value;
Changed(False);
end;
end;

procedure TWebActionItem.SetOnAction(Value: THTTPMethodEvent);
begin
FOnAction := Value;
Changed(False);
end;

procedure TWebActionItem.SetPathInfo(const Value: string);
var
NewValue: string;
begin
if Value <> '' then NewValue := DosPathToUnixPath(Value);
if (NewValue <> '') and (NewValue[1] <> '/') then Insert('/', NewValue, 1);
if Assigned(FProducer) and (NewValue = ProducerPathInfo) then
NewValue := '';
if AnsiCompareText(FPathInfo, NewValue) <> 0 then
begin
FPathInfo := NewValue;
Changed(False);
end;
end;

procedure TWebActionItem.SetProducer(const Value: TCustomContentProducer);
begin
if Assigned(Value) then
Value.FreeNotification(TWebActionItems(Collection).WebDispatcher);
FProducer := Value;
end;

function TWebActionItem.ProducerPathInfo: string;
begin
Assert(Assigned(FProducer));
Result := '/' + FProducer.Name
end;

function TWebActionItem.GetPathInfo: string;
begin
if (FPathInfo = '') and Assigned(FProducer) then
Result := ProducerPathInfo
else
Result := FPathInfo;
end;

function TWebActionItem.GetMask: TMask;
var
Mask: TMask;
MaskPathInfo: string;
begin
MaskPathInfo := GetPathInfo;
if (not Assigned(FMask)) or
(AnsiCompareText(FMaskPathInfo, MaskPathInfo) <> 0) then
begin
Mask := TMask.Create(MaskPathInfo);
try
FMaskPathInfo := MaskPathInfo;
if Assigned(FMask) then
begin
FMask.Free;
FMask := nil;
end;
except
Mask.Free;
raise;
end;
FMask := Mask;
end;
Result := FMask;
end;

{ TWebActionItems }

constructor TWebActionItems.Create(WebDispatcher: TCustomWebDispatcher;
ItemClass: TCollectionItemClass);
begin
inherited Create(ItemClass);
FWebDispatcher := WebDispatcher;
end;

function TWebActionItems.Add: TWebActionItem;
begin
Result := TWebActionItem(inherited Add);
end;

function TWebActionItems.GetActionItem(Index: Integer): TWebActionItem;
begin
Result := TWebActionItem(inherited Items[Index]);
end;

function TWebActionItems.GetAttrCount: Integer;
begin
Result := 5;
end;

function TWebActionItems.GetAttr(Index: Integer): string;
begin
case Index of
0: Result := sHTTPItemName;
1: Result := sHTTPItemURI;
2: Result := sHTTPItemEnabled;
3: Result := sHTTPItemDefault;
4: Result := sHTTPItemProducer;
else
Result := '';
end;
end;

function TWebActionItems.GetItemAttr(Index, ItemIndex: Integer): string;
begin
case Index of
0: Result := Items[ItemIndex].Name;
1: Result := Items[ItemIndex].PathInfo;
2: if Items[ItemIndex].Enabled then
Result := 'True' else Result := 'False'; // do not localize
3: if Items[ItemIndex].Default then
Result := '*' else Result := ''; //do not localize
4: if Items[ItemIndex].Producer <> nil then
Result := Items[ItemIndex].Producer.Name else Result := ''; //do not localize
else
Result := '';
end;
end;

function TWebActionItems.GetOwner: TPersistent;
begin
Result := FWebDispatcher;
end;

procedure TWebActionItems.SetActionItem(Index: Integer; Value: TWebActionItem);
begin
Items[Index].Assign(Value);
end;

procedure TWebActionItems.SetItemName(Item: TCollectionItem);
var
I, J: Integer;
ItemName: string;
CurItem: TWebActionItem;
begin
J := 1;
while True do
begin
ItemName := Format('WebActionItem%d', [J]);
I := 0;
while I < Count do
begin
CurItem := Items as TWebActionItem;
if (CurItem <> Item) and (CompareText(CurItem.Name, ItemName) = 0) then
begin
Inc(J);
Break;
end;
Inc(I);
end;
if I >= Count then
begin
(Item as TWebActionItem).Name := ItemName;
Break;
end;
end;
end;

procedure TWebActionItems.Update(Item: TCollectionItem);
begin
{!!! if (FWebDispatcher <> nil) and
not (csLoading in FWebDispatcher.ComponentState) then }
end;

{ TCustomWebDispatcher }

constructor TCustomWebDispatcher.Create(AOwner: TComponent);
var
I: Integer;
Component: TComponent;
DispatchIntf: IWebDispatch;
begin
RPR;
FDispatchList := TComponentList.Create;
FDispatchList.OwnsObjects := False;
if (AOwner <> nil) and (AOwner <> Application) then
if AOwner is TCustomWebDispatcher then
raise Exception.Create(sOnlyOneDispatcher)
else if csDesigning in ComponentState then
for I := 0 to AOwner.ComponentCount - 1 do
if AOwner.Components is TCustomWebDispatcher then
raise Exception.Create(sOnlyOneDispatcher);
inherited CreateNew(AOwner);
FActions := TWebActionItems.Create(Self, TWebActionItem);
if Owner <> nil then
for I := 0 to Owner.ComponentCount - 1 do
begin
Component := Owner.Components;
if Component is TCustomContentProducer then
TCustomContentProducer(Component).Dispatcher := Self
else if Component.GetInterface(IWebDispatch, DispatchIntf) then
FDispatchList.Add(Component);
end;
end;

destructor TCustomWebDispatcher.Destroy;
begin
inherited Destroy;
FActions.Free;
FDispatchList.Free;
end;

function TCustomWebDispatcher.ActionByName(const AName: string): TWebActionItem;
var
I: Integer;
begin
for I := 0 to FActions.Count - 1 do
begin
Result := FActions;
if AnsiCompareText(AName, Result.Name) = 0 then Exit;
end;
Result := nil;
end;

function TCustomWebDispatcher.DoAfterDispatch(Request: TWebRequest; Response: TWebResponse): Boolean;
begin
Result := True;
if Assigned(FAfterDispatch) then
FAfterDispatch(Self, Request, Response, Result);
end;

function TCustomWebDispatcher.DoBeforeDispatch(Request: TWebRequest; Response: TWebResponse): Boolean;
begin
Result := False;
if Assigned(FBeforeDispatch) then
FBeforeDispatch(Self, Request, Response, Result);
end;

function DispatchHandler(Sender: TObject; Dispatch: IWebDispatch; Request: TWebRequest; Response: TWebResponse;
DoDefault: Boolean): Boolean;
begin
Result := False;
if (Dispatch.Enabled and ((Dispatch.MethodType = mtAny) or
(Dispatch.MethodType = Dispatch.MethodType)) and
Dispatch.Mask.Matches(Request.PathInfo)) then
begin
Result := Dispatch.DispatchRequest(Sender, Request, Response);
end;
end;

function TCustomWebDispatcher.DispatchAction(Request: TWebRequest;
Response: TWebResponse): Boolean;
var
I: Integer;
Action, Default: TWebActionItem;
Dispatch: IWebDispatch;
begin
FRequest := Request;
FResponse := Response;
I := 0;
Default := nil;
Result := DoBeforeDispatch(Request, Response) or Response.Sent;
while not Result and (I < FActions.Count) do
begin
Action := FActions;
Result := Action.DispatchAction(Request, Response, False);
if Action.Default then Default := Action;
Inc(I);
end;
// Dispatch to self registering components
I := 0;
while not Result and (I < FDispatchList.Count) do
begin
if FDispatchList.Items.GetInterface(IWebDispatch, Dispatch) then
begin
Result := DispatchHandler(Self, Dispatch,
Request, Response, False);
end;
Inc(I);
end;

if not Result and Assigned(Default) then
Result := Default.DispatchAction(Request, Response, True);
if Result and not Response.Sent then
Result := DoAfterDispatch(Request, Response);

end;

function TCustomWebDispatcher.GetAction(Index: Integer): TWebActionItem;
begin
Result := FActions[Index];
end;

procedure TCustomWebDispatcher.Notification(AComponent: TComponent;
Operation: TOperation);
var
I: Integer;
DispatchIntf: IWebDispatch;
begin
inherited Notification(AComponent, Operation);
if (Operation = opInsert) then
begin
if (AComponent is TCustomContentProducer) then
TCustomContentProducer(AComponent).Dispatcher := Self
else if AComponent.GetInterface(IWebDispatch, DispatchIntf) then
FDispatchList.Add(AComponent);
end;
if (Operation = opRemove) and (AComponent is TCustomContentProducer) then
for I := 0 to FActions.Count - 1 do
if FActions.Items.Producer = AComponent then
FActions.Items.Producer := nil;
end;

procedure TCustomWebDispatcher.SetActions(Value: TWebActionItems);
begin
FActions.Assign(Value);
end;

{ TWebModule }

constructor TWebModule.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
if (ClassType <> TCustomWebDispatcher) and not (csDesigning in ComponentState) then
begin
if not InitInheritedComponent(Self, TCustomWebDispatcher) then
raise EResNotFound.CreateFmt(SResNotFound, [ClassName]);
try
if Assigned(OnCreate) and OldCreateOrder then OnCreate(Self);
except
Forms.Application.HandleException(Self);
end;
end;
end;

function HTTPDecode(const AStr: String): String;
var
Sp, Rp, Cp: PChar;
begin
SetLength(Result, Length(AStr));
Sp := PChar(AStr);
Rp := PChar(Result);
while Sp^ <> #0 do
begin
if not (Sp^ in ['+','%']) then
Rp^ := Sp^
else
if Sp^ = '+' then
Rp^ := ' '
else
begin
inc(Sp);
if Sp^ = '%' then
Rp^ := '%'
else
begin
Cp := Sp;
Inc(Sp);
Rp^ := Chr(StrToInt(Format('$%s%s',[Cp^, Sp^])));
end;
end;
Inc(Rp);
Inc(Sp);
end;
SetLength(Result, Rp - PChar(Result));
end;

function HTTPEncode(const AStr: String): String;
const
NoConversion = ['A'..'Z','a'..'z','*','@','.','_','-',
'0'..'9','$','!','''','(',')'];
var
Sp, Rp: PChar;
begin
SetLength(Result, Length(AStr) * 3);
Sp := PChar(AStr);
Rp := PChar(Result);
while Sp^ <> #0 do
begin
if Sp^ in NoConversion then
Rp^ := Sp^
else
if Sp^ = ' ' then
Rp^ := '+'
else
begin
FormatBuf(Rp^, 3, '%%%.2x', 6, [Ord(Sp^)]);
Inc(Rp,2);
end;
Inc(Rp);
Inc(Sp);
end;
SetLength(Result, Rp - PChar(Result));
end;

const
// These strings are NOT to be resourced

Months: array[1..12] of string = (
'Jan', 'Feb', 'Mar', 'Apr',
'May', 'Jun', 'Jul', 'Aug',
'Sep', 'Oct', 'Nov', 'Dec');
DaysOfWeek: array[1..7] of string = (
'Sun', 'Mon', 'Tue', 'Wed',
'Thu', 'Fri', 'Sat');

function ParseDate(const DateStr: string): TDateTime;
var
Month, Day, Year, Hour, Minute, Sec: Integer;
Parser: TParser;
StringStream: TStringStream;

function GetMonth: Boolean;
begin
Month := 1;
while not Parser.TokenSymbolIs(Months[Month]) and (Month < 13) do Inc(Month);
Result := Month < 13;
end;

procedure GetTime;
begin
with Parser do
begin
Hour := TokenInt;
NextToken;
if Token = ':' then NextToken;
Minute := TokenInt;
NextToken;
if Token = ':' then NextToken;
Sec := TokenInt;
NextToken;
end;
end;

begin
StringStream := TStringStream.Create(DateStr);
try
Parser := TParser.Create(StringStream);
with Parser do
try
NextToken;
if Token = ':' then NextToken;
NextToken;
if Token = ',' then NextToken;
if GetMonth then
begin
NextToken;
Day := TokenInt;
NextToken;
GetTime;
Year := TokenInt;
end else
begin
Day := TokenInt;
NextToken;
if Token = '-' then NextToken;
GetMonth;
NextToken;
if Token = '-' then NextToken;
Year := TokenInt;
if Year < 100 then Inc(Year, 1900);
NextToken;
GetTime;
end;
Result := EncodeDate(Year, Month, Day) + EncodeTime(Hour, Minute, Sec, 0);
finally
Free;
end;
finally
StringStream.Free;
end;
end;

procedure ExtractHeaderFields(Separators, WhiteSpace: TSysCharSet; Content: PChar;
Strings: TStrings; Decode: Boolean; StripQuotes: Boolean = False);
var
Head, Tail: PChar;
EOS, InQuote, LeadQuote: Boolean;
QuoteChar: Char;

function DoStripQuotes(const S: string): string;
var
I: Integer;
begin
Result := S;
if StripQuotes then
for I := Length(Result) downto 1 do
if Result in ['''', '"'] then
Delete(Result, I, 1);
end;

begin
if (Content = nil) or (Content^ = #0) then Exit;
Tail := Content;
InQuote := False;
QuoteChar := #0;
repeat
while Tail^ in WhiteSpace + [#13, #10] do Inc(Tail);
Head := Tail;
LeadQuote := False;
while True do
begin
while (InQuote and (Tail^ <> '"')) or
not (Tail^ in Separators + [#0, #13, #10, '"']) do Inc(Tail);
if Tail^ = '"' then
begin
if (QuoteChar <> #0) and (QuoteChar = Tail^) then
QuoteChar := #0
else
begin
LeadQuote := Head = Tail;
QuoteChar := Tail^;
if LeadQuote then Inc(Head);
end;
InQuote := QuoteChar <> #0;
if InQuote then
Inc(Tail)
else Break;
end else Break;
end;
if not LeadQuote and (Tail^ <> #0) and (Tail^ = '"') then
Inc(Tail);
EOS := Tail^ = #0;
Tail^ := #0;
if Head^ <> #0 then
if Decode then
Strings.Add(DoStripQuotes(HTTPDecode(Head)))
else Strings.Add(DoStripQuotes(Head));
Inc(Tail);
until EOS;
end;

procedure ExtractHTTPFields(Separators, WhiteSpace: TSysCharSet; Content: PChar;
Strings: TStrings; StripQuotes: Boolean = False);
begin
ExtractHeaderFields(Separators, WhiteSpace, Content, Strings, True, StripQuotes);
end;

function StatusString(StatusCode: Integer): string;
begin
case StatusCode of
100: Result := 'Continue';
101: Result := 'Switching Protocols';
200: Result := 'OK';
201: Result := 'Created';
202: Result := 'Accepted';
203: Result := 'Non-Authoritative Information';
204: Result := 'No Content';
205: Result := 'Reset Content';
206: Result := 'Partial Content';
300: Result := 'Multiple Choices';
301: Result := 'Moved Permanently';
302: Result := 'Moved Temporarily';
303: Result := 'See Other';
304: Result := 'Not Modified';
305: Result := 'Use Proxy';
400: Result := 'Bad Request';
401: Result := 'Unauthorized';
402: Result := 'Payment Required';
403: Result := 'Forbidden';
404: Result := 'Not Found';
405: Result := 'Method Not Allowed';
406: Result := 'None Acceptable';
407: Result := 'Proxy Authentication Required';
408: Result := 'Request Timeout';
409: Result := 'Conflict';
410: Result := 'Gone';
411: Result := 'Length Required';
412: Result := 'Unless True';
500: Result := 'Internal Server Error';
501: Result := 'Not Implemented';
502: Result := 'Bad Gateway';
503: Result := 'Service Unavailable';
504: Result := 'Gateway Timeout';
else
Result := '';
end
end;

function TranslateChar(const Str: string; FromChar, ToChar: Char): string;
var
I: Integer;
begin
Result := Str;
for I := 1 to Length(Result) do
if Result = FromChar then
Result := ToChar;
end;

function UnixPathToDosPath(const Path: string): string;
begin
Result := TranslateChar(Path, '/', '/');
end;

function DosPathToUnixPath(const Path: string): string;
begin
Result := TranslateChar(Path, '/', '/');
end;

function MonthStr(DateTime: TDateTime): string;
var
Year, Month, Day: Word;
begin
DecodeDate(DateTime, Year, Month, Day);
Result := Months[Month];
end;

function DayOfWeekStr(DateTime: TDateTime): string;
begin
Result := DaysOfWeek[DayOfWeek(DateTime)];
end;

end.

>>001China
所用的协议应该是相同的,我认为.
 
to:freeforever
老兄的帖子实在惊心动魄,我收了半天才结束,谢谢,谢谢,又多了解了一些东西,呵呵
 
不好意思了 因为我一般使用FG 所以没有注意到NETANTS 的设置
看>>NETANTS ......
2001/08/16 01:43:50 GET /album/77/22505.jpg HTTP/1.1
2001/08/16 01:43:50 Host: album.chinaren.com
2001/08/16 01:43:50 Accept: */*
2001/08/16 01:43:50 User-Agent: NetAnts/1.23
2001/08/16 01:43:50 Pragma: no-cache
2001/08/16 01:43:50 Cache-Control: no-cache
2001/08/16 01:43:50 Connection: close
2001/08/16 01:43:50 Cookie: CHINARENUSER=************; OWP=Y //****为已做修改
2001/08/16 01:43:50 HTTP/1.1 302 Found

>>FG ......
Thu Aug 16 01:47:34 2001 GET /album/77/22505.jpg HTTP/1.1
Thu Aug 16 01:47:34 2001 HOST: album.chinaren.com
Thu Aug 16 01:47:34 2001 ACCEPT: */*
Thu Aug 16 01:47:34 2001 Referer: http://album.chinaren.com/album/77
Thu Aug 16 01:47:34 2001 Cookie: CHINARENUSER=************; OWP=Y //****为已做修改
Thu Aug 16 01:47:34 2001 User-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)
Thu Aug 16 01:47:34 2001 Pragma: no-cache
Thu Aug 16 01:47:34 2001 Cache-Control: no-cache
Thu Aug 16 01:47:34 2001 Connection: close

对比一下 我个人认为是因为它们编程的不同性 分析上面可见
1、NETANTS 先GET 过程中没有使用COOKIE ???
2、你仔细看可以发觉它们的执行过程不一样 具体请自己看吧

我个人认为是因为FG 采用先获得COOKIE 这步 因为COOKIE 和当前活动的地址有关
请自己看看吧
 
注意到flash get有这个头部
Referer: http://album.chinaren.com/album/77
表示从该网址过来,而Net Ant没有,
有的网站不允许从别的网站直接调用他的图片或者其他的东西,
这样就会导致错误。
用Net Vampire试试,关掉打开Referer选项试试。
就可以判断是不是这个原因了。
 
>>Pan Ying
经过分析,你的解答是正确.我在NetAnts中加入如下信息:
“referer”栏中加入http://album.chinaren.com/album/77
结果成功:2001/08/19 23:34:47 Resolve host address ...
2001/08/19 23:34:47 Host address resolved
2001/08/19 23:34:47 Connect to host (album.chinaren.com:80) ...
2001/08/19 23:34:48 Connect to host successfully
2001/08/19 23:34:48 GET /album/77/22505.jpg HTTP/1.1
2001/08/19 23:34:48 Host: album.chinaren.com
2001/08/19 23:34:48 Accept: */*
2001/08/19 23:34:48 Referer: http://album.chinaren.com/album/77
2001/08/19 23:34:48 User-Agent: NetAnts/1.23
2001/08/19 23:34:48 Pragma: no-cache
2001/08/19 23:34:48 Cache-Control: no-cache
2001/08/19 23:34:48 Connection: close
2001/08/19 23:34:48 Cookie: CHINARENUSER=***********; OWP=Y; ZKEY//***为已做修改
2001/08/19 23:34:49 HTTP/1.1 200 OK
2001/08/19 23:34:49 Date: Sun, 19 Aug 2001 15:11:21 GMT
2001/08/19 23:34:49 Server: Apache/1.3.12 (Unix) PHP/4.0.4pl1
2001/08/19 23:34:49 Cache-Control: max-age=31536000
2001/08/19 23:34:49 Expires: Mon, 19 Aug 2002 15:11:21 GMT
2001/08/19 23:34:49 Last-Modified: Sun, 22 Jul 2001 08:42:59 GMT
2001/08/19 23:34:49 ETag: "13b91e4-916b-3b5a9213"
2001/08/19 23:34:49 Accept-Ranges: bytes
2001/08/19 23:34:49 Content-Length: 37227
2001/08/19 23:34:49 Connection: close
2001/08/19 23:34:49 Content-Type: image/jpeg
2001/08/19 23:34:49 Receiving data...
2001/08/19 23:35:01 No block left, ant finish
msdn中得到如下信息:
IHTMLDocument2::referrer Property Internet Development Index

----------------------------------------------------------------------------

Retrieves the URL of the location that referred the user to the current page.

Syntax

HRESULT IHTMLDocument2::get_referrer(BSTR *p);
Parameters

p
BSTR that specifies the URL of the referring page.
Return Value

Returns S_OK if successful, or an error value otherwise.
Remarks

This property returns a value only when the user reaches the current
page through a link from the previous page. Otherwise, document.referrer
returns an empty string; it also returns an empty string when the link is
from a secure site.

For example, if PageA.htm includes a link to PageB.htm, and the user clicks
that link, the document.referrer on PageB.htm returns "PageA.htm". However,
if the user is on PageA.htm and types PageB.htm into the address line or uses
Open in the File menu to get to PageB.htm, the document.referrer returns an
empty string.


ics中的httpport.pas发现如下代码:
if FReference <> '' then
SendCommand('Referer: ' + FReference);
谢谢各位
 
后退
顶部