1{ 2 This file is part of the Free Pascal run time library. 3 Copyright (c) 2019 by the Free Pascal development team 4 5 TCustomMicroHTTPApplication class. 6 7 See the file COPYING.FPC, included in this distribution, 8 for details about the copyright. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 14 **********************************************************************} 15{ $define CGIDEBUG} 16{$mode objfpc} 17{$H+} 18 19unit custmicrohttpapp; 20 21Interface 22 23uses 24 Classes, SysUtils, httpprotocol, httpdefs, custweb, libmicrohttpd; 25 26Type 27 TCustomMicroHTTPApplication = Class; 28 TMicroServerOption = ( 29 mcoDebug, 30 mcoSSL, 31 mcoThreadPerConnection, 32 mcoSelectInternally, 33 mcoIPV6, 34 mcoPedanticChecks, 35 mcoPoll, 36 mcoSuppressDateNoClock, 37 mcoNoListenSocket, 38 mcoEPollLinuxOnly, 39 mcoPipeForShutdown, 40 mcoDualStack, 41 mcoEPollTurbo, 42 mcoSuspendResume, 43 mcoTCPFastOpen 44 ); 45 TMicroServerOptions = Set of TMicroServerOption; 46 47 TMicroHTTPHandler = Class; 48 TRequestHandler = Class; 49 50 { TMicroRequest } 51 52 TMicroRequest = Class(TRequest) 53 Private 54 FHandler : TRequestHandler; 55 FMyQueryString : String; 56 // Return amount of data handled 57 Procedure DoSetHeader(K,V : String); 58 Procedure AddQueryField(K,V : String); 59 Function AddData(Data: PAnsiChar; DataSize: Size_t) : Size_t; 60 Procedure Initialize(const aUrl, aMethod, aVersion: String); 61 procedure InitRequestVars; override; 62 Protected 63 Property Handler : TRequestHandler Read FHandler; 64 end; 65 66 { TMicroResponse } 67 68 TMicroResponse = Class(TResponse) 69 Private 70 FHandler : TRequestHandler; 71 FResponse : PMHD_Response; 72 Protected 73 Procedure MaybeAllocateResponse; virtual; 74 Procedure DoSendHeaders(Headers: TStrings); override; 75 Procedure DoSendContent; override; 76 Property Handler : TRequestHandler Read FHandler; 77 Property Response : PMHD_Response Read FResponse; 78 Public 79 Destructor Destroy; override; 80 end; 81 82 { TRequestHandler } 83 84 TRequestHandler = Class 85 FConnection : PMHD_Connection; 86 FWebHandler : TMicroHTTPHandler; 87 FRequest : TMicroRequest; 88 FResponse : TMicroResponse; 89 Public 90 Constructor Create(aHandler : TMicroHTTPHandler; aConnection :PMHD_Connection); 91 Destructor Destroy; override; 92 Procedure Initialize(const aUrl, aMethod, aVersion: String); 93 Function ContinueRequest(Data: PAnsiChar; var DataSize: Size_t) : Cint; 94 Property Connection : PMHD_Connection Read FConnection; 95 Property WebHandler : TMicroHTTPHandler Read FWebHandler; 96 Property Request : TMicroRequest Read FRequest; 97 Property Response : TMicroResponse Read FResponse; 98 end; 99 100 { TMicroHTTPHandler } 101 102 TAcceptHandler = Procedure (Sender : TObject; Addr : PSockAddr; addrLen : socklen_t; var Allow : Boolean) of object; 103 TRequestErrorHandler = Procedure (Sender : TObject; E : Exception) of object; 104 105 TMicroHTTPHandler = class(TWebHandler) 106 Private 107 FAcceptHandler: TAcceptHandler; 108 FExtraHeaders: TStrings; 109 FOnRequestError: TRequestErrorHandler; 110 FPort : Word; 111 FOptions: TMicroServerOptions; 112 FServer: PMHD_Daemon; 113 FHostName : string; 114 procedure MaybeStopServer; 115 procedure RequestCompleted(aRequest: TRequestHandler); 116 function DoRequest(connection: PMHD_Connection; const aUrl, aMethod, aVersion: String; Data: PAnsiChar; var DataSize: Size_t): TRequestHandler; 117 procedure SetExtraHeaders(AValue: TStrings); 118 procedure SetHostName(AValue: String); 119 procedure SetOptions(AValue: TMicroServerOptions); 120 procedure SetPort(const AValue: Word); 121 protected 122 function OptionsToFlags : Integer; 123 Function DoAcceptConnection(Addr : PSockAddr; addrLen : socklen_t) : Boolean; 124 procedure CheckInactive; 125 function CreateServer: PMHD_Daemon; virtual; 126 procedure HandleRequestError(Sender: TObject; E: Exception); virtual; 127 Procedure InitRequest(ARequest : TRequest); override; 128 Procedure InitResponse(AResponse : TResponse); override; 129 function WaitForRequest(out ARequest : TRequest; out AResponse : TResponse) : boolean; override; 130 Property Daemon : PMHD_Daemon Read FServer; 131 Public 132 Procedure Run; override; 133 constructor Create(AOwner: TComponent); override; 134 destructor Destroy; override; 135 // Port to listen on. 136 Property Port : Word Read FPort Write SetPort Default 80; 137 // HostName to use when using SSL 138 Property HostName : String Read FHostName Write SetHostName; 139 // ServerOPtions 140 Property Options : TMicroServerOptions Read FOptions Write SetOptions; 141 // On Accept handler 142 Property OnAccept : TAcceptHandler Read FAcceptHandler Write FAcceptHandler; 143 // Handle On Request error. If not set, error is logged. 144 Property OnRequestError : TRequestErrorHandler Read FOnRequestError Write FOnRequestError; 145 // Extra non-standard headers which can be accepted as part of requests 146 Property ExtraHeaders : TStrings Read FExtraHeaders Write SetExtraHeaders; 147 end; 148 149 { TCustomMicroHTTPApplication } 150 151 TCustomMicroHTTPApplication = Class(TCustomWebApplication) 152 private 153 function GetExtraHeaders: TStrings; 154 function GetHostName: String; 155 function GetOptions: TMicroServerOptions; 156 function GetPort: Word; 157 function GetUseSSL: Boolean; 158 procedure SetExtraHeaders(AValue: TStrings); 159 procedure SetHostName(AValue: String); 160 procedure SetOptions(AValue: TMicroServerOptions); 161 procedure SetPort(AValue: Word); 162 procedure SetUseSSL(AValue: Boolean); 163 protected 164 function InitializeWebHandler: TWebHandler; override; 165 Function HTTPHandler : TMicroHTTPHandler; 166 Public 167 constructor Create(aOwner : TComponent); override; 168 destructor Destroy; override; 169 Property Port : Word Read GetPort Write SetPort Default 80; 170 // Hostname to use when using SSL 171 Property HostName : String Read GetHostName Write SetHostName; 172 // ServerOptions 173 Property Options : TMicroServerOptions Read GetOptions Write SetOptions; 174 // For compatibility 175 Property UseSSL : Boolean Read GetUseSSL Write SetUSeSSL; 176 // Extra non-standard headers which can be accepted as part of requests 177 Property ExtraHeaders : TStrings Read GetExtraHeaders Write SetExtraHeaders; 178 end; 179 180 181Implementation 182 183Resourcestring 184 SErrServerActive = 'Operation cannot be performed while server is active'; 185 SErrFailedToStartServer = 'Failed to start server'; 186 187 188Const 189 BoolToYesNo : Array[Boolean] of Integer = (MHD_NO,MHD_YES); 190 191Const 192 OptionFlags : Array[TMicroServerOption] of Integer = ( 193 MHD_USE_DEBUG, 194 MHD_USE_SSL, 195 MHD_USE_THREAD_PER_CONNECTION, 196 MHD_USE_SELECT_INTERNALLY, 197 MHD_USE_IPv6, 198 MHD_USE_PEDANTIC_CHECKS, 199 MHD_USE_POLL, 200 MHD_SUPPRESS_DATE_NO_CLOCK, 201 MHD_USE_NO_LISTEN_SOCKET, 202 MHD_USE_EPOLL_LINUX_ONLY, 203 MHD_USE_PIPE_FOR_SHUTDOWN, 204 MHD_USE_DUAL_STACK, 205 MHD_USE_EPOLL_TURBO, 206 MHD_USE_SUSPEND_RESUME, 207 MHD_USE_TCP_FASTOPEN); 208 209{ --------------------------------------------------------------------- 210 libmicrohttp Callbacks 211 ---------------------------------------------------------------------} 212 213Function MaybeS(p : pchar) : String; 214begin 215 if Assigned(P) then Result:=P else Result:=''; 216end; 217 218function GetRequestData(cls: Pointer; kind: MHD_ValueKind; key: Pcchar; value: Pcchar): cint; cdecl; 219 220var 221 K,V : String; 222 223 224begin 225 K:=MaybeS(key); 226 V:=MaybeS(Value); 227 if kind=MHD_HEADER_KIND then 228 TMicroRequest(Cls).DoSetHeader(K,V) 229 else if kind=MHD_GET_ARGUMENT_KIND then 230 TMicroRequest(Cls).AddQueryField(K,V); 231 Result:=MHD_YES; 232end; 233 234 235procedure DoPanic(cls: Pointer; &file: Pcchar; line: cuint; reason: Pcchar); cdecl; 236 237begin 238 if Assigned(cls) then 239 TCustomMicroHTTPApplication(Cls).Log(etError,Format('Panic at %s(%d): %s ',[MaybeS(&File),line,MaybeS(reason)])) 240 else if IsConsole then 241 writeln('Panic: File ',MaybeS(&File),'(',line,')',MaybeS(Reason)); 242end; 243 244 245function DoReadResponse(cls: pointer; pos: cuint64; buf: Pcchar; max: size_t): ssize_t; cdecl; 246 247Var 248 Resp : TMicroResponse; 249 250begin 251 Resp:=TMicroResponse(cls); 252 if Pos<>Resp.ContentStream.Position then 253 Resp.ContentStream.Position:=Pos; 254 Result:=Resp.ContentStream.Read(buf^,max); 255end; 256 257 258function AcceptCallBack(cls: Pointer; addr: psockaddr; addrlen: socklen_t): cint; cdecl; 259begin 260 Result:=BoolToYesNo[TMicroHTTPHandler(Cls).DoAcceptConnection(addr,addrlen)]; 261end; 262 263 264function DoMHDRequest(cls: Pointer; connection: PMHD_Connection; url: Pcchar; method: Pcchar; version: Pcchar; upload_data: Pcchar; 265 upload_data_size: pSize_t; con_cls: PPointer): cint; cdecl; 266 267Var 268 aURL : String; 269 aMethod : String; 270 aVersion : String; 271 H : TMicroHTTPHandler; 272 273begin 274 aURL:=URl; 275 aMethod:=Method; 276 aVersion:=Version; 277 if (Con_cls^=Nil) then 278 begin 279 H:=TMicroHTTPHandler(Cls); 280 Con_cls^:=H.DoRequest(connection,aURL,aMethod,aVersion,Upload_Data,Upload_data_size^); 281 Result:=BoolToYesNo[con_cls^<>Nil]; 282 end 283 else 284 Result:=TRequestHandler(Con_cls^).ContinueRequest(Upload_Data,Upload_data_size^); 285end; 286 287procedure HandleRequestCompleted(ACls: Pointer; AConnection: PMHD_Connection; AConCls: PPointer; AToe: MHD_RequestTerminationCode); cdecl; 288var 289 Req: TRequestHandler; 290 H : TMicroHTTPHandler; 291begin 292 Req:=TRequestHandler(AConCls^); 293 if not Assigned(Req) then 294 Exit; 295 H:=TMicroHTTPHandler(aCls); 296 if not Assigned(H) then 297 H:=Req.WebHandler; 298 if Assigned(H) then 299 H.RequestCompleted(Req) 300 else 301 Req.Free; 302 AConCls^ := nil; 303end; 304 305 306{ --------------------------------------------------------------------- 307 TMicroRequest 308 ---------------------------------------------------------------------} 309 310 311procedure TMicroRequest.DoSetHeader(K, V: String); 312 313Var 314 H : THeader; 315 316begin 317 H:=HeaderType(K); 318 if hdRequest in HTTPHeaderDirections[h] then 319 SetHeader(H,V) 320 else 321 SetCustomHeader(K,V); 322end; 323 324procedure TMicroRequest.AddQueryField(K, V: String); 325 326Var 327 S : String; 328 329begin 330 if V<>'' then 331 QueryFields.Values[K]:=V 332 else 333 QueryFields.Add(K+'='); 334 S:=FMyQueryString; 335 if S<>'' then 336 S:=S+'&'; 337 FMyQueryString:=S+K+'='+HTTPEncode(V); 338end; 339 340function TMicroRequest.AddData(Data: PAnsiChar; DataSize: Size_t): Size_t; 341 342Var 343 C : String; 344 L : Integer; 345 346begin 347 C:=Content; 348 L:=Length(C); 349 SetLength(C,L+Datasize); 350 Move(Data^,C[L+1],DataSize); 351 InitContent(C); 352 Result:=Datasize; 353end; 354 355procedure TMicroRequest.Initialize(const aUrl, aMethod, aVersion: String); 356 357begin 358 SetHTTPVariable(hvURL,aURL); 359 SetHTTPVariable(hvMethod,aMethod); 360 SetHTTPVariable(hvHTTPVersion,aVersion); 361 InitRequestVars; 362end; 363 364procedure TMicroRequest.InitRequestVars; 365 366Var 367 P : Pchar; 368 N,S : String; 369 I : integer; 370 371begin 372 MHD_get_connection_values(FHandler.FConnection, MHD_GET_ARGUMENT_KIND,@GetRequestData,Self); 373 MHD_get_connection_values(FHandler.FConnection, MHD_HEADER_KIND,@GetRequestData,Self); 374 for N in FHandler.WebHandler.ExtraHeaders do 375 begin 376 P:=MHD_lookup_connection_value(FHandler.FConnection, MHD_HEADER_KIND,Pchar(N)); 377 If P<>Nil then 378 SetCustomHeader(N,P); 379 end; 380 S:=URL; 381 I:=Pos('?',S); 382 if (I>0) then 383 S:=Copy(S,1,I-1); 384 If (Length(S)>1) and (S[1]<>'/') then 385 S:='/'+S 386 else if S='/' then 387 S:=''; 388 PathInfo:=S; 389 Inherited; 390 // We set this afterwards, otherwise double processing 391 if FMyQueryString<>'' then 392 SetHTTPVariable(hvQuery,FMyQueryString) 393end; 394 395{ --------------------------------------------------------------------- 396 TMicroResponse 397 ---------------------------------------------------------------------} 398 399procedure TMicroResponse.MaybeAllocateResponse; 400 401Var 402 L : Integer; 403 P : PChar; 404 B : TBytes; 405 406begin 407 if FResponse<>Nil then exit; 408 if Assigned(ContentStream) then 409 begin 410 ContentStream.Position:=0; 411 L:=ContentStream.Size; 412 if FreeContentStream then 413 FResponse:=MHD_create_response_from_callback(L,4096,@DoReadResponse,Self,Nil) 414 else 415 // We must copy the bytes, because we don't know when the stream is freed. 416 begin 417 SetLength(B,L); 418 ContentStream.ReadBuffer(B[0],L); 419 P:=Pchar(B); 420 FResponse:=MHD_create_response_from_buffer(L,P,MHD_RESPMEM_MUST_COPY); 421 end; 422 end 423 else 424 begin 425 L:=Length(Content); 426 P:=PChar(Content); 427 FResponse:=MHD_create_response_from_buffer(L,P,MHD_RESPMEM_MUST_COPY); 428 end; 429end; 430 431procedure TMicroResponse.DoSendHeaders(Headers: TStrings); 432 433Var 434 I : Integer; 435 N,V : String; 436 437begin 438 // Note that if the response is allocated, then you cannot set the content stream any more... 439 MaybeAllocateResponse; 440 Headers.NameValueSeparator:=':'; 441 For I:=0 to Headers.Count-1 do 442 begin 443 Headers.GetNameValue(I,N,V); 444 MHD_add_response_header(FResponse,PAnsiChar(N),PAnsiChar(V)); 445 end; 446end; 447 448procedure TMicroResponse.DoSendContent; 449begin 450 MaybeAllocateResponse; 451 MHD_queue_response(FHandler.FConnection,Self.Code,FResponse); 452end; 453 454destructor TMicroResponse.Destroy; 455begin 456 if (FResponse<>Nil) then 457 MHD_destroy_response(FResponse); 458 inherited Destroy; 459end; 460 461{ --------------------------------------------------------------------- 462 TRequestHandler 463 ---------------------------------------------------------------------} 464 465constructor TRequestHandler.Create(aHandler: TMicroHTTPHandler; aConnection: PMHD_Connection); 466begin 467 FWebHandler:=aHandler; 468 FConnection:=aConnection; 469 FRequest:=TMicroRequest.Create; 470 FRequest.FHandler:=Self; 471 FResponse:=TMicroResponse.Create(FRequest); 472 FResponse.FHandler:=Self; 473end; 474 475destructor TRequestHandler.Destroy; 476begin 477 FreeAndNil(FRequest); 478 FreeAndNil(FResponse); 479 inherited Destroy; 480end; 481 482procedure TRequestHandler.Initialize(const aUrl, aMethod, aVersion: String); 483begin 484 FRequest.Initialize(aURL,aMethod,aVersion); 485end; 486 487function TRequestHandler.ContinueRequest(Data: PAnsiChar; var DataSize: Size_t): Cint; 488 489Var 490 CanHandleRequest : Boolean; 491 492begin 493 CanHandleRequest:=Datasize=0; 494 if Datasize>0 then 495 DataSize:=DataSize-FRequest.AddData(Data,Datasize); 496 If Not CanHandleRequest then 497 Result:=BoolToYesNo[DataSize=0] 498 else 499 begin 500 try 501 WebHandler.HandleRequest(FRequest,FResponse); 502 If Not FResponse.ContentSent then 503 try 504 FResponse.SendContent; 505 except 506 On E : Exception do 507 WebHandler.HandleRequestError(WebHandler,E); 508 end; 509 Result:=MHD_YES; 510 except 511 On E : Exception do 512 begin 513 Result:=MHD_NO; 514 WebHandler.HandleRequestError(WebHandler,E); 515 end; 516 end; 517 end; 518end; 519 520 521{ --------------------------------------------------------------------- 522 TMicroHTTPHandler 523 ---------------------------------------------------------------------} 524 525procedure TMicroHTTPHandler.RequestCompleted(aRequest: TRequestHandler); 526 527begin 528 try 529 EndRequest(aRequest.FRequest,aRequest.FResponse); 530 aRequest.FRequest:=Nil; 531 aRequest.FResponse:=Nil; 532 aRequest.Free; 533 except 534 On E: Exception do 535 HandleRequestError(Self,E); 536 end; 537end; 538 539function TMicroHTTPHandler.DoRequest(connection: PMHD_Connection; Const aUrl,aMethod,aVersion: String; Data: PAnsiChar; var DataSize: Size_t) : TRequestHandler; 540 541begin 542 Result:=TRequestHandler.Create(Self,Connection); 543 Result.Initialize(aURl,aMethod,AVersion); 544 if (DataSize>0) then 545 if Result.ContinueRequest(Data,Datasize)<>MHD_YES then 546 FreeAndNil(Result); 547end; 548 549procedure TMicroHTTPHandler.SetExtraHeaders(AValue: TStrings); 550begin 551 if FExtraHeaders=AValue then Exit; 552 FExtraHeaders.Assign(AValue); 553end; 554 555procedure TMicroHTTPHandler.HandleRequestError(Sender: TObject; E: Exception); 556begin 557 Try 558 If Assigned(FOnRequestError) then 559 FOnRequestError(Sender,E) 560 else 561 Log(etError,Format('Error (%s) handling request : %s',[E.ClassName,E.Message])); 562 except 563 // Do not let errors escape 564 end; 565end; 566 567procedure TMicroHTTPHandler.CheckInactive; 568 569begin 570 if Assigned(FServer) then 571 Raise EHTTP.Create(SErrServerActive); 572end; 573 574procedure TMicroHTTPHandler.SetHostName(AValue: String); 575begin 576 CheckInactive; 577 FHostName:=aValue; 578end; 579 580 581procedure TMicroHTTPHandler.SetOptions(AValue: TMicroServerOptions); 582begin 583 if FOptions=AValue then Exit; 584 CheckInactive; 585 FOptions:=AValue; 586end; 587 588procedure TMicroHTTPHandler.SetPort(const AValue: Word); 589begin 590 CheckInactive; 591 FPort:=Avalue 592end; 593 594procedure TMicroHTTPHandler.InitRequest(ARequest: TRequest); 595begin 596 inherited InitRequest(ARequest); 597end; 598 599procedure TMicroHTTPHandler.InitResponse(AResponse: TResponse); 600begin 601 inherited InitResponse(AResponse); 602end; 603 604function TMicroHTTPHandler.WaitForRequest(out ARequest: TRequest; 605 out AResponse: TResponse): boolean; 606begin 607 Result:=False; 608 ARequest:=Nil; 609 AResponse:=Nil; 610end; 611 612Function TMicroHTTPHandler.DoAcceptConnection(Addr : PSockAddr; addrLen : socklen_t) : Boolean; 613 614begin 615 Result:=True; 616 if Assigned(FAcceptHandler) then 617 FAcceptHandler(Self,Addr,addrLen,Result); 618end; 619 620 621function TMicroHTTPHandler.OptionsToFlags : Integer; 622 623Var 624 O : TMicroServerOption; 625 626begin 627 Result:=0; 628 For O in TMicroServerOption do 629 if O in Options then 630 Result:=Result or OptionFlags[O]; 631end; 632 633 634function TMicroHTTPHandler.CreateServer: PMHD_Daemon; 635 636Var 637 F,P : Integer; 638 639begin 640 F:=OptionsToFlags; 641 P:=Port; 642 Result:= MHD_start_daemon(F,P, 643 @AcceptCallBack, Self, 644 @DoMHDRequest, Self, 645 MHD_OPTION_NOTIFY_COMPLETED, @HandleRequestCompleted, 646 Nil,MHD_OPTION_END); 647 if Result=Nil then 648 Writeln('a') 649 else 650 Writeln('b'); 651end; 652 653procedure TMicroHTTPHandler.Run; 654begin 655 FServer:=CreateServer; 656 if (FServer=Nil) then 657 Raise EHTTP.Create(SErrFailedToStartServer); 658 Repeat 659 Sleep(50); 660 Until Terminated; 661end; 662 663procedure TMicroHTTPHandler.MaybeStopServer; 664 665begin 666 if Assigned(FServer) then 667 begin 668 MHD_stop_daemon(FServer); 669 FServer:=Nil; 670 end; 671end; 672 673constructor TMicroHTTPHandler.Create(AOwner: TComponent); 674begin 675 inherited Create(AOwner); 676 FExtraHeaders:=TStringList.Create; 677 Options:=[mcoSelectInternally]; 678 Port:=80; 679end; 680 681destructor TMicroHTTPHandler.Destroy; 682begin 683 MaybeStopServer; 684 FreeAndNil(FExtraHeaders); 685 inherited Destroy; 686end; 687 688 689{ --------------------------------------------------------------------- 690 TCustomMicroHTTPApplication 691 ---------------------------------------------------------------------} 692 693 694procedure TCustomMicroHTTPApplication.SetHostName(AValue: String); 695begin 696 HTTPHandler.HostName:=aValue; 697end; 698 699procedure TCustomMicroHTTPApplication.SetOptions(AValue: TMicroServerOptions); 700begin 701 HTTPHandler.Options:=aValue; 702end; 703 704procedure TCustomMicroHTTPApplication.SetPort(AValue: Word); 705begin 706 HTTPHandler.Port:=aValue; 707end; 708 709procedure TCustomMicroHTTPApplication.SetUSeSSL(AValue: Boolean); 710begin 711 if AValue then 712 Options:=Options+[mcoSSL] 713 else 714 Options:=Options-[mcoSSL] 715end; 716 717function TCustomMicroHTTPApplication.GetPort: Word; 718begin 719 Result:=HTTPHandler.Port; 720end; 721 722function TCustomMicroHTTPApplication.GetUseSSL: Boolean; 723begin 724 Result:=mcoSSL in Options; 725end; 726 727procedure TCustomMicroHTTPApplication.SetExtraHeaders(AValue: TStrings); 728begin 729 HTTPHandler.ExtraHeaders.Assign(AValue); 730end; 731 732function TCustomMicroHTTPApplication.InitializeWebHandler: TWebHandler; 733begin 734 Result:=TMicroHTTPHandler.Create(Self); 735end; 736 737function TCustomMicroHTTPApplication.HTTPHandler: TMicroHTTPHandler; 738begin 739 Result:=Webhandler as TMicroHTTPHandler; 740end; 741 742constructor TCustomMicroHTTPApplication.Create(aOwner: TComponent); 743begin 744 inherited Create(aOwner); 745 MHD_set_panic_func(@DoPanic,Self); 746end; 747 748destructor TCustomMicroHTTPApplication.Destroy; 749begin 750 MHD_set_panic_func(@DoPanic,Nil); 751 inherited Destroy; 752end; 753 754function TCustomMicroHTTPApplication.GetExtraHeaders: TStrings; 755begin 756 Result:=HTTPHandler.ExtraHeaders; 757end; 758 759function TCustomMicroHTTPApplication.GetHostName: String; 760begin 761 Result:=HTTPHandler.HostName; 762end; 763 764function TCustomMicroHTTPApplication.GetOptions: TMicroServerOptions; 765begin 766 Result:=HTTPHandler.Options; 767end; 768 769 770end. 771