[EMAIL PROTECTED] pisze:
Hi all,
I'm trying to do an HTTPserver daemon under linux.
I reduced the HTTPserver demo main program to the following lines:
program fpmain;
{$MODE Delphi}
uses
cthreads,
crt,
Classes,
http;
var
dm: TTCPHttpDaemon;
begin
dm := TTCPHttpDaemon.create;
readln;
dm.Free;
end.
I play many with thttpDaemon. In xlMainSyn You have may unit of http
Server based on Synapse. It works with FPC.
I had problems like You, but don't remember what was a reason, so I
send whole unit.
I've added sessions, cookies, detection of user agent etc.
If You want, You can use it.
But sorry, code is form me, its not beautiful.
Darek
{$I start.inc}
unit xlmainsyn;
interface
{$DEFINE LOGD}
{.$DEFINE THREADSESSION}
uses
syncobjs,
// windows,
Classes, blcksock, synsock,{winsock,} Synautil, SysUtils;
const
GSessionIDCookie = 'IDHTTPSESSIONID'; {Do not Localize}
type
{
tSessionThread = class(TThread)
procedure Execute; override;
end;
}
{$IFDEF THREADSESSION}
tSession = class(tThread)
{$ELSE}
tSession = class(tObject)
{$ENDIF}
application : tObject;
FSessionID: string;
FRemoteHost: string;
remoteIP : string;
name : string;
agentID : integer;
// Content: TStringList;
FLock: TCriticalSection;
// czekajResponse : tSimpleEvent;
lastTime : tDateTime;
constructor create;
destructor destroy;override;
function doZwolnienia(aTime : tDateTime):boolean;
procedure Lock;
procedure Unlock;
// procedure Execute; override;
// procedure request;
end;
tHttpInfo = class
request,
method,
protocol : shortString;
document,
FormParams,
query : ansiString;
uri : ansistring;
ResponseNo : integer;
contentText : ansiString;
data : tMemoryStream;
ContentStream : tStream;
Headers: TStringList;
session : tSession;
fHost : string;
fuserAgent,
fEncodings,
fLanguage,
fCharset,
fReferer,
contentType : shortstring;
pragma,
cacheControl : string;
CloseConnection : boolean;
LastModified,
fDate,
Expires : tDateTime;
remoteIP : shortstring;
fCookies : tStringList;
constructor create;
destructor destroy;override;
procedure clear;
function userAgent : string;
function params(aParam:string):string;
function contentLength:integer;
function addCookie(ass : string):integer;
function setCookie(fName,fValue,fPath,fExpires,fDomain,fSecures:string):integer;
function getCookie(aValue:ansistring;var fName,fValue,fPath,fExpires,fDomain,fSecures,fSession:string):integer;
end;
TIdHTTPRequestInfo = tHttpInfo;
TIdHTTPResponseInfo = tHttpInfo;
// THTTPGetEvent = procedure(Request, URI: string;InputData,OutputData :tMemoryStream ):integer;
THTTPGetEvent = procedure( ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo) of object;
TTCPHttpDaemon = class(TThread)
private
Sock:TTCPBlockSocket;
fPort : integer;
fCommandGet : THTTPGetEvent;
FSessionList: TStringList;
FSessionState: Boolean;
FSessionTimeOut: Integer;
FLock: TCriticalSection;
fAutoStartSession : boolean;
public
Constructor Create(aPort : integer);
Destructor Destroy; override;
procedure Execute; override;
property defaultport:integer read fPort write fPort;
property onCommandGet: tHttpGetEvent read fCommandGet write fCommandGet;
property sessions : tStringList read fSessionList;
function GetSessionFromCookie({AContext:TIdContext;}
AHTTPrequest,aHttpResponse: THTTPInfo;
var VContinueProcessing: Boolean): TSession;
procedure removeSessions;
function CreateSession{(AContext:TIdContext;
HTTPResponse: TIdHTTPResponseInfo;
HTTPRequest: TIdHTTPRequestInfo)}: TSession;
function getSession(const aSessionName : string) :tSession;
function EndSession(const aSessionName: string): boolean;
end;
TTCPHttpThrd = class(TThread)
private
Sock:TTCPBlockSocket;
fOnProcessHttpRequest : tHttpGetEvent;
fServer : TTCPHttpDaemon;
public
Input, Output: THttpInfo;
Constructor Create (hsock:tSocket;aServer : tTCPHttpDaemon; aOnProcess : tHttpGetEvent);
Destructor Destroy; override;
procedure Execute; override;
// function ProcessHttpRequest(Request, URI: string): integer;
end;
implementation
const
agPC = 0;
agGSM = 1;
agPalm = 2;
function detectAgent(aAgent:string):integer;
var
agentID : integer;
begin
aAgent:=UpperCase(aAgent);
agentID:=agGSM;
if pos('NOKIA',aAgent)>0 then agentID:=agGSM;
if{ (pos('MOZILLA',aAgent)>0)and }(pos('WINDOWS;',aAgent)>0) then agentID:=agPC;
if{ (pos('MOZILLA',aAgent)>0)and }(pos('WINDOWS NT',aAgent)>0) then agentID:=agPC;
if (pos('X11;',aAgent)>0) then agentID:=agPC;
if pos('WINDOWS CE',aAgent)>0 then agentID:=agPalm;
result:=agentID;
end;
function AddCookieProperty(AProperty, AValue, ACookie: String): String;
begin
if Length(AValue) > 0 then
begin
if Length(ACookie) > 0 then
begin
ACookie := ACookie + '; '; {Do not Localize}
end;
ACookie := ACookie + AProperty + '=' + AValue; {Do not Localize}
end;
result := ACookie;
end;
constructor tSession.create;
begin
inherited create;
// FreeOnTerminate:=true;
// Priority:=tpNormal;
application:=nil;
remoteIP:='';
name:='';
// content:=tStringList.create;
fLock:=tCriticalSection.create;
// czekajResponse:=tSimpleEvent.create;
// InitializeCriticalSection(FLock);
end;
destructor tSession.destroy;
begin
// unlock;
// DeleteCriticalSection(FLock);
writeln('session destroy :',name);
fLock.free;
// czekajResponse.free;
// content.free;
inherited destroy;
end;
procedure TSession.Lock;
begin
// ToDo: Add session locking code here
FLock.Enter;
// EnterCriticalSection(FLock);
end;
procedure TSession.Unlock;
begin
// ToDo: Add session unlocking code here
FLock.Leave;
// LeaveCriticalSection(FLock);
end;
function tSession.doZwolnienia;
begin
result:=LastTime<aTime;
end;
constructor tHttpInfo.create;
begin
inherited create;
data:=tMemoryStream.create;
Headers:= TStringList.create;
fCookies:=tStringList.create;
ContentStream:=nil;
clear;
end;
destructor tHttpInfo.destroy;
begin
data.free;
headers.free;
fCookies.Free;
inherited destroy;
FreeAndNil(ContentStream);
end;
procedure tHttpInfo.clear;
begin
data.clear;
contentText:='';
headers.clear;
fCookies.clear;
fHost:='';
fuserAgent:='';
fEncodings:='';
fLanguage:='';
fCharset:='';
cacheControl:='';
pragma:='';
fDate:=0;
Expires:=0;
lastModified:=0;
uri:='';
responseNo:=0;
FreeAndNil(ContentStream);
end;
function tHttpInfo.userAgent:string;
begin
result:=fUserAgent;
end;
function tHttpInfo.params;
begin
result:=getParameter(query,aParam);
end;
function tHttpInfo.contentLength;
begin
result:=-1;
if ContentText <> '' then begin
result:= Length(ContentText);
end else if Assigned(ContentStream) then begin
result:= ContentStream.Size;
end else result:=data.size;
end;
function tHttpInfo.addCookie;
begin
result:=fCookies.Add(ass);
end;
function THttpInfo.setCookie;
var
sCookie:string;
begin
sCookie:= AddCookieProperty(FName, FValue, ''); {Do not Localize}
if fPath<>'' then
sCookie := AddCookieProperty('path', FPath, sCookie); {Do not Localize}
// if FInternalVersion = cvNetscape then
// begin
if fExpires<>'' then
sCookie := AddCookieProperty('expires', FExpires, sCookie); {Do not Localize}
// end;
if fDomain<>'' then
sCookie:= AddCookieProperty('domain', FDomain, sCookie); {Do not Localize}
result:=addCookie(sCookie);
// if FSecure then
// begin
// result := AddCookieFlag('secure', result); {Do not Localize}
// end;
end;
function THttpInfo.getCookie;
Var
i: Integer;
CookieProp: TStringList;
procedure LoadProperties(APropertyList: TStringList);
begin
FPath := APropertyList.values['PATH']; {Do not Localize}
// Tomcat can return SetCookie2 with path wrapped in "
if (Length(FPath) > 0) then
begin
if FPath[1] = '"' then {Do not Localize}
Delete(FPath, 1, 1);
if FPath[Length(FPath)] = '"' then {Do not Localize}
SetLength(FPath, Length(FPath) - 1);
end
else begin
FPath := '/'; {Do not Localize}
end;
fExpires := APropertyList.values['EXPIRES']; {Do not Localize}
FDomain := APropertyList.values['DOMAIN']; {Do not Localize}
fSecures:='';
FSession := APropertyList.values[GSessionIDCookie]; {Do not Localize}
// FSecure := APropertyList.IndexOf('SECURE') <> -1; {Do not Localize}
end;
begin
CookieProp := TStringList.Create;
try
while Pos(';', AValue) > 0 do {Do not Localize}
begin
CookieProp.Add(Trim(Fetch(AValue, ';'))); {Do not Localize}
if (Pos(';', AValue) = 0) and (Length(AValue) > 0) then CookieProp.Add(Trim(AValue)); {Do not Localize}
end;
if CookieProp.Count = 0 then CookieProp.Text := AValue;
FName := CookieProp.Names[0];
FValue := CookieProp.Values[CookieProp.Names[0]];
CookieProp.Delete(0);
for i := 0 to CookieProp.Count - 1 do
if Pos('=', CookieProp[i]) = 0 then {Do not Localize}
begin
CookieProp[i] := UpperCase(CookieProp[i]); // This is for cookie flags (secure)
end
else begin
CookieProp[i] := UpperCase(CookieProp.Names[i]) + '=' + CookieProp.values[CookieProp.Names[i]]; {Do not Localize}
end;
LoadProperties(CookieProp);
finally
FreeAndNil(CookieProp);
end;
result:=1;
end;
function GetRandomString(NumChar: cardinal): string;
const
CharMap='qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM1234567890'; {Do not Localize}
var
i: integer;
MaxChar: cardinal;
begin
result:='';
MaxChar := length(CharMap) - 1;
for i := 1 to NumChar do
begin
// Add one because CharMap is 1-based
Result := result + CharMap[Random(maxChar) + 1];
end;
end;
{ TTCPHttpDaemon }
Constructor TTCPHttpDaemon.Create;
{$IFDEF LOGD}
var
str : tFileStream;
{$ENDIF}
begin
sock:=TTCPBlockSocket.create;
fPort:=aPort;
inherited create(false);
FreeOnTerminate:=true;
Priority:=tpNormal;
fSessionList:=tStringList.create;
FLock := TCriticalSection.Create;
fAutostartSession:=true;
fSessionState:=true;
randomize;
{$IFDEF LOGD}
str:=tFileStream.create('log3',fmCreate);
str.free;
{$ENDIF}
// inicjalizacja;
end;
Destructor TTCPHttpDaemon.Destroy;
begin
FLock.Free;
Sock.free;
fSessionList.destroy;
inherited Destroy;
end;
procedure TTCPHttpDaemon.Execute;
var
ClientSock:TSocket;
begin
with sock do
begin
CreateSocket;
setLinger(true,10);
bind(cAnyHost,inttostr(defaultport));
listen;
repeat
if terminated then break;
if canread(1000) then
begin
ClientSock:=accept;
if lastError=0 then TTCPHttpThrd.create(ClientSock,self,fCommandGet);
end
else removeSessions;
until false;
end;
end;
function TTCPHttpDaemon.getSession;
var
pSes : tSession;
id : integer;
begin
id:=sessions.indexOf(aSessionName);
// writeln('testsess:',aSessionName,'@',id);
if id<0 then begin
result:=nil;
end else begin
result:=sessions.objects[id] as tSession
end;
end;
function TTCPHttpDaemon.CreateSession;
var
xSessionID: String;
begin
result:=tSession.Create;
xSessionID := GetRandomString(15);
while sessions.indexOf(xSessionID)>=0 do
xSessionID := GetRandomString(15);
result.FSessionID:=xsessionID;
result.lastTime:=sysutils.now;
sessions.addObject(xsessionID,result);
end;
procedure tTCPHttpDaemon.removeSessions;
var
i : integer;
pSes : tSession;
xTime: tDateTIme;
begin
xTime:=sysUtils.now - 0.5;
for i :=sessions.count-1 downto 0 do begin
pSes:=sessions.objects[i] as tSession;
if pSes.DoZwolnienia(xTime) then begin
fLock.Enter;
try
sessions.delete(i);
pSes.free;
finally
fLock.Leave;
end;
end;
end;
end;
function TTCPHttpDaemon.EndSession(const aSessionName: string): boolean;
var
pSes: TSession;
id : integer;
begin
result:=false;
id := Sessions.indexOf(aSessionName); {Do not Localize}
if id>=0 then begin
fLock.enter;
try
pSes:=sessions.objects[id] as tSession;
sessions.delete(id);
pSes.free;
result:=true;
finally
fLock.leave;
end;
end;
end;
function TTCPHttpDaemon.GetSessionFromCookie;
var
CurrentCookieIndex: Integer;
xCookie:ansistring;
xxSessionId : String;
xName,xValue,xPath,xExpires,xDomain,xSecures:string;
procedure parseRequest;
var
i : integer;
begin
for i:=aHttpRequest.fcookies.count-1 downto 0 do begin
xCookie:=AHTTPRequest.fCookies[i];
// writeln('getCookie: ',xcookie);
if pos(gSessionIdCookie,xCookie)>0 then begin
AHTTPRequest.getCookie(xCookie,xName,xValue,xPath,xExpires,xDomain,xSecures,xxSessionId);
if xName=gSessionIdCookie then begin
xxsessionId:=xValue;
end;
// writeln('getCookieA: ',xName,'@',xValue,'@',xxSessionID);
// SessionId := AHTTPRequest.Cookies.Items[CurrentCookieIndex].Value;
if xxsessionID<>'' then begin
Result := GetSession(xxSessionID{, AHTTPrequest.RemoteIP});
if result<> nil then break;
end;
end;
end; { while }
end;
begin
Result := nil;
VContinueProcessing := True;
if fSessionState then begin
parseRequest;
if result= nil then begin
fLock.enter;
try
parseRequest;
if (FAutoStartSession and VContinueProcessing) and (result = nil) then
begin
Result := CreateSession{(AContext, AHTTPResponse, AHTTPrequest)};
// aHttpResponse.setCookie(GSessionIDCookie,result.FSessionID,'/','-','','');
aHttpResponse.setCookie(GSessionIDCookie,result.FSessionID,'','','','');
writeln('create session:',result.FSessionID);
// result.lastTime:=sysutils.now;
end;
finally
fLock.Leave;
end;
end;
end;
if result<>nil then
result.lastTime:=sysutils.now;
end;
{ TTCPHttpThrd }
Constructor TTCPHttpThrd.Create(Hsock:TSocket;aServer : tTCPHttpDaemon; aOnProcess : tHttpGetEvent);
begin
sock:=TTCPBlockSocket.create;
// Headers := TStringList.Create;
Input := THttpInfo.Create;
Output := THttpInfo.Create;
Sock.socket:=HSock;
fOnProcessHttpRequest:=aOnProcess;
fServer:=aServer;
inherited create(false);
FreeOnTerminate:=true;
Priority:=tpNormal;
end;
Destructor TTCPHttpThrd.Destroy;
begin
// writeln('destroy');
sleep(3000);
Input.Free;
Output.Free;
inherited Destroy;
Sock.free;
end;
procedure TTCPHttpThrd.Execute;
var
// b: byte;
timeout: integer;
sp1,sp2,
s: ansistring;
// method, uri, protocol: string;
size: integer;
x,n: integer;
xcontentLength,
resultcode: integer;
log : boolean;
xclose,
xContinue : boolean;
{$IFDEF LOGD}
str : tFileStream;
{$ENDIF}
procedure divide(const cS:ansistring;ch : char;var s1,s2 : ansiString);
var
i : integer;
begin
i := Pos(ch, cs);
if i>0 then begin
s1:= copy(cs,1,i-1);
if cs[i+1]=' ' then inc(i);
s2:= copy(cs,i+1,length(cs));
end else begin
s1:=cs;
s2:='';
end;
end;
procedure wypiszError(ch : char);
begin
{$IFDEF LOGD}
s:='====='+crlf;
str.Write(pchar(s)^,length(s));
s:='sockerror '+ch+inttostr(sock.lastError)+crlf;
str.Write(pchar(s)^,length(s));
{$ENDIF}
end;
begin
xContentLength:=1;
{$IFDEF LOGD}
try
write('3');
str:=tFileStream.create('log3',fmOpenReadWrite+fmShareDenyNone);
str.seek(0,sofromend);
write('4');
{$ENDIF}
timeout := 120000;
//read request line
s := sock.RecvString(timeout);
{$IFDEF LOGD}
str.Write(pchar(s)^,length(s));
// sp1:=' |'+inttostr(GetTickCount);
// str.Write(pchar(sp1)^,length(sp1));
str.Write(crlf,2);
{$ENDIF}
if sock.lasterror <> 0 then begin
wypiszError('O');
Exit;
end;
if s = '' then
Exit;
// input.clear;
input.method := fetch(s, ' ');
if (s = '') or (input.method = '') then
Exit;
input.uri := fetch(s, ' ');
if input.uri = '' then
Exit;
divide(input.uri,'?',input.document,input.query);
// write('5');
input.protocol := fetch(s, ' ');
// headers.Clear;
size := -1;
x:=0;
//read request headers
// Output.Clear;
if input.protocol <> '' then
begin
if pos('HTTP/', input.protocol) <> 1 then
Exit;
repeat
s := sock.RecvString(Timeout);
{$IFDEF LOGD}
str.Write(pchar(s)^,length(s));
str.Write(crlf,2);
{$ENDIF}
if sock.lasterror <> 0 then begin
wypiszError('b');
Exit;
end;
if s <> '' then begin
divide(s,':',sp1,sp2);
sp1:=Uppercase(sp1);
if 'CONTENT-LENGTH'=sp1 then Size := StrToIntDef(SeparateRight(s, ' '), -1)
else if 'CONTENT-TYPE'=sp1 then input.contentType:=trim(sp2)
else if 'CONNECTION'=sp1 then input.closeConnection:=uppercase(sp2)='CLOSE'
// sp2<>'Keep-alive'
else if 'USER-AGENT'=sp1 then input.fuserAgent:=sp2
else if 'HOST'=sp1 then input.fHost:=sp2
else if 'ACCEPT-ENCODING'=sp1 then input.fEncodings:=sp2
else if 'ACCEPT-LANGUAGE'=sp1 then input.fLanguage:=sp2
else if 'ACCEPT-CHARSET'=sp1 then input.fcharset:=sp2
else if 'REFERER'=sp1 then input.freferer:=sp2
else if 'COOKIE'=sp1 then input.addCookie(sp2)
else input.Headers.add(s);
end;
until s = '';
end;
// output.protocol:=input.Protocol;
//recv document...
// Input.Clear;
{$IFDEF LOGD}
// s:='*****'+crlf;
// str.Write(pchar(s)^,length(s));
// sp1:=' B|'+inttostr(GetTickCount);
// str.Write(pchar(sp1)^,length(sp1));
{$ENDIF}
xClose:=true;
if detectAgent(input.fUserAgent)=2 then begin
xClose:=false;
write('KEEP');
end;
input.session:=fServer.getSessionFromCookie(input,output,xContinue);
if size >= 0 then
begin
Input.data.SetSize(Size);
// setstring(input.contentText,nil,size);
x := Sock.RecvBufferEx(Input.data.Memory, Size, Timeout);
Input.data.SetSize(x);
{$IFDEF LOGD}
input.data.saveToStream(str);
{$ENDIF}
if sock.lasterror <> 0 then begin
wypiszError('Z');
Exit;
end;
end;
if input.contentType='application/x-www-form-urlencoded' then begin
setlength(input.formParams,x);
input.data.seek(0,soFromBeginning);
input.data.read(pchar(input.formParams)^,x);
end;
{ResultCode :=} fOnProcessHttpRequest(input,output);
{
if output.responseNo = 200 then
sock.SendString('HTTP/1.1 200 OK'+ CRLF)
else
sock.SendString('HTTP/1.1 ' + IntTostr(output.ResponseNo) + CRLF);
}
// sp1:=' H|'+inttostr(GetTickCount);
// str.Write(pchar(sp1)^,length(sp1));
try
xcontentLength:=output.contentLength;
with output do begin
if output.responseNo = 200 then
headers.add('HTTP/1.1 200 OK')
else
headers.add('HTTP/1.1 ' + IntTostr(output.ResponseNo));
// headers.Add('X-Pad: avoid browser bug');
if output.CacheControl<>'' then
headers.Add('Cache-Control: '+output.cacheControl);
if output.Pragma<>'' then
headers.Add('Pragma: '+output.pragma);
for n := 0 to output.fCookies.count-1 do
Headers.Add( 'Set-Cookie: ' + output.fCookies[n]);
headers.Add('Server: Madar Mobile');
headers.add('Accept-Ranges: bytes');
// s:=headers.GetTextStr;
// sock.sendString(s);
// headers.add('Server: Apache/2.0.54 (Linux/SUSE)');
// headers.add('ETag: "4b0047-285f-4adbae00"');
if fDate>0 then begin
headers.Add('Date: ' + Rfc822DateTime(fDate));
end;
if expires>0 then
headers.Add('Expires: ' + Rfc822DateTime(expires));
if output.contentType<>'' then
headers.Add('Content-Type: '+output.contentType);
if xContentLength>0 then
headers.Add('Content-Length: ' + IntTostr(xcontentLength));
if {output.closeConnection} xClose then begin
headers.Add('Connection: close');
end else begin
// headers.add('Keep-Alive: 300');
headers.add('Keep-Alive: timeout=15,max=100');
headers.add('Connection: Keep-Alive');
end;
headers.Add('');
// for n := 0 to headers.count - 1 do begin
// sock.sendstring(output.headers[n] + CRLF);
// end;
if output.contenttext<>'' then
headers.add(output.contentText);
sock.sendString(headers.Text);
{$IFDEF LOGD}
headers.saveTostream(str);
{$ENDIF}
// end;
end;
{ if sock.lasterror <> 0 then begin
wypiszError('B');
Exit;
end;
}
if output.contenttext<>'' then begin
// sock.sendString(output.contentText);
{$IFDEF LOGD}
// sp1:=' T|'+inttostr(GetTickCount);
// str.Write(pchar(sp1)^,length(sp1));
// s:=output.contentText;
// str.Write(pchar(s)^,length(s));
{$ENDIF}
end else if output.ContentStream<>nil then begin
{$IFDEF LOGD}
// str.copyFrom(output.ContentStream,output.ContentStream.Size);
// output.contentStream.Position:=0;
{$ENDIF}
sock.SendStreamRaw(output.contentStream);
// output.contentStream.free;
end else if output.data.size<>0 then
{$IFDEF LOGD}
// output.data.saveToStream(str);
// output.data.Position:=0;
{$ENDIF}
Sock.SendBuffer(Output.data.Memory, Output.data.Size);
if sock.lasterror <> 0 then begin
wypiszError('C');
Exit;
end;
// sleep(10000);
// output.clear;
except
on e : exception do begin
{$IFDEF LOGD}
s:='=====';
str.Write(pchar(s)^,length(s));
s:='exception '+e.Message+crlf;
str.Write(pchar(s)^,length(s));
{$ENDIF}
writeln(e.message);
end;
end;
{$IFDEF LOGD}
finally
// sp1:=' t|'+inttostr(GetTickCount)+crlf;
write('1');
sleep(xContentLength);
str.Write(pchar(sp1)^,length(sp1));
// sock.closeSocket;
str.free;
write('2');
end;
{$ENDIF}
end;
(*
function TTCPHttpThrd.ProcessHttpRequest(Request, URI: string): integer;
var
l: TStringlist;
begin
//sample of precessing HTTP request:
// InputData is uploaded document, headers is stringlist with request headers.
// Request is type of request and URI is URI of request
// OutputData is document with reply, headers is stringlist with reply headers.
// Result is result code
result := 504;
if request = 'GET' then
begin
headers.Clear;
headers.Add('Content-type: Text/Html');
l := TStringList.Create;
try
l.Add('<html>');
l.Add('<head></head>');
l.Add('<body>');
l.Add('Request Uri: ' + uri);
l.Add('<br>');
l.Add('This document is generated by Synapse HTTP server demo!');
l.Add('</body>');
l.Add('</html>');
l.SaveToStream(OutputData);
finally
l.free;
end;
Result := 200;
end;
end;
*)
end.
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
synalist-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/synalist-public