IdHTTPProxyServer.pas 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 13890: IdHTTPProxyServer.pas
  11. {
  12. { Rev 1.4 10/14/2004 2:07:40 PM BGooijen
  13. { changed WriteHeader to WriteStrings
  14. }
  15. {
  16. { Rev 1.3 10/14/2004 1:44:04 PM BGooijen
  17. { reverted back to 1.1
  18. }
  19. {
  20. { Rev 1.1 10/14/2004 1:42:00 PM BGooijen
  21. { Ported back from I10
  22. }
  23. {
  24. { Rev 1.0 2002.11.22 8:37:16 PM czhower
  25. }
  26. unit IdHTTPProxyServer;
  27. interface
  28. {
  29. Indy HTTP proxy Server
  30. Original Programmer: Bas Gooijen ([email protected])
  31. Current Maintainer: Bas Gooijen
  32. Code is given to the Indy Pit Crew.
  33. Modifications by Chad Z. Hower (Kudzu)
  34. Quick Notes:
  35. Revision History:
  36. 10-May-2002: Created Unit.
  37. }
  38. uses
  39. Classes,
  40. IdAssignedNumbers,
  41. IdGlobal,
  42. IdTCPConnection,
  43. IdTCPServer,
  44. IdHeaderList;
  45. const
  46. IdPORT_HTTPProxy = 8080;
  47. type
  48. { not needed (yet)
  49. TIdHTTPProxyServerThread = class( TIdPeerThread )
  50. protected
  51. // what needs to be stored...
  52. fUser: string;
  53. fPassword: string;
  54. public
  55. constructor Create( ACreateSuspended: Boolean = True ) ; override;
  56. destructor Destroy; override;
  57. // Any functions for vars
  58. property Username: string read fUser write fUser;
  59. property Password: string read fPassword write fPassword;
  60. end;
  61. }
  62. TIdHTTPProxyServer = class;
  63. TOnHTTPDocument = procedure(ASender: TIdHTTPProxyServer; const ADocument: string;
  64. var VStream: TStream; const AHeaders: TIdHeaderList) of object;
  65. TIdHTTPProxyServer = class(TIdTcpServer)
  66. protected
  67. FOnHTTPDocument: TOnHTTPDocument;
  68. // CommandHandlers
  69. procedure CommandGET(ASender: TIdCommand);
  70. procedure CommandPOST(ASender: TIdCommand);
  71. procedure CommandHEAD(ASender: TIdCommand);
  72. procedure CommandConnect(ASender: TIdCommand); // for ssl
  73. procedure DoHTTPDocument(const ADocument: string; var VStream: TStream; const AHeaders: TIdHeaderList);
  74. procedure InitializeCommandHandlers; override;
  75. procedure TransferData(ASrc: TIdTCPConnection; ADest: TIdTCPConnection; const ADocument: string;
  76. const ASize: Integer; const AHeaders: TIdHeaderList);
  77. public
  78. constructor Create( AOwner: TComponent ) ; override;
  79. published
  80. property DefaultPort default IdPORT_HTTPProxy;
  81. property OnHTTPDocument: TOnHTTPDocument read FOnHTTPDocument write FOnHTTPDocument;
  82. end;
  83. // Procs
  84. procedure Register;
  85. implementation
  86. uses
  87. IdResourceStrings,
  88. IdRFCReply,
  89. IdTCPClient,
  90. IdURI,
  91. SysUtils;
  92. procedure Register;
  93. begin
  94. RegisterComponents('Indy 10', [TIdHTTPProxyServer]);
  95. end;
  96. procedure TIdHTTPProxyServer.InitializeCommandHandlers;
  97. begin
  98. inherited;
  99. with CommandHandlers.Add do begin
  100. Command := 'GET'; {do not localize}
  101. OnCommand := CommandGet;
  102. ParseParams := True;
  103. Disconnect := true;
  104. end;
  105. with CommandHandlers.Add do
  106. begin
  107. Command := 'POST'; {do not localize}
  108. OnCommand := CommandPOST;
  109. ParseParams := True;
  110. Disconnect := true;
  111. end;
  112. with CommandHandlers.Add do
  113. begin
  114. Command := 'HEAD'; {do not localize}
  115. OnCommand := CommandHEAD;
  116. ParseParams := True;
  117. Disconnect := true;
  118. end;
  119. with CommandHandlers.Add do
  120. begin
  121. Command := 'CONNECT'; {do not localize}
  122. OnCommand := Commandconnect;
  123. ParseParams := True;
  124. Disconnect := true;
  125. end;
  126. //HTTP Servers/Proxies do not send a greeting
  127. Greeting.Clear;
  128. end;
  129. procedure TIdHTTPProxyServer.TransferData(
  130. ASrc: TIdTCPConnection;
  131. ADest: TIdTCPConnection;
  132. const ADocument: string;
  133. const ASize: Integer;
  134. const AHeaders: TIdHeaderList
  135. );
  136. //TODO: This captures then sends. This is great and we need this as an option for proxies that
  137. // modify data. However we also need another option that writes as it captures.
  138. // Two modes? Intercept and not?
  139. var
  140. LStream: TStream;
  141. begin
  142. //TODO: Have an event to let the user perform stream creation
  143. LStream := TMemoryStream.Create; try
  144. ASrc.ReadStream(LStream, ASize, ASize = -1);
  145. LStream.Position := 0;
  146. DoHTTPDocument(ADocument, LStream, AHeaders);
  147. // Need to recreate IdStream, DoHTTPDocument passes it as a var and user can change the
  148. // stream that is returned
  149. ADest.WriteStream(LStream);
  150. finally FreeAndNil(LStream); end;
  151. end;
  152. procedure TIdHTTPProxyServer.CommandGET( ASender: TIdCommand ) ;
  153. var
  154. LClient: TIdTCPClient;
  155. LDocument: string;
  156. LHeaders: TIdHeaderList;
  157. LRemoteHeaders: TIdHeaderList;
  158. LURI: TIdURI;
  159. LPageSize: Integer;
  160. begin
  161. ASender.PerformReply := false;
  162. LHeaders := TIdHeaderList.Create; try
  163. ASender.Thread.Connection.Capture(LHeaders, '');
  164. LClient := TIdTCPClient.Create(nil); try
  165. LURI := TIdURI.Create(ASender.Params.Strings[0]); try
  166. LClient.Port := StrToIntDef(LURI.Port, 80);
  167. LClient.Host := LURI.Host;
  168. //We have to remove the host and port from the request
  169. LDocument := LURI.Path + LURI.Document + LURI.Params;
  170. finally FreeAndNil(LURI); end;
  171. LClient.Connect; try
  172. LClient.WriteLn('GET ' + LDocument + ' HTTP/1.0'); {Do not Localize}
  173. LClient.WriteStrings(LHeaders);
  174. LClient.WriteLn('');
  175. LRemoteHeaders := TIdHeaderList.Create; try
  176. LClient.Capture(LRemoteHeaders, '');
  177. ASender.Thread.Connection.WriteStrings(LRemoteHeaders);
  178. ASender.Thread.Connection.WriteLn('');
  179. LPageSize := StrToIntDef(LRemoteHeaders.Values['Content-Length'], -1) ; {Do not Localize}
  180. TransferData(LClient, ASender.Thread.Connection, LDocument, LPageSize, LRemoteHeaders);
  181. finally FreeAndNil(LRemoteHeaders); end;
  182. finally LClient.Disconnect; end;
  183. finally FreeAndNil(LClient); end;
  184. finally FreeAndNil(LHeaders); end;
  185. end;
  186. procedure TIdHTTPProxyServer.CommandPOST( ASender: TIdCommand ) ;
  187. var
  188. LClient: TIdTCPClient;
  189. LDocument: string;
  190. LHeaders: TIdHeaderList;
  191. LRemoteHeaders: TIdHeaderList;
  192. LURI: TIdURI;
  193. LPageSize: Integer;
  194. LPostStream: TMemoryStream;
  195. begin
  196. ASender.PerformReply := false;
  197. LHeaders := TIdHeaderList.Create; try
  198. ASender.Thread.Connection.Capture(LHeaders, '');
  199. LPostStream:=tmemorystream.Create;
  200. try
  201. LPostStream.size:=StrToIntDef( LHeaders.Values['Content-Length'], 0 ); {Do not Localize}
  202. ASender.Thread.Connection.ReadStream(LPostStream,LPostStream.Size,false);
  203. LClient := TIdTCPClient.Create(nil); try
  204. LURI := TIdURI.Create(ASender.Params.Strings[0]); try
  205. LClient.Port := StrToIntDef(LURI.Port, 80);
  206. LClient.Host := LURI.Host;
  207. //We have to remove the host and port from the request
  208. LDocument := LURI.Path + LURI.Document + LURI.Params;
  209. finally FreeAndNil(LURI); end;
  210. LClient.Connect; try
  211. LClient.WriteLn('POST ' + LDocument + ' HTTP/1.0'); {Do not Localize}
  212. LClient.WriteStrings(LHeaders);
  213. LClient.WriteLn('');
  214. LClient.WriteStream(LPostStream);
  215. LRemoteHeaders := TIdHeaderList.Create; try
  216. LClient.Capture(LRemoteHeaders, '');
  217. ASender.Thread.Connection.WriteStrings(LRemoteHeaders);
  218. ASender.Thread.Connection.Writeln('');
  219. LPageSize := StrToIntDef(LRemoteHeaders.Values['Content-Length'], -1) ; {Do not Localize}
  220. TransferData(LClient, ASender.Thread.Connection, LDocument, LPageSize, LRemoteHeaders);
  221. finally FreeAndNil(LRemoteHeaders); end;
  222. finally LClient.Disconnect; end;
  223. finally FreeAndNil(LClient); end;
  224. finally FreeAndNil(LPostStream); end;
  225. finally FreeAndNil(LHeaders); end;
  226. end;
  227. procedure TIdHTTPProxyServer.CommandConnect( ASender: TIdCommand ) ;
  228. begin
  229. end;
  230. procedure TIdHTTPProxyServer.CommandHEAD( ASender: TIdCommand ) ;
  231. begin
  232. end;
  233. constructor TIdHTTPProxyServer.Create( AOwner: TComponent ) ;
  234. begin
  235. inherited;
  236. DefaultPort := IdPORT_HTTPProxy;
  237. Greeting.Text.Text := ''; // RS
  238. ReplyUnknownCommand.Text.Text := ''; // RS
  239. end;
  240. procedure TIdHTTPProxyServer.DoHTTPDocument(const ADocument: string; var VStream: TStream; const AHeaders: TIdHeaderList);
  241. begin
  242. if Assigned(OnHTTPDocument) then begin
  243. OnHTTPDocument(Self, ADocument, VStream, AHeaders);
  244. end;
  245. end;
  246. end.