123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807 |
- {
- This file is part of the Free Component Library (FCL)
- Copyright (c) 2017-2018 by the Free Pascal development team
- Windows HTTP Server API based TCustomWebApplication
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit custHTTPSys;
- {$mode objfpc}{$H+}
- interface
- uses
- SysUtils, Classes, HttpApi, custWeb, HTTPDefs;
- type
- { THTTPSysRequest }
- THTTPSysRequest = class(TRequest)
- private
- fHandle: THandle;
- fRequestId: HTTP_REQUEST_ID;
- function GetBaseUrl(const aUrl: AnsiString): AnsiString;
- procedure FillHeader(aRequest: PHTTP_REQUEST);
- procedure FillHTTPVariables(aRequest: PHTTP_REQUEST);
- procedure InitFromRequest(aRequest: PHTTP_REQUEST);
- protected
- procedure ReadContent; override;
- public
- constructor CreateReq(aHandle: THandle; const aUrl: String; aRequest: PHTTP_REQUEST);
- end;
- THTTPSysRequestClass = class of THTTPSysRequest;
- { THTTPSysResponse }
- THTTPSysResponse = class(TResponse)
- protected
- fHandle: THandle;
- fRequestId: HTTP_REQUEST_ID;
- fRequestVersion: HTTP_VERSION;
- procedure DoSendHeaders(aHeaders: TStrings); override;
- procedure DoSendContent; override;
- end;
- THTTPSysResponseClass = class of THTTPSysResponse;
- { THTTPSysHandler }
- THTTPSysHandler = class(TWebHandler)
- private
- fUrls: TStrings;
- fHandle: THandle;
- fServerSession: HTTP_SERVER_SESSION_ID;
- fUrlGroup: HTTP_URL_GROUP_ID;
- fBuffer: PHTTP_REQUEST;
- fBufferSize: LongWord;
- procedure InitUrls;
- protected
- function CreateRequest(aRequest: PHTTP_REQUEST; const aUrl: String): THTTPSysRequest; virtual;
- function CreateResponse(aRequest: THTTPSysRequest): THTTPSysResponse; virtual;
- procedure ProcessRequest(aBuffer: PHTTP_REQUEST; aSize: LongWord; out aRequest: TRequest; out aResponse: TResponse);
- function WaitForRequest(out aRequest: TRequest; out aResponse: TResponse): Boolean; override;
- public
- procedure Terminate; override;
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- end;
- THTTPSysHandlerClass = class of THTTPSysHandler;
- { TCustomHTTPSysApplication }
- TCustomHTTPSysApplication = class(TCustomWebApplication)
- private
- fUrls: TStrings;
- protected
- function InitializeWebHandler: TWebHandler; override;
- procedure DoRun; override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- property Urls: TStrings read fUrls;
- end;
- EHTTPSys = class(EFPWebError);
- var
- HTTPSysRequestClass: THTTPSysRequestClass = THTTPSysRequest;
- HTTPSysResponseClass: THTTPSysResponseClass = THTTPSysResponse;
- HTTPSysHandlerClass: THTTPSysHandlerClass = THTTPSysHandler;
- implementation
- uses
- Windows, httpprotocol, WinSock2;
- resourcestring
- SErrReceiveRequest = 'Failed to receive HTTP request (Errorcode: 0x%x)';
- SErrReceiveRequestBody = 'Failed to receive body of HTTP request (Errorcode: 0x%x)';
- SErrSendResponse = 'Failed to send HTTP response (Errorcode: 0x%x)';
- SErrSendResponseBody = 'Failed to send body of HTTP response (Errorcode: 0x%x)';
- SErrInitializeHttpApi = 'Failed to initialize HTTP API (Errorcode: 0x%x)';
- SErrCreateRequestQueue = 'Failed to create request queue (Errorcode: 0x%x)';
- SErrCreateServerSession = 'Failed to create server session (Errorcode: 0x%x)';
- SErrCreateUrlGroup = 'Failed to create URL group (Errorcode: 0x%x)';
- SErrAddUrl = 'Failed to add URL ''%s'' to URL group (Errorcode: 0x%x)';
- SErrBindGroupToQueue = 'Failed to bind URL group to queue (Errorcode: 0x%x)';
- function HeaderToHttpHeaderId(aHeader: THeader; out aId: HTTP_HEADER_ID): Boolean;
- begin
- Result := True;
- case aHeader of
- hhAccept:
- aId := HttpHeaderAccept;
- hhAcceptCharset:
- aId := HttpHeaderAcceptCharset;
- hhAcceptEncoding:
- aId := HttpHeaderAcceptEncoding;
- hhAcceptLanguage:
- aId := HttpHeaderAcceptLanguage;
- hhAcceptRanges:
- aId := HttpHeaderAcceptRanges;
- hhAge:
- aId := HttpHeaderAge;
- hhAllow:
- aId := HttpHeaderAllow;
- hhAuthorization:
- aId := HttpHeaderAuthorization;
- hhCacheControl:
- aId := HttpHeaderCacheControl;
- hhConnection:
- aId := HttpHeaderConnection;
- hhContentEncoding:
- aId := HttpHeaderContentEncoding;
- hhContentLanguage:
- aId := HttpHeaderContentLanguage;
- hhContentLength:
- aId := HttpHeaderContentLength;
- hhContentLocation:
- aId := HttpHeaderContentLocation;
- hhContentMD5:
- aId := HttpHeaderContentMd5;
- hhContentRange:
- aId := HttpHeaderContentRange;
- hhContentType:
- aId := HttpHeaderContentType;
- hhDate:
- aId := HttpHeaderDate;
- hhETag:
- aId := HttpHeaderEtag;
- hhExpires:
- aId := HttpHeaderExpires;
- hhExpect:
- aId := HttpHeaderExpect;
- hhFrom:
- aId := HttpHeaderFrom;
- hhHost:
- aId := HttpHeaderHost;
- hhIfMatch:
- aId := HttpHeaderIfMatch;
- hhIfModifiedSince:
- aId := HttpHeaderIfModifiedSince;
- hhIfNoneMatch:
- aId := HttpHeaderIfNoneMatch;
- hhIfRange:
- aId := HttpHeaderIfRange;
- hhIfUnModifiedSince:
- aId := HttpHeaderIfUnmodifiedSince;
- hhLastModified:
- aId := HttpHeaderLastModified;
- hhLocation:
- aId := HttpHeaderLocation;
- hhMaxForwards:
- aId := HttpHeaderMaxForwards;
- hhPragma:
- aId := HttpHeaderPragma;
- //hhProxyAuthenticate: ;
- //hhProxyAuthorization: ;
- hhRange:
- aId := HttpHeaderRange;
- hhReferer:
- aId := HttpHeaderReferer;
- hhRetryAfter:
- aId := HttpHeaderRetryAfter;
- hhServer:
- aId := HttpHeaderServer;
- hhTE:
- aId := HttpHeaderTe;
- hhTrailer:
- aId := HttpHeaderTrailer;
- hhTransferEncoding:
- aId := HttpHeaderTransferEncoding;
- hhUpgrade:
- aId := HttpHeaderUpgrade;
- hhUserAgent:
- aId := HttpHeaderUserAgent;
- hhVary:
- aId := HttpHeaderVary;
- hhVia:
- aId := HttpHeaderVia;
- hhWarning:
- aId := HttpHeaderWarning;
- hhWWWAuthenticate:
- aId := HttpHeaderWwwAuthenticate;
- otherwise
- Result := False;
- end;
- end;
- function IgnoreHttpHeaderForRequest(aHeader: THeader): Boolean;
- begin
- case aHeader of
- hhAcceptRanges,
- hhAge,
- hhETag,
- hhLocation,
- hhProxyAuthenticate,
- hhRetryAfter,
- hhServer,
- hhVary,
- hhWWWAuthenticate:
- Result := True;
- otherwise
- Result := False;
- end;
- end;
- { THTTPSysResponse }
- Type
- TAnsiHeader = record
- name : ansistring;
- value : ansistring;
- end;
- procedure THTTPSysResponse.DoSendHeaders(aHeaders: TStrings);
- function UnknownHeader(aheader : String; out hh : THeader; out aHeaderID : HTTP_HEADER_ID) : Boolean;
- begin
- Result:=True;
- hh:=HeaderType(aHeader);
- if hh = hhUnknown then
- Exit;
- if not (hdResponse in HTTPHeaderDirections[hh]) then
- Exit;
- if not HeaderToHttpHeaderId(hh, aHeaderID) then
- Exit;
- if (aHeaderID>=HttpHeaderResponseMaximum) then
- Exit;
- Result:=False;
- end;
- var
- resp: HTTP_RESPONSE;
- flags, bytessend: LongWord;
- i, idx, colonidx: LongInt;
- headerline,headerstr, headerval: String;
- res: ULONG;
- hh: THeader;
- headerid: HTTP_HEADER_ID;
- hID : Integer;
- headerstrs, unknownheaders: TStrings;
- unknownheadersarr: array of HTTP_UNKNOWN_HEADER;
- knownheaderstrarr : array[0..Ord(HttpHeaderResponseMaximum)] of TAnsiHeader;
- unknownheaderstrarr : array of TAnsiHeader;
- CT : AnsiString;
- begin
- {$IF SIZEOF(CHAR)=1}
- CT:=CodeText;
- {$ELSE}
- CT:=UTF8Encode(CodeText);
- {$ENDIF}
- resp := Default(HTTP_RESPONSE);
- resp.Version := fRequestVersion;
- resp.StatusCode := Code;
- if CodeText <> '' then begin
- resp.pReason := PAnsiChar(CT);
- resp.ReasonLength := Length(CT);
- end;
- flags := 0;
- if (Assigned(ContentStream) and (ContentStream.Size > 0)) or (Contents.Count > 0) then
- flags := flags or HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
- // Process known headers
- for i := 0 to aHeaders.Count - 1 do begin
- headerline:=aHeaders[i];
- colonidx := Pos(':', headerline);
- if colonidx = 0 then
- Continue;
- headerstr := Copy(headerline, 1, colonidx - 1);
- headerval := Trim(Copy(headerline, colonidx + 1, Length(headerline) - colonidx));
- if not UnknownHeader(HeaderStr,hh,headerID) then
- begin
- HID:=Ord(headerid);
- {$if SIZEOF(CHAR)=1}
- knownheaderstrarr[HID].value:=HeaderVal;
- {$ELSE}
- knownheaderstrarr[HID].value:=UTF8Encode(HeaderVal);
- {$ENDIF}
- resp.Headers.KnownHeaders[HID].RawValueLength := Length(knownheaderstrarr[HID].value);
- resp.Headers.KnownHeaders[HID].pRawValue := PAnsiChar(knownheaderstrarr[HID].value);
- end;
- end;
- // Process unknown headers. Start by allocating enough room.
- SetLength(unknownheaderstrarr, aheaders.Count);
- Idx:=0;
- for i := 0 to aheaders.Count - 1 do begin
- headerline:=aHeaders[i];
- colonidx := Pos(':', headerline);
- if colonidx = 0 then
- Continue;
- headerstr := Copy(headerline, 1, colonidx - 1);
- headerval := Trim(Copy(headerline, colonidx + 1, Length(headerline) - colonidx));
- if UnknownHeader(HeaderStr,hh,headerID) then begin
- {$if SIZEOF(CHAR)=1}
- unknownheaderstrarr[Idx].name:=headerstr;
- unknownheaderstrarr[Idx].value:=headerval;
- {$ELSE}
- unknownheaderstrarr[Idx].name:=UTF8Encode(headerstr);
- unknownheaderstrarr[Idx].value:=UTF8Encode(headerval);
- {$ENDIF}
- Inc(Idx);
- end;
- end;
- if Idx > 0 then begin
- SetLength(unknownheadersarr,Idx);
- For I:=0 to Idx-1 do
- begin
- unknownheadersarr[I].NameLength := Length(unknownheaderstrarr[i].name);
- unknownheadersarr[I].pName := PAnsiChar(unknownheaderstrarr[i].name);
- unknownheadersarr[I].RawValueLength :=Length(unknownheaderstrarr[i].value);
- unknownheadersarr[I].pRawValue := PAnsiChar(unknownheaderstrarr[i].value);
- end;
- resp.Headers.UnknownHeaderCount := Idx;
- resp.Headers.pUnknownHeaders := @unknownheadersarr[0];
- end;
- res := HttpSendHttpResponse(fHandle, fRequestId, flags, @resp, Nil, @bytessend, Nil, 0, Nil, Nil);
- if res <> NO_ERROR then
- raise EHTTPSys.CreateFmtHelp(SErrSendResponse, [res], 500);
- end;
- procedure THTTPSysResponse.DoSendContent;
- var
- chunk: HTTP_DATA_CHUNK;
- bytessend: LongWord;
- memstrm: TMemoryStream;
- res: ULONG;
- begin
- if not (Assigned(ContentStream) and (ContentStream.Size > 0)) and not (Contents.Count > 0) then
- Exit;
- memstrm := TMemoryStream.Create;
- try
- if Assigned(ContentStream) then
- memstrm.CopyFrom(ContentStream, ContentStream.Size)
- else
- MemStrm.Write(Content[1],Length(Content));
- chunk := Default(HTTP_DATA_CHUNK);
- chunk.DataChunkType := HttpDataChunkFromMemory;
- chunk.FromMemory.pBuffer := memstrm.Memory;
- chunk.FromMemory.BufferLength := memstrm.Size;
- res := HttpSendResponseEntityBody(fHandle, fRequestId, 0, 1, @chunk, @bytessend, Nil, Nil, Nil, Nil);
- if res <> NO_ERROR then
- raise EHTTPSys.CreateFmtHelp(SErrSendResponseBody, [res], 500);
- finally
- memstrm.Free;
- end;
- end;
- { THTTPSysRequest }
- function THTTPSysRequest.GetBaseUrl(const aUrl: AnsiString): AnsiString;
- const
- ProtocolHttp = 'http://';
- ProtocolHttps = 'https://';
- var
- prefix: AnsiString;
- slashidx: LongInt;
- begin
- prefix := aUrl;
- if Copy(prefix, 1, Length(ProtocolHttp)) = ProtocolHttp then
- Delete(prefix, 1, Length(ProtocolHttp))
- else if Copy(prefix, 1, Length(ProtocolHttps)) = ProtocolHttps then
- Delete(prefix, 1, Length(ProtocolHttps))
- else
- Exit('');
- slashidx := Pos('/', prefix);
- if slashidx = 0 then
- Exit('');
- Delete(prefix, 1, slashidx - 1);
- Result := prefix;
- end;
- procedure THTTPSysRequest.FillHeader(aRequest: PHTTP_REQUEST);
- var
- hh: THeader;
- hid: HTTP_HEADER_ID;
- unkheader: PHTTP_UNKNOWN_HEADER;
- i: LongInt;
- name, value: AnsiString;
- hv: THTTPVariableType;
- begin
- for hh := Low(THeader) to High(THeader) do begin
- if not (hdRequest in HTTPHeaderDirections[hh]) or IgnoreHttpHeaderForRequest(hh) then
- Continue;
- if not HeaderToHttpHeaderId(hh, hid) then
- Continue;
- if aRequest^.Headers.KnownHeaders[Ord(hid)].RawValueLength > 0 then
- SetHeader(hh, StrPas(aRequest^.Headers.KnownHeaders[Ord(hid)].pRawValue));
- end;
- for i := 0 to aRequest^.Headers.UnknownHeaderCount - 1 do begin
- unkheader := @aRequest^.Headers.pUnknownHeaders[i];
- if (unkheader^.NameLength > 0) and Assigned(unkheader^.pName) then begin
- name := StrPas(unkheader^.pName);
- value := StrPas(unkheader^.pRawValue);
- if name = HeaderProxyAuthenticate then
- hh := hhProxyAuthenticate
- else if name = HeaderProxyAuthorization then
- hh := hhProxyAuthorization
- else begin
- hh := hhUnknown;
- hv := hvUnknown;
- if name = HeaderSetCookie then
- hv := hvSetCookie
- else if name = HeaderCookie then
- hv := hvCookie
- else if name = HeaderXRequestedWith then
- hv := hvXRequestedWith;
- if hv <> hvUnknown then
- SetHTTPVariable(hvSetCookie, value)
- else
- SetCustomHeader(name, value);
- end;
- if hh <> hhUnknown then
- SetHeader(hh, value);
- end;
- end;
- end;
- procedure THTTPSysRequest.FillHTTPVariables(aRequest: PHTTP_REQUEST);
- function GetMethodStr(aRequest: PHTTP_REQUEST): String;
- begin
- case aRequest^.Verb of
- HttpVerbOPTIONS:
- Result := 'OPTIONS';
- HttpVerbGET:
- Result := 'GET';
- HttpVerbHEAD:
- Result := 'HEAD';
- HttpVerbPOST:
- Result := 'POST';
- HttpVerbPUT:
- Result := 'PUT';
- HttpVerbDELETE:
- Result := 'DELETE';
- HttpVerbTRACE:
- Result := 'TRACE';
- HttpVerbCONNECT:
- Result := 'CONNECT';
- HttpVerbTRACK:
- Result := 'TRACK';
- HttpVerbMOVE:
- Result := 'MOVE';
- HttpVerbCOPY:
- Result := 'COPY';
- HttpVerbPROPFIND:
- Result := 'PROPFIND';
- HttpVerbPROPPATCH:
- Result := 'PROPPATCH';
- HttpVerbMKCOL:
- Result := 'MKCOL';
- HttpVerbLOCK:
- Result := 'LOCK';
- HttpVerbUNLOCK:
- Result := 'UNLOCK';
- HttpVerbSEARCH:
- Result := 'SEARCH';
- otherwise
- if (aRequest^.UnknownVerbLength > 0) and Assigned(aRequest^.pUnknownVerb) then
- Result := StrPas(aRequest^.pUnknownVerb)
- else
- Result := '';
- end;
- end;
- function GetRemoteAddress: String;
- var
- len, size: DWord;
- begin
- if not Assigned(aRequest^.Address.pRemoteAddress) then
- Exit('');
- if aRequest^.Address.pRemoteAddress^.sa_family = AF_INET then
- size := SizeOf(TSockAddrIn)
- else if aRequest^.Address.pRemoteAddress^.sa_family = AF_INET6 then
- size := SizeOf(TSockAddrIn6)
- else
- Exit('');
- len := 32;
- SetLength(Result, len - 1);
- if WSAAddressToString(aRequest^.Address.pRemoteAddress^, size, Nil, PAnsiChar(Result), len) <> 0 then begin
- //Writeln('Failed to retrieve address string; error: ', WSAGetLastError);
- Exit('');
- end;
- SetLength(Result, len - 1);
- end;
- var
- s: AnsiString;
- urlstr, urlprefix: UTF8String;
- idx: LongInt;
- begin
- SetHTTPVariable(hvHTTPVersion, IntToStr(aRequest^.Version.MajorVersion) + '.' + IntToStr(aRequest^.Version.MinorVersion));
- SetHTTPVariable(hvMethod, GetMethodStr(aRequest));
- urlstr := Utf8String(StrPas(aRequest^.CookedUrl.pAbsPath));
- urlprefix := ReturnedPathInfo;
- SetHTTPVariable(hvURL, urlstr);
- if Copy(urlstr, 1, Length(urlprefix)) = urlprefix then
- Delete(urlstr, 1, Length(urlprefix));
- idx := Pos('?', urlstr);
- if idx > 0 then begin
- SetHTTPVariable(hvPathInfo, Copy(urlstr, 1, idx - 1));
- SetHTTPVariable(hvQuery, Copy(urlstr, idx + 1, Length(urlstr) - idx));
- end else
- SetHTTPVariable(hvPathInfo, urlstr);
- // ToDo
- {s := GetRemoteAddress;
- if s <> '' then
- SetHTTPVariable(hvRemoteAddress, s)}
- end;
- procedure THTTPSysRequest.InitFromRequest(aRequest: PHTTP_REQUEST);
- begin
- FillHeader(aRequest);
- FillHTTPVariables(aRequest);
- ParseCookies;
- ReadContent;
- InitRequestVars;
- end;
- procedure THTTPSysRequest.ReadContent;
- const
- BufLen = 4096;
- var
- ss: TStringStream;
- res, bytesreturned: ULONG;
- buf: PByte;
- e: EHTTPSys;
- s: AnsiString;
- begin
- buf := Nil;
- ss := TStringStream.Create('');
- try
- buf := GetMem(BufLen);
- repeat
- res := HttpReceiveRequestEntityBody(fHandle, fRequestId, 0, buf, BufLen, @bytesreturned, Nil);
- if res = NO_ERROR then
- ss.Write(buf^, bytesreturned)
- else if res <> ERROR_HANDLE_EOF then begin
- e := EHTTPSys.CreateFmt(SErrReceiveRequestBody, [res]);
- e.StatusCode := 500;
- raise e;
- end;
- until res = ERROR_HANDLE_EOF;
- s := ss.DataString;
- InitContent(s);
- finally
- Freemem(buf);
- ss.Free;
- end;
- end;
- constructor THTTPSysRequest.CreateReq(aHandle: THandle; const aUrl: String;
- aRequest: PHTTP_REQUEST);
- begin
- fHandle := aHandle;
- fRequestId := aRequest^.RequestId;
- ReturnedPathInfo := GetBaseUrl(aUrl);
- inherited Create;
- InitFromRequest(aRequest);
- end;
- { THTTPSysHandler }
- function THTTPSysHandler.CreateRequest(aRequest: PHTTP_REQUEST;
- const aUrl: String): THTTPSysRequest;
- var
- c: THTTPSysRequestClass;
- begin
- c := HTTPSysRequestClass;
- if not Assigned(c) then
- c := THTTPSysRequest;
- Result := c.CreateReq(fHandle, aUrl, aRequest);
- end;
- function THTTPSysHandler.CreateResponse(aRequest: THTTPSysRequest
- ): THTTPSysResponse;
- var
- c: THTTPSysResponseClass;
- begin
- c := HTTPSysResponseClass;
- if not Assigned(c) then
- c := THTTPSysResponse;
- Result := c.Create(aRequest);
- end;
- procedure THTTPSysHandler.ProcessRequest(aBuffer: PHTTP_REQUEST;
- aSize: LongWord; out aRequest: TRequest; out aResponse: TResponse);
- var
- locrequest: THTTPSysRequest;
- locresponse: THTTPSysResponse;
- url: String;
- begin
- if aBuffer^.UrlContext < fUrls.Count then
- url := fUrls[aBuffer^.UrlContext];
- locrequest := CreateRequest(aBuffer, url);
- InitRequest(locrequest);
- locresponse := CreateResponse(locrequest);
- InitResponse(locresponse);
- locresponse.fRequestId := aBuffer^.RequestId;
- locresponse.fRequestVersion := aBuffer^.Version;
- locresponse.fHandle := fHandle;
- aRequest := locrequest;
- aResponse := locresponse;
- end;
- function THTTPSysHandler.WaitForRequest(out aRequest: TRequest; out
- aResponse: TResponse): Boolean;
- var
- readsize: ULONG;
- res: ULONG;
- begin
- Result := False;
- if not Assigned(fBuffer) then begin
- InitUrls;
- fBufferSize := 4096;
- fBuffer := GetMem(fBufferSize);
- end;
- repeat
- repeat
- res := HttpReceiveHttpRequest(fHandle, HTTP_NULL_ID, 0, fBuffer, fBufferSize, @readsize, Nil);
- if res = ERROR_MORE_DATA then begin
- FreeMem(fBuffer);
- fBufferSize := fBufferSize + 4096;
- fBuffer := GetMem(fBufferSize);
- end;
- until res <> ERROR_MORE_DATA;
- if res = ERROR_OPERATION_ABORTED then
- Break
- else if res <> NO_ERROR then
- DoError(SErrReceiveRequest, [res])
- else begin
- ProcessRequest(fBuffer, readsize, aRequest, aResponse);
- Result := True;
- end;
- until Result or (fHandle = INVALID_HANDLE_VALUE);
- end;
- procedure THTTPSysHandler.InitUrls;
- var
- i: LongInt;
- res: ULONG;
- binding: HTTP_BINDING_INFO;
- s: String;
- begin
- for i := 0 to fUrls.Count - 1 do begin
- s := fUrls[i];
- Log(etInfo, 'Adding URL ' + s);
- res := HttpAddUrlToUrlGroup(fUrlGroup, PWideChar(WideString(s)), i, 0);
- if res <> NO_ERROR then
- DoError(SErrAddUrl, [s, res]);
- end;
- binding := Default(HTTP_BINDING_INFO);
- set_Present(binding.Flags, 1);
- binding.RequestQueueHandle := fHandle;
- res := HttpSetUrlGroupProperty(fUrlGroup, HttpServerBindingProperty, @binding, SizeOf(binding));
- if res <> NO_ERROR then
- DoError(SErrBindGroupToQueue, [res]);
- end;
- procedure THTTPSysHandler.Terminate;
- begin
- if fHandle <> INVALID_HANDLE_VALUE then begin
- HttpCloseRequestQueue(fHandle);
- fHandle := INVALID_HANDLE_VALUE;
- end;
- inherited Terminate;
- end;
- constructor THTTPSysHandler.Create(AOwner: TComponent);
- var
- res: ULONG;
- begin
- fUrls := TStringList.Create;
- inherited Create(AOwner);
- fHandle := INVALID_HANDLE_VALUE;
- res := HttpCreateRequestQueue(HTTPAPI_VERSION_2, Nil, Nil, 0, @fHandle);
- if res <> NO_ERROR then
- DoError(SErrCreateRequestQueue, [res]);
- res := HttpCreateServerSession(HTTPAPI_VERSION_2, @fServerSession, 0);
- if res <> NO_ERROR then
- DoError(SErrCreateServerSession, [res]);
- res := HttpCreateUrlGroup(fServerSession, @fUrlGroup, 0);
- if res <> NO_ERROR then
- DoError(SErrCreateUrlGroup, [res]);
- end;
- destructor THTTPSysHandler.Destroy;
- begin
- if fUrlGroup <> HTTP_NULL_ID then
- HttpCloseUrlGroup(fUrlGroup);
- if fServerSession <> HTTP_NULL_ID then
- HttpCloseServerSession(fServerSession);
- if fHandle <> INVALID_HANDLE_VALUE then
- HttpCloseRequestQueue(fHandle);
- FreeMem(fBuffer);
- fUrls.Free;
- inherited Destroy;
- end;
- { TCustomHTTPSysApplication }
- function TCustomHTTPSysApplication.InitializeWebHandler: TWebHandler;
- var
- c: THTTPSysHandlerClass;
- begin
- c := HTTPSysHandlerClass;
- if not Assigned(c) then
- c := THTTPSysHandler;
- Result := c.Create(Self);
- end;
- procedure TCustomHTTPSysApplication.DoRun;
- begin
- if WebHandler is THTTPSysHandler then
- THTTPSysHandler(WebHandler).fUrls.Assign(fUrls);
- inherited DoRun;
- end;
- constructor TCustomHTTPSysApplication.Create(AOwner: TComponent);
- var
- res: ULONG;
- begin
- fUrls := TStringList.Create;
- res := HttpInitialize(HTTPAPI_VERSION_2, HTTP_INITIALIZE_SERVER, Nil);
- if res <> NO_ERROR then
- raise Exception.CreateFmt(SErrInitializeHttpApi, [res]);
- inherited Create(AOwner);
- end;
- destructor TCustomHTTPSysApplication.Destroy;
- begin
- fUrls.Free;
- HttpTerminate(HTTP_INITIALIZE_SERVER, Nil);
- inherited Destroy;
- end;
- end.
|