source: branches/DirectWeb/UHTTPServer.pas

Last change on this file was 88, checked in by george, 15 years ago
  • Upraveno: Nedokončené přepracování správy vláken. Použit systém přidělování ze společné sady o dané velikosti namísto přidělování vláken ke každému požadavku samostatně. Vlákna jsou inicializována při spuštění aplikace, jsou opakovaně používána a uvolněna až při ukončení běhu aplikace.
  • Přidáno: Třída pro práci s opakovaně spustitelnými vlákny.
  • Přidáno: Třída přidělování objektů ze zásoby o dané velikosti.
  • Přidáno: Třída pro zobrazování stránkování seznamů položek.
File size: 9.5 KB
Line 
1unit UHTTPServer;
2
3{$mode Delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, UTCPServer, UCommon, UMemoryStreamEx, UMIMEType,
9 Synautil;
10
11type
12 THTTPServer = class;
13
14 TQueryParameterList = class(TStringList)
15 procedure Parse(Text: string);
16 function Syntetize: string;
17 end;
18
19 { TCookieList }
20
21 TCookieList = class(TStringList)
22 procedure Parse(Text: string);
23 function Syntetize: string;
24 end;
25
26 { THTTPRequest }
27
28 THTTPRequest = class
29 Query: TQueryParameterList;
30 Path: string;
31 Method: string;
32 Headers: TStringList;
33 Cookies: TCookieList;
34 constructor Create;
35 destructor Destroy; override;
36 end;
37
38 { THTTPResponse }
39
40 THTTPResponse = class
41 ContentType: string;
42 Stream: TMemoryStreamEx;
43 Headers: TStringList;
44 Cookies: TCookieList;
45 constructor Create;
46 destructor Destroy; override;
47 end;
48
49 { THTTPHandlerData }
50
51 THTTPHandlerData = class
52 Server: THTTPServer;
53 Request: THTTPRequest;
54 Response: THTTPResponse;
55 SessionId: string;
56 Session: TStringList;
57 constructor Create;
58 destructor Destroy; override;
59 end;
60
61 TRequestEvent = procedure(HandlerData: THTTPHandlerData) of object;
62
63 TRequestHandler = class
64 Name: string;
65 Handler: TRequestEvent;
66 end;
67
68 { TRequestHandlerList }
69
70 TRequestHandlerList = class(TList)
71 procedure Add(AName: string; AHandler: TRequestEvent);
72 function IndexOfName(AName: string): TRequestHandler;
73 end;
74
75 { THTTPSession }
76
77 { THTTPSessionStorage }
78
79 THTTPSessionStorage = class
80 procedure Load(HandlerData: THTTPHandlerData); virtual;
81 procedure Save(HandlerData: THTTPHandlerData); virtual;
82 constructor Create; virtual;
83 destructor Destroy; override;
84 end;
85
86 { THTTPServer }
87
88 THTTPServer = class
89 private
90 procedure HandleClient(Sender: TObject);
91 procedure ErrorResponse(HandlerData: THTTPHandlerData);
92 public
93 Name: string;
94 Socket: TTCPServer;
95 DocumentRoot: string;
96 MaxConnection: Integer;
97 RequestHandlerList: TRequestHandlerList;
98 SessionStorage: THTTPSessionStorage;
99 procedure FileResponse(HandlerData: THTTPHandlerData);
100 constructor Create;
101 destructor Destroy; override;
102 end;
103
104implementation
105
106{ THTTPServer }
107
108procedure THTTPServer.HandleClient(Sender: TObject);
109var
110 RequestHandler: TRequestHandler;
111 Line: string;
112 LineIndex: Integer;
113 LineParts: array of string;
114 HandlerData: THTTPHandlerData;
115 I: Integer;
116 QueryString: string;
117begin
118 with TTCPClientThread(Sender), Socket do begin
119 WriteLn('Used thrads ' + IntToStr(Parent.ThreadPool.UsedCount) + '. Client connected from ' + GetRemoteSinIP);
120
121 HandlerData := THTTPHandlerData.Create;
122 with HandlerData do begin
123 Server := Self;
124
125 Response := THTTPResponse.Create;
126 Response.Headers.Values['Server'] := Name;
127 Request := THTTPRequest.Create;
128 LineIndex := 0;
129 repeat
130 Line := RecvString(10000);
131 if (LineIndex = 0) then begin
132 LineParts := Explode(' ', Line);
133 if (Length(LineParts) >= 3) then begin
134 Request.Method := LineParts[0];
135 if Pos('?', LineParts[1]) > 0 then begin
136 Request.Path := Copy(LineParts[1], 1, Pos('?', LineParts[1]) - 1);
137 Request.Query.Parse(Copy(LineParts[1], Pos('?', LineParts[1]) + 1, Length(LineParts[1])));
138 end else Request.Path := LineParts[1];
139 end;
140 end else begin
141 LineParts := Explode(' ', Line, 2);
142 if (Length(LineParts) = 2) and (LineParts[0][Length(LineParts[0])] = ':') then begin
143 LineParts[0] := Copy(LineParts[0], 1, Length(LineParts[0]) - 1);
144 Request.Headers.Values[LineParts[0]] := LineParts[1];
145 //WriteLn(Line);
146 end;
147 end;
148 Inc(LineIndex);
149 until Line = '';
150
151 // Process cookies
152 if Request.Headers.IndexOfName('Cookie') <> -1 then
153 Request.Cookies.Parse(Request.Headers.Values['Cookie']);
154
155 // Load session variables
156 if Assigned(SessionStorage) then
157 SessionStorage.Load(HandlerData);
158
159 Response.Stream.Clear;
160 Response.Headers.Values['Content-Type'] := 'text/html';
161
162 WriteLn('Requested path: ' + Request.Path);
163 RequestHandler := RequestHandlerList.IndexOfName(Request.Path);
164
165 if Assigned(RequestHandler) then RequestHandler.Handler(HandlerData)
166 else ErrorResponse(HandlerData);
167
168 // Store session variables
169 if Assigned(SessionStorage) then
170 SessionStorage.Save(HandlerData);
171
172 with Response do begin
173 SendString('HTTP/1.0 200 OK'#13#10);
174 Headers.Values['Content-Length'] := IntToStr(Stream.Size);
175 Headers.Values['Connection'] := 'close';
176 Headers.Values['Date'] := RFC822DateTime(Now);
177
178 // Handle cookies
179 for I := 0 to Cookies.Count - 1 do
180 Headers.Add('Set-Cookie' + Headers.NameValueSeparator + Cookies.Names[I] + '=' + Cookies.ValueFromIndex[I]);
181 // + ';path=/;expires=' + RFC822DateTime(Now);
182
183 // Send headers
184 for I := 0 to Headers.Count - 1 do begin
185 //WriteLn(Headers.Names[I] + ': ' + Headers.ValueFromIndex[I] + #13#10);
186 SendString(Headers.Names[I] + ': ' + Headers.ValueFromIndex[I] + #13#10);
187 end;
188 SendString(#13#10);
189 SendBuffer(Stream.Memory, Stream.Size);
190 SendString(#13#10);
191 end;
192
193 Destroy;
194 end;
195 end;
196end;
197
198procedure THTTPServer.ErrorResponse(HandlerData: THTTPHandlerData);
199begin
200 with HandlerData, Response.Stream do begin
201 WriteString('<html><body>Page ' + Request.Path + ' not found.</body></html>');
202 end;
203end;
204
205procedure THTTPServer.FileResponse(HandlerData: THTTPHandlerData);
206var
207 BinaryFile: TFileStream;
208 FileName: string;
209begin
210 with HandlerData do begin
211 FileName := DocumentRoot + Request.Path;
212 if FileExists(FileName) then begin
213 Response.Headers.Values['Content-Type'] := GetMIMEType(Copy(ExtractFileExt(FileName), 2, 255));
214 BinaryFile := TFileStream.Create(FileName, fmOpenRead);
215 Response.Stream.WriteStream(BinaryFile);
216 BinaryFile.Destroy;
217 end else
218 with Response.Stream do begin
219 WriteLn('File ' + Request.Path + ' not found.');
220 WriteString('<html><body>File ' + Request.Path + ' not found.</body></html>');
221 end;
222 end;
223end;
224
225constructor THTTPServer.Create;
226begin
227 Socket := TTCPServer.Create;
228 Socket.OnClientConnect := HandleClient;
229 DocumentRoot := './';
230 RequestHandlerList := TRequestHandlerList.Create;
231 Name := 'THTTPServer';
232 MaxConnection := 10000;
233end;
234
235destructor THTTPServer.Destroy;
236begin
237 Socket.Destroy;
238 RequestHandlerList.Destroy;
239 inherited Destroy;
240end;
241
242{ THTTPResponse }
243
244constructor THTTPResponse.Create;
245begin
246 Stream := TMemoryStreamEx.Create;
247 Cookies := TCookieList.Create;
248 Headers := TStringList.Create;
249end;
250
251destructor THTTPResponse.Destroy;
252begin
253 Stream.Destroy;
254 Headers.Destroy;
255 inherited Destroy;
256end;
257
258{ TRequestHandlerList }
259
260procedure TRequestHandlerList.Add(AName: string; AHandler: TRequestEvent);
261begin
262 with TRequestHandler(Items[inherited Add(TRequestHandler.Create)]) do begin
263 Name := AName;
264 Handler := AHandler;
265 end;
266end;
267
268function TRequestHandlerList.IndexOfName(AName: string): TRequestHandler;
269var
270 I: Integer;
271begin
272 I := 0;
273 while (I < Count) and (TRequestHandler(Items[I]).Name <> AName) do Inc(I);
274 if I < Count then Result := TRequestHandler(Items[I]) else Result := nil;
275end;
276
277{ THTTPRequest }
278
279constructor THTTPRequest.Create;
280begin
281 Query := TQueryParameterList.Create;
282 Headers := TStringList.Create;
283 Cookies := TCookieList.Create;
284end;
285
286destructor THTTPRequest.Destroy;
287begin
288 Query.Destroy;
289 Headers.Destroy;
290 inherited Destroy;
291end;
292
293{ TQueryParameterList }
294
295procedure TQueryParameterList.Parse(Text: string);
296var
297 I: Integer;
298 Parts: TArrayOfString;
299 Pair: TArrayOfString;
300begin
301 Clear;
302 Parts := Explode('&', Text);
303 for I := 0 to Length(Parts) - 1 do begin
304 Pair := Explode('=', Parts[I]);
305 if Length(Pair) >= 2 then
306 Values[Pair[0]] := Pair[1];
307 end;
308end;
309
310function TQueryParameterList.Syntetize: string;
311var
312 I: Integer;
313begin
314 Result := '';
315 for I := 0 to Count - 1 do
316 Result := Result + '&amp;' + Names[I] + '=' + ValueFromIndex[I];
317 Result := Copy(Result, 6, Length(Result));
318end;
319
320{ TCookieList }
321
322procedure TCookieList.Parse(Text: string);
323var
324 I: Integer;
325 Parts: TArrayOfString;
326 Pair: TArrayOfString;
327begin
328 Clear;
329 Parts := Explode(';', Text);
330 for I := 0 to Length(Parts) - 1 do begin
331 Pair := Explode('=', Parts[I]);
332 if Length(Pair) >= 2 then
333 Values[Trim(Pair[0])] := Trim(Pair[1]);
334 end;
335end;
336
337function TCookieList.Syntetize: string;
338var
339 I: Integer;
340begin
341 Result := '';
342 for I := 0 to Count - 1 do
343 Result := Result + '; ' + Names[I] + '=' + ValueFromIndex[I];
344 Result := Copy(Result, 2, Length(Result));
345end;
346
347{ THTTPSessionStorage }
348
349procedure THTTPSessionStorage.Load(HandlerData: THTTPHandlerData);
350begin
351
352end;
353
354procedure THTTPSessionStorage.Save(HandlerData: THTTPHandlerData);
355begin
356
357end;
358
359constructor THTTPSessionStorage.Create;
360begin
361
362end;
363
364destructor THTTPSessionStorage.Destroy;
365begin
366 inherited Destroy;
367end;
368
369{ THTTPHandlerData }
370
371constructor THTTPHandlerData.Create;
372begin
373 Request := THTTPRequest.Create;
374 Response := THTTPResponse.Create;
375 Session := TStringList.Create;
376end;
377
378destructor THTTPHandlerData.Destroy;
379begin
380 Request.Destroy;
381 Response.Destroy;
382 Session.Destroy;
383 inherited Destroy;
384end;
385
386end.
387
Note: See TracBrowser for help on using the repository browser.