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 |
|
---|