IdHTTPHeaderInfo.pas 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.9 2/16/2005 7:58:56 AM DSiders
  18. Modified TIdRequestHeaderInfo to restore the Range property.
  19. Modified TIdRequestHeaderInfo methods AssignTo, Clear, ProcessHeaders, and
  20. SetHeaders to include Range property.
  21. Rev 1.8 11/11/2004 12:55:38 AM DSiders
  22. Modified TIdEntityHeaderInfo to fix problems with content-range header
  23. handling.
  24. Added ContentRangeInstanceLength property.
  25. Added HasContentRange property (read-ony).
  26. Added HasContentRangeInstance property (read-only).
  27. Moved reading and writing methods to ProcessHeaders and SetHeaders in
  28. TIdEntityHeaderInfo.
  29. Rev 1.7 6/8/2004 10:35:46 AM BGooijen
  30. fixed overflow
  31. Rev 1.6 2004.02.03 5:43:46 PM czhower
  32. Name changes
  33. Rev 1.5 1/22/2004 7:10:08 AM JPMugaas
  34. Tried to fix AnsiSameText depreciation.
  35. Rev 1.4 13.1.2004 ã. 17:17:44 DBondzhev
  36. moved few methods into protected section to remove some warnings
  37. Rev 1.3 10/17/2003 12:09:28 AM DSiders
  38. Added localization comments.
  39. Rev 1.2 20/4/2003 3:46:34 PM SGrobety
  40. Fix to previous fix... (Dumb me)
  41. Rev 1.1 20/4/2003 3:33:58 PM SGrobety
  42. Changed Content-type default in TIdEntityHeaderInfo back to empty string
  43. and changed the default of the response object. Solved compatibility
  44. issue with Netscape servers
  45. Rev 1.0 11/13/2002 07:54:24 AM JPMugaas
  46. }
  47. unit IdHTTPHeaderInfo;
  48. {
  49. HTTP Header definition - RFC 2616
  50. Author: Doychin Bondzhev ([email protected])
  51. }
  52. interface
  53. {$i IdCompilerDefines.inc}
  54. uses
  55. Classes,
  56. IdAuthentication,
  57. IdGlobal,
  58. IdGlobalProtocols,
  59. IdHeaderList;
  60. type
  61. TIdEntityHeaderInfo = class(TPersistent)
  62. protected
  63. {$IF DEFINED(HAS_UNSAFE_OBJECT_REF)}[Unsafe]
  64. {$ELSEIF DEFINED(HAS_WEAK_OBJECT_REF)}[Weak]
  65. {$IFEND} FOwner: TPersistent;
  66. //
  67. FCacheControl: String;
  68. FRawHeaders: TIdHeaderList;
  69. FCharSet: String;
  70. FConnection: string;
  71. FContentDisposition: string;
  72. FContentEncoding: string;
  73. FContentLanguage: string;
  74. FContentLength: Int64;
  75. FContentRangeEnd: Int64;
  76. FContentRangeStart: Int64;
  77. FContentRangeInstanceLength: Int64;
  78. FContentRangeUnits: String;
  79. FContentType: string;
  80. FContentVersion: string;
  81. FCustomHeaders: TIdHeaderList;
  82. FDate: TDateTime;
  83. FExpires: TDateTime;
  84. FETag: string;
  85. FLastModified: TDateTime;
  86. FPragma: string;
  87. FHasContentLength: Boolean;
  88. FTransferEncoding: String;
  89. //
  90. procedure AssignTo(Destination: TPersistent); override;
  91. procedure ProcessHeaders; virtual;
  92. procedure SetHeaders; virtual;
  93. function GetOwner: TPersistent; override;
  94. function GetOwnerComponent: TComponent;
  95. procedure SetContentLength(const AValue: Int64);
  96. procedure SetContentType(const AValue: String);
  97. procedure SetCustomHeaders(const AValue: TIdHeaderList);
  98. function GetHasContentRange: Boolean;
  99. function GetHasContentRangeInstance: Boolean;
  100. public
  101. procedure AfterConstruction; override;
  102. procedure Clear; virtual;
  103. constructor Create(AOwner: TPersistent); virtual;
  104. destructor Destroy; override;
  105. //
  106. property OwnerComponent: TComponent read GetOwnerComponent;
  107. property HasContentLength: Boolean read FHasContentLength;
  108. property HasContentRange: Boolean read GetHasContentRange;
  109. property HasContentRangeInstance: Boolean read GetHasContentRangeInstance;
  110. property RawHeaders: TIdHeaderList read FRawHeaders;
  111. published
  112. property CacheControl: String read FCacheControl write FCacheControl;
  113. property CharSet: String read FCharSet write FCharSet;
  114. property Connection: string read FConnection write FConnection;
  115. property ContentDisposition: string read FContentDisposition write FContentDisposition;
  116. property ContentEncoding: string read FContentEncoding write FContentEncoding;
  117. property ContentLanguage: string read FContentLanguage write FContentLanguage;
  118. property ContentLength: Int64 read FContentLength write SetContentLength;
  119. property ContentRangeEnd: Int64 read FContentRangeEnd write FContentRangeEnd;
  120. property ContentRangeStart: Int64 read FContentRangeStart write FContentRangeStart;
  121. property ContentRangeInstanceLength: Int64 read FContentRangeInstanceLength write FContentRangeInstanceLength;
  122. property ContentRangeUnits: String read FContentRangeUnits write FContentRangeUnits;
  123. property ContentType: string read FContentType write SetContentType;
  124. property ContentVersion: string read FContentVersion write FContentVersion;
  125. property CustomHeaders: TIdHeaderList read FCustomHeaders write SetCustomHeaders;
  126. property Date: TDateTime read FDate write FDate;
  127. property ETag: string read FETag write FETag;
  128. property Expires: TDateTime read FExpires write FExpires;
  129. property LastModified: TDateTime read FLastModified write FLastModified;
  130. property Pragma: string read FPragma write FPragma;
  131. property TransferEncoding: string read FTransferEncoding write FTransferEncoding;
  132. end;
  133. TIdProxyConnectionInfo = class(TPersistent)
  134. protected
  135. FAuthentication: TIdAuthentication;
  136. FPassword: string;
  137. FPort: Integer;
  138. FServer: string;
  139. FUsername: string;
  140. FBasicByDefault: Boolean;
  141. procedure AssignTo(Destination: TPersistent); override;
  142. procedure SetProxyPort(const Value: Integer);
  143. procedure SetProxyServer(const Value: string);
  144. public
  145. procedure AfterConstruction; override;
  146. constructor Create;
  147. procedure Clear;
  148. destructor Destroy; override;
  149. procedure SetHeaders(Headers: TIdHeaderList);
  150. //
  151. property Authentication: TIdAuthentication read FAuthentication write FAuthentication;
  152. published
  153. property BasicAuthentication: boolean read FBasicByDefault write FBasicByDefault;
  154. property ProxyPassword: string read FPassword write FPassword;
  155. property ProxyPort: Integer read FPort write SetProxyPort;
  156. property ProxyServer: string read FServer write SetProxyServer;
  157. property ProxyUsername: string read FUsername write FUserName;
  158. end;
  159. TIdEntityRange = class(TCollectionItem)
  160. protected
  161. FStartPos: Int64;
  162. FEndPos: Int64;
  163. FSuffixLength: Int64;
  164. function GetText: String;
  165. procedure SetText(const AValue: String);
  166. public
  167. constructor Create(Collection: TCollection); override;
  168. published
  169. property StartPos: Int64 read FStartPos write FStartPos;
  170. property EndPos: Int64 read FEndPos write FEndPos;
  171. property SuffixLength: Int64 read FSuffixLength write FSuffixLength;
  172. property Text: String read GetText write SetText;
  173. end;
  174. TIdEntityRanges = class(TOwnedCollection)
  175. protected
  176. FUnits: String;
  177. function GetRange(Index: Integer): TIdEntityRange;
  178. procedure SetRange(Index: Integer; AValue: TIdEntityRange);
  179. function GetText: String;
  180. procedure SetText(const AValue: String);
  181. procedure SetUnits(const AValue: String);
  182. public
  183. constructor Create(AOwner: TPersistent); reintroduce;
  184. function Add: TIdEntityRange; reintroduce;
  185. property Ranges[Index: Integer]: TIdEntityRange read GetRange write SetRange; default;
  186. published
  187. property Text: String read GetText write SetText;
  188. property Units: String read FUnits write SetUnits;
  189. end;
  190. TIdRequestHeaderInfo = class(TIdEntityHeaderInfo)
  191. protected
  192. FAccept: String;
  193. FAcceptCharSet: String;
  194. FAcceptEncoding: String;
  195. FAcceptLanguage: String;
  196. FExpect: String;
  197. FFrom: String;
  198. FPassword: String;
  199. FReferer: String;
  200. FUserAgent: String;
  201. FUserName: String;
  202. FHost: String;
  203. FProxyConnection: String;
  204. FRanges: TIdEntityRanges;
  205. FBasicByDefault: Boolean;
  206. FAuthentication: TIdAuthentication;
  207. FMethodOverride: String;
  208. //
  209. procedure AssignTo(Destination: TPersistent); override;
  210. procedure ProcessHeaders; override;
  211. procedure SetHeaders; override;
  212. function GetRange: String;
  213. procedure SetRange(const AValue: String);
  214. procedure SetRanges(AValue: TIdEntityRanges);
  215. public
  216. //
  217. constructor Create(AOwner: TPersistent); override;
  218. destructor Destroy; override;
  219. procedure Clear; override;
  220. property Authentication: TIdAuthentication read FAuthentication write FAuthentication;
  221. published
  222. property Accept: String read FAccept write FAccept;
  223. property AcceptCharSet: String read FAcceptCharSet write FAcceptCharSet;
  224. property AcceptEncoding: String read FAcceptEncoding write FAcceptEncoding;
  225. property AcceptLanguage: String read FAcceptLanguage write FAcceptLanguage;
  226. property BasicAuthentication: boolean read FBasicByDefault write FBasicByDefault;
  227. property Host: String read FHost write FHost;
  228. property From: String read FFrom write FFrom;
  229. property Password: String read FPassword write FPassword;
  230. property Referer: String read FReferer write FReferer;
  231. property UserAgent: String read FUserAgent write FUserAgent;
  232. property Username: String read FUsername write FUsername;
  233. property ProxyConnection: String read FProxyConnection write FProxyConnection;
  234. property Range: String read GetRange write SetRange; //deprecated 'Use Ranges property';
  235. property Ranges: TIdEntityRanges read FRanges write SetRanges;
  236. property MethodOverride: String read FMethodOverride write FMethodOverride;
  237. end;
  238. TIdResponseHeaderInfo = class(TIdEntityHeaderInfo)
  239. protected
  240. FAcceptPatch: string;
  241. FAcceptRanges: string;
  242. FLocation: string;
  243. FServer: string;
  244. FProxyConnection: string;
  245. FProxyAuthenticate: TIdHeaderList;
  246. FWWWAuthenticate: TIdHeaderList;
  247. //
  248. procedure SetProxyAuthenticate(const Value: TIdHeaderList);
  249. procedure SetWWWAuthenticate(const Value: TIdHeaderList);
  250. procedure SetAcceptPatch(const Value: string);
  251. procedure SetAcceptRanges(const Value: string);
  252. procedure ProcessHeaders; override;
  253. procedure SetHeaders; override;
  254. public
  255. procedure Clear; override;
  256. constructor Create(AOwner: TPersistent); override;
  257. destructor Destroy; override;
  258. published
  259. property AcceptPatch: string read FAcceptPatch write SetAcceptPatch;
  260. property AcceptRanges: string read FAcceptRanges write SetAcceptRanges;
  261. property Location: string read FLocation write FLocation;
  262. property ProxyConnection: string read FProxyConnection write FProxyConnection;
  263. property ProxyAuthenticate: TIdHeaderList read FProxyAuthenticate write SetProxyAuthenticate;
  264. property Server: string read FServer write FServer;
  265. property WWWAuthenticate: TIdHeaderList read FWWWAuthenticate write SetWWWAuthenticate;
  266. end;
  267. TIdMetaHTTPEquiv = class(TIdEntityHeaderInfo)
  268. public
  269. procedure ProcessMetaHTTPEquiv(AStream: TStream);
  270. end;
  271. var
  272. GIdDefaultUserAgent: String = 'Mozilla/3.0 (compatible; Indy Library)'; {do not localize}
  273. implementation
  274. uses
  275. SysUtils;
  276. { TIdEntityHeaderInfo }
  277. constructor TIdEntityHeaderInfo.Create(AOwner: TPersistent);
  278. begin
  279. inherited Create;
  280. FOwner := AOwner;
  281. // HTTP does not fold headers based on line length
  282. FRawHeaders := TIdHeaderList.Create(QuoteHTTP);
  283. FRawHeaders.FoldLength := MaxInt;
  284. FCustomHeaders := TIdHeaderList.Create(QuoteHTTP);
  285. FCustomHeaders.FoldLength := MaxInt;
  286. end;
  287. procedure TIdEntityHeaderInfo.AfterConstruction;
  288. begin
  289. inherited AfterConstruction;
  290. Clear;
  291. end;
  292. destructor TIdEntityHeaderInfo.Destroy;
  293. begin
  294. FRawHeaders.Free;
  295. FCustomHeaders.Free;
  296. inherited Destroy;
  297. end;
  298. procedure TIdEntityHeaderInfo.AssignTo(Destination: TPersistent);
  299. var
  300. LDest: TIdEntityHeaderInfo;
  301. begin
  302. if Destination is TIdEntityHeaderInfo then
  303. begin
  304. LDest := TIdEntityHeaderInfo(Destination);
  305. LDest.FRawHeaders.Assign(FRawHeaders);
  306. LDest.FCustomHeaders.Assign(FCustomHeaders);
  307. LDest.FCacheControl := FCacheControl;
  308. LDest.FCharSet := FCharSet;
  309. LDest.FConnection := FConnection;
  310. LDest.FContentDisposition := FContentDisposition;
  311. LDest.FContentEncoding := FContentEncoding;
  312. LDest.FContentLanguage := FContentLanguage;
  313. LDest.FContentType := FContentType;
  314. LDest.FContentVersion := FContentVersion;
  315. LDest.FContentLength := FContentLength;
  316. LDest.FContentRangeEnd:= FContentRangeEnd;
  317. LDest.FContentRangeStart:= FContentRangeStart;
  318. LDest.FContentRangeInstanceLength := FContentRangeInstanceLength;
  319. LDest.FContentRangeUnits := FContentRangeUnits;
  320. LDest.FDate := FDate;
  321. LDest.FETag := FETag;
  322. LDest.FExpires := FExpires;
  323. LDest.FLastModified := FLastModified;
  324. LDest.FPragma := FPragma;
  325. LDest.FHasContentLength := FHasContentLength;
  326. LDest.FTransferEncoding := FTransferEncoding;
  327. end else
  328. begin
  329. inherited AssignTo(Destination);
  330. end;
  331. end;
  332. procedure TIdEntityHeaderInfo.Clear;
  333. begin
  334. FCacheControl := '';
  335. FCharSet := '';
  336. FConnection := '';
  337. FContentVersion := '';
  338. FContentDisposition := '';
  339. FContentEncoding := '';
  340. FContentLanguage := '';
  341. { S.G. 20/4/2003
  342. Was FContentType := 'Text/HTML'
  343. Shouldn't be set here but in response.
  344. Requests, by default, have NO content-type.
  345. This caused problems with some netscape servers
  346. }
  347. FContentType := '';
  348. FContentLength := -1;
  349. FContentRangeStart := -1;
  350. FContentRangeEnd := -1;
  351. FContentRangeInstanceLength := -1;
  352. FContentRangeUnits := '';
  353. FDate := 0;
  354. FLastModified := 0;
  355. FETag := '';
  356. FExpires := 0;
  357. FCustomHeaders.Clear;
  358. FRawHeaders.Clear;
  359. end;
  360. procedure TIdEntityHeaderInfo.ProcessHeaders;
  361. var
  362. LSecs: Int64;
  363. lValue: string;
  364. lCRange: string;
  365. lILength: string;
  366. begin
  367. FCacheControl := FRawHeaders.Values['Cache-control']; {do not localize}
  368. FConnection := FRawHeaders.Values['Connection']; {do not localize}
  369. FContentVersion := FRawHeaders.Values['Content-Version']; {do not localize}
  370. FContentDisposition := FRawHeaders.Values['Content-Disposition']; {do not localize}
  371. FContentEncoding := FRawHeaders.Values['Content-Encoding']; {do not localize}
  372. FContentLanguage := FRawHeaders.Values['Content-Language']; {do not localize}
  373. ContentType := FRawHeaders.Values['Content-Type']; {do not localize}
  374. FContentLength := IndyStrToInt64(FRawHeaders.Values['Content-Length'], -1); {do not localize}
  375. FHasContentLength := FContentLength >= 0;
  376. FContentRangeStart := -1;
  377. FContentRangeEnd := -1;
  378. FContentRangeInstanceLength := -1;
  379. FContentRangeUnits := '';
  380. {
  381. handle content-range headers, like:
  382. content-range: bytes 1-65536/102400
  383. content-range: bytes */102400
  384. content-range: bytes 1-65536/*
  385. }
  386. lValue := FRawHeaders.Values['Content-Range']; {do not localize}
  387. if lValue <> '' then
  388. begin
  389. // strip the bytes unit, and keep the range and instance info
  390. FContentRangeUnits := Fetch(lValue);
  391. lCRange := Fetch(lValue, '/');
  392. lILength := Fetch(lValue);
  393. FContentRangeStart := IndyStrToInt64(Fetch(lCRange, '-'), -1);
  394. FContentRangeEnd := IndyStrToInt64(lCRange, -1);
  395. FContentRangeInstanceLength := IndyStrToInt64(lILength, -1);
  396. end;
  397. // RLebeau 03/04/2009: RFC 2616 Section 14.18 says:
  398. //
  399. // "A received message that does not have a Date header field MUST be
  400. // assigned one by the recipient if the message will be cached by that
  401. // recipient or gatewayed via a protocol which requires a Date."
  402. lValue := FRawHeaders.Values['Date']; {do not localize}
  403. if lValue <> '' then
  404. begin
  405. FDate := GMTToLocalDateTime(lValue);
  406. end else
  407. begin
  408. FDate := Now;
  409. end;
  410. FLastModified := GMTToLocalDateTime(FRawHeaders.Values['Last-Modified']); {do not localize}
  411. // RLebeau 01/23/2006 - IIS fix
  412. lValue := FRawHeaders.Values['Expires']; {do not localize}
  413. if IsNumeric(lValue) then
  414. begin
  415. // This is happening when expires is an integer number in seconds
  416. LSecs := IndyStrToInt64(lValue);
  417. // RLebeau 01/23/2005 - IIS sometimes sends an 'Expires: -1' header
  418. // should we be handling it as actually meaning "Now minus 1 second" instead?
  419. if LSecs >= 0 then begin
  420. FExpires := Now + (LSecs / SecsPerDay);
  421. end else begin
  422. FExpires := 0.0;
  423. end;
  424. end else
  425. begin
  426. // RLebeau 03/04/2009: RFC 2616 Section 14.21 says:
  427. //
  428. // "The format is an absolute date and time as defined by HTTP-date in
  429. // section 3.3.1; it MUST be in RFC 1123 date format:
  430. //
  431. // Expires = "Expires" ":" HTTP-date
  432. //
  433. // HTTP/1.1 clients and caches MUST treat other invalid date formats,
  434. // especially including the value "0", as in the past (i.e., "already
  435. // expired")."
  436. try
  437. FExpires := GMTToLocalDateTime(lValue);
  438. except
  439. FExpires := Now - (1 / SecsPerDay);
  440. end;
  441. end;
  442. FETag := FRawHeaders.Values['ETag']; {do not localize}
  443. FPragma := FRawHeaders.Values['Pragma']; {do not localize}
  444. FTransferEncoding := FRawHeaders.Values['Transfer-Encoding']; {do not localize}
  445. end;
  446. procedure TIdEntityHeaderInfo.SetHeaders;
  447. var
  448. sUnits: String;
  449. sCR: String;
  450. sCI: String;
  451. begin
  452. FRawHeaders.Clear;
  453. if FConnection <> '' then
  454. begin
  455. FRawHeaders.Values['Connection'] := FConnection; {do not localize}
  456. end;
  457. if FContentVersion <> '' then
  458. begin
  459. FRawHeaders.Values['Content-Version'] := FContentVersion; {do not localize}
  460. end;
  461. if FContentDisposition <> '' then
  462. begin
  463. FRawHeaders.Values['Content-Disposition'] := FContentDisposition; {do not localize}
  464. end;
  465. if FContentEncoding <> '' then
  466. begin
  467. FRawHeaders.Values['Content-Encoding'] := FContentEncoding; {do not localize}
  468. end;
  469. if FContentLanguage <> '' then
  470. begin
  471. FRawHeaders.Values['Content-Language'] := FContentLanguage; {do not localize}
  472. end;
  473. if FContentType <> '' then
  474. begin
  475. FRawHeaders.Values['Content-Type'] := FContentType; {do not localize}
  476. FRawHeaders.Params['Content-Type', 'charset'] := FCharSet; {do not localize}
  477. end;
  478. if FContentLength >= 0 then
  479. begin
  480. FRawHeaders.Values['Content-Length'] := IntToStr(FContentLength); {do not localize}
  481. end;
  482. // Rlebeau 10/11/2021: Content-Range is allowed in client requests, not just responses.
  483. // For instance, Microsoft's Graph API uses it!
  484. if HasContentRange or HasContentRangeInstance then
  485. begin
  486. sUnits := iif(FContentRangeUnits <> '',
  487. FContentRangeUnits, 'bytes'); {do not localize}
  488. sCR := iif(HasContentRange,
  489. IndyFormat('%d-%d', [FContentRangeStart, FContentRangeEnd]), '*'); {do not localize}
  490. sCI := iif(HasContentRangeInstance,
  491. IndyFormat('%d', [FContentRangeInstanceLength]), '*'); {do not localize}
  492. FRawHeaders.Values['Content-Range'] := sUnits + ' ' + sCR + '/' + sCI; {do not localize}
  493. end;
  494. if FCacheControl <> '' then
  495. begin
  496. FRawHeaders.Values['Cache-control'] := FCacheControl; {do not localize}
  497. end;
  498. if FDate > 0 then
  499. begin
  500. FRawHeaders.Values['Date'] := LocalDateTimeToHttpStr(FDate); {do not localize}
  501. end;
  502. if FETag <> '' then
  503. begin
  504. FRawHeaders.Values['ETag'] := FETag; {do not localize}
  505. end;
  506. if FExpires > 0 then
  507. begin
  508. FRawHeaders.Values['Expires'] := LocalDateTimeToHttpStr(FExpires); {do not localize}
  509. end;
  510. if FPragma <> '' then
  511. begin
  512. FRawHeaders.Values['Pragma'] := FPragma; {do not localize}
  513. end;
  514. if FTransferEncoding <> '' then
  515. begin
  516. FRawHeaders.Values['Transfer-Encoding'] := FTransferEncoding; {do not localize}
  517. end;
  518. if FCustomHeaders.Count > 0 then
  519. begin
  520. // append custom headers
  521. // TODO: use AddStrings() instead?
  522. FRawHeaders.Text := FRawHeaders.Text + FCustomHeaders.Text;
  523. end;
  524. end;
  525. procedure TIdEntityHeaderInfo.SetCustomHeaders(const AValue: TIdHeaderList);
  526. begin
  527. FCustomHeaders.Assign(AValue);
  528. end;
  529. procedure TIdEntityHeaderInfo.SetContentLength(const AValue: Int64);
  530. begin
  531. FContentLength := AValue;
  532. FHasContentLength := FContentLength >= 0;
  533. end;
  534. procedure TIdEntityHeaderInfo.SetContentType(const AValue: String);
  535. var
  536. S, LCharSet: string;
  537. LComp: TComponent;
  538. begin
  539. if AValue <> '' then begin
  540. FContentType := RemoveHeaderEntry(AValue, 'charset', LCharSet, QuoteHTTP); {do not localize}
  541. {RLebeau: the ContentType property is streamed after the CharSet property,
  542. so do not overwrite it during streaming}
  543. LComp := OwnerComponent;
  544. if Assigned(LComp) and (csReading in LComp.ComponentState) then begin
  545. Exit;
  546. end;
  547. // RLebeau: per RFC 2616 Section 3.7.1:
  548. //
  549. // The "charset" parameter is used with some media types to define the
  550. // character set (section 3.4) of the data. When no explicit charset
  551. // parameter is provided by the sender, media subtypes of the "text"
  552. // type are defined to have a default charset value of "ISO-8859-1" when
  553. // received via HTTP. Data in character sets other than "ISO-8859-1" or
  554. // its subsets MUST be labeled with an appropriate charset value. See
  555. // section 3.4.1 for compatibility problems.
  556. // RLebeau: per RFC 3023 Sections 3.1, 3.3, 3.6, and 8.5:
  557. //
  558. // Conformant with [RFC2046], if a text/xml entity is received with
  559. // the charset parameter omitted, MIME processors and XML processors
  560. // MUST use the default charset value of "us-ascii"[ASCII]. In cases
  561. // where the XML MIME entity is transmitted via HTTP, the default
  562. // charset value is still "us-ascii". (Note: There is an
  563. // inconsistency between this specification and HTTP/1.1, which uses
  564. // ISO-8859-1[ISO8859] as the default for a historical reason. Since
  565. // XML is a new format, a new default should be chosen for better
  566. // I18N. US-ASCII was chosen, since it is the intersection of UTF-8
  567. // and ISO-8859-1 and since it is already used by MIME.)
  568. //
  569. // ...
  570. //
  571. // The charset parameter of text/xml-external-parsed-entity is
  572. // handled the same as that of text/xml as described in Section 3.1
  573. //
  574. // ...
  575. //
  576. // The following list applies to text/xml, text/xml-external-parsed-
  577. // entity, and XML-based media types under the top-level type "text"
  578. // that define the charset parameter according to this specification:
  579. //
  580. // - If the charset parameter is not specified, the default is "us-
  581. // ascii". The default of "iso-8859-1" in HTTP is explicitly
  582. // overridden.
  583. //
  584. // ...
  585. //
  586. // Omitting the charset parameter is NOT RECOMMENDED for text/xml. For
  587. // example, even if the contents of the XML MIME entity are UTF-16 or
  588. // UTF-8, or the XML MIME entity has an explicit encoding declaration,
  589. // XML and MIME processors MUST assume the charset is "us-ascii".
  590. if (LCharSet = '') and (FCharSet = '') and IsHeaderMediaType(FContentType, 'text') then begin {do not localize}
  591. S := ExtractHeaderMediaSubType(FContentType);
  592. if (PosInStrArray(S, ['xml', 'xml-external-parsed-entity'], False) >= 0) or TextEndsWith(S, '+xml') then begin {do not localize}
  593. LCharSet := 'us-ascii'; {do not localize}
  594. end else begin
  595. LCharSet := 'ISO-8859-1'; {do not localize}
  596. end;
  597. end;
  598. {RLebeau: override the current CharSet only if the header specifies a new value}
  599. if LCharSet <> '' then begin
  600. FCharSet := LCharSet;
  601. end;
  602. end else begin
  603. FContentType := '';
  604. FCharSet := '';
  605. end;
  606. end;
  607. function TIdEntityHeaderInfo.GetHasContentRange: Boolean;
  608. begin
  609. Result := (FContentRangeEnd >= 0);
  610. end;
  611. function TIdEntityHeaderInfo.GetHasContentRangeInstance: Boolean;
  612. begin
  613. Result := (FContentRangeInstanceLength >= 0);
  614. end;
  615. function TIdEntityHeaderInfo.GetOwner: TPersistent;
  616. begin
  617. Result := FOwner;
  618. end;
  619. type
  620. TPersistentAccess = class(TPersistent)
  621. end;
  622. function TIdEntityHeaderInfo.GetOwnerComponent: TComponent;
  623. var
  624. // under ARC, convert a weak reference to a strong reference before working with it
  625. LOwner: TPersistent;
  626. begin
  627. Result := nil;
  628. LOwner := GetOwner;
  629. while LOwner <> nil do begin
  630. if LOwner is TComponent then begin
  631. Result := TComponent(LOwner);
  632. Exit;
  633. end;
  634. {$I IdObjectChecksOff.inc}
  635. LOwner := TPersistentAccess(LOwner).GetOwner;
  636. {$I IdObjectChecksOn.inc}
  637. end;
  638. end;
  639. { TIdProxyConnectionInfo }
  640. constructor TIdProxyConnectionInfo.Create;
  641. begin
  642. inherited Create;
  643. end;
  644. procedure TIdProxyConnectionInfo.AfterConstruction;
  645. begin
  646. inherited AfterConstruction;
  647. Clear;
  648. end;
  649. destructor TIdProxyConnectionInfo.Destroy;
  650. begin
  651. FAuthentication.Free;
  652. inherited Destroy;
  653. end;
  654. procedure TIdProxyConnectionInfo.AssignTo(Destination: TPersistent);
  655. var
  656. LDest: TIdProxyConnectionInfo;
  657. begin
  658. if Destination is TIdProxyConnectionInfo then
  659. begin
  660. LDest := TIdProxyConnectionInfo(Destination);
  661. LDest.FPassword := FPassword;
  662. LDest.FPort := FPort;
  663. LDest.FServer := FServer;
  664. LDest.FUsername := FUsername;
  665. LDest.FBasicByDefault := FBasicByDefault;
  666. end else
  667. begin
  668. inherited AssignTo(Destination);
  669. end;
  670. end;
  671. procedure TIdProxyConnectionInfo.Clear;
  672. begin
  673. FServer := '';
  674. FUsername := '';
  675. FPassword := '';
  676. FPort := 0;
  677. end;
  678. procedure TIdProxyConnectionInfo.SetHeaders(Headers: TIdHeaderList);
  679. var
  680. S: String;
  681. begin
  682. if Assigned(Authentication) then begin
  683. S := Authentication.Authentication;
  684. end
  685. // Use Basic authentication by default
  686. else if FBasicByDefault then begin
  687. FAuthentication := TIdBasicAuthentication.Create;
  688. // TODO: use FAuthentication Username/Password properties instead
  689. FAuthentication.Params.Values['Username'] := FUsername; {do not localize}
  690. FAuthentication.Params.Values['Password'] := FPassword; {do not localize}
  691. S := FAuthentication.Authentication;
  692. end else begin
  693. S := '';
  694. end;
  695. if S <> '' then begin
  696. Headers.Values['Proxy-Authorization'] := S; {do not localize}
  697. end;
  698. end;
  699. procedure TIdProxyConnectionInfo.SetProxyPort(const Value: Integer);
  700. begin
  701. if Value <> FPort then
  702. begin
  703. FreeAndNil(FAuthentication);
  704. end;
  705. FPort := Value;
  706. end;
  707. procedure TIdProxyConnectionInfo.SetProxyServer(const Value: string);
  708. begin
  709. if not TextIsSame(Value, FServer) then
  710. begin
  711. FreeAndNil(FAuthentication);
  712. end;
  713. FServer := Value;
  714. end;
  715. { TIdEntityRange }
  716. constructor TIdEntityRange.Create(Collection: TCollection);
  717. begin
  718. inherited Create(Collection);
  719. FStartPos := -1;
  720. FEndPos := -1;
  721. FSuffixLength := -1;
  722. end;
  723. function TIdEntityRange.GetText: String;
  724. begin
  725. if (FStartPos >= 0) or (FEndPos >= 0) then
  726. begin
  727. if FEndPos >= 0 then
  728. begin
  729. Result := IntToStr(FStartPos) + '-' + IntToStr(FEndPos); {do not localize}
  730. end else begin
  731. Result := IntToStr(FStartPos) + '-'; {do not localize}
  732. end;
  733. end
  734. else if FSuffixLength >= 0 then begin
  735. Result := '-' + IntToStr(FSuffixLength);
  736. end
  737. else begin
  738. Result := '';
  739. end;
  740. end;
  741. procedure TIdEntityRange.SetText(const AValue: String);
  742. var
  743. LValue, S: String;
  744. begin
  745. LValue := Trim(AValue);
  746. if LValue <> '' then
  747. begin
  748. S := Fetch(LValue, '-'); {do not localize}
  749. if S <> '' then begin
  750. FStartPos := StrToInt64Def(S, -1);
  751. FEndPos := StrToInt64Def(Fetch(LValue), -1);
  752. FSuffixLength := -1;
  753. end else begin
  754. FStartPos := -1;
  755. FEndPos := -1;
  756. FSuffixLength := StrToInt64Def(Fetch(LValue), -1);
  757. end;
  758. end else begin
  759. FStartPos := -1;
  760. FEndPos := -1;
  761. FSuffixLength := -1;
  762. end;
  763. end;
  764. { TIdEntityRanges }
  765. constructor TIdEntityRanges.Create(AOwner: TPersistent);
  766. begin
  767. inherited Create(AOwner, TIdEntityRange);
  768. FUnits := 'bytes'; {do not localize}
  769. end;
  770. function TIdEntityRanges.Add: TIdEntityRange;
  771. begin
  772. Result := TIdEntityRange(inherited Add);
  773. end;
  774. function TIdEntityRanges.GetRange(Index: Integer): TIdEntityRange;
  775. begin
  776. Result := TIdEntityRange(inherited GetItem(Index));
  777. end;
  778. procedure TIdEntityRanges.SetRange(Index: Integer; AValue: TIdEntityRange);
  779. begin
  780. inherited SetItem(Index, AValue);
  781. end;
  782. function TIdEntityRanges.GetText: String;
  783. var
  784. I: Integer;
  785. S: String;
  786. begin
  787. Result := '';
  788. for I := 0 to Count-1 do begin
  789. S := Ranges[I].Text;
  790. if S <> '' then begin
  791. if Result <> '' then begin
  792. Result := Result + ','; {do not localize}
  793. end;
  794. Result := Result + S;
  795. end;
  796. end;
  797. if Result <> '' then begin
  798. Result := FUnits + '=' + Result; {do not localize}
  799. end;
  800. end;
  801. procedure TIdEntityRanges.SetText(const AValue: String);
  802. var
  803. LUnits, LTmp: String;
  804. LRanges: TStringList;
  805. I: Integer;
  806. LRange: TIdEntityRange;
  807. begin
  808. LTmp := Trim(AValue);
  809. BeginUpdate;
  810. try
  811. Clear;
  812. if Pos('=', LTmp) > 0 then begin {do not localize}
  813. LUnits := Fetch(LTmp, '='); {do not localize}
  814. end;
  815. SetUnits(LUnits);
  816. LRanges := TStringList.Create;
  817. try
  818. SplitDelimitedString(LTmp, LRanges, True, ','); {do not localize}
  819. for I := 0 to LRanges.Count-1 do begin
  820. LTmp := Trim(LRanges[I]);
  821. if LTmp <> '' then begin
  822. LRange := Add;
  823. try
  824. LRange.Text := LTmp;
  825. except
  826. LRange.Free;
  827. raise;
  828. end;
  829. end;
  830. end;
  831. finally
  832. LRanges.Free;
  833. end;
  834. finally
  835. EndUpdate;
  836. end;
  837. end;
  838. procedure TIdEntityRanges.SetUnits(const AValue: String);
  839. var
  840. LUnits: String;
  841. begin
  842. LUnits := Trim(AValue);
  843. if LUnits <> '' then begin
  844. FUnits := LUnits;
  845. end else begin
  846. FUnits := 'bytes'; {do not localize}
  847. end;
  848. end;
  849. { TIdRequestHeaderInfo }
  850. constructor TIdRequestHeaderInfo.Create(AOwner: TPersistent);
  851. begin
  852. inherited Create(AOwner);
  853. FRanges := TIdEntityRanges.Create(Self);
  854. end;
  855. destructor TIdRequestHeaderInfo.Destroy;
  856. begin
  857. FAuthentication.Free;
  858. FRanges.Free;
  859. inherited Destroy;
  860. end;
  861. procedure TIdRequestHeaderInfo.ProcessHeaders;
  862. begin
  863. inherited ProcessHeaders;
  864. FAccept := FRawHeaders.Values['Accept']; {do not localize}
  865. FAcceptCharSet := FRawHeaders.Values['Accept-Charset']; {do not localize}
  866. FAcceptEncoding := FRawHeaders.Values['Accept-Encoding']; {do not localize}
  867. FAcceptLanguage := FRawHeaders.Values['Accept-Language']; {do not localize}
  868. FHost := FRawHeaders.Values['Host']; {do not localize}
  869. FFrom := FRawHeaders.Values['From']; {do not localize}
  870. FReferer := FRawHeaders.Values['Referer']; {do not localize}
  871. FUserAgent := FRawHeaders.Values['User-Agent']; {do not localize}
  872. FRanges.Text := FRawHeaders.Values['Range']; {do not localize}
  873. FMethodOverride := FRawHeaders.Values['X-HTTP-Method-Override']; {do not localize}
  874. end;
  875. procedure TIdRequestHeaderInfo.AssignTo(Destination: TPersistent);
  876. var
  877. LDest: TIdRequestHeaderInfo;
  878. begin
  879. if Destination is TIdRequestHeaderInfo then
  880. begin
  881. LDest := TIdRequestHeaderInfo(Destination);
  882. LDest.FAccept := FAccept;
  883. LDest.FAcceptCharSet := FAcceptCharset;
  884. LDest.FAcceptEncoding := FAcceptEncoding;
  885. LDest.FAcceptLanguage := FAcceptLanguage;
  886. LDest.FFrom := FFrom;
  887. LDest.FUsername := FUsername;
  888. LDest.FPassword := FPassword;
  889. LDest.FReferer := FReferer;
  890. LDest.FUserAgent := FUserAgent;
  891. LDest.FBasicByDefault := FBasicByDefault;
  892. LDest.FRanges.Assign(FRanges);
  893. LDest.FMethodOverride := FMethodOverride;
  894. // TODO: omitted intentionally?
  895. // LDest.FHost := FHost;
  896. // LDest.FProxyConnection := FProxyConnection;
  897. end;
  898. // always allow TIdEntityHeaderInfo to assign its properties as well
  899. inherited AssignTo(Destination);
  900. end;
  901. procedure TIdRequestHeaderInfo.Clear;
  902. begin
  903. FAccept := 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; // 'text/html, */*'; {do not localize}
  904. FAcceptCharSet := '';
  905. FUserAgent := GIdDefaultUserAgent;
  906. FBasicByDefault := false;
  907. FRanges.Text := '';
  908. FMethodOverride := '';
  909. // TODO: omitted intentionally?
  910. // FAcceptEncoding := '';
  911. // FAcceptLanguage := '';
  912. // FHost := '';
  913. // FFrom := '';
  914. // FPassword := '';
  915. // FUsername := '';
  916. // FReferer := '';
  917. // FProxyConnection := '';
  918. inherited Clear;
  919. end;
  920. function TIdRequestHeaderInfo.GetRange: String;
  921. begin
  922. Result := FRanges.Text;
  923. end;
  924. procedure TIdRequestHeaderInfo.SetRange(const AValue: String);
  925. begin
  926. FRanges.Text := AValue;
  927. end;
  928. procedure TIdRequestHeaderInfo.SetRanges(AValue: TIdEntityRanges);
  929. begin
  930. FRanges.Assign(AValue);
  931. end;
  932. procedure TIdRequestHeaderInfo.SetHeaders;
  933. var
  934. S: String;
  935. begin
  936. inherited SetHeaders;
  937. if FProxyConnection <> '' then
  938. begin
  939. FRawHeaders.Values['Proxy-Connection'] := FProxyConnection; {do not localize}
  940. end;
  941. if FHost <> '' then
  942. begin
  943. FRawHeaders.Values['Host'] := FHost; {do not localize}
  944. end;
  945. if FAccept <> '' then
  946. begin
  947. FRawHeaders.Values['Accept'] := FAccept; {do not localize}
  948. end;
  949. if FAcceptCharset <> '' then
  950. begin
  951. FRawHeaders.Values['Accept-Charset'] := FAcceptCharSet; {do not localize}
  952. end;
  953. if FAcceptEncoding <> '' then
  954. begin
  955. FRawHeaders.Values['Accept-Encoding'] := FAcceptEncoding; {do not localize}
  956. end;
  957. if FAcceptLanguage <> '' then
  958. begin
  959. FRawHeaders.Values['Accept-Language'] := FAcceptLanguage; {do not localize}
  960. end;
  961. if FFrom <> '' then
  962. begin
  963. FRawHeaders.Values['From'] := FFrom; {do not localize}
  964. end;
  965. if FReferer <> '' then
  966. begin
  967. FRawHeaders.Values['Referer'] := FReferer; {do not localize}
  968. end;
  969. if FUserAgent <> '' then
  970. begin
  971. FRawHeaders.Values['User-Agent'] := FUserAgent; {do not localize}
  972. end;
  973. S := FRanges.Text;
  974. if S <> '' then
  975. begin
  976. FRawHeaders.Values['Range'] := S; {do not localize}
  977. end;
  978. // use 'Last-Modified' entity header in the conditional request
  979. if FLastModified > 0 then
  980. begin
  981. FRawHeaders.Values['If-Modified-Since'] := LocalDateTimeToHttpStr(FLastModified); {do not localize}
  982. end;
  983. if Assigned(Authentication) then
  984. begin
  985. S := Authentication.Authentication;
  986. end
  987. else if FBasicByDefault then begin
  988. FAuthentication := TIdBasicAuthentication.Create;
  989. // TODO: use FAuthentication Username/Password properties instead
  990. FAuthentication.Params.Values['Username'] := FUserName; {do not localize}
  991. FAuthentication.Params.Values['Password'] := FPassword; {do not localize}
  992. S := FAuthentication.Authentication;
  993. end else begin
  994. S := '';
  995. end;
  996. if S <> '' then
  997. begin
  998. FRawHeaders.Values['Authorization'] := S; {do not localize}
  999. end;
  1000. if FMethodOverride <> '' then
  1001. begin
  1002. FRawHeaders.Values['X-HTTP-Method-Override'] := FMethodOverride; {Do not Localize}
  1003. end;
  1004. end;
  1005. { TIdResponseHeaderInfo }
  1006. constructor TIdResponseHeaderInfo.Create(AOwner: TPersistent);
  1007. begin
  1008. inherited Create(AOwner);
  1009. // RLebeau 5/15/2012: don't set any default ContentType, make the user set it...
  1010. FContentType := '';
  1011. FCharSet := '';
  1012. FWWWAuthenticate := TIdHeaderList.Create(QuoteHTTP);
  1013. FProxyAuthenticate := TIdHeaderList.Create(QuoteHTTP);
  1014. FAcceptPatch := '';
  1015. FAcceptRanges := '';
  1016. end;
  1017. destructor TIdResponseHeaderInfo.Destroy;
  1018. begin
  1019. FWWWAuthenticate.Free;
  1020. FProxyAuthenticate.Free;
  1021. inherited Destroy;
  1022. end;
  1023. procedure TIdResponseHeaderInfo.SetProxyAuthenticate(const Value: TIdHeaderList);
  1024. begin
  1025. FProxyAuthenticate.Assign(Value);
  1026. end;
  1027. procedure TIdResponseHeaderInfo.SetWWWAuthenticate(const Value: TIdHeaderList);
  1028. begin
  1029. FWWWAuthenticate.Assign(Value);
  1030. end;
  1031. procedure TIdResponseHeaderInfo.ProcessHeaders;
  1032. begin
  1033. inherited ProcessHeaders;
  1034. FLocation := FRawHeaders.Values['Location']; {do not localize}
  1035. FServer := FRawHeaders.Values['Server']; {do not localize}
  1036. FProxyConnection := FRawHeaders.Values['Proxy-Connection']; {do not localize}
  1037. FWWWAuthenticate.Clear;
  1038. FRawHeaders.Extract('WWW-Authenticate', FWWWAuthenticate); {do not localize}
  1039. FProxyAuthenticate.Clear;
  1040. FRawHeaders.Extract('Proxy-Authenticate', FProxyAuthenticate);{do not localize}
  1041. FAcceptPatch := FRawHeaders.Values['Accept-Patch']; {do not localize}
  1042. FAcceptRanges := FRawHeaders.Values['Accept-Ranges']; {do not localize}
  1043. end;
  1044. procedure TIdResponseHeaderInfo.SetHeaders;
  1045. begin
  1046. inherited SetHeaders;
  1047. if FAcceptPatch <> '' then
  1048. begin
  1049. RawHeaders.Values['Accept-Patch'] := FAcceptPatch; {do not localize}
  1050. end;
  1051. if FAcceptRanges <> '' then
  1052. begin
  1053. RawHeaders.Values['Accept-Ranges'] := FAcceptRanges; {do not localize}
  1054. end;
  1055. if FLastModified > 0 then
  1056. begin
  1057. RawHeaders.Values['Last-Modified'] := LocalDateTimeToHttpStr(FLastModified); {do not localize}
  1058. end;
  1059. end;
  1060. procedure TIdResponseHeaderInfo.Clear;
  1061. begin
  1062. inherited Clear;
  1063. // RLebeau 5/15/2012: don't set any default ContentType, make the user set it...
  1064. FContentType := '';
  1065. FCharSet := '';
  1066. FLocation := '';
  1067. FServer := '';
  1068. FAcceptPatch := '';
  1069. FAcceptRanges := '';
  1070. if Assigned(FProxyAuthenticate) then
  1071. begin
  1072. FProxyAuthenticate.Clear;
  1073. end;
  1074. if Assigned(FWWWAuthenticate) then
  1075. begin
  1076. FWWWAuthenticate.Clear;
  1077. end;
  1078. end;
  1079. procedure TIdResponseHeaderInfo.SetAcceptPatch(const Value: string);
  1080. begin
  1081. FAcceptPatch := Value;
  1082. end;
  1083. procedure TIdResponseHeaderInfo.SetAcceptRanges(const Value: string);
  1084. begin
  1085. FAcceptRanges := Value;
  1086. end;
  1087. { TIdMetaHTTPEquiv }
  1088. procedure TIdMetaHTTPEquiv.ProcessMetaHTTPEquiv(AStream: TStream);
  1089. var
  1090. LCharSet: string;
  1091. begin
  1092. ParseMetaHTTPEquiv(AStream, RawHeaders, LCharSet);
  1093. if FRawHeaders.Count > 0 then begin
  1094. ProcessHeaders;
  1095. end;
  1096. if LCharSet <> '' then begin
  1097. FCharSet := LCharset;
  1098. end;
  1099. end;
  1100. end.