| 1 | unit WebApp;
|
|---|
| 2 |
|
|---|
| 3 | interface
|
|---|
| 4 |
|
|---|
| 5 | uses
|
|---|
| 6 | Classes, SysUtils, WebPage, HTTPSessionFile, HTTPServer, Forms, FileUtil,
|
|---|
| 7 | Generics.Collections;
|
|---|
| 8 |
|
|---|
| 9 | type
|
|---|
| 10 | THTTPServerType = (stCGI, stTCP, stTurboPower);
|
|---|
| 11 |
|
|---|
| 12 | { TRegistredPage }
|
|---|
| 13 |
|
|---|
| 14 | TRegistredPage = class
|
|---|
| 15 | Name: string;
|
|---|
| 16 | Page: TWebPage;
|
|---|
| 17 | destructor Destroy; override;
|
|---|
| 18 | end;
|
|---|
| 19 |
|
|---|
| 20 | { TPageList }
|
|---|
| 21 |
|
|---|
| 22 | TPageList = class(TObjectList<TRegistredPage>)
|
|---|
| 23 | RootDir: string;
|
|---|
| 24 | function FindByPage(Page: TWebPage): TRegistredPage;
|
|---|
| 25 | function FindByName(Name: string): TRegistredPage;
|
|---|
| 26 | procedure RegisterPage(Page: TWebPage; Path: string);
|
|---|
| 27 | procedure UnregisterPage(Page: TWebPage);
|
|---|
| 28 | function ProducePage(HandlerData: THTTPHandlerData): Boolean;
|
|---|
| 29 | constructor Create(FreeObjects: Boolean = True);
|
|---|
| 30 | end;
|
|---|
| 31 |
|
|---|
| 32 | { TWebApp }
|
|---|
| 33 |
|
|---|
| 34 | TWebApp = class(TComponent)
|
|---|
| 35 | private
|
|---|
| 36 | FOnPageProduce: TOnProduceEvent;
|
|---|
| 37 | FOnInitialize: TNotifyEvent;
|
|---|
| 38 | FServerType: THTTPServerType;
|
|---|
| 39 | function DumpExceptionCallStack(E: Exception): string;
|
|---|
| 40 | procedure HTTPServerRequest(HandlerData: THTTPHandlerData);
|
|---|
| 41 | procedure SetServerType(AValue: THTTPServerType);
|
|---|
| 42 | public
|
|---|
| 43 | HTTPServer: THTTPServer;
|
|---|
| 44 | HTTPSessionStorageFile: THTTPSessionStorageFile;
|
|---|
| 45 | LogException: Boolean;
|
|---|
| 46 | procedure ShowException(E: Exception);
|
|---|
| 47 | constructor Create(AOwner: TComponent); override;
|
|---|
| 48 | destructor Destroy; override;
|
|---|
| 49 | procedure Run;
|
|---|
| 50 | published
|
|---|
| 51 | property OnPageProduce: TOnProduceEvent read FOnPageProduce write FOnPageProduce;
|
|---|
| 52 | property OnInitialize: TNotifyEvent read FOnInitialize write FOnInitialize;
|
|---|
| 53 | property ServerType: THTTPServerType read FServerType write SetServerType;
|
|---|
| 54 | end;
|
|---|
| 55 |
|
|---|
| 56 |
|
|---|
| 57 | procedure Register;
|
|---|
| 58 |
|
|---|
| 59 | implementation
|
|---|
| 60 |
|
|---|
| 61 | uses
|
|---|
| 62 | HTTPServerCGI, HTTPServerTCP, HTTPServerTurboPower;
|
|---|
| 63 |
|
|---|
| 64 | procedure Register;
|
|---|
| 65 | begin
|
|---|
| 66 | RegisterComponents('CoolWeb', [TWebApp]);
|
|---|
| 67 | end;
|
|---|
| 68 |
|
|---|
| 69 | { TRegistredPage }
|
|---|
| 70 |
|
|---|
| 71 | destructor TRegistredPage.Destroy;
|
|---|
| 72 | begin
|
|---|
| 73 | if Assigned(Page) then FreeAndNil(Page);
|
|---|
| 74 | end;
|
|---|
| 75 |
|
|---|
| 76 | { TPageList }
|
|---|
| 77 |
|
|---|
| 78 | function TPageList.FindByPage(Page: TWebPage): TRegistredPage;
|
|---|
| 79 | var
|
|---|
| 80 | I: Integer;
|
|---|
| 81 | begin
|
|---|
| 82 | I := 0;
|
|---|
| 83 | while (I < Count) and (Items[I].Page <> Page) do Inc(I);
|
|---|
| 84 | if I < Count then Result := Items[I]
|
|---|
| 85 | else Result := nil;
|
|---|
| 86 | end;
|
|---|
| 87 |
|
|---|
| 88 | function TPageList.FindByName(Name: string): TRegistredPage;
|
|---|
| 89 | var
|
|---|
| 90 | I: Integer;
|
|---|
| 91 | begin
|
|---|
| 92 | I := 0;
|
|---|
| 93 | while (I < Count) and (Items[I].Name <> Name) do Inc(I);
|
|---|
| 94 | if I < Count then Result := Items[I]
|
|---|
| 95 | else Result := nil;
|
|---|
| 96 | end;
|
|---|
| 97 |
|
|---|
| 98 | { TWebApp }
|
|---|
| 99 |
|
|---|
| 100 | procedure TWebApp.Run;
|
|---|
| 101 | begin
|
|---|
| 102 | if Assigned(FOnInitialize) then FOnInitialize(Self);
|
|---|
| 103 | HTTPServer.Run;
|
|---|
| 104 | if (ServerType = stCGI) or (ServerType = stTCP) then
|
|---|
| 105 | Application.Terminate;
|
|---|
| 106 | end;
|
|---|
| 107 |
|
|---|
| 108 | function TWebApp.DumpExceptionCallStack(E: Exception): string;
|
|---|
| 109 | var
|
|---|
| 110 | I: Integer;
|
|---|
| 111 | Frames: PPointer;
|
|---|
| 112 | Report: string;
|
|---|
| 113 | begin
|
|---|
| 114 | Report := 'Program exception! ' + LineEnding +
|
|---|
| 115 | 'Stacktrace:' + LineEnding + LineEnding;
|
|---|
| 116 | if E <> nil then begin
|
|---|
| 117 | Report := Report + 'Exception class: ' + E.ClassName + LineEnding +
|
|---|
| 118 | 'Message: ' + E.Message + LineEnding;
|
|---|
| 119 | end;
|
|---|
| 120 | Report := Report + BackTraceStrFunc(ExceptAddr);
|
|---|
| 121 | Frames := ExceptFrames;
|
|---|
| 122 | for I := 0 to ExceptFrameCount - 1 do
|
|---|
| 123 | Report := Report + LineEnding + BackTraceStrFunc(PointerArray(Frames)[I]);
|
|---|
| 124 | Result := Report;
|
|---|
| 125 | end;
|
|---|
| 126 |
|
|---|
| 127 | procedure TPageList.RegisterPage(Page: TWebPage; Path: string);
|
|---|
| 128 | var
|
|---|
| 129 | NewPage: TRegistredPage;
|
|---|
| 130 | begin
|
|---|
| 131 | NewPage := TRegistredPage.Create;
|
|---|
| 132 | // NewPage.Page := PageClass.Create(Self);
|
|---|
| 133 | NewPage.Page := Page;
|
|---|
| 134 | NewPage.Name := Path;
|
|---|
| 135 | Add(NewPage);
|
|---|
| 136 | end;
|
|---|
| 137 |
|
|---|
| 138 | procedure TPageList.UnregisterPage(Page: TWebPage);
|
|---|
| 139 | var
|
|---|
| 140 | RegPage: TRegistredPage;
|
|---|
| 141 | begin
|
|---|
| 142 | RegPage := FindByPage(Page);
|
|---|
| 143 | Remove(RegPage);
|
|---|
| 144 | end;
|
|---|
| 145 |
|
|---|
| 146 | function TPageList.ProducePage(HandlerData: THTTPHandlerData): Boolean;
|
|---|
| 147 | var
|
|---|
| 148 | Page: TRegistredPage;
|
|---|
| 149 | PageName: string;
|
|---|
| 150 | begin
|
|---|
| 151 | with HandlerData do begin
|
|---|
| 152 | if Request.Path.Count > 0 then PageName := Request.Path[0]
|
|---|
| 153 | else PageName := '';
|
|---|
| 154 | Page := FindByName(PageName);
|
|---|
| 155 | if Assigned(Page) then begin
|
|---|
| 156 | Page.Page.OnProduce(HandlerData);
|
|---|
| 157 | Result := True;
|
|---|
| 158 | end else Result := False;
|
|---|
| 159 | end;
|
|---|
| 160 | end;
|
|---|
| 161 |
|
|---|
| 162 | constructor TPageList.Create;
|
|---|
| 163 | begin
|
|---|
| 164 | inherited;
|
|---|
| 165 | FreeObjects := False;
|
|---|
| 166 | end;
|
|---|
| 167 |
|
|---|
| 168 | procedure TWebApp.HTTPServerRequest(HandlerData: THTTPHandlerData);
|
|---|
| 169 | begin
|
|---|
| 170 | if Assigned(FOnPageProduce) then
|
|---|
| 171 | FOnPageProduce(HandlerData);
|
|---|
| 172 | end;
|
|---|
| 173 |
|
|---|
| 174 | procedure TWebApp.SetServerType(AValue: THTTPServerType);
|
|---|
| 175 | begin
|
|---|
| 176 | if FServerType = AValue then Exit;
|
|---|
| 177 | FServerType := AValue;
|
|---|
| 178 | HTTPServer.Free;
|
|---|
| 179 | case FServerType of
|
|---|
| 180 | stCGI: HTTPServer := THTTPServerCGI.Create(nil);
|
|---|
| 181 | stTCP: HTTPServer := THTTPServerTCP.Create(nil);
|
|---|
| 182 | stTurboPower: HTTPServer := THTTPServerTurboPower.Create(nil);
|
|---|
| 183 | end;
|
|---|
| 184 | HTTPServer.OnRequest := HTTPServerRequest;
|
|---|
| 185 | end;
|
|---|
| 186 |
|
|---|
| 187 | procedure TWebApp.ShowException(E: Exception);
|
|---|
| 188 | var
|
|---|
| 189 | hstdout: ^Text;
|
|---|
| 190 | begin
|
|---|
| 191 | if not LogException then begin
|
|---|
| 192 | hstdout := @stdout;
|
|---|
| 193 | WriteLn(hstdout^, 'Content-type: text/html');
|
|---|
| 194 | WriteLn(hstdout^);
|
|---|
| 195 | Writeln(hstdout^, 'An unhandled exception occurred: ' + E.Message + '<br>');
|
|---|
| 196 | WriteLn(hstdout^, StringReplace(DumpExceptionCallStack(E), LineEnding, '<br>', [rfReplaceAll]));
|
|---|
| 197 | end else begin
|
|---|
| 198 | hstdout := @stdout;
|
|---|
| 199 | WriteLn(hstdout^, 'Content-type: text/html');
|
|---|
| 200 | WriteLn(hstdout^);
|
|---|
| 201 | WriteLn(hstdout^, 'Error occured during page generation.');
|
|---|
| 202 | hstdout := @stderr;
|
|---|
| 203 | Writeln(hstdout^, 'An unhandled exception occurred: ' + E.Message + '<br>');
|
|---|
| 204 | WriteLn(hstdout^, DumpExceptionCallStack(E));
|
|---|
| 205 | end;
|
|---|
| 206 | end;
|
|---|
| 207 |
|
|---|
| 208 | constructor TWebApp.Create(AOwner: TComponent);
|
|---|
| 209 | begin
|
|---|
| 210 | inherited;
|
|---|
| 211 | HTTPServer := THTTPServerCGI.Create(nil);
|
|---|
| 212 | HTTPServer.OnRequest := HTTPServerRequest;
|
|---|
| 213 | end;
|
|---|
| 214 |
|
|---|
| 215 | destructor TWebApp.Destroy;
|
|---|
| 216 | begin
|
|---|
| 217 | FreeAndNil(HTTPServer);
|
|---|
| 218 | inherited;
|
|---|
| 219 | end;
|
|---|
| 220 |
|
|---|
| 221 | end.
|
|---|
| 222 |
|
|---|