httpclient.pp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. {
  2. $Id$
  3. HTTPClient: HTTP client component
  4. Copyright (C) 2000-2003 by Sebastian Guenther ([email protected])
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. }
  11. unit HTTPClient;
  12. interface
  13. uses Classes, HTTPBase, fpSock, fpAsync;
  14. type
  15. TCustomHTTPClient = class(TCustomTCPClient)
  16. protected
  17. SendBuffer: TAsyncWriteStream;
  18. FOnPrepareSending: TNotifyEvent;
  19. FOnHeaderSent: TNotifyEvent;
  20. FOnStreamSent: TNotifyEvent;
  21. FOnPrepareReceiving: TNotifyEvent;
  22. FOnHeaderReceived: TNotifyEvent;
  23. FOnStreamReceived: TNotifyEvent;
  24. FOnDestroy: TNotifyEvent;
  25. RecvSize: Integer; // How many bytes are still to be read. -1 if unknown.
  26. DataAvailableNotifyHandle: Pointer;
  27. ReceivedHTTPVersion: String;
  28. procedure HeaderToSendCompleted(Sender: TObject);
  29. procedure StreamToSendCompleted(Sender: TObject);
  30. procedure ReceivedHeaderCompleted(Sender: TObject);
  31. procedure ReceivedHeaderEOF(Sender: TObject);
  32. procedure DataAvailable(Sender: TObject);
  33. procedure ReceivedStreamCompleted(Sender: TObject);
  34. property OnPrepareSending: TNotifyEvent read FOnPrepareSending write FOnPrepareSending;
  35. property OnHeaderSent: TNotifyEvent read FOnHeaderSent write FOnHeaderSent;
  36. property OnStreamSent: TNotifyEvent read FOnStreamSent write FOnStreamSent;
  37. property OnPrepareReceiving: TNotifyEvent read FOnPrepareReceiving write FOnPrepareReceiving;
  38. property OnHeaderReceived: TNotifyEvent read FOnHeaderReceived write FOnHeaderReceived;
  39. property OnStreamReceived: TNotifyEvent read FOnStreamReceived write FOnStreamReceived;
  40. property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
  41. public
  42. HeaderToSend: THttpHeader;
  43. StreamToSend: TStream;
  44. ReceivedHeader: THttpHeader;
  45. ReceivedStream: TStream;
  46. DoDestroy: Boolean;
  47. destructor Destroy; override;
  48. procedure Receive;
  49. procedure Send;
  50. end;
  51. THttpClient = class(TCustomHttpClient)
  52. public
  53. property OnPrepareSending;
  54. property OnHeaderSent;
  55. property OnStreamSent;
  56. property OnPrepareReceiving;
  57. property OnHeaderReceived;
  58. property OnStreamReceived;
  59. property OnDestroy;
  60. end;
  61. {TCustomHTTPClient = class
  62. protected
  63. FEventLoop: TEventLoop;
  64. FSocket: TInetSocket;
  65. SendBuffer: TAsyncWriteStream;
  66. FOnPrepareSending: TNotifyEvent;
  67. FOnHeaderSent: TNotifyEvent;
  68. FOnStreamSent: TNotifyEvent;
  69. FOnPrepareReceiving: TNotifyEvent;
  70. FOnHeaderReceived: TNotifyEvent;
  71. FOnStreamReceived: TNotifyEvent;
  72. FOnDestroy: TNotifyEvent;
  73. RecvSize: Integer; // How many bytes are still to be read. -1 if unknown.
  74. DataAvailableNotifyHandle: Pointer;
  75. ReceivedHTTPVersion: String;
  76. procedure HeaderToSendCompleted(Sender: TObject);
  77. procedure StreamToSendCompleted(Sender: TObject);
  78. procedure ReceivedHeaderCompleted(Sender: TObject);
  79. procedure ReceivedHeaderEOF(Sender: TObject);
  80. procedure DataAvailable(Sender: TObject);
  81. procedure ReceivedStreamCompleted(Sender: TObject);
  82. property OnPrepareSending: TNotifyEvent read FOnPrepareSending write FOnPrepareSending;
  83. property OnHeaderSent: TNotifyEvent read FOnHeaderSent write FOnHeaderSent;
  84. property OnStreamSent: TNotifyEvent read FOnStreamSent write FOnStreamSent;
  85. property OnPrepareReceiving: TNotifyEvent read FOnPrepareReceiving write FOnPrepareReceiving;
  86. property OnHeaderReceived: TNotifyEvent read FOnHeaderReceived write FOnHeaderReceived;
  87. property OnStreamReceived: TNotifyEvent read FOnStreamReceived write FOnStreamReceived;
  88. property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
  89. public
  90. HeaderToSend: THttpHeader;
  91. StreamToSend: TStream;
  92. ReceivedHeader: THttpHeader;
  93. ReceivedStream: TStream;
  94. DoDestroy: Boolean;
  95. constructor Create(AEventLoop: TEventLoop; ASocket: TInetSocket);
  96. destructor Destroy; override;
  97. procedure Receive;
  98. procedure Send;
  99. end;}
  100. implementation
  101. uses SysUtils;
  102. procedure TCustomHttpClient.HeaderToSendCompleted(Sender: TObject);
  103. begin
  104. // WriteLn('TCustomHttpClient.HeaderToSendCompleted');
  105. if Assigned(FOnHeaderSent) then
  106. FOnHeaderSent(Self);
  107. if Assigned(StreamToSend) then
  108. begin
  109. SendBuffer := TAsyncWriteStream.Create(EventLoop, Stream);
  110. SendBuffer.CopyFrom(StreamToSend, StreamToSend.Size);
  111. SendBuffer.OnBufferSent := @StreamToSendCompleted;
  112. end else
  113. begin
  114. StreamToSendCompleted(nil);
  115. if DoDestroy then
  116. Self.Free;
  117. end;
  118. end;
  119. procedure TCustomHttpClient.StreamToSendCompleted(Sender: TObject);
  120. begin
  121. // WriteLn('TCustomHttpClient.StreamToSendCompleted');
  122. if Assigned(FOnStreamSent) then
  123. FOnStreamSent(Self);
  124. FreeAndNil(SendBuffer);
  125. if DoDestroy then
  126. Self.Free
  127. else
  128. Receive;
  129. end;
  130. procedure TCustomHttpClient.ReceivedHeaderCompleted(Sender: TObject);
  131. var
  132. BytesInBuffer: Integer;
  133. NeedMoreData: Boolean;
  134. begin
  135. // WriteLn('TCustomHttpClient.ReceivedHeaderCompleted');
  136. ReceivedHeader.DataReceived := False;
  137. ReceivedHTTPVersion := ReceivedHeader.HttpVersion;
  138. BytesInBuffer := ReceivedHeader.Reader.BytesInBuffer;
  139. //WriteLn('BytesInBuffer: ', BytesInBuffer, ', Content length: ', ReceivedHeader.ContentLength);
  140. if Assigned(FOnHeaderReceived) then
  141. FOnHeaderReceived(Self);
  142. RecvSize := ReceivedHeader.ContentLength;
  143. if Assigned(ReceivedStream) then
  144. begin
  145. if BytesInBuffer = 0 then
  146. NeedMoreData := True
  147. else
  148. begin
  149. ReceivedStream.Write(ReceivedHeader.Reader.Buffer^, BytesInBuffer);
  150. if RecvSize > 0 then
  151. Dec(RecvSize, BytesInBuffer);
  152. if BytesInBuffer = ReceivedHeader.ContentLength then
  153. NeedMoreData := False
  154. else
  155. NeedMoreData := (not ReceivedHeader.InheritsFrom(THttpRequestHeader)) or
  156. (THttpRequestHeader(ReceivedHeader).Command <> 'GET');
  157. end;
  158. end else
  159. NeedMoreData := False;
  160. if NeedMoreData then
  161. DataAvailableNotifyHandle :=
  162. EventLoop.SetDataAvailableNotify(Stream.Handle, @DataAvailable, Stream)
  163. else
  164. ReceivedStreamCompleted(nil);
  165. if DoDestroy then
  166. Self.Free;
  167. end;
  168. procedure TCustomHttpClient.ReceivedHeaderEOF(Sender: TObject);
  169. begin
  170. Self.Free;
  171. end;
  172. procedure TCustomHttpClient.DataAvailable(Sender: TObject);
  173. var
  174. FirstRun: Boolean;
  175. ReadNow, BytesRead: Integer;
  176. buf: array[0..1023] of Byte;
  177. begin
  178. FirstRun := True;
  179. while True do
  180. begin
  181. if RecvSize >= 0 then
  182. begin
  183. ReadNow := RecvSize;
  184. if ReadNow > 1024 then
  185. ReadNow := 1024;
  186. end else
  187. ReadNow := 1024;
  188. BytesRead := Stream.Read(buf, ReadNow);
  189. // WriteLn('TCustomHttpClient.DataAvailable: Read ', BytesRead, ' bytes; RecvSize=', RecvSize);
  190. if BytesRead <= 0 then
  191. begin
  192. if FirstRun then
  193. ReceivedStreamCompleted(nil);
  194. break;
  195. end;
  196. FirstRun := False;
  197. ReceivedStream.Write(buf, BytesRead);
  198. if RecvSize > 0 then
  199. Dec(RecvSize, BytesRead);
  200. if RecvSize = 0 then
  201. begin
  202. ReceivedStreamCompleted(nil);
  203. break;
  204. end;
  205. end;
  206. if DoDestroy then
  207. Self.Free;
  208. end;
  209. procedure TCustomHttpClient.ReceivedStreamCompleted(Sender: TObject);
  210. begin
  211. // WriteLn('TCustomHttpClient.ReceivedStreamCompleted');
  212. if Assigned(DataAvailableNotifyHandle) then
  213. begin
  214. EventLoop.ClearDataAvailableNotify(DataAvailableNotifyHandle);
  215. DataAvailableNotifyHandle := nil;
  216. end;
  217. if Assigned(FOnStreamReceived) then
  218. FOnStreamReceived(Self);
  219. if DoDestroy then
  220. Self.Free
  221. else
  222. Send;
  223. end;
  224. {constructor TCustomHttpClient.Create(AManager: TEventLoop; ASocket: TInetSocket);
  225. begin
  226. inherited Create;
  227. EventLoop := AManager;
  228. Stream := ASocket;
  229. end;}
  230. destructor TCustomHttpClient.Destroy;
  231. begin
  232. if Assigned(DataAvailableNotifyHandle) then
  233. EventLoop.ClearDataAvailableNotify(DataAvailableNotifyHandle);
  234. if Assigned(OnDestroy) then
  235. OnDestroy(Self);
  236. FreeAndNil(SendBuffer);
  237. inherited Destroy;
  238. end;
  239. procedure TCustomHttpClient.Receive;
  240. begin
  241. // Start receiver
  242. ReceivedHttpVersion := '';
  243. if Assigned(OnPrepareReceiving) then
  244. OnPrepareReceiving(Self);
  245. if Assigned(ReceivedHeader) then
  246. begin
  247. ReceivedHeader.OnCompleted := @ReceivedHeaderCompleted;
  248. ReceivedHeader.OnEOF := @ReceivedHeaderEOF;
  249. ReceivedHeader.AsyncReceive(EventLoop, Stream);
  250. end;
  251. end;
  252. procedure TCustomHttpClient.Send;
  253. begin
  254. // Start sender
  255. if Assigned(OnPrepareSending) then
  256. OnPrepareSending(Self);
  257. if Assigned(HeaderToSend) then
  258. begin
  259. if ReceivedHttpVersion <> '' then
  260. begin
  261. HeaderToSend.HttpVersion := ReceivedHttpVersion;
  262. ReceivedHttpVersion := '';
  263. end;
  264. HeaderToSend.OnCompleted := @HeaderToSendCompleted;
  265. HeaderToSend.AsyncSend(EventLoop, Stream);
  266. end;
  267. end;
  268. end.
  269. {
  270. $Log$
  271. Revision 1.2 2004-02-02 17:12:01 sg
  272. * Some small fixes to get the code at least compiling again; the HTTP
  273. client class is not expected to work at the moment, and the XML-RPC
  274. client has been fully disabled for now.
  275. Revision 1.1 2004/01/31 19:13:14 sg
  276. * Splittet old HTTP unit into httpbase and httpclient
  277. * Many improvements in fpSock (e.g. better disconnection detection)
  278. }