Entwickler-Ecke

Internet / Netzwerk - IdHttpserver Frage


fsg4u - Do 03.11.05 16:42
Titel: IdHttpserver Frage
Moin. Ich will mir einen einfachen HTTP Server bauen. Finde aber nicht heraus, wo ich beim ID HTTP Server einstelle in welchem Ordner die Daten gespeichert sind, auf die Zugegriffen werden... Habt ihr da nen Plan für mich? Danke FSG


Stefan.Buchholtz - Do 03.11.05 16:53

Die idHttpServer-Komponente implementiert die Server-Seite des http-Protokolls, nichts weiter. Das ist kein vollständiger Web-Server. Den Rest musst schon schon selbst implementieren.

Stefan


fsg4u - Do 03.11.05 20:40

achso. ich dachte, weil man auch den port einstellt, dass man dies so einfach tun könnte. Danke FSG


avenger - Mi 15.09.10 14:43

Gibt es hierzu irgendwo ein tutorial ? Moechte eigentlich das gleiche wie fsg4u machen.


Muck - Mi 15.09.10 16:05

Hallo,

habe mal hier was zusammenkopiert. Ungetestet. Nur so als Geruest zur eigenen Verwendung. Natuerlich sollten Domain Names etc aus einer Einstellungsdatei kommen. Beispiel zeigt
- wie man mit einem Server verschiedene Domainnamen verwaltet (setze Verzeichnis, sende bestehende dateien mit ServeFile)
- wie man z.B. eine jpeg datei zurueckgibt die online berechnet wird (counter)
- wie man ein cookie schreibt
- wie man eingabeparameter ( sess ) einliest
- wie man einen XML String zurueckgibt, online berechnet

wie gesagt, ungetestet, einfach als Beispiel aus einem bestehenden Project rauskopiert.
Vielleicht hilft es ja als Start.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdBaseComponent, IdComponent, IdCustomHTTPServer,
  IdHTTPServer, StdCtrls, IdContext,inifiles,jpeg, ComCtrls, AppEvnts, ExtCtrls,
  idcookie;

var
BS:Int64;

Procedure Log(W:String);
begin
//Write To LogFile;
end;

Function WriteCounter(W:String):String;
begin
//Move the content of a jpeg stream into the return string
end;

Function MakeTheXML(W:String):String;
begin
//Return XML Data
end;

Function DoTheHTML(W:String):String;
begin
//Return HTML content
end;


procedure TForm1.HTTPServerCommandGet(Context: TIdContext;  RequestInfo: TIdHTTPRequestInfo; ResponseInfo: TIdHTTPResponseInfo);
var LocalRoot,LocalDoc,Cook:String;ResultFile:TFileStream;WriteCookie:TIdCookieRFC2109;HostNo:Byte;I:Integer;TS:TStringList;
begin
LocalRoot:=Root;HostNo:=0;
if (Pos('henry.com',lowercase(RequestInfo.Host))>0then begin
  LocalRoot:='C:\henry web files';HostNo:=3;
end else if Pos('asianmart.com',lowercase(RequestInfo.Host))>0 then begin
  LocalRoot:='C:\JMart';HostNo:=1;
end else if (Pos('piano.com',lowercase(RequestInfo.Host))>0then begin
  LocalRoot:='C:\piano files';HostNo:=2;
end;
LocalDoc:=LowerCase(StringReplace(ExpandFileName(LocalRoot+RequestInfo.Document),'%20',' ',[rfReplaceAll]));
if not FileExists(LocalDoc) and DirectoryExists(LocalDoc) and FileExists(ExpandFileName(LocalDoc + '/index.htm')) then begin
  LocalDoc := ExpandFileName(LocalDoc + '/index.htm');
end;
Log(LocalDoc+' to '+Context.Connection.Socket.Binding.PeerIP);
ResponseInfo.ContentType:=HTTPServer.MimeTable.GetFileMIMEType(LocalDoc);
if Pos('counter.jpg',LocalDoc)>0 then begin
  ResponseInfo.ContentType:='image/JPEG';
  ResponseInfo.ContentText:=WriteCounter(localDoc); // return content of an jpeg file
end else begin
  // Default is index.htm
  if fileexists(LocalDoc) or (length(RequestInfo.Params.Values['sess'])>0then begin
    if AnsiSameText(RequestInfo.Command, 'HEAD'then begin
      Log('HEAD HEAD HEAD ------------------ '+LocalDoc);
      // HEAD request, don't send the document but still send back it's size
      ResultFile := TFileStream.create(LocalDoc, fmOpenRead or fmShareDenyWrite);
      try
        ResponseInfo.ResponseNo := 200;
        ResponseInfo.ContentLength := ResultFile.Size;
      finally
        ResultFile.Free;
      end;
    end else begin
      case HostNo of
      0:begin
      if (length(RequestInfo.Params.Values['sess'])>0then begin // session parameter found, create html on the fly
        ResponseInfo.ContentText:=DoTheHTML(RequestInfo,LocalDoc,Context.Connection.Socket.Binding.PeerIp);
        WriteCookie := responseinfo.Cookies.Add;
        WriteCookie.CookieName := 'rememberme';
        WriteCookie.Value := 'Its me';
        WriteCookie.Domain := 'henry.com';
        WriteCookie.Expires := 'Wed, 30-SEP-2020 01:00:01 GMT';
      end else begin
        if Pos('xml.htm',LowerCase(localDoc))>0 then begin
          ResponseInfo.ContentType:='text/xml';
          ResponseInfo.ContentText:=MakeTheXML(RequestInfo);
          Inc(BS,length(ResponseInfo.ContentText));
        end else Inc(BS,ResponseInfo.ServeFile(Context,LocalDoc));
      end;
      end;
      1,2:begin
        Inc(BS,ResponseInfo.ServeFile(Context,LocalDoc));
        end;
      end// end of case HostNo
    end;
  end else begin
    ResponseInfo.ContentType:='text/HTML';
    ResponseInfo.ResponseNo := 404// Not found
    ResponseInfo.ContentText := '<html><head><title>Error</title></head><body><h1>' + ResponseInfo.ResponseText + '</h1></body></html>';
  end;
end;
end;


avenger - Mi 15.09.10 19:25

danke fuer die info aber ich komme damit ueberhaupt nicht klar. Wie schaff ich es das der server mit der einer index.html oder index.php antwortet ?

Muss ich dazu auch einen Filestream erzeugen ? Hast du veilleicht ein ganz einfaches Grundbeispiel ?


Muck - Mi 15.09.10 19:41

Hi,
das war eigentlich schon in dem letzten Code enthalten. Also hier nochmal verkuerzt.
Um ein file zurueckzugeben wird ServeFile in ResponseInfo benutzt.

Lege einen Ordner C:\WebFiles an und kopiere eine komplette Website in den Ordner.
Starte Testprogramm und dann Deinen browser und teste mit http://127.0.0.1
Die Hauptdatei muss in diesem Beispiel index.htm heissen.

Markus


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
procedure TForm1.HTTPServerCommandGet(Context: TIdContext;  RequestInfo: TIdHTTPRequestInfo; ResponseInfo: TIdHTTPResponseInfo);
var LocalRoot,LocalDoc:String;ResultFile:TFileStream;
begin
LocalRoot:='C:\WebFiles';
LocalDoc:=LowerCase(StringReplace(ExpandFileName(LocalRoot+RequestInfo.Document),'%20',' ',[rfReplaceAll]));
if not FileExists(LocalDoc) and DirectoryExists(LocalDoc) and FileExists(ExpandFileName(LocalDoc + '/index.htm')) then begin
  LocalDoc := ExpandFileName(LocalDoc + '/index.htm');
end;
ResponseInfo.ContentType:=HTTPServer.MimeTable.GetFileMIMEType(LocalDoc);
// Default is index.htm
if fileexists(LocalDoc) then begin
  if AnsiSameText(RequestInfo.Command, 'HEAD'then begin
    Log('HEAD HEAD HEAD ------------------ '+LocalDoc);
    // HEAD request, don't send the document but still send back it's size
    ResultFile := TFileStream.create(LocalDoc, fmOpenRead or fmShareDenyWrite);
    try
      ResponseInfo.ResponseNo := 200;
      ResponseInfo.ContentLength := ResultFile.Size;
    finally
      ResultFile.Free;
    end;
  end else ResponseInfo.ServeFile(Context,LocalDoc); // <----- Datei zurueckgeben
end else begin
  ResponseInfo.ContentType:='text/HTML';
  ResponseInfo.ResponseNo := 404// Not found
  ResponseInfo.ContentText := '<html><head><title>Error</title></head><body><h1>' + ResponseInfo.ResponseText + '</h1></body></html>';
end;
end;


avenger - Mi 15.09.10 19:50

AResponseInfo.ContentType:=tIdHTTPServer.MimeTable.GetFileMIMEType(LocalDoc);

bekomme in der Zeile die Fehlermeldung das mimetable inaccessible here ist ! Was bedeutet MimeTable ?


Muck - Mi 15.09.10 20:14

Nun, damit wird der ContentType fuer die Responseinfo gesetzt.
Falls Du den ContentType nicht setzt werden mp3 Dateien aufeinmal im Browser angezeigt.
Meine Procedur laueft auf Delphi 2007.
Du kannst die Zeile auch weglassen und konstant mit 'text/html' setzen, falls Du eh nur htm Dateien zurueckgibts.
Ansonsten, in aelteren Indy Versionen sollte es so gehen.

Ersetze die fehlerhafte Zeile in CommandGet mit:

Delphi-Quelltext
1:
ResponseInfo.ContentType:= GetMIMEType(LocalDoc);                    


Ausserdem addiere zum Testprogramm:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
var
MIME1: TIdMIMETable;

procedure TForm1.FormCreate(Sender: TObject);
begin
MIME1:= TIdMIMETable.Create(true);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
MIME1.Free;
end;

function GetMIMEType(sFile: TFileName): string;
begin
result:= MIME1.GetFileMIMEType(sFile);
end;


avenger - Mi 15.09.10 20:29

Hallo,

var
MIME1: TIdMIMETable;

die variable laesst sich so nicht deklarieren. Muss da noch etwa in die USES ?


Ich nutze D2010 aber eigentlich sollte das mit den Indys doch auch funkionieren. Habe leider mit dem tidhttpserver noch nie zu tun gehabt. hab schon oefers mit den Smtp und dem TCP Server gearbeitet und das leiss sich relativ leicht nach D2010 portieren ?


Muck - Mi 15.09.10 20:53

Hallo,

Du hast Delphi 2010, nun hier ist MimeTable bereits in IdHTTPServer enthalten.
Addieren im ersten Beispiel IDGlobalProtocols zum uses, das ist neu in Delphi2010.
Dann sollte

Delphi-Quelltext
1:
ResponseInfo.ContentType:=IdHTTPServer1.MimeTable.GetFileMIMEType(LocalDoc);                    

funktionieren.
Brauchst also nicht selbst im Form Create anzulegen.

Markus


avenger - Mi 15.09.10 21:24

Hallo,

Ich habs jetzt zumindest mal so das es kompiliert. Beim aufrufen im Browser wird oeffnet sichjedoch der download dialog und man kann die index.htm laden und dann zeigt ers ie erst im Browser an. Also es wird nicht direkt im Browser angezeigt !
Danke fuer deine Hilfe !!




Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
procedure TForm2.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var LocalRoot,LocalDoc:String;ResultFile:TFileStream;
begin
LocalRoot:='C:\WebFiles';
LocalDoc:=LowerCase(StringReplace(ExpandFileName(LocalRoot+ARequestInfo.Document),'%20',' ',[rfReplaceAll]));
if not FileExists(LocalDoc) and DirectoryExists(LocalDoc) and FileExists(ExpandFileName(LocalDoc + '/index.htm')) then begin
  LocalDoc := ExpandFileName(LocalDoc + '/index.htm');
end;
AResponseInfo.ContentType:=IdHTTPServer1.MimeTable.GetFileMIMEType(LocalDoc);
// Default is index.htm
if fileexists(LocalDoc) then begin
  if AnsiSameText(ARequestInfo.Command, 'HEAD'then begin
    //Log('HEAD HEAD HEAD ------------------ '+LocalDoc);
    // HEAD request, don't send the document but still send back it's size
    ResultFile := TFileStream.create(LocalDoc, fmOpenRead or fmShareDenyWrite);
    try
      AResponseInfo.ResponseNo := 200;
      AResponseInfo.ContentLength := ResultFile.Size;
    finally
      ResultFile.Free;
    end;
  end else AResponseInfo.ServeFile(aContext,LocalDoc); // <----- Datei zurueckgeben
end else begin
  AResponseInfo.ContentType:='text/HTML';
  AResponseInfo.ResponseNo := 404// Not found
  AResponseInfo.ContentText := '<html><head><title>Error</title></head><body><h1>' + AResponseInfo.ResponseText + '</h1></body></html>';
end;
end;


Muck - Mi 15.09.10 21:39

Hallo,

nun da hat sich was in Delphi2010 geaendert. Der Code laeuft problemlos in Delphi 2007 und Delphi 2009. Compiliere ich mit 2010 wird zunaechst gefragt ob ich 127_0_0_1.txt downloaden will.

Leider gibt es noch keine Indy 10 Demos. Veilleicht findet sich was in der Hilfe. Es hat mit dem MimeTable zu tun, index.htm sollte nicht als txt Datei zum download angeboten werden.

Markus

---Moderiert von user profile iconNarses: Beiträge zusammengefasst---

Hi,


Delphi-Quelltext
1:
2:
3:
4:
5:
    ResultFile:=TFileStream.create(LocalDoc, fmOpenRead or fmShareDenyWrite);
    ResponseInfo.ResponseNo := 200;
    ResponseInfo.ContentLength := ResultFile.Size;
    ResponseInfo.ContentStream:=ResultFile;
//    ResponseInfo.ServeFile(AContext,LocalDoc); // <----- Datei zurueckgeben


Stream statt ServeFile funktioniert unter Delphi 2010.

Markus


avenger - Mi 15.09.10 22:06

Soo ?? Also bei mir kommt immer noch der download Dialog.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
procedure TForm2.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var LocalRoot,LocalDoc:String;ResultFile:TFileStream;
begin
LocalRoot:='C:\WebFiles';
LocalDoc:=LowerCase(StringReplace(ExpandFileName(LocalRoot+ARequestInfo.Document),'%20',' ',[rfReplaceAll]));
if not FileExists(LocalDoc) and DirectoryExists(LocalDoc) and FileExists(ExpandFileName(LocalDoc + '/index.htm')) then begin
  LocalDoc := ExpandFileName(LocalDoc + '/index.htm');
end;
AResponseInfo.ContentType:=IdHTTPServer1.MimeTable.GetFileMIMEType(LocalDoc);
// Default is index.htm
if fileexists(LocalDoc) then begin
  if AnsiSameText(ARequestInfo.Command, 'HEAD'then begin
    //Log('HEAD HEAD HEAD ------------------ '+LocalDoc);
    // HEAD request, don't send the document but still send back it's size
    ResultFile := TFileStream.create(LocalDoc, fmOpenRead or fmShareDenyWrite);
    try
      AResponseInfo.ResponseNo := 200;
      AResponseInfo.ContentLength := ResultFile.Size;
    finally
      ResultFile.Free;
    end;
  end else AResponseInfo.ContentStream:=ResultFile;///AResponseInfo.ServeFile(aContext,LocalDoc); // <----- Datei zurueckgeben

end else begin
  AResponseInfo.ContentType:='text/HTML';
  AResponseInfo.ResponseNo := 404// Not found
  AResponseInfo.ContentText := '<html><head><title>Error</title></head><body><h1>' + AResponseInfo.ResponseText + '</h1></body></html>';

end;
end;


Muck - Mi 15.09.10 22:15

Hallo,

nun, am besten mal den Internet cache leeren. Der browser liest immer noch 127_0_0_1.txt vom cache.
Zu Deinem Code:
Den Stream auch oeffnen.
Wie im letzten Post die kompletten 4 Zeilen in den else Zweig statt der ServeFile Zeile.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
if AnsiSameText(ARequestInfo.Command, 'HEAD'then begin
.
.
.
.
.
.
end else begin
  ResultFile:=TFileStream.create(LocalDoc, fmOpenRead or fmShareDenyWrite);
  ResponseInfo.ResponseNo := 200;
  ResponseInfo.ContentLength := ResultFile.Size;
  ResponseInfo.ContentStream:=ResultFile;
end;


Markus