custhttpsys.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2017-2018 by the Free Pascal development team
  4. Windows HTTP Server API based TCustomWebApplication
  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 custHTTPSys;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. SysUtils, Classes, HttpApi, custWeb, HTTPDefs;
  16. type
  17. { THTTPSysRequest }
  18. THTTPSysRequest = class(TRequest)
  19. private
  20. fHandle: THandle;
  21. fRequestId: HTTP_REQUEST_ID;
  22. function GetBaseUrl(const aUrl: AnsiString): AnsiString;
  23. procedure FillHeader(aRequest: PHTTP_REQUEST);
  24. procedure FillHTTPVariables(aRequest: PHTTP_REQUEST);
  25. procedure InitFromRequest(aRequest: PHTTP_REQUEST);
  26. protected
  27. procedure ReadContent; override;
  28. public
  29. constructor CreateReq(aHandle: THandle; const aUrl: String; aRequest: PHTTP_REQUEST);
  30. end;
  31. THTTPSysRequestClass = class of THTTPSysRequest;
  32. { THTTPSysResponse }
  33. THTTPSysResponse = class(TResponse)
  34. protected
  35. fHandle: THandle;
  36. fRequestId: HTTP_REQUEST_ID;
  37. fRequestVersion: HTTP_VERSION;
  38. procedure DoSendHeaders(aHeaders: TStrings); override;
  39. procedure DoSendContent; override;
  40. end;
  41. THTTPSysResponseClass = class of THTTPSysResponse;
  42. { THTTPSysHandler }
  43. THTTPSysHandler = class(TWebHandler)
  44. private
  45. fUrls: TStrings;
  46. fHandle: THandle;
  47. fServerSession: HTTP_SERVER_SESSION_ID;
  48. fUrlGroup: HTTP_URL_GROUP_ID;
  49. fBuffer: PHTTP_REQUEST;
  50. fBufferSize: LongWord;
  51. procedure InitUrls;
  52. protected
  53. function CreateRequest(aRequest: PHTTP_REQUEST; const aUrl: String): THTTPSysRequest; virtual;
  54. function CreateResponse(aRequest: THTTPSysRequest): THTTPSysResponse; virtual;
  55. procedure ProcessRequest(aBuffer: PHTTP_REQUEST; aSize: LongWord; out aRequest: TRequest; out aResponse: TResponse);
  56. function WaitForRequest(out aRequest: TRequest; out aResponse: TResponse): Boolean; override;
  57. public
  58. procedure Terminate; override;
  59. constructor Create(AOwner: TComponent); override;
  60. destructor Destroy; override;
  61. end;
  62. THTTPSysHandlerClass = class of THTTPSysHandler;
  63. { TCustomHTTPSysApplication }
  64. TCustomHTTPSysApplication = class(TCustomWebApplication)
  65. private
  66. fUrls: TStrings;
  67. protected
  68. function InitializeWebHandler: TWebHandler; override;
  69. procedure DoRun; override;
  70. public
  71. constructor Create(AOwner: TComponent); override;
  72. destructor Destroy; override;
  73. property Urls: TStrings read fUrls;
  74. end;
  75. EHTTPSys = class(EFPWebError);
  76. var
  77. HTTPSysRequestClass: THTTPSysRequestClass = THTTPSysRequest;
  78. HTTPSysResponseClass: THTTPSysResponseClass = THTTPSysResponse;
  79. HTTPSysHandlerClass: THTTPSysHandlerClass = THTTPSysHandler;
  80. implementation
  81. uses
  82. Windows, httpprotocol, WinSock2;
  83. resourcestring
  84. SErrReceiveRequest = 'Failed to receive HTTP request (Errorcode: 0x%x)';
  85. SErrReceiveRequestBody = 'Failed to receive body of HTTP request (Errorcode: 0x%x)';
  86. SErrSendResponse = 'Failed to send HTTP response (Errorcode: 0x%x)';
  87. SErrSendResponseBody = 'Failed to send body of HTTP response (Errorcode: 0x%x)';
  88. SErrInitializeHttpApi = 'Failed to initialize HTTP API (Errorcode: 0x%x)';
  89. SErrCreateRequestQueue = 'Failed to create request queue (Errorcode: 0x%x)';
  90. SErrCreateServerSession = 'Failed to create server session (Errorcode: 0x%x)';
  91. SErrCreateUrlGroup = 'Failed to create URL group (Errorcode: 0x%x)';
  92. SErrAddUrl = 'Failed to add URL ''%s'' to URL group (Errorcode: 0x%x)';
  93. SErrBindGroupToQueue = 'Failed to bind URL group to queue (Errorcode: 0x%x)';
  94. function HeaderToHttpHeaderId(aHeader: THeader; out aId: HTTP_HEADER_ID): Boolean;
  95. begin
  96. Result := True;
  97. case aHeader of
  98. hhAccept:
  99. aId := HttpHeaderAccept;
  100. hhAcceptCharset:
  101. aId := HttpHeaderAcceptCharset;
  102. hhAcceptEncoding:
  103. aId := HttpHeaderAcceptEncoding;
  104. hhAcceptLanguage:
  105. aId := HttpHeaderAcceptLanguage;
  106. hhAcceptRanges:
  107. aId := HttpHeaderAcceptRanges;
  108. hhAge:
  109. aId := HttpHeaderAge;
  110. hhAllow:
  111. aId := HttpHeaderAllow;
  112. hhAuthorization:
  113. aId := HttpHeaderAuthorization;
  114. hhCacheControl:
  115. aId := HttpHeaderCacheControl;
  116. hhConnection:
  117. aId := HttpHeaderConnection;
  118. hhContentEncoding:
  119. aId := HttpHeaderContentEncoding;
  120. hhContentLanguage:
  121. aId := HttpHeaderContentLanguage;
  122. hhContentLength:
  123. aId := HttpHeaderContentLength;
  124. hhContentLocation:
  125. aId := HttpHeaderContentLocation;
  126. hhContentMD5:
  127. aId := HttpHeaderContentMd5;
  128. hhContentRange:
  129. aId := HttpHeaderContentRange;
  130. hhContentType:
  131. aId := HttpHeaderContentType;
  132. hhDate:
  133. aId := HttpHeaderDate;
  134. hhETag:
  135. aId := HttpHeaderEtag;
  136. hhExpires:
  137. aId := HttpHeaderExpires;
  138. hhExpect:
  139. aId := HttpHeaderExpect;
  140. hhFrom:
  141. aId := HttpHeaderFrom;
  142. hhHost:
  143. aId := HttpHeaderHost;
  144. hhIfMatch:
  145. aId := HttpHeaderIfMatch;
  146. hhIfModifiedSince:
  147. aId := HttpHeaderIfModifiedSince;
  148. hhIfNoneMatch:
  149. aId := HttpHeaderIfNoneMatch;
  150. hhIfRange:
  151. aId := HttpHeaderIfRange;
  152. hhIfUnModifiedSince:
  153. aId := HttpHeaderIfUnmodifiedSince;
  154. hhLastModified:
  155. aId := HttpHeaderLastModified;
  156. hhLocation:
  157. aId := HttpHeaderLocation;
  158. hhMaxForwards:
  159. aId := HttpHeaderMaxForwards;
  160. hhPragma:
  161. aId := HttpHeaderPragma;
  162. //hhProxyAuthenticate: ;
  163. //hhProxyAuthorization: ;
  164. hhRange:
  165. aId := HttpHeaderRange;
  166. hhReferer:
  167. aId := HttpHeaderReferer;
  168. hhRetryAfter:
  169. aId := HttpHeaderRetryAfter;
  170. hhServer:
  171. aId := HttpHeaderServer;
  172. hhTE:
  173. aId := HttpHeaderTe;
  174. hhTrailer:
  175. aId := HttpHeaderTrailer;
  176. hhTransferEncoding:
  177. aId := HttpHeaderTransferEncoding;
  178. hhUpgrade:
  179. aId := HttpHeaderUpgrade;
  180. hhUserAgent:
  181. aId := HttpHeaderUserAgent;
  182. hhVary:
  183. aId := HttpHeaderVary;
  184. hhVia:
  185. aId := HttpHeaderVia;
  186. hhWarning:
  187. aId := HttpHeaderWarning;
  188. hhWWWAuthenticate:
  189. aId := HttpHeaderWwwAuthenticate;
  190. otherwise
  191. Result := False;
  192. end;
  193. end;
  194. function IgnoreHttpHeaderForRequest(aHeader: THeader): Boolean;
  195. begin
  196. case aHeader of
  197. hhAcceptRanges,
  198. hhAge,
  199. hhETag,
  200. hhLocation,
  201. hhProxyAuthenticate,
  202. hhRetryAfter,
  203. hhServer,
  204. hhVary,
  205. hhWWWAuthenticate:
  206. Result := True;
  207. otherwise
  208. Result := False;
  209. end;
  210. end;
  211. { THTTPSysResponse }
  212. Type
  213. TAnsiHeader = record
  214. name : ansistring;
  215. value : ansistring;
  216. end;
  217. procedure THTTPSysResponse.DoSendHeaders(aHeaders: TStrings);
  218. function UnknownHeader(aheader : String; out hh : THeader; out aHeaderID : HTTP_HEADER_ID) : Boolean;
  219. begin
  220. Result:=True;
  221. hh:=HeaderType(aHeader);
  222. if hh = hhUnknown then
  223. Exit;
  224. if not (hdResponse in HTTPHeaderDirections[hh]) then
  225. Exit;
  226. if not HeaderToHttpHeaderId(hh, aHeaderID) then
  227. Exit;
  228. if (aHeaderID>=HttpHeaderResponseMaximum) then
  229. Exit;
  230. Result:=False;
  231. end;
  232. var
  233. resp: HTTP_RESPONSE;
  234. flags, bytessend: LongWord;
  235. i, idx, colonidx: LongInt;
  236. headerline,headerstr, headerval: String;
  237. res: ULONG;
  238. hh: THeader;
  239. headerid: HTTP_HEADER_ID;
  240. hID : Integer;
  241. headerstrs, unknownheaders: TStrings;
  242. unknownheadersarr: array of HTTP_UNKNOWN_HEADER;
  243. knownheaderstrarr : array[0..Ord(HttpHeaderResponseMaximum)] of TAnsiHeader;
  244. unknownheaderstrarr : array of TAnsiHeader;
  245. CT : AnsiString;
  246. begin
  247. {$IF SIZEOF(CHAR)=1}
  248. CT:=CodeText;
  249. {$ELSE}
  250. CT:=UTF8Encode(CodeText);
  251. {$ENDIF}
  252. resp := Default(HTTP_RESPONSE);
  253. resp.Version := fRequestVersion;
  254. resp.StatusCode := Code;
  255. if CodeText <> '' then begin
  256. resp.pReason := PAnsiChar(CT);
  257. resp.ReasonLength := Length(CT);
  258. end;
  259. flags := 0;
  260. if (Assigned(ContentStream) and (ContentStream.Size > 0)) or (Contents.Count > 0) then
  261. flags := flags or HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
  262. // Process known headers
  263. for i := 0 to aHeaders.Count - 1 do begin
  264. headerline:=aHeaders[i];
  265. colonidx := Pos(':', headerline);
  266. if colonidx = 0 then
  267. Continue;
  268. headerstr := Copy(headerline, 1, colonidx - 1);
  269. headerval := Trim(Copy(headerline, colonidx + 1, Length(headerline) - colonidx));
  270. if not UnknownHeader(HeaderStr,hh,headerID) then
  271. begin
  272. HID:=Ord(headerid);
  273. {$if SIZEOF(CHAR)=1}
  274. knownheaderstrarr[HID].value:=HeaderVal;
  275. {$ELSE}
  276. knownheaderstrarr[HID].value:=UTF8Encode(HeaderVal);
  277. {$ENDIF}
  278. resp.Headers.KnownHeaders[HID].RawValueLength := Length(knownheaderstrarr[HID].value);
  279. resp.Headers.KnownHeaders[HID].pRawValue := PAnsiChar(knownheaderstrarr[HID].value);
  280. end;
  281. end;
  282. // Process unknown headers. Start by allocating enough room.
  283. SetLength(unknownheaderstrarr, aheaders.Count);
  284. Idx:=0;
  285. for i := 0 to aheaders.Count - 1 do begin
  286. headerline:=aHeaders[i];
  287. colonidx := Pos(':', headerline);
  288. if colonidx = 0 then
  289. Continue;
  290. headerstr := Copy(headerline, 1, colonidx - 1);
  291. headerval := Trim(Copy(headerline, colonidx + 1, Length(headerline) - colonidx));
  292. if UnknownHeader(HeaderStr,hh,headerID) then begin
  293. {$if SIZEOF(CHAR)=1}
  294. unknownheaderstrarr[Idx].name:=headerstr;
  295. unknownheaderstrarr[Idx].value:=headerval;
  296. {$ELSE}
  297. unknownheaderstrarr[Idx].name:=UTF8Encode(headerstr);
  298. unknownheaderstrarr[Idx].value:=UTF8Encode(headerval);
  299. {$ENDIF}
  300. Inc(Idx);
  301. end;
  302. end;
  303. if Idx > 0 then begin
  304. SetLength(unknownheadersarr,Idx);
  305. For I:=0 to Idx-1 do
  306. begin
  307. unknownheadersarr[I].NameLength := Length(unknownheaderstrarr[i].name);
  308. unknownheadersarr[I].pName := PAnsiChar(unknownheaderstrarr[i].name);
  309. unknownheadersarr[I].RawValueLength :=Length(unknownheaderstrarr[i].value);
  310. unknownheadersarr[I].pRawValue := PAnsiChar(unknownheaderstrarr[i].value);
  311. end;
  312. resp.Headers.UnknownHeaderCount := Idx;
  313. resp.Headers.pUnknownHeaders := @unknownheadersarr[0];
  314. end;
  315. res := HttpSendHttpResponse(fHandle, fRequestId, flags, @resp, Nil, @bytessend, Nil, 0, Nil, Nil);
  316. if res <> NO_ERROR then
  317. raise EHTTPSys.CreateFmtHelp(SErrSendResponse, [res], 500);
  318. end;
  319. procedure THTTPSysResponse.DoSendContent;
  320. var
  321. chunk: HTTP_DATA_CHUNK;
  322. bytessend: LongWord;
  323. memstrm: TMemoryStream;
  324. res: ULONG;
  325. begin
  326. if not (Assigned(ContentStream) and (ContentStream.Size > 0)) and not (Contents.Count > 0) then
  327. Exit;
  328. memstrm := TMemoryStream.Create;
  329. try
  330. if Assigned(ContentStream) then
  331. memstrm.CopyFrom(ContentStream, ContentStream.Size)
  332. else
  333. MemStrm.Write(Content[1],Length(Content));
  334. chunk := Default(HTTP_DATA_CHUNK);
  335. chunk.DataChunkType := HttpDataChunkFromMemory;
  336. chunk.FromMemory.pBuffer := memstrm.Memory;
  337. chunk.FromMemory.BufferLength := memstrm.Size;
  338. res := HttpSendResponseEntityBody(fHandle, fRequestId, 0, 1, @chunk, @bytessend, Nil, Nil, Nil, Nil);
  339. if res <> NO_ERROR then
  340. raise EHTTPSys.CreateFmtHelp(SErrSendResponseBody, [res], 500);
  341. finally
  342. memstrm.Free;
  343. end;
  344. end;
  345. { THTTPSysRequest }
  346. function THTTPSysRequest.GetBaseUrl(const aUrl: AnsiString): AnsiString;
  347. const
  348. ProtocolHttp = 'http://';
  349. ProtocolHttps = 'https://';
  350. var
  351. prefix: AnsiString;
  352. slashidx: LongInt;
  353. begin
  354. prefix := aUrl;
  355. if Copy(prefix, 1, Length(ProtocolHttp)) = ProtocolHttp then
  356. Delete(prefix, 1, Length(ProtocolHttp))
  357. else if Copy(prefix, 1, Length(ProtocolHttps)) = ProtocolHttps then
  358. Delete(prefix, 1, Length(ProtocolHttps))
  359. else
  360. Exit('');
  361. slashidx := Pos('/', prefix);
  362. if slashidx = 0 then
  363. Exit('');
  364. Delete(prefix, 1, slashidx - 1);
  365. Result := prefix;
  366. end;
  367. procedure THTTPSysRequest.FillHeader(aRequest: PHTTP_REQUEST);
  368. var
  369. hh: THeader;
  370. hid: HTTP_HEADER_ID;
  371. unkheader: PHTTP_UNKNOWN_HEADER;
  372. i: LongInt;
  373. name, value: AnsiString;
  374. hv: THTTPVariableType;
  375. begin
  376. for hh := Low(THeader) to High(THeader) do begin
  377. if not (hdRequest in HTTPHeaderDirections[hh]) or IgnoreHttpHeaderForRequest(hh) then
  378. Continue;
  379. if not HeaderToHttpHeaderId(hh, hid) then
  380. Continue;
  381. if aRequest^.Headers.KnownHeaders[Ord(hid)].RawValueLength > 0 then
  382. SetHeader(hh, StrPas(aRequest^.Headers.KnownHeaders[Ord(hid)].pRawValue));
  383. end;
  384. for i := 0 to aRequest^.Headers.UnknownHeaderCount - 1 do begin
  385. unkheader := @aRequest^.Headers.pUnknownHeaders[i];
  386. if (unkheader^.NameLength > 0) and Assigned(unkheader^.pName) then begin
  387. name := StrPas(unkheader^.pName);
  388. value := StrPas(unkheader^.pRawValue);
  389. if name = HeaderProxyAuthenticate then
  390. hh := hhProxyAuthenticate
  391. else if name = HeaderProxyAuthorization then
  392. hh := hhProxyAuthorization
  393. else begin
  394. hh := hhUnknown;
  395. hv := hvUnknown;
  396. if name = HeaderSetCookie then
  397. hv := hvSetCookie
  398. else if name = HeaderCookie then
  399. hv := hvCookie
  400. else if name = HeaderXRequestedWith then
  401. hv := hvXRequestedWith;
  402. if hv <> hvUnknown then
  403. SetHTTPVariable(hvSetCookie, value)
  404. else
  405. SetCustomHeader(name, value);
  406. end;
  407. if hh <> hhUnknown then
  408. SetHeader(hh, value);
  409. end;
  410. end;
  411. end;
  412. procedure THTTPSysRequest.FillHTTPVariables(aRequest: PHTTP_REQUEST);
  413. function GetMethodStr(aRequest: PHTTP_REQUEST): String;
  414. begin
  415. case aRequest^.Verb of
  416. HttpVerbOPTIONS:
  417. Result := 'OPTIONS';
  418. HttpVerbGET:
  419. Result := 'GET';
  420. HttpVerbHEAD:
  421. Result := 'HEAD';
  422. HttpVerbPOST:
  423. Result := 'POST';
  424. HttpVerbPUT:
  425. Result := 'PUT';
  426. HttpVerbDELETE:
  427. Result := 'DELETE';
  428. HttpVerbTRACE:
  429. Result := 'TRACE';
  430. HttpVerbCONNECT:
  431. Result := 'CONNECT';
  432. HttpVerbTRACK:
  433. Result := 'TRACK';
  434. HttpVerbMOVE:
  435. Result := 'MOVE';
  436. HttpVerbCOPY:
  437. Result := 'COPY';
  438. HttpVerbPROPFIND:
  439. Result := 'PROPFIND';
  440. HttpVerbPROPPATCH:
  441. Result := 'PROPPATCH';
  442. HttpVerbMKCOL:
  443. Result := 'MKCOL';
  444. HttpVerbLOCK:
  445. Result := 'LOCK';
  446. HttpVerbUNLOCK:
  447. Result := 'UNLOCK';
  448. HttpVerbSEARCH:
  449. Result := 'SEARCH';
  450. otherwise
  451. if (aRequest^.UnknownVerbLength > 0) and Assigned(aRequest^.pUnknownVerb) then
  452. Result := StrPas(aRequest^.pUnknownVerb)
  453. else
  454. Result := '';
  455. end;
  456. end;
  457. function GetRemoteAddress: String;
  458. var
  459. len, size: DWord;
  460. begin
  461. if not Assigned(aRequest^.Address.pRemoteAddress) then
  462. Exit('');
  463. if aRequest^.Address.pRemoteAddress^.sa_family = AF_INET then
  464. size := SizeOf(TSockAddrIn)
  465. else if aRequest^.Address.pRemoteAddress^.sa_family = AF_INET6 then
  466. size := SizeOf(TSockAddrIn6)
  467. else
  468. Exit('');
  469. len := 32;
  470. SetLength(Result, len - 1);
  471. if WSAAddressToString(aRequest^.Address.pRemoteAddress^, size, Nil, PAnsiChar(Result), len) <> 0 then begin
  472. //Writeln('Failed to retrieve address string; error: ', WSAGetLastError);
  473. Exit('');
  474. end;
  475. SetLength(Result, len - 1);
  476. end;
  477. var
  478. s: AnsiString;
  479. urlstr, urlprefix: UTF8String;
  480. idx: LongInt;
  481. begin
  482. SetHTTPVariable(hvHTTPVersion, IntToStr(aRequest^.Version.MajorVersion) + '.' + IntToStr(aRequest^.Version.MinorVersion));
  483. SetHTTPVariable(hvMethod, GetMethodStr(aRequest));
  484. urlstr := Utf8String(StrPas(aRequest^.CookedUrl.pAbsPath));
  485. urlprefix := ReturnedPathInfo;
  486. SetHTTPVariable(hvURL, urlstr);
  487. if Copy(urlstr, 1, Length(urlprefix)) = urlprefix then
  488. Delete(urlstr, 1, Length(urlprefix));
  489. idx := Pos('?', urlstr);
  490. if idx > 0 then begin
  491. SetHTTPVariable(hvPathInfo, Copy(urlstr, 1, idx - 1));
  492. SetHTTPVariable(hvQuery, Copy(urlstr, idx + 1, Length(urlstr) - idx));
  493. end else
  494. SetHTTPVariable(hvPathInfo, urlstr);
  495. // ToDo
  496. {s := GetRemoteAddress;
  497. if s <> '' then
  498. SetHTTPVariable(hvRemoteAddress, s)}
  499. end;
  500. procedure THTTPSysRequest.InitFromRequest(aRequest: PHTTP_REQUEST);
  501. begin
  502. FillHeader(aRequest);
  503. FillHTTPVariables(aRequest);
  504. ParseCookies;
  505. ReadContent;
  506. InitRequestVars;
  507. end;
  508. procedure THTTPSysRequest.ReadContent;
  509. const
  510. BufLen = 4096;
  511. var
  512. ss: TStringStream;
  513. res, bytesreturned: ULONG;
  514. buf: PByte;
  515. e: EHTTPSys;
  516. s: AnsiString;
  517. begin
  518. buf := Nil;
  519. ss := TStringStream.Create('');
  520. try
  521. buf := GetMem(BufLen);
  522. repeat
  523. res := HttpReceiveRequestEntityBody(fHandle, fRequestId, 0, buf, BufLen, @bytesreturned, Nil);
  524. if res = NO_ERROR then
  525. ss.Write(buf^, bytesreturned)
  526. else if res <> ERROR_HANDLE_EOF then begin
  527. e := EHTTPSys.CreateFmt(SErrReceiveRequestBody, [res]);
  528. e.StatusCode := 500;
  529. raise e;
  530. end;
  531. until res = ERROR_HANDLE_EOF;
  532. s := ss.DataString;
  533. InitContent(s);
  534. finally
  535. Freemem(buf);
  536. ss.Free;
  537. end;
  538. end;
  539. constructor THTTPSysRequest.CreateReq(aHandle: THandle; const aUrl: String;
  540. aRequest: PHTTP_REQUEST);
  541. begin
  542. fHandle := aHandle;
  543. fRequestId := aRequest^.RequestId;
  544. ReturnedPathInfo := GetBaseUrl(aUrl);
  545. inherited Create;
  546. InitFromRequest(aRequest);
  547. end;
  548. { THTTPSysHandler }
  549. function THTTPSysHandler.CreateRequest(aRequest: PHTTP_REQUEST;
  550. const aUrl: String): THTTPSysRequest;
  551. var
  552. c: THTTPSysRequestClass;
  553. begin
  554. c := HTTPSysRequestClass;
  555. if not Assigned(c) then
  556. c := THTTPSysRequest;
  557. Result := c.CreateReq(fHandle, aUrl, aRequest);
  558. end;
  559. function THTTPSysHandler.CreateResponse(aRequest: THTTPSysRequest
  560. ): THTTPSysResponse;
  561. var
  562. c: THTTPSysResponseClass;
  563. begin
  564. c := HTTPSysResponseClass;
  565. if not Assigned(c) then
  566. c := THTTPSysResponse;
  567. Result := c.Create(aRequest);
  568. end;
  569. procedure THTTPSysHandler.ProcessRequest(aBuffer: PHTTP_REQUEST;
  570. aSize: LongWord; out aRequest: TRequest; out aResponse: TResponse);
  571. var
  572. locrequest: THTTPSysRequest;
  573. locresponse: THTTPSysResponse;
  574. url: String;
  575. begin
  576. if aBuffer^.UrlContext < fUrls.Count then
  577. url := fUrls[aBuffer^.UrlContext];
  578. locrequest := CreateRequest(aBuffer, url);
  579. InitRequest(locrequest);
  580. locresponse := CreateResponse(locrequest);
  581. InitResponse(locresponse);
  582. locresponse.fRequestId := aBuffer^.RequestId;
  583. locresponse.fRequestVersion := aBuffer^.Version;
  584. locresponse.fHandle := fHandle;
  585. aRequest := locrequest;
  586. aResponse := locresponse;
  587. end;
  588. function THTTPSysHandler.WaitForRequest(out aRequest: TRequest; out
  589. aResponse: TResponse): Boolean;
  590. var
  591. readsize: ULONG;
  592. res: ULONG;
  593. begin
  594. Result := False;
  595. if not Assigned(fBuffer) then begin
  596. InitUrls;
  597. fBufferSize := 4096;
  598. fBuffer := GetMem(fBufferSize);
  599. end;
  600. repeat
  601. repeat
  602. res := HttpReceiveHttpRequest(fHandle, HTTP_NULL_ID, 0, fBuffer, fBufferSize, @readsize, Nil);
  603. if res = ERROR_MORE_DATA then begin
  604. FreeMem(fBuffer);
  605. fBufferSize := fBufferSize + 4096;
  606. fBuffer := GetMem(fBufferSize);
  607. end;
  608. until res <> ERROR_MORE_DATA;
  609. if res = ERROR_OPERATION_ABORTED then
  610. Break
  611. else if res <> NO_ERROR then
  612. DoError(SErrReceiveRequest, [res])
  613. else begin
  614. ProcessRequest(fBuffer, readsize, aRequest, aResponse);
  615. Result := True;
  616. end;
  617. until Result or (fHandle = INVALID_HANDLE_VALUE);
  618. end;
  619. procedure THTTPSysHandler.InitUrls;
  620. var
  621. i: LongInt;
  622. res: ULONG;
  623. binding: HTTP_BINDING_INFO;
  624. s: String;
  625. begin
  626. for i := 0 to fUrls.Count - 1 do begin
  627. s := fUrls[i];
  628. Log(etInfo, 'Adding URL ' + s);
  629. res := HttpAddUrlToUrlGroup(fUrlGroup, PWideChar(WideString(s)), i, 0);
  630. if res <> NO_ERROR then
  631. DoError(SErrAddUrl, [s, res]);
  632. end;
  633. binding := Default(HTTP_BINDING_INFO);
  634. set_Present(binding.Flags, 1);
  635. binding.RequestQueueHandle := fHandle;
  636. res := HttpSetUrlGroupProperty(fUrlGroup, HttpServerBindingProperty, @binding, SizeOf(binding));
  637. if res <> NO_ERROR then
  638. DoError(SErrBindGroupToQueue, [res]);
  639. end;
  640. procedure THTTPSysHandler.Terminate;
  641. begin
  642. if fHandle <> INVALID_HANDLE_VALUE then begin
  643. HttpCloseRequestQueue(fHandle);
  644. fHandle := INVALID_HANDLE_VALUE;
  645. end;
  646. inherited Terminate;
  647. end;
  648. constructor THTTPSysHandler.Create(AOwner: TComponent);
  649. var
  650. res: ULONG;
  651. begin
  652. fUrls := TStringList.Create;
  653. inherited Create(AOwner);
  654. fHandle := INVALID_HANDLE_VALUE;
  655. res := HttpCreateRequestQueue(HTTPAPI_VERSION_2, Nil, Nil, 0, @fHandle);
  656. if res <> NO_ERROR then
  657. DoError(SErrCreateRequestQueue, [res]);
  658. res := HttpCreateServerSession(HTTPAPI_VERSION_2, @fServerSession, 0);
  659. if res <> NO_ERROR then
  660. DoError(SErrCreateServerSession, [res]);
  661. res := HttpCreateUrlGroup(fServerSession, @fUrlGroup, 0);
  662. if res <> NO_ERROR then
  663. DoError(SErrCreateUrlGroup, [res]);
  664. end;
  665. destructor THTTPSysHandler.Destroy;
  666. begin
  667. if fUrlGroup <> HTTP_NULL_ID then
  668. HttpCloseUrlGroup(fUrlGroup);
  669. if fServerSession <> HTTP_NULL_ID then
  670. HttpCloseServerSession(fServerSession);
  671. if fHandle <> INVALID_HANDLE_VALUE then
  672. HttpCloseRequestQueue(fHandle);
  673. FreeMem(fBuffer);
  674. fUrls.Free;
  675. inherited Destroy;
  676. end;
  677. { TCustomHTTPSysApplication }
  678. function TCustomHTTPSysApplication.InitializeWebHandler: TWebHandler;
  679. var
  680. c: THTTPSysHandlerClass;
  681. begin
  682. c := HTTPSysHandlerClass;
  683. if not Assigned(c) then
  684. c := THTTPSysHandler;
  685. Result := c.Create(Self);
  686. end;
  687. procedure TCustomHTTPSysApplication.DoRun;
  688. begin
  689. if WebHandler is THTTPSysHandler then
  690. THTTPSysHandler(WebHandler).fUrls.Assign(fUrls);
  691. inherited DoRun;
  692. end;
  693. constructor TCustomHTTPSysApplication.Create(AOwner: TComponent);
  694. var
  695. res: ULONG;
  696. begin
  697. fUrls := TStringList.Create;
  698. res := HttpInitialize(HTTPAPI_VERSION_2, HTTP_INITIALIZE_SERVER, Nil);
  699. if res <> NO_ERROR then
  700. raise Exception.CreateFmt(SErrInitializeHttpApi, [res]);
  701. inherited Create(AOwner);
  702. end;
  703. destructor TCustomHTTPSysApplication.Destroy;
  704. begin
  705. fUrls.Free;
  706. HttpTerminate(HTTP_INITIALIZE_SERVER, Nil);
  707. inherited Destroy;
  708. end;
  709. end.