IdHTTPHeaderInfo.pas 38 KB

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