IdHTTPWebBrokerBridge.pas 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  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.7 6/26/2004 12:11:16 AM BGooijen
  18. updates for D8
  19. Rev 1.6 4/8/2004 4:00:40 PM BGooijen
  20. Fix for D8
  21. Rev 1.5 07/04/2004 20:44:06 HHariri
  22. Updates
  23. Rev 1.4 07/04/2004 20:07:50 HHariri
  24. Updates for .NET
  25. Rev 1.3 10/19/2003 4:50:10 PM DSiders
  26. Added localization comments.
  27. Rev 1.2 10/12/2003 1:49:48 PM BGooijen
  28. Changed comment of last checkin
  29. Rev 1.1 10/12/2003 1:43:32 PM BGooijen
  30. Changed IdCompilerDefines.inc to Core\IdCompilerDefines.inc
  31. Rev 1.0 11/13/2002 07:54:34 AM JPMugaas
  32. }
  33. unit IdHTTPWebBrokerBridge;
  34. {
  35. Original Author: Dave Nottage.
  36. Modified by: Grahame Grieve
  37. Modified by: Chad Z. Hower (Kudzu)
  38. }
  39. interface
  40. {$i IdCompilerDefines.inc}
  41. uses
  42. Classes,
  43. HTTPApp,
  44. SysUtils,
  45. IdContext, IdCustomHTTPServer, IdException, IdTCPServer, IdIOHandlerSocket,
  46. {$IFDEF CLR}System.Text,{$ENDIF}
  47. WebReq;
  48. type
  49. EWBBException = class(EIdException);
  50. EWBBInvalidIdxGetDateVariable = class(EWBBException);
  51. EWBBInvalidIdxSetDateVariable = class(EWBBException );
  52. EWBBInvalidIdxGetIntVariable = class(EWBBException );
  53. EWBBInvalidIdxSetIntVariable = class(EWBBException );
  54. EWBBInvalidIdxGetStrVariable = class(EWBBException);
  55. EWBBInvalidIdxSetStringVar = class(EWBBException);
  56. EWBBInvalidStringVar = class(EWBBException);
  57. {$IFNDEF VCL_10_1_OR_ABOVE}
  58. {$DEFINE WBB_ANSI}
  59. {$ENDIF}
  60. {$IFDEF VCL_11_OR_ABOVE}
  61. {$DEFINE WBB_BIG_INTS}
  62. {$ENDIF}
  63. TIdHTTPAppRequest = class(TWebRequest)
  64. protected
  65. FRequestInfo : TIdHTTPRequestInfo;
  66. FResponseInfo : TIdHTTPResponseInfo;
  67. FThread : TIdContext;
  68. FContentStream : TStream;
  69. FFreeContentStream : Boolean;
  70. //
  71. function GetDateVariable(Index: Integer): TDateTime; override;
  72. function GetIntegerVariable(Index: Integer): {$IFDEF WBB_BIG_INTS}Int64{$ELSE}Integer{$ENDIF}; override;
  73. function GetStringVariable(Index: Integer): {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}; override;
  74. {$IFDEF VCL_XE_OR_ABOVE}
  75. function GetRemoteIP: string; override;
  76. function GetRawPathInfo: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}; override;
  77. {$ENDIF}
  78. {$IFDEF VCL_10_1_OR_ABOVE}
  79. function GetRawContent: TBytes; override;
  80. {$ENDIF}
  81. public
  82. constructor Create(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
  83. AResponseInfo: TIdHTTPResponseInfo);
  84. destructor Destroy; override;
  85. {$IFDEF WBB_ANSI}
  86. function GetFieldByName(const Name: AnsiString): AnsiString; override;
  87. {$ELSE}
  88. function GetFieldByName(const Name: string): string; override;
  89. {$ENDIF}
  90. function ReadClient(var Buffer{$IFDEF CLR}: TBytes{$ENDIF}; Count: Integer): Integer; override;
  91. function ReadString(Count: Integer): {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}; override;
  92. {function ReadUnicodeString(Count: Integer): string;}
  93. function TranslateURI(const URI: string): string; override;
  94. function WriteClient(var ABuffer; ACount: Integer): Integer; override;
  95. {$IFDEF VCL_6_OR_ABOVE}
  96. {$DEFINE VCL_6_OR_ABOVE_OR_CLR}
  97. {$ENDIF}
  98. {$IFDEF CLR}
  99. {$DEFINE VCL_6_OR_ABOVE_OR_CLR}
  100. {$ENDIF}
  101. {$IFDEF VCL_6_OR_ABOVE_OR_CLR}
  102. function WriteHeaders(StatusCode: Integer; const ReasonString, Headers: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}): Boolean; override;
  103. {$ENDIF}
  104. function WriteString(const AString: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}): Boolean; override;
  105. end;
  106. TIdHTTPAppResponse = class(TWebResponse)
  107. protected
  108. FContent: string;
  109. FRequestInfo: TIdHTTPRequestInfo;
  110. FResponseInfo: TIdHTTPResponseInfo;
  111. FSent: Boolean;
  112. FThread: TIdContext;
  113. FContentType: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}; // Workaround to preserve value of ContentType property
  114. //
  115. function GetContent: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}; override;
  116. function GetDateVariable(Index: Integer): TDateTime; override;
  117. function GetStatusCode: Integer; override;
  118. function GetIntegerVariable(Index: Integer): {$IFDEF WBB_BIG_INTS}Int64{$ELSE}Integer{$ENDIF}; override;
  119. function GetLogMessage: string; override;
  120. function GetStringVariable(Index: Integer): {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}; override;
  121. procedure SetContent(const AValue: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}); override;
  122. procedure SetContentStream(AValue: TStream); override;
  123. procedure SetStatusCode(AValue: Integer); override;
  124. procedure SetStringVariable(Index: Integer; const Value: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}); override;
  125. procedure SetDateVariable(Index: Integer; const Value: TDateTime); override;
  126. procedure SetIntegerVariable(Index: Integer; Value: {$IFDEF WBB_BIG_INTS}Int64{$ELSE}Integer{$ENDIF}); override;
  127. procedure SetLogMessage(const Value: string); override;
  128. procedure MoveCookiesAndCustomHeaders;
  129. public
  130. constructor Create(AHTTPRequest: TWebRequest; AThread: TIdContext;
  131. ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  132. procedure SendRedirect(const URI: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}); override;
  133. procedure SendResponse; override;
  134. procedure SendStream(AStream: TStream); override;
  135. function Sent: Boolean; override;
  136. end;
  137. TIdHTTPWebBrokerBridge = class(TIdCustomHTTPServer)
  138. private
  139. procedure RunWebModuleClass(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
  140. AResponseInfo: TIdHTTPResponseInfo);
  141. protected
  142. FWebModuleClass: TComponentClass;
  143. //
  144. procedure DoCommandGet(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
  145. AResponseInfo: TIdHTTPResponseInfo); override;
  146. procedure DoCommandOther(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
  147. AResponseInfo: TIdHTTPResponseInfo); override;
  148. procedure InitComponent; override;
  149. public
  150. procedure RegisterWebModuleClass(AClass: TComponentClass);
  151. end;
  152. implementation
  153. uses
  154. IdResourceStringsProtocols,
  155. IdBuffer, IdHTTPHeaderInfo, IdGlobal, IdGlobalProtocols, IdCookie, IdStream,
  156. {$IFDEF STRING_IS_UNICODE}IdCharsets,{$ENDIF}
  157. Math
  158. {$IFDEF HAS_TNetEncoding}
  159. , System.NetEncoding
  160. {$ENDIF}
  161. ;
  162. type
  163. // Make HandleRequest accessible
  164. TWebDispatcherAccess = class(TCustomWebDispatcher);
  165. const
  166. INDEX_RESP_Version = 0;
  167. INDEX_RESP_ReasonString = 1;
  168. INDEX_RESP_Server = 2;
  169. INDEX_RESP_WWWAuthenticate = 3;
  170. INDEX_RESP_Realm = 4;
  171. INDEX_RESP_Allow = 5;
  172. INDEX_RESP_Location = 6;
  173. INDEX_RESP_ContentEncoding = 7;
  174. INDEX_RESP_ContentType = 8;
  175. INDEX_RESP_ContentVersion = 9;
  176. INDEX_RESP_DerivedFrom = 10;
  177. INDEX_RESP_Title = 11;
  178. //
  179. INDEX_RESP_ContentLength = 0;
  180. //
  181. INDEX_RESP_Date = 0;
  182. INDEX_RESP_Expires = 1;
  183. INDEX_RESP_LastModified = 2;
  184. //
  185. //Borland coder didn't define constants in HTTPApp
  186. INDEX_Method = 0;
  187. INDEX_ProtocolVersion = 1;
  188. INDEX_URL = 2;
  189. INDEX_Query = 3;
  190. INDEX_PathInfo = 4;
  191. INDEX_PathTranslated = 5;
  192. INDEX_CacheControl = 6;
  193. INDEX_Date = 7;
  194. INDEX_Accept = 8;
  195. INDEX_From = 9;
  196. INDEX_Host = 10;
  197. INDEX_IfModifiedSince = 11;
  198. INDEX_Referer = 12;
  199. INDEX_UserAgent = 13;
  200. INDEX_ContentEncoding = 14;
  201. INDEX_ContentType = 15;
  202. INDEX_ContentLength = 16;
  203. INDEX_ContentVersion = 17;
  204. INDEX_DerivedFrom = 18;
  205. INDEX_Expires = 19;
  206. INDEX_Title = 20;
  207. INDEX_RemoteAddr = 21;
  208. INDEX_RemoteHost = 22;
  209. INDEX_ScriptName = 23;
  210. INDEX_ServerPort = 24;
  211. INDEX_Content = 25;
  212. INDEX_Connection = 26;
  213. INDEX_Cookie = 27;
  214. INDEX_Authorization = 28;
  215. { TIdHTTPAppRequest }
  216. constructor TIdHTTPAppRequest.Create(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  217. var
  218. i: Integer;
  219. begin
  220. FThread := AThread;
  221. FRequestInfo := ARequestInfo;
  222. FResponseInfo := AResponseInfo;
  223. inherited Create;
  224. for i := 0 to ARequestInfo.Cookies.Count - 1 do begin
  225. CookieFields.Add(ARequestInfo.Cookies[i].ClientCookie);
  226. end;
  227. if Assigned(FRequestInfo.PostStream) then
  228. begin
  229. FContentStream := FRequestInfo.PostStream;
  230. FFreeContentStream := False;
  231. end else
  232. begin
  233. if FRequestInfo.FormParams <> '' then begin {do not localize}
  234. // an input form that was submitted as "application/www-url-encoded"...
  235. FContentStream := TStringStream.Create(FRequestInfo.FormParams);
  236. end else
  237. begin
  238. // anything else for now...
  239. FContentStream := TStringStream.Create(FRequestInfo.UnparsedParams);
  240. end;
  241. FFreeContentStream := True;
  242. end;
  243. end;
  244. destructor TIdHTTPAppRequest.Destroy;
  245. begin
  246. if FFreeContentStream then begin
  247. FreeAndNil(FContentStream);
  248. end;
  249. inherited;
  250. end;
  251. function TIdHTTPAppRequest.GetDateVariable(Index: Integer): TDateTime;
  252. var
  253. LValue: string;
  254. begin
  255. LValue := string(GetStringVariable(Index));
  256. if Length(LValue) > 0 then begin
  257. Result := ParseDate(LValue);
  258. end else begin
  259. Result := -1;
  260. end;
  261. end;
  262. function TIdHTTPAppRequest.GetIntegerVariable(Index: Integer): {$IFDEF WBB_BIG_INTS}Int64{$ELSE}Integer{$ENDIF};
  263. begin
  264. Result := {$IFDEF WBB_BIG_INTS}StrToInt64Def{$ELSE}StrToIntDef{$ENDIF}(string(GetStringVariable(Index)), -1)
  265. end;
  266. {$IFDEF VCL_XE_OR_ABOVE}
  267. function TIdHTTPAppRequest.GetRawPathInfo: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF};
  268. begin
  269. {$IFDEF WBB_ANSI}
  270. Result := AnsiString(FRequestInfo.URI);
  271. {$ELSE}
  272. Result := FRequestInfo.URI;
  273. {$ENDIF}
  274. end;
  275. function TIdHTTPAppRequest.GetRemoteIP: string;
  276. begin
  277. Result := FRequestInfo.RemoteIP;
  278. end;
  279. {$ENDIF}
  280. {$IFDEF VCL_10_1_OR_ABOVE}
  281. function TIdHTTPAppRequest.GetRawContent: TBytes;
  282. var
  283. LPos: TIdStreamSize;
  284. begin
  285. LPos := FContentStream.Position;
  286. FContentStream.Position := 0;
  287. try
  288. //TIdStreamHelper.ReadBytes(FContentStream, PIdBytes(@Result)^);
  289. SetLength(Result, FContentStream.Size);
  290. FContentStream.Read(Result, 0, Length(Result));
  291. finally
  292. FContentStream.Position := LPos;
  293. end;
  294. end;
  295. {$ENDIF}
  296. function TIdHTTPAppRequest.GetStringVariable(Index: Integer): {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF};
  297. var
  298. LValue: string;
  299. LPos: TIdStreamSize;
  300. {$IFDEF WBB_ANSI}
  301. LBytes: TIdBytes;
  302. {$ENDIF}
  303. begin
  304. // RLebeau 1/15/2016: Now accessing FRequestInfo.RawHeaders.Values[] directly
  305. // instead of using GetFieldByName(). On Delphi versions prior to 10.1 Berlin,
  306. // GetFieldByName() returned an AnsiString, even in Unicode versions. So as not
  307. // to have to IFDEF all of these fields, now doing one conversion at the end of
  308. // this method, which means having a local String variable. Don't want the
  309. // overhead of performing an AnsiString->String->AnsiString conversion...
  310. {$IFDEF WBB_ANSI}
  311. LBytes := nil;
  312. {$ENDIF}
  313. case Index of
  314. INDEX_Method : LValue := FRequestInfo.Command;
  315. INDEX_ProtocolVersion : LValue := FRequestInfo.Version;
  316. //INDEX_URL : LValue := FRequestInfo.Document;
  317. INDEX_URL : LValue := ''; // Root - consistent with ISAPI which return path to root
  318. INDEX_Query : LValue := FRequestInfo.QueryParams;
  319. INDEX_PathInfo : LValue := FRequestInfo.Document;
  320. INDEX_PathTranslated : LValue := FRequestInfo.Document; // it's not clear quite what should be done here - we can't translate to a path
  321. INDEX_CacheControl : LValue := FRequestInfo.RawHeaders.Values['Cache-Control']; {do not localize}
  322. INDEX_Date : LValue := FRequestInfo.RawHeaders.Values['Date']; {do not localize}
  323. INDEX_Accept : LValue := FRequestInfo.Accept;
  324. INDEX_From : LValue := FRequestInfo.From;
  325. INDEX_Host: begin
  326. LValue := FRequestInfo.Host;
  327. LValue := Fetch(LValue, ':', False);
  328. end;
  329. INDEX_IfModifiedSince : LValue := FRequestInfo.RawHeaders.Values['If-Modified-Since']; {do not localize}
  330. INDEX_Referer : LValue := FRequestInfo.Referer;
  331. INDEX_UserAgent : LValue := FRequestInfo.UserAgent;
  332. INDEX_ContentEncoding : LValue := FRequestInfo.ContentEncoding;
  333. INDEX_ContentType : LValue := FRequestInfo.ContentType;
  334. INDEX_ContentLength : LValue := IntToStr(FContentStream.Size);
  335. INDEX_ContentVersion : LValue := FRequestInfo.RawHeaders.Values['CONTENT_VERSION']; {do not localize}
  336. INDEX_DerivedFrom : LValue := FRequestInfo.RawHeaders.Values['Derived-From']; {do not localize}
  337. INDEX_Expires : LValue := FRequestInfo.RawHeaders.Values['Expires']; {do not localize}
  338. INDEX_Title : LValue := FRequestInfo.RawHeaders.Values['Title']; {do not localize}
  339. INDEX_RemoteAddr : LValue := FRequestInfo.RemoteIP;
  340. INDEX_RemoteHost : LValue := FRequestInfo.RawHeaders.Values['REMOTE_HOST']; {do not localize}
  341. INDEX_ScriptName : LValue := '';
  342. INDEX_ServerPort: begin
  343. LValue := FRequestInfo.Host;
  344. Fetch(LValue, ':');
  345. if Length(LValue) = 0 then begin
  346. LValue := IntToStr(FThread.Connection.Socket.Binding.Port);
  347. // LValue := '80';
  348. end;
  349. end;
  350. INDEX_Content: begin
  351. if FFreeContentStream then
  352. begin
  353. LValue := TStringStream(FContentStream).DataString;
  354. end else
  355. begin
  356. LPos := FContentStream.Position;
  357. FContentStream.Position := 0;
  358. try
  359. // TODO: just use TIdHTTPAppRequest.ReadString() instead?
  360. //s := ReadString(FContentStream.Size);
  361. {$IFDEF WBB_ANSI}
  362. // RLebeau 2/21/2009: not using ReadStringAsCharSet() anymore. Since
  363. // this method returns an AnsiString, the stream data should not be
  364. // decoded to Unicode and then converted to Ansi. That can lose
  365. // characters...
  366. // Result := ReadStringAsCharSet(FContentStream, FRequestInfo.CharSet);
  367. // TODO: instead of using a temp memory buffer, just pre-allocate the
  368. // Result to the size of the stream and then read directly into it...
  369. TIdStreamHelper.ReadBytes(FContentStream, LBytes);
  370. {$IFDEF DOTNET}
  371. // RLebeau: how to handle this correctly in .NET?
  372. Result := AnsiString(BytesToStringRaw(LBytes));
  373. {$ELSE}
  374. SetString(Result, PAnsiChar(LBytes), Length(LBytes));
  375. {$IFDEF HAS_SetCodePage}
  376. // RLebeau 2/21/2009: For D2009+, the AnsiString payload should have
  377. // the proper codepage assigned to it as well so it can be converted
  378. // correctly if assigned to other string variables later on...
  379. SetCodePage(PRawByteString(@Result)^, CharsetToCodePage(FRequestInfo.CharSet), False);
  380. {$ENDIF}
  381. {$ENDIF}
  382. {$ELSE}
  383. // RLebeau 1/15/2016: this method now returns a UnicodeString, so
  384. // lets use ReadStringAsCharSet() once again...
  385. Result := ReadStringAsCharset(FContentStream, FRequestInfo.CharSet);
  386. {$ENDIF}
  387. finally
  388. FContentStream.Position := LPos;
  389. end;
  390. Exit;
  391. end;
  392. end;
  393. INDEX_Connection : LValue := FRequestInfo.RawHeaders.Values['Connection']; {do not localize}
  394. INDEX_Cookie : LValue := ''; // not available at present. FRequestInfo.Cookies....;
  395. INDEX_Authorization : LValue := FRequestInfo.RawHeaders.Values['Authorization']; {do not localize}
  396. else
  397. LValue := '';
  398. end;
  399. Result := {$IFDEF WBB_ANSI}AnsiString(LValue){$ELSE}LValue{$ENDIF};
  400. end;
  401. {$IFDEF WBB_ANSI}
  402. function TIdHTTPAppRequest.GetFieldByName(const Name: AnsiString): AnsiString;
  403. begin
  404. Result := AnsiString(FRequestInfo.RawHeaders.Values[string(Name)]);
  405. end;
  406. {$ELSE}
  407. function TIdHTTPAppRequest.GetFieldByName(const Name: string): string;
  408. begin
  409. Result := FRequestInfo.RawHeaders.Values[Name];
  410. end;
  411. {$ENDIF}
  412. function TIdHTTPAppRequest.ReadClient(var Buffer{$IFDEF CLR}: TBytes{$ENDIF};
  413. Count: Integer): Integer;
  414. begin
  415. {$IFDEF CLR}
  416. Result := TIdStreamHelper.ReadBytes(FContentStream, Buffer, Count);
  417. {$ELSE}
  418. Result := FContentStream.Read(Buffer, Count);
  419. {$ENDIF}
  420. // well, it shouldn't be less than 0. but let's not take chances
  421. if Result < 0 then begin
  422. Result := 0;
  423. end;
  424. end;
  425. function TIdHTTPAppRequest.ReadString(Count: Integer): {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF};
  426. {$IFDEF WBB_ANSI}
  427. var
  428. LBytes: TIdBytes;
  429. {$ENDIF}
  430. begin
  431. {$IFDEF WBB_ANSI}
  432. // RLebeau 2/21/2009: not using ReadStringFromStream() anymore. Since
  433. // this method returns an AnsiString, the stream data should not be
  434. // decoded to Unicode and then converted to Ansi. That can lose
  435. // characters.
  436. // Result := AnsiString(ReadStringFromStream(FContentStream, Count));
  437. LBytes := nil;
  438. TIdStreamHelper.ReadBytes(FContentStream, LBytes, Count);
  439. {$IFDEF DOTNET}
  440. // RLebeau: how to handle this correctly in .NET?
  441. Result := AnsiString(BytesToStringRaw(LBytes));
  442. {$ELSE}
  443. SetString(Result, PAnsiChar(LBytes), Length(LBytes));
  444. {$IFDEF HAS_SetCodePage}
  445. // RLebeau 2/21/2009: For D2009+, the AnsiString payload should have
  446. // the proper codepage assigned to it as well so it can be converted
  447. // correctly if assigned to other string variables later on...
  448. SetCodePage(PRawByteString(@Result)^, CharsetToCodePage(FRequestInfo.CharSet), False);
  449. {$ENDIF}
  450. {$ENDIF}
  451. {$ELSE}
  452. // RLebeau 1/15/2016: this method now returns a UnicodeString, so
  453. // lets use ReadStringFromStream() once again...
  454. Result := ReadStringFromStream(FContentStream, Count, CharsetToEncoding(FRequestInfo.CharSet));
  455. {$ENDIF}
  456. end;
  457. function TIdHTTPAppRequest.TranslateURI(const URI: string): string;
  458. begin
  459. // we don't have the concept of a path translation. It's not quite clear
  460. // what to do about this. Comments welcome ([email protected])
  461. Result := URI;
  462. end;
  463. {$IFDEF VCL_6_OR_ABOVE_OR_CLR}
  464. function TIdHTTPAppRequest.WriteHeaders(StatusCode: Integer; const ReasonString, Headers: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}): Boolean;
  465. begin
  466. FResponseInfo.ResponseNo := StatusCode;
  467. FResponseInfo.ResponseText := {$IFDEF WBB_ANSI}string(ReasonString){$ELSE}ReasonString{$ENDIF};
  468. FResponseInfo.CustomHeaders.Add({$IFDEF WBB_ANSI}string(Headers){$ELSE}Headers{$ENDIF});
  469. FResponseInfo.WriteHeader;
  470. Result := True;
  471. end;
  472. {$ENDIF}
  473. function TIdHTTPAppRequest.WriteString(const AString: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}): Boolean;
  474. begin
  475. FThread.Connection.IOHandler.Write({$IFDEF WBB_ANSI}string(AString){$ELSE}AString{$ENDIF});
  476. Result := True;
  477. end;
  478. function TIdHTTPAppRequest.WriteClient(var ABuffer; ACount: Integer): Integer;
  479. var
  480. LBuffer: TIdBytes;
  481. begin
  482. SetLength(LBuffer, ACount);
  483. {$IFNDEF CLR}
  484. Move(ABuffer, LBuffer[0], ACount);
  485. {$ELSE}
  486. // RLebeau: this can't be right? It is interpretting the source as a
  487. // null-terminated character string, which is likely not the case...
  488. CopyTIdBytes(ToBytes(string(ABuffer)), 0, LBuffer, 0, ACount);
  489. {$ENDIF}
  490. FThread.Connection.IOHandler.Write(LBuffer);
  491. Result := ACount;
  492. end;
  493. { TIdHTTPAppResponse }
  494. constructor TIdHTTPAppResponse.Create(AHTTPRequest: TWebRequest; AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  495. begin
  496. FThread := AThread;
  497. FRequestInfo := ARequestInfo;
  498. FResponseInfo := AResponseInfo;
  499. inherited Create(AHTTPRequest);
  500. if Length(FHTTPRequest.ProtocolVersion) = 0 then begin
  501. Version := '1.0'; {do not localize}
  502. end;
  503. StatusCode := 200;
  504. LastModified := -1;
  505. Expires := -1;
  506. Date := -1;
  507. // RLebeau 8/13/2015: no longer setting a default ContentType here. Doing so
  508. // sets a default CharSet, which would get carried over if the user assigns a
  509. // new *non-text* ContentType without an explicit charset. TAppResponse does
  510. // not expose access to the FResponseInfo.CharSet property. For example, if
  511. // the user sets TAppResponse.ContentType to 'image/jpeg', the resulting
  512. // Content-Type header woud be 'image/jpeg; charset=ISO-8859-1', which can
  513. // cause problems for some clients. Besides, TIdHTTPResponseInfo.WriteHeader()
  514. // sets the ContentType to 'text/html; charset=ISO-8859-1' if no ContentType
  515. // has been provided but there is ContentText/ContentStream data, so this is
  516. // redundant here anyway...
  517. //
  518. // ContentType := 'text/html'; {do not localize}
  519. end;
  520. {$UNDEF CONVERT_UNICODE_TO_ANSI}
  521. {$IFDEF WBB_ANSI}
  522. {$IFDEF STRING_IS_UNICODE}
  523. {$DEFINE CONVERT_UNICODE_TO_ANSI}
  524. {$ENDIF}
  525. {$ENDIF}
  526. function TIdHTTPAppResponse.GetContent: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF};
  527. {$IFDEF CONVERT_UNICODE_TO_ANSI}
  528. var
  529. LBytes: TIdBytes;
  530. {$ENDIF}
  531. begin
  532. {$IFDEF CONVERT_UNICODE_TO_ANSI}
  533. // RLebeau 2/21/2009: encode the content using the specified charset.
  534. Result := '';
  535. LBytes := CharsetToEncoding(FResponseInfo.CharSet).GetBytes(FResponseInfo.ContentText);
  536. {$IFDEF DOTNET}
  537. // RLebeau: how to handle this correctly in .NET?
  538. Result := AnsiString(BytesToStringRaw(LBytes));
  539. {$ELSE}
  540. SetString(Result, PAnsiChar(LBytes), Length(LBytes));
  541. {$IFDEF HAS_SetCodePage}
  542. // RLebeau 2/21/2009: for D2009+, the AnsiString payload should have
  543. // the proper codepage assigned to it as well so it can be converted
  544. // correctly if assigned to other string variables later on...
  545. SetCodePage(PRawByteString(@Result)^, CharsetToCodePage(FResponseInfo.CharSet), False);
  546. {$ENDIF}
  547. {$ENDIF}
  548. {$ELSE}
  549. Result := FResponseInfo.ContentText;
  550. {$ENDIF}
  551. end;
  552. function TIdHTTPAppResponse.GetLogMessage: string;
  553. begin
  554. Result := '';
  555. end;
  556. function TIdHTTPAppResponse.GetStatusCode: Integer;
  557. begin
  558. Result := FResponseInfo.ResponseNo;
  559. end;
  560. function TIdHTTPAppResponse.GetDateVariable(Index: Integer): TDateTime;
  561. // WebBroker apps are responsible for conversion to GMT, Indy HTTP server expects apps to pas local time
  562. function ToGMT(ADateTime: TDateTime): TDateTime;
  563. begin
  564. Result := ADateTime;
  565. if Result <> -1 then
  566. Result := LocalTimeToUTCTime(Result);
  567. end;
  568. begin
  569. //TODO: resource string these
  570. case Index of
  571. INDEX_RESP_Date : Result := ToGMT(FResponseInfo.Date);
  572. INDEX_RESP_Expires : Result := ToGMT(FResponseInfo.Expires);
  573. INDEX_RESP_LastModified : Result := ToGMT(FResponseInfo.LastModified);
  574. else
  575. raise EWBBInvalidIdxGetDateVariable.Create( Format( RSWBBInvalidIdxGetDateVariable,[inttostr(Index)]));
  576. end;
  577. end;
  578. procedure TIdHTTPAppResponse.SetDateVariable(Index: Integer; const Value: TDateTime);
  579. // WebBroker apps are responsible for conversion to GMT, Indy HTTP server expects apps to pas local time
  580. function ToLocal(ADateTime: TDateTime): TDateTime;
  581. begin
  582. Result := ADateTime;
  583. if Result <> -1 then
  584. Result := UTCTimeToLocalTime(Result);
  585. end;
  586. begin
  587. //TODO: resource string these
  588. case Index of
  589. INDEX_RESP_Date : FResponseInfo.Date := ToLocal(Value);
  590. INDEX_RESP_Expires : FResponseInfo.Expires := ToLocal(Value);
  591. INDEX_RESP_LastModified : FResponseInfo.LastModified := ToLocal(Value);
  592. else
  593. raise EWBBInvalidIdxSetDateVariable.Create(Format(RSWBBInvalidIdxSetDateVariable,[inttostr(Index) ]));
  594. end;
  595. end;
  596. function TIdHTTPAppResponse.GetIntegerVariable(Index: Integer): {$IFDEF WBB_BIG_INTS}Int64{$ELSE}Integer{$ENDIF};
  597. begin
  598. //TODO: resource string these
  599. case Index of
  600. INDEX_RESP_ContentLength: Result := FResponseInfo.ContentLength;
  601. else
  602. raise EWBBInvalidIdxGetIntVariable.Create( Format( RSWBBInvalidIdxGetIntVariable,[inttostr(Index)]));
  603. end;
  604. end;
  605. procedure TIdHTTPAppResponse.SetIntegerVariable(Index: Integer;
  606. Value: {$IFDEF WBB_BIG_INTS}Int64{$ELSE}Integer{$ENDIF});
  607. begin
  608. //TODO: resource string these
  609. case Index of
  610. INDEX_RESP_ContentLength: FResponseInfo.ContentLength := Value;
  611. else
  612. raise EWBBInvalidIdxSetIntVariable.Create( Format(RSWBBInvalidIdxSetIntVariable,[inttostr(Index)])); {do not localize}
  613. end;
  614. end;
  615. function TIdHTTPAppResponse.GetStringVariable(Index: Integer): {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF};
  616. var
  617. LValue: string;
  618. begin
  619. // RLebeau 1/15/2016: On Delphi versions prior to 10.1 Berlin, this method
  620. // returned an AnsiString, even in Unicode versions. So as not to have to
  621. // IFDEF all of these fields, now doing one conversion at the end of this
  622. // method, which means having a local String variable...
  623. //TODO: resource string these
  624. case Index of
  625. INDEX_RESP_Version : LValue := FRequestInfo.Version;
  626. INDEX_RESP_ReasonString : LValue := FResponseInfo.ResponseText;
  627. INDEX_RESP_Server : LValue := FResponseInfo.Server;
  628. INDEX_RESP_WWWAuthenticate : LValue := FResponseInfo.WWWAuthenticate.Text;
  629. INDEX_RESP_Realm : LValue := FResponseInfo.AuthRealm;
  630. INDEX_RESP_Allow : LValue := FResponseInfo.CustomHeaders.Values['Allow']; {do not localize}
  631. INDEX_RESP_Location : LValue := FResponseInfo.Location;
  632. INDEX_RESP_ContentEncoding : LValue := FResponseInfo.ContentEncoding;
  633. INDEX_RESP_ContentType :
  634. begin
  635. if FContentType <> '' then begin
  636. Result := FContentType;
  637. Exit;
  638. end;
  639. LValue := FResponseInfo.ContentType;
  640. end;
  641. INDEX_RESP_ContentVersion : LValue := FResponseInfo.ContentVersion;
  642. INDEX_RESP_DerivedFrom : LValue := FResponseInfo.CustomHeaders.Values['Derived-From']; {do not localize}
  643. INDEX_RESP_Title : LValue := FResponseInfo.CustomHeaders.Values['Title']; {do not localize}
  644. else
  645. raise EWBBInvalidIdxGetStrVariable.Create(Format(RSWBBInvalidIdxGetStrVariable,[ IntToStr(Index)]));
  646. end;
  647. Result := {$IFDEF WBB_ANSI}AnsiString(LValue){$ELSE}LValue{$ENDIF};
  648. end;
  649. procedure TIdHTTPAppResponse.SetStringVariable(Index: Integer; const Value: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF});
  650. var
  651. LValue: string;
  652. begin
  653. LValue := {$IFDEF WBB_ANSI}string(Value){$ELSE}Value{$ENDIF};
  654. //TODO: resource string these
  655. case Index of
  656. INDEX_RESP_Version : EWBBInvalidStringVar.Create(RSWBBInvalidStringVar); // RLebeau: shouldn't this be calling 'raise'?
  657. INDEX_RESP_ReasonString : FResponseInfo.ResponseText := LValue;
  658. INDEX_RESP_Server : FResponseInfo.Server := LValue;
  659. INDEX_RESP_WWWAuthenticate : FResponseInfo.WWWAuthenticate.Text := LValue;
  660. INDEX_RESP_Realm : FResponseInfo.AuthRealm := LValue;
  661. INDEX_RESP_Allow : FResponseInfo.CustomHeaders.Values['Allow'] := LValue; {do not localize}
  662. INDEX_RESP_Location : FResponseInfo.Location := LValue;
  663. INDEX_RESP_ContentEncoding : FResponseInfo.ContentEncoding := LValue;
  664. INDEX_RESP_ContentType :
  665. begin
  666. FResponseInfo.ContentType := LValue;
  667. FContentType := Value; // using the original input variable, not the converted local variable
  668. end;
  669. INDEX_RESP_ContentVersion : FResponseInfo.ContentVersion := LValue;
  670. INDEX_RESP_DerivedFrom : FResponseInfo.CustomHeaders.Values['Derived-From'] := LValue; {do not localize}
  671. INDEX_RESP_Title : FResponseInfo.CustomHeaders.Values['Title'] := LValue; {do not localize}
  672. else
  673. raise EWBBInvalidIdxSetStringVar.Create( Format(RSWBBInvalidIdxSetStringVar,[IntToStr(Index)])); {do not localize}
  674. end;
  675. end;
  676. procedure TIdHTTPAppResponse.SendRedirect(const URI: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF});
  677. begin
  678. FSent := True;
  679. MoveCookiesAndCustomHeaders;
  680. FResponseInfo.Redirect({$IFDEF WBB_ANSI}string(URI){$ELSE}URI{$ENDIF});
  681. end;
  682. procedure TIdHTTPAppResponse.SendResponse;
  683. begin
  684. FSent := True;
  685. // Reset to -1 so Indy will auto set it
  686. FResponseInfo.ContentLength := -1;
  687. MoveCookiesAndCustomHeaders;
  688. {$IFDEF VCL_10_1_OR_ABOVE}
  689. // TODO: This code may not be in the correct location.
  690. if (FResponseInfo.ContentType = '') and
  691. ((FResponseInfo.ContentText <> '') or (Assigned(FResponseInfo.ContentStream))) and
  692. (HTTPApp.DefaultCharSet <> '') then
  693. begin
  694. // Indicate how to convert UTF16 when write.
  695. ContentType := Format('text/html; charset=%s', [HTTPApp.DefaultCharSet]); {Do not Localize}
  696. end;
  697. {$ENDIF}
  698. FResponseInfo.WriteContent;
  699. end;
  700. procedure TIdHTTPAppResponse.SendStream(AStream: TStream);
  701. begin
  702. FThread.Connection.IOHandler.Write(AStream);
  703. end;
  704. function TIdHTTPAppResponse.Sent: Boolean;
  705. begin
  706. Result := FSent;
  707. end;
  708. {$UNDEF CONVERT_ANSI_TO_UNICODE}
  709. {$IFDEF WBB_ANSI}
  710. {$IFDEF STRING_IS_UNICODE}
  711. {$DEFINE CONVERT_ANSI_TO_UNICODE}
  712. {$ENDIF}
  713. {$ENDIF}
  714. procedure TIdHTTPAppResponse.SetContent(const AValue: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF});
  715. {$IFDEF CONVERT_ANSI_TO_UNICODE}
  716. var
  717. LValue : string;
  718. {$ENDIF}
  719. begin
  720. {$IFDEF CONVERT_ANSI_TO_UNICODE}
  721. // AValue contains Encoded bytes
  722. if AValue <> '' then begin
  723. // RLebeau 3/28/2013: decode the content using the specified charset.
  724. if FResponseInfo.CharSet <> '' then begin
  725. LValue := CharsetToEncoding(FResponseInfo.CharSet).GetString(
  726. {$IFDEF DOTNET}
  727. RawToBytes(PAnsiChar(AValue)^, Length(AValue))
  728. {$ELSE}
  729. PByte(PAnsiChar(AValue)), Length(AValue)
  730. {$ENDIF}
  731. );
  732. end else begin
  733. LValue := string(AValue);
  734. end;
  735. end;
  736. FResponseInfo.ContentText := LValue;
  737. // TODO: use Length(AValue) instead, as the ContentText *should* get re-encoded
  738. // back to the same value as AValue when transmitted. Or, just set ContentLength
  739. // to -1 and let Indy calculate it later...
  740. FResponseInfo.ContentLength := Length(LValue);
  741. {$ELSE}
  742. FResponseInfo.ContentText := AValue;
  743. FResponseInfo.ContentLength := Length(AValue);
  744. {$ENDIF}
  745. end;
  746. procedure TIdHTTPAppResponse.SetLogMessage(const Value: string);
  747. begin
  748. // logging not supported
  749. end;
  750. procedure TIdHTTPAppResponse.SetStatusCode(AValue: Integer);
  751. begin
  752. FResponseInfo.ResponseNo := AValue;
  753. end;
  754. procedure TIdHTTPAppResponse.SetContentStream(AValue: TStream);
  755. begin
  756. inherited;
  757. FResponseInfo.ContentStream := AValue;
  758. end;
  759. function DoHTTPEncode(const AStr: {$IFDEF WBB_ANSI}AnsiString{$ELSE}string{$ENDIF}): String;
  760. begin
  761. {$IFDEF HAS_TNetEncoding}
  762. Result := TNetEncoding.URL.Encode(string(AStr));
  763. {$ELSE}
  764. Result := String(HTTPEncode(AStr));
  765. {$ENDIF}
  766. end;
  767. procedure TIdHTTPAppResponse.MoveCookiesAndCustomHeaders;
  768. var
  769. i: Integer;
  770. LSrcCookie: TCookie;
  771. LDestCookie: TIdCookie;
  772. begin
  773. for i := 0 to Cookies.Count - 1 do begin
  774. LSrcCookie := Cookies[i];
  775. LDestCookie := FResponseInfo.Cookies.Add;
  776. LDestCookie.CookieName := DoHTTPEncode(LSrcCookie.Name);
  777. LDestCookie.Value := DoHTTPEncode(LSrcCookie.Value);
  778. LDestCookie.Domain := String(LSrcCookie.Domain);
  779. LDestCookie.Path := String(LSrcCookie.Path);
  780. LDestCookie.Expires := LSrcCookie.Expires;
  781. LDestCookie.Secure := LSrcCookie.Secure;
  782. {$IFDEF VCL_10_2_OR_ABOVE}
  783. LDestCookie.HttpOnly := LSrcCookie.HttpOnly;
  784. {$ENDIF}
  785. {$IFDEF VCL_10_4_UPDATE2_OR_ABOVE}
  786. LDestCookie.SameSite := LSrcCookie.SameSite;
  787. {$ENDIF}
  788. end;
  789. FResponseInfo.CustomHeaders.Clear;
  790. FResponseInfo.CustomHeaders.AddStdValues(CustomHeaders);
  791. end;
  792. { TIdHTTPWebBrokerBridge }
  793. procedure TIdHTTPWebBrokerBridge.DoCommandOther(AThread: TIdContext;
  794. ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  795. begin
  796. DoCommandGet(AThread, ARequestInfo, AResponseInfo);
  797. end;
  798. procedure TIdHTTPWebBrokerBridge.InitComponent;
  799. begin
  800. inherited InitComponent;
  801. // FOkToProcessCommand := True;
  802. end;
  803. type
  804. TIdHTTPWebBrokerBridgeRequestHandler = class(TWebRequestHandler)
  805. {$IFDEF HAS_CLASSVARS}
  806. private
  807. class var FWebRequestHandler: TIdHTTPWebBrokerBridgeRequestHandler;
  808. {$ENDIF}
  809. public
  810. constructor Create(AOwner: TComponent); override;
  811. {$IFDEF HAS_CLASSVARS}
  812. {$IFDEF HAS_CLASSDESTRUCTOR}
  813. class destructor Destroy;
  814. {$ENDIF}
  815. {$ENDIF}
  816. destructor Destroy; override;
  817. procedure Run(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  818. end;
  819. {$IFNDEF HAS_CLASSVARS}
  820. var
  821. IndyWebRequestHandler: TIdHTTPWebBrokerBridgeRequestHandler = nil;
  822. {$ENDIF}
  823. { TIdHTTPWebBrokerBridgeRequestHandler }
  824. procedure TIdHTTPWebBrokerBridgeRequestHandler.Run(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  825. var
  826. LRequest: TIdHTTPAppRequest;
  827. LResponse: TIdHTTPAppResponse;
  828. begin
  829. try
  830. LRequest := TIdHTTPAppRequest.Create(AThread, ARequestInfo, AResponseInfo);
  831. try
  832. LResponse := TIdHTTPAppResponse.Create(LRequest, AThread, ARequestInfo, AResponseInfo);
  833. try
  834. // WebBroker will free it and we cannot change this behaviour
  835. AResponseInfo.FreeContentStream := False;
  836. HandleRequest(LRequest, LResponse);
  837. finally
  838. FreeAndNil(LResponse);
  839. end;
  840. finally
  841. FreeAndNil(LRequest);
  842. end;
  843. except
  844. // Let Indy handle this exception
  845. raise;
  846. end;
  847. end;
  848. constructor TIdHTTPWebBrokerBridgeRequestHandler.Create(AOwner: TComponent);
  849. begin
  850. inherited;
  851. Classes.ApplicationHandleException := HandleException;
  852. end;
  853. destructor TIdHTTPWebBrokerBridgeRequestHandler.Destroy;
  854. begin
  855. Classes.ApplicationHandleException := nil;
  856. inherited;
  857. end;
  858. {$IFDEF HAS_CLASSVARS}
  859. {$IFDEF HAS_CLASSDESTRUCTOR}
  860. class destructor TIdHTTPWebBrokerBridgeRequestHandler.Destroy;
  861. begin
  862. FreeAndNil(FWebRequestHandler);
  863. end;
  864. {$ENDIF}
  865. {$ENDIF}
  866. function IdHTTPWebBrokerBridgeRequestHandler: TWebRequestHandler;
  867. begin
  868. {$IFDEF HAS_CLASSVARS}
  869. if not Assigned(TIdHTTPWebBrokerBridgeRequestHandler.FWebRequestHandler) then
  870. TIdHTTPWebBrokerBridgeRequestHandler.FWebRequestHandler := TIdHTTPWebBrokerBridgeRequestHandler.Create(nil);
  871. Result := TIdHTTPWebBrokerBridgeRequestHandler.FWebRequestHandler;
  872. {$ELSE}
  873. if not Assigned(IndyWebRequestHandler) then
  874. IndyWebRequestHandler := TIdHTTPWebBrokerBridgeRequestHandler.Create(nil);
  875. Result := IndyWebRequestHandler;
  876. {$ENDIF}
  877. end;
  878. procedure TIdHTTPWebBrokerBridge.DoCommandGet(AThread: TIdContext;
  879. ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  880. begin
  881. if FWebModuleClass <> nil then begin
  882. // FWebModuleClass, RegisterWebModuleClass supported for backward compatability
  883. RunWebModuleClass(AThread, ARequestInfo, AResponseInfo)
  884. end else
  885. begin
  886. {$IFDEF HAS_CLASSVARS}
  887. TIdHTTPWebBrokerBridgeRequestHandler.FWebRequestHandler.Run(AThread, ARequestInfo, AResponseInfo);
  888. {$ELSE}
  889. IndyWebRequestHandler.Run(AThread, ARequestInfo, AResponseInfo);
  890. {$ENDIF}
  891. end;
  892. end;
  893. procedure TIdHTTPWebBrokerBridge.RunWebModuleClass(AThread: TIdContext;
  894. ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  895. var
  896. LRequest: TIdHTTPAppRequest;
  897. LResponse: TIdHTTPAppResponse;
  898. LWebModule: TCustomWebDispatcher;
  899. {$IFDEF VCL_6_OR_ABOVE}
  900. WebRequestHandler: IWebRequestHandler;
  901. {$ENDIF}
  902. Handled: Boolean;
  903. begin
  904. LRequest := TIdHTTPAppRequest.Create(AThread, ARequestInfo, AResponseInfo);
  905. try
  906. LResponse := TIdHTTPAppResponse.Create(LRequest, AThread, ARequestInfo, AResponseInfo);
  907. try
  908. // WebBroker will free it and we cannot change this behaviour
  909. AResponseInfo.FreeContentStream := False;
  910. // There are better ways in D6, but this works in D5
  911. LWebModule := FWebModuleClass.Create(nil) as TCustomWebDispatcher;
  912. try
  913. {$IFDEF VCL_6_OR_ABOVE}
  914. if Supports(LWebModule, IWebRequestHandler, WebRequestHandler) then begin
  915. try
  916. Handled := WebRequestHandler.HandleRequest(LRequest, LResponse);
  917. finally
  918. WebRequestHandler := nil;
  919. end;
  920. end else begin
  921. {$I IdObjectChecksOff.inc}
  922. Handled := TWebDispatcherAccess(LWebModule).DispatchAction(LRequest, LResponse);
  923. {$I IdObjectChecksOn.inc}
  924. end;
  925. {$ELSE}
  926. {$I IdObjectChecksOff.inc}
  927. Handled := TWebDispatcherAccess(LWebModule).DispatchAction(LRequest, LResponse);
  928. {$I IdObjectChecksOn.inc}
  929. {$ENDIF}
  930. if Handled and (not LResponse.Sent) then begin
  931. LResponse.SendResponse;
  932. end;
  933. finally
  934. FreeAndNil(LWebModule);
  935. end;
  936. finally
  937. FreeAndNil(LResponse);
  938. end;
  939. finally
  940. FreeAndNil(LRequest);
  941. end;
  942. end;
  943. // FWebModuleClass, RegisterWebModuleClass supported for backward compatability
  944. // Instead set WebModuleClass using: WebReq.WebRequestHandler.WebModuleClass := TWebModule1;
  945. procedure TIdHTTPWebBrokerBridge.RegisterWebModuleClass(AClass: TComponentClass);
  946. begin
  947. FWebModuleClass := AClass;
  948. end;
  949. initialization
  950. WebReq.WebRequestHandlerProc := IdHTTPWebBrokerBridgeRequestHandler;
  951. {$IFDEF HAS_CLASSVARS}
  952. {$IFNDEF HAS_CLASSDESTRUCTOR}
  953. finalization
  954. FreeAndNil(TIdHTTPWebBrokerBridgeRequestHandler.FWebRequestHandler);
  955. {$ENDIF}
  956. {$ELSE}
  957. finalization
  958. FreeAndNil(IndyWebRequestHandler);
  959. {$ENDIF}
  960. end.