# kleiner Webserver in C



## huebstAr (13. Dezember 2011)

Hi an Alle!

Wie im Topic zu lesen soll dieses Programm einen kleinen Webserver darstellen, der zunächst einmal nur die Seite bei einem Request in den Socket zurückschreiben soll.

Leider scheint hier irgendwo ein Fehler zu sein, da ich, wenn ich die Seite 127.0.0.1 aufrufe, eine Fehlermeldung im Browser  bekomme.

Ich stehe nur etwas auf dem Schlauch, da die Kontrollausgaben im Programm so aussehen, wie ich sie mir vorgestellt habe.

Wisst ihr vielleicht weiter?


```
//
// Programm:         einfacher Webserver
// Funktiosumfang:    Lauschen auf Port 80, bei Anfrage einer Seite,
//            diese zum anfragenden Client zurÃ¼cksenden


//----------------------------------------------------------------------------
// Einbinden der Headerdateien
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

// Prototypen der verwendeten Funktionen
int deploy_server();
void process_request(int result_accept);

int main()
{
    int     sock=-1,
        source=0,
        result_accept=0,
        pid=-1,
        len_addr=0,
        status=0;
    struct sockaddr_in requestor;
   
    printf(".\n");
    printf(".\n");   
    printf("Webserver v1.0 gestartet\n");
    printf(".\n");
    printf(".\n");

    do {

        sock = deploy_server();
        if(sock<0)
        {       
            printf("Fehler beim Deployen des Servers!\n");
            printf("<RETURN> fÃ¼r Neuversuch\n\n");
            getchar();
        }

    }while(sock < 0);

    while(1)
    {
        len_addr = sizeof(source);
        result_accept = accept(sock, (struct sockaddr*) &source, &len_addr);
       
        if(-1 == result_accept)
        {
            printf("Fehler beim Verbindungsaufbau\n");
        }
        else
        {
            printf("Verbindungsaufbau erfolgreich\n");
        }

        pid = fork();
       
        if(-1 == pid)
        {   
            printf("Fehler beim erstellen des Sohnprozesses!\n");
        }
       
        if(0 == pid)
        {
            process_request(result_accept);
            exit(0);
            waitpid(-1, &status, WNOHANG);
            printf("Status: %d", status);
        }
       
        close(result_accept);

    }

}

int deploy_server()       
{
    int     sock,
        result_bind=5;
    struct     sockaddr_in adressinfo;

    sock = socket(AF_INET, SOCK_STREAM, 0);
   
    bzero(&adressinfo, sizeof(adressinfo));
   
    adressinfo.sin_family = AF_INET;
    adressinfo.sin_port = htons(80);
    adressinfo.sin_addr.s_addr = INADDR_ANY;
   
    result_bind = bind(sock, (struct sockaddr*) &adressinfo, sizeof(adressinfo));

    if(result_bind == -1)
    {   
        printf("Fehler bei Bind");
        return -1;   
    }

    listen(sock, 2);
    return(sock);
}

void process_request(int sock)
{
    char     	sendbuffer[8096],
        	request[8096],
		filename[8096],
        	buffer;
    int    	i=0,
        	k=0,f=0,
        	ext_laenge=0,
        	anzahl=0,
        	file_descript=0;
    char     	get_ext[4];
   
    	bzero(&request, sizeof(request));
	bzero(&filename, sizeof(filename));
   
    while(i < sizeof(request)-1)    // solange die LÃ¤nge des Strings nicht Ã¼berschritten wird
    {
        if(    read(sock, &buffer, 1) > 0    // Solange ein Zeichen gelesen werden kann
            && buffer != '\n'         // UND kein Zeilenumbruch
            && buffer != '\r')
        {       
            request[i] = buffer;        // weiter einlesen
            i++;
        }
        else
        {
            request[i] = '\0';        // Sonst String abschlieÃŸen
            break;                // und Schleife abbrechen
        }
    }

    // Kontrollausgabe der Anfrage
    for(k=0; k< sizeof(request); k++)
        printf("%c", request[k]);
    printf("\n\n");
   
    // PrÃ¼fen ob Get-Anfrage (nicht Case-Sensitive)
    if(!strncmp(request, "GET ", 4) || !strncmp(request, "get ", 4)) // falls GET
    {   
        i=5;        					// Startwert des Index, GET wird ignoriert
   
        if(!strncmp(&request[5], " ", 1))    		// Wenn keine Seite angegeben
        {     
            	strcpy(request, "GET /index.html");    	// String auf index.html setzen                              
        }
       
	while(strncmp(&request[i], " ", 1) != 0)	// SOLANGE KEIN Leerzeichen gefunden
	{      
		strncpy(&filename[f], &request[i], 1);	// Zeichen an Filename anhÃ¤ngen
		f++; i++;
	}

        // Extensions prÃ¼fen
        // FEHLT NOCH
        // FEHLT NOCH
        // FEHLT NOCH
        // FEHLT NOCH
   
	printf("OPENING: >%s<\n", filename);
	file_descript=open(filename, O_RDONLY);		// Angefordertes File Ã¶ffnen
        
	if(file_descript != -1)
        {
         /*   	while(anzahl=read(file_descript, sendbuffer, sizeof(sendbuffer)))
                	write(sock, sendbuffer, anzahl);*/
		write(sock, sendbuffer, read(file_descript, sendbuffer, sizeof(sendbuffer)));
	        close(file_descript);
        }       
        else
            printf("Fehler! File konnte nicht geÃ¶ffnet werden!\n");
   
        close(sock);   
	printf("--> ENDE \n");
    }
    else
        printf("Nur GET-Anfragen werden bearbeitet!\n");
}
```

Desweiteren bin ich mir nicht ganz sicher, ob die Anweisung close(sock); (*in Zeile 185) hier an der richtigen Stelle steht, da dort der socket ja eignetlich immer offen gehalten werden sollte?!

Wo kann ich sie sonst unterbringen? Das Programm wird auf einem SuSe-System ausgefürt und mit Strg+C terminiert. Ich habe die Vermutung, dass hier eventuell der Fehler steckt, da nach einiger Zeit der Aufruf zunächst funktioniert (Seite wird an Client zurückgegeben) und anschließend für eine längere Zeit nicht mehr.


Gruß
huebstAr


----------



## Bratkartoffel (13. Dezember 2011)

Hi,

welche Fehlermeldung? Hast du schon mal den Request über telnet abgesetzt und geschaut was wirklich vom Server kommt?

Welchen Standard folgst du? HTTP/1.0 oder HTTP/1.1?

Gruß
BK


----------



## huebstAr (13. Dezember 2011)

Hi!

Das mit Telnet werde ich gleich mal versuchen.

Hier zu der Fehlermeldung:



Gruss

Kleiner Edit: Das Spuckt telnet aus



Wobei "lalelu.txt" der Inhalt von index.html ist.


----------



## sheel (13. Dezember 2011)

Hi

Dein Server schließt nach Übertragung die Socketverbindung von sich aus.
Diesen Teil sollte der Browser übernehmen.
Sonst kann es passieren, dass nicht alle Byte ankommen.

Also nach Übertragung weitere Befehle abwarten.
Wenn recv mit einem Fehlerreturnwert kommt (macht es bei geschlossener Verbindung),
dann Ende.

Gruß


----------



## huebstAr (13. Dezember 2011)

Hi!

Also verstehe ich nun richtig: Das close(socket); sollte nicht an dieser Stelle stehen, sondern wenn von dem Browser (Client) eine Fehlermeldung kommt, aufgerufen werden?

€: Nein, falsch verstanden, ich Denke du meinst das close(result_accept); !?


----------



## sheel (13. Dezember 2011)

Beides nur so halb.
Erstens handelt es sich bei result_accept und sock in process_request
um den gleichen Socket.

Dann schließt du (nicht in jedem Fall, aber doch) sock schon in process_request,
und dann schließt du result_accept nocheinmal.

Drittens soll das nicht gemacht werden, wenn die Fehlermeldung kommt,
sondern eben, um diese zu verhindern.


Der Browser schickt "GET irgendwas".
Dein Server schickt den Inhalt (wo ist eigentlich der Header :suspekt.
Wenn der Browser alles hat, schließt der die Verbindung.
Der Server muss warten, ob geschlossen wird oder weitere Befehle kommen.

Abe wo der Head ist, wäre interessant...


----------



## huebstAr (13. Dezember 2011)

Danke erstmal!



sheel hat gesagt.:


> Beides nur so halb.
> Erstens handelt es sich bei result_accept und sock in process_request
> um den gleichen Socket.
> 
> ...


Leuchtet mir so halb ein. Wenn ich den Socket schon geschlossen habe und dann nochmals schließe (wobei aber noch keine neue Socket-Nr eingetragen wurde), passiert ja im Prinzip nichts, oder?



sheel hat gesagt.:


> Drittens soll das nicht gemacht werden, wenn die Fehlermeldung kommt,
> sondern eben, um diese zu verhindern.


Hier weiß ich nicht, was du damit meinst. Der Socket soll doch nach jedem mal geschlossen werden, falls eine Seite übertragen wurde. Sofern bin ich mir nun nicht ganz sicher, was du meinst mit "Fehlermeldung verhindern".



sheel hat gesagt.:


> Dein Server schickt den Inhalt (wo ist eigentlich der Header :suspekt.
> Wenn der Browser alles hat, schließt der die Verbindung.


Meinst du den Kopf der HTML-Seite? Habe ich nun nachträglich eingefügt. Das dürfte ja aber nicht zu der nicht-anzeige führen, oder?



sheel hat gesagt.:


> Der Server muss warten, ob geschlossen wird oder weitere Befehle kommen.


Wie kann ich auf dieses Ereignis warten? Was schickt der Browser denn für eine Stop-Condition? Der Server soll nur eine Seite anzeigen, weiteres nicht.


Gruß


----------



## sheel (13. Dezember 2011)

Zum Schließen: Ob da was passiert oder nicht, ist nicht garantiert.
Das Programm könnte auch ebensogut abstürzen.

Mit Header meinte ich den des HTTP-Protokolls...
hier das Inhaltsverzeichnis 

Genauer das:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4

Und wie man erkennt, ob die Gegenseite den Socket schließt:
recv liefert einen Fehlercode.
read ist sowieso fehl am Platz.


----------



## Bratkartoffel (14. Dezember 2011)

Hi,

zuerstmal: Es ist egal, ob der Server oder der Client die Verbindung schließt.
Bei persistenten Verbindungen (ab HTTP/1.1) wird die Verbindung (mit einem richtigen Header) zum Beispiel primär vom Client geschlossen, wenn der nichts mehr zu sagen hat. Bei HTTP/1.0 oder nicht persistenten Verbindungen schließt der Server die Verbindung, sobald er alle Daten gesendet hat. Der entsprechende Header nennt sich "Connection" und hat dann entweder "close" oder "Keep-Alive" als Wert.

Ich denke mal, dass du das HTTP-Protokoll nicht RFC-konform umsetzt und sich daher der Firefox weigert was anzuzeigen.

Wie sieht dein Request an den Server und die Antwort darauf exakt aus?
Es sollte in etwa so aussehen:

```
/* REQUEST START */
GET /index.html HTTP/1.0
Zusaetzliche-Header: Felder

/* REQUEST ENDE */
/* ANSWER START */
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 29

dies ist der text der antwort
/* ANSWER ENDE*/
```

Woruaf ich dich besonders hinweisen möchte: Zwischen dem Header und dem Body steht eine Leerzeile (genauso am Ende des Requests) und bei der Antwort muss das Feld "Content-Length" gesetzt sein. Ob der "Content-Type" auch benötigt wird, kann ich dir ausm Gedächtnis leider nicht sagen, würde den aber trotzdem mitsenden.

Edit: Hier noch ein bisschen was zum Lesen für dich: RFC 2616

Gruß,
BK


----------



## huebstAr (14. Dezember 2011)

Hi!

Danke erstmal für die Ausführung. Habe nun (erst einmal) den Header so eingefügt. Da ich noch einige kleiner Änderungen durchgeführt habe, schreibe ich hier nochmal den aktuellen Code rein:


```
//----------------------------------------------------------------------------
// Einbinden der Headerdateien
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

// Prototypen der verwendeten Funktionen
int deploy_server();
void process_request(int result_accept);

int main()
{
    int     sock=-1,
        source=0,
        result_accept=0,
        pid=-1,
        len_addr=0,
        status=0;
    struct sockaddr_in requestor;
   
    printf(".\n");
    printf(".\n");   
    printf("Webserver v1.0 gestartet\n");
    printf(".\n");
    printf(".\n");

    do {

        sock = deploy_server();
        if(sock<0)
        {       
            printf("Fehler beim Deployen des Servers!\n");
            printf("<RETURN> für Neuversuch\n\n");
            getchar();
        }

    }while(sock < 0);

    while(1)
    {
        len_addr = sizeof(source);
        result_accept = accept(sock, (struct sockaddr*) &source, &len_addr);
       
        if(-1 == result_accept)
        {
            printf("Fehler beim Verbindungsaufbau\n");
        }
        else
        {
            printf("Verbindungsaufbau erfolgreich\n");
        }

        pid = fork();
       
        if(-1 == pid)
        {   
            printf("Fehler beim erstellen des Sohnprozesses!\n");
        }
       
        if(0 == pid)
        {
            process_request(result_accept);
            exit(0);
            waitpid(-1, &status, WNOHANG);
            printf("Status: %d", status);
        }
       
        close(result_accept);

    }

}

int deploy_server()       
{
    int     sock,
        result_bind=5;
    struct     sockaddr_in adressinfo;

    sock = socket(AF_INET, SOCK_STREAM, 0);
   
    bzero(&adressinfo, sizeof(adressinfo));
   
    adressinfo.sin_family = AF_INET;
    adressinfo.sin_port = htons(80);
    adressinfo.sin_addr.s_addr = INADDR_ANY;
   
    result_bind = bind(sock, (struct sockaddr*) &adressinfo, sizeof(adressinfo));

    if(result_bind == -1)
    {   
        printf("Fehler bei Bind");
        return -1;   
    }

    listen(sock, 5);
    return(sock);
}

void process_request(int sock)
{
    char     	sendbuffer[8096],
        	request[8096],
		filename[8096],
        	buffer;
    int    	i=0,
        	k=0,f=0,
        	ext_laenge=0,
        	anzahl=0,
        	file_descript=0;
    char     	ex_extension[4];
   
    	bzero(&request, sizeof(request));
	bzero(&filename, sizeof(filename));
	bzero(&sendbuffer, sizeof(sendbuffer));
	bzero(&ex_extension, sizeof(ex_extension));
   
    while(i < sizeof(request)-1)    // solange die Länge des Strings nicht überschritten wird
    {
        if(    read(sock, &buffer, 1) > 0    	// Solange ein Zeichen gelesen werden kann
            && buffer != '\n'         		// UND kein Zeilenumbruch
            && buffer != '\r')
        {       
            request[i] = buffer;        // weiter einlesen
            i++;
        }
        else
        {
            request[i] = '\0';        	// Sonst String abschließen
            break;                	// und Schleife abbrechen
        }
    }

    // Kontrollausgabe der Anfrage
    for(k=0; k< sizeof(request); k++)
        printf("%c", request[k]);
    printf("\n\n");
   
    // Prüfen ob Get-Anfrage (nicht Case-Sensitive)
    if(!strncmp(request, "GET ", 4) || !strncmp(request, "get ", 4)) // falls GET
    {   
        i=5;        					// Startwert des Index, GET wird ignoriert
	f=0;
   
        if(!strncmp(&request[5], "\0", 1) || !strncmp(&request[5], "\0", 1))    // Wenn keine Seite angegeben
        {     
		printf("keine page\n");
            	strcpy(request, "get /index.html ");    	// String auf index.html setzen                              
        }
       
	while(strncmp(&request[i], " ", 1))	// SOLANGE KEIN Leerzeichen erreicht
	{      
		strncpy(&filename[f], &request[i], 1);	// Zeichen an Filename anhängen
		f++; i++;
	}

	i=0;
	
        // Extensions extrahieren
        while(strncmp(&filename[i], ".", 1))    	// Punkt suchen
        {     
		i++;
        }
	strcpy(ex_extension, &filename[i+1]);		// Fileextension extrahieren
   
	 // Extension zuordnen
	 // FEHLT
	 // FEHLT
	 // FEHLT
	  
	printf("OPENING: >%s<\n", filename);
	printf("EXTENSION: >%s<\n", ex_extension);
	file_descript=open(filename, O_RDONLY);		// Angefordertes File öffnen
        
	if(file_descript != -1)
        {
	    sprintf(request, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
	    anzahl=read(file_descript, sendbuffer, sizeof(sendbuffer));
	    {
		write(sock, sendbuffer, anzahl);
	    }
	    
	    close(file_descript);
        }       
        else
            printf("Fehler! File konnte nicht geöffnet werden!\n");
   
	printf("--> ENDE \n");
    }
    else
        printf("Nur GET-Anfragen werden bearbeitet!\n");
}
```

Nun, das Programm tut bis hierhin was es soll, jedenfalls via Telnet. Das Problem ist, dass der FF scheinbar H*TTP*TML/1.1 requestet. 
Kann man den Firefox irgendwie 'toleranter' schalten?

Das interessante ist, dass durchschnittlich jedes 2. Mal die Page angezeigt wird, wenn ich einfach nochmal einen Refresh durchfuehre, kann es sein, dass die Page mit der Fehlermeldung "The connection was reset" terminiert wird.

Im Fenster des Programms "webserver" auf Konsolenebene wird jedoch der richtige Request / bzw. nichts auffaelliges angezeigt.

```
OPENING: >index.html<
EXTENSION: >html<
--> ENDE
Verbindungsaufbau erfolgreich
GET /index.html HTTP/1.1

OPENING: >index.html<
EXTENSION: >html<
--> ENDE
Verbindungsaufbau erfolgreich
GET /index.html HTTP/1.1

OPENING: >index.html<
EXTENSION: >html<
--> ENDE
Verbindungsaufbau erfolgreich
GET /index.html HTTP/1.1

OPENING: >index.html<
EXTENSION: >html<
--> ENDE
Verbindungsaufbau erfolgreich
GET /index.html HTTP/1.1

OPENING: >index.html<
EXTENSION: >html<
--> ENDE
```

Hat da jemand ne Idee?


----------



## sheel (14. Dezember 2011)

HTML1.1: Du meinst HTTP. Großer Unterschied.

Kannst du die Telneteinagbe/ausgabe auch mal zeigen?

PS: content-length...


----------



## huebstAr (14. Dezember 2011)

Hi,
sorry, meinte natuerlich HTTP/1.1.

Hier mal 2 Screenys:
1. 2. 3. Request sind vom Telnet-Fenster, also ohne HTTP/1.1

4. und 5. request sind vom Firefox.






Was meinst Du mit Content-Length? Ist hier was falsch? Sehe da nun nichts >x


----------



## sheel (14. Dezember 2011)

Also, nocheinmal:
Außer dem Content-Type musst du die Content-Length angeben.
Als Zahl, wieviel Chars (oder Byte?, muss nachschauen) die Datei hat.

Der Zeichensatz ist auch eines der essentiellen Sachen, die möglichst dabei sein sollten.

Dein Header wird nirgends geschickt,

Zum Senden (Header und Daten) über den Socket solltest du Socketfunktionen verwenden und deren Eigenheiten beachten (uU. wird nicht mit einem Aufruf alles gesendet).

Und wenn FF HTTP1.1 verlangt (was übrigens nicht umstellbar ist und auch verwendet werden sollte, da 1.0 mit heutigem Zeug Probleme hat), dann gib ihm im Header doch HTTP1.1, nicht 1.0.


----------



## Bratkartoffel (15. Dezember 2011)

Hi,

dem Firefox ist es relativ egal, ob er nun HTTP/1.0 oder 1.1 Antworten bekommt. Ich würde auch auf die fehlende Angabe des "Content-Length" Headers in der Antwort tippen.

Grüße,
BK


----------



## huebstAr (17. Dezember 2011)

Moin Zusammen!

Danke erstmal für die Tipps, habe mich noch ein wenig damit beschäftigt und bin auch 'ne Ecke weiter gekommen (meiner Ansicht nach zumindest )

Also stand der Dinge:

```
//

//----------------------------------------------------------------------------
// Einbinden der Headerdateien
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>


// Prototypen der verwendeten Funktionen
int deploy_server();
void process_request(int result_accept);

// Struktur mit erlaubten MIME-Types
struct {
    char *ext;
    char *filetype;
      }
extensions[] =
    {
    {"gif", "image/gif"},
    {"jpg", "image/jpg"},
    {"jpeg", "image/jpeg"},
    {"png", "image/png"},
    {"zip", "image/zip"},
    {"gz", "image/gz"},
    {"tar", "image/tar"},
    {"htm", "text/htm"},
    {"html", "text/html"},
    {0,0}
    };


int main()
{
    int     sock=-1,
	    source=0,
	    result_accept=0,
	    pid=-1,
	    len_addr=0,
	    status=0;
    struct sockaddr_in requestor;
   
    printf(".\n");
    printf(".\n");   
    printf("Webserver v1.3 gestartet\n");
    printf(".\n");
    printf(".\n");


    do {


        sock = deploy_server();
        if(sock<0)
        {       
            printf("Fehler beim Deployen des Servers!\n");
            printf("<RETURN> für Neuversuch\n\n");
            getchar();
        }


    }while(sock < 0);


    while(1)
    {
        len_addr = sizeof(source);
        result_accept = accept(sock, (struct sockaddr*) &source, &len_addr);
       
        if(-1 == result_accept)
        {
            printf("Fehler beim Verbindungsaufbau\n");
        }
        else
        {
            printf("Verbindungsaufbau erfolgreich\n");
        }


        pid = fork();
       
        if(-1 == pid)
        {   
            printf("Fehler beim erstellen des Sohnprozesses!\n");
        }
       
        if(0 == pid)		// wenn Sohnprozesses
        {
            process_request(result_accept);
            exit(0);
        }
	waitpid(-1, &status, WNOHANG);
        close(result_accept);
    }
}


int deploy_server()       
{
    int     sock,
	    result_bind=5;
    struct     sockaddr_in adressinfo;


    sock = socket(AF_INET, SOCK_STREAM, 0);
   
    bzero(&adressinfo, sizeof(adressinfo));
   
    adressinfo.sin_family = AF_INET;
    adressinfo.sin_port = htons(80);
    adressinfo.sin_addr.s_addr = INADDR_ANY;
   
    result_bind = bind(sock, (struct sockaddr*) &adressinfo, sizeof(adressinfo));


    if(result_bind == -1)
    {   
        printf("Fehler bei Bind");
        return -1;   
    }


    listen(sock, 5);
    return(sock);
}


void process_request(int sock)
{
    char     	sendbuffer[8096],
        	request[8096],
		filename[8096],
		buffer,
		ex_extension[4];
    int    	i=0,
        	k=0,f=0,
        	ext_laenge=0,
        	anzahl=0,
        	file_descript=0;
    char     	*format;
   
    	bzero(&request, sizeof(request));
	bzero(&filename, sizeof(filename));
	bzero(&sendbuffer, sizeof(sendbuffer));
	bzero(&ex_extension, sizeof(ex_extension));
   
    while(i < sizeof(request)-1)    // solange die Länge des Strings nicht überschritten wird
    {
        if(    read(sock, &buffer, 1) > 0    	// Solange ein Zeichen gelesen werden kann
            && buffer != '\n'         		// UND kein Zeilenumbruch
            && buffer != '\r')
        {       
            request[i] = buffer;        // weiter einlesen
            i++;
        }
        else
        {
            request[i] = '\0';        	// Sonst String abschließen
            break;                	// und Schleife abbrechen
        }
    }


    // Kontrollausgabe der Anfrage
    for(k=0; k< sizeof(request); k++)
        printf("%c", request[k]);
    printf("\n\n");
   
    // Prüfen ob Get-Anfrage (nicht Case-Sensitive)
    if(!strncmp(request, "GET ", 4) || !strncmp(request, "get ", 4)) // falls GET
    {   
	  i=5;        					// Startwert des Index, GET wird ignoriert
	  f=0;
    
	  if(!strncmp(&request[5], "\0", 1) || !strncmp(&request[5], " ", 1))    // Wenn keine Seite angegeben
	  {     
		  strcpy(request, "GET /index.html");    	// String auf index.html setzen                              
	  }
	
	  while(strncmp(&request[i], " ", 1))		// SOLANGE KEIN Leerzeichen erreicht
	  {      
	  strncpy(&filename[f], &request[i], 1);	// Zeichen an Filename anhängen
	  f++; i++;
	  }


	  i=0;
	  
	  // Extensions extrahieren
	  while(strncmp(&filename[i], ".", 1))    	// Punkt suchen
	  {     
		  i++;
	  }
	  strcpy(ex_extension, &filename[i+1]);		// Fileextension extrahieren
    
	  // Extension zuordnen
	  i=0;
	  format = (char *) 0;
	  while(extensions[i].ext != 0)
	  {
	    if(!strncmp(ex_extension, extensions[i].ext, strlen(ex_extension)))
	    {
		format = extensions[i].filetype;
		printf("FORMAT: %s\n", format);
		break;
	    }
	    i++;
	  }	    
	  
	  if(format != 0)
	  {
	    printf("OPENING: >%s<\n", filename);
	    printf("EXTENSION: >%s<\n", ex_extension);
	    file_descript=open(filename, O_RDONLY);		// Angefordertes File öffnen
	    
	    if(file_descript != -1)
	    { 
		strcpy(request, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
		printf("size> %i\n=========================================================\n\n", strlen(request));
		write(sock, request, strlen(request));	   
	      
		while((anzahl=read(file_descript, sendbuffer, sizeof(sendbuffer))) > 0)
		    write(sock, sendbuffer, anzahl);
		
		getchar();
		
		close(file_descript);
	    }       
	    else
		printf("Fehler! File konnte nicht geöffnet werden!\n");
     
	  }
	  else
	    printf("Falscher MIME-Type!\n");
	}
	else
	    printf("Nur GET-Anfragen werden bearbeitet\n");
}
```

Jetzt ist mir folgendes aufgefallen:
Über Telnet wird alles übertragen (inkl. Header, anschließend die angeforderte Seite) - Soweit sogut. Das Problem ist tatsächlich nun, dass die Browser nach sehr kurzer (kaum sehbarer Zeit) die Seite verlässt mit der Fehlermeldung "The connection was reset".

Daher habe ich mal das getchar() eingebaut und siehe da, die Page bleibt im Browser, leider eben nur solange mit Enter bestätigt wird.

Was kann ich dagegen tun?

Desweiteren habe ich das Problem, dass ich gerne nachträglich die Art der Anforderung (also HTML, JPG, etc.) einfügen würde. Die Zuweisung klappt schon und in der Variable "format" steht auch der richtige MIME-Type.

Leider habe ich es noch nicht geschafft, diesen in den HTTP-Header einzufügen :\
Hat da jemand ne fixxe Idee? 

Gruß


----------



## sheel (17. Dezember 2011)

Mal eine ganz blöde Idee: Schick nach der Datei, vor dem Schließen des Ganzen
noch zwei Zeilenwechsel raus.
\r\n\r\n

Und zum Mimetyp: Du musst doch nur statt dem text/html in request
das Andere schicken 
Wo ist das Problem?


----------



## huebstAr (17. Dezember 2011)

Hi! 

Danke für die Antwort.. Machmal sieht man den Wald vor lauter Bäumen nicht.. Wahnsinn..
Aber zu meiner Verteidigung: War ja auch schon spät! 

Zu dem anderen Problem (mit dem schließen).
Das mit den Zeilenwechseln hat nicht geklappt. Nach wie vor das selbe Verhalten.

Hat jemand noch eine andere Idee?
Vielleicht am Ende des Sendens der Seite eine Stopp-Kondition o.Ä., damit der Browser weiss, dass die Seite komplett ist?!

Gruß


----------



## sheel (17. Dezember 2011)

...
Irgendwann heute schau ich mir den Apachesource an.
Ist zwar sehr viel komplexer, aber irgendwas muss der ja prinzipiell anders machen...


----------



## deepthroat (19. Dezember 2011)

Hi.

Ich kann das Problem mit deinem Code und meiner Firefox Version nicht nachvollziehen. Funktioniert alles wunderbar.

Sicher, dass du nicht in der HTML Seite eine Weiterleitung drin hast, die dann nicht funktioniert?

Übrigens ist bzero veraltet, man sollte memset verwenden.

Und dein accept Aufruf ist etwas seltsam. Warum übergibst du denn da einen Zeiger auf int als zweiten Parameter? Es sollte ein Zeiger auf eine sockaddr Struktur sein (dann mußt du auch nicht casten). Und das dritte Argument sollte ein Zeiger auf eine socklen_t Variable sein.

Aber wenn dich die Adresse sowieso nicht interessiert (source und len_addr benutzt du ja überhaupt nicht), dann übergib doch einfach NULL.

Gruß


----------



## huebstAr (19. Dezember 2011)

deepthroat hat gesagt.:


> Ich kann das Problem mit deinem Code und meiner Firefox Version nicht nachvollziehen. Funktioniert alles wunderbar.
> 
> Sicher, dass du nicht in der HTML Seite eine Weiterleitung drin hast, die dann nicht funktioniert?


Hm, komisch.. Ich habe eine ganz einfache HTML-Seite erstellt:

```
notroot@linux-kqq0:~/Documents> cat index.html
<html>
        <head><title> Lala
                </title>
        </head>

<body>
                HTML Testseite von mir
</body>

</html>
notroot@linux-kqq0:~/Documents>
```

Welche Firefox-Version benutzt du? Liegt es vielleicht daran? 
Ich hab Version 3.5.4 mit Suse 11.2.



deepthroat hat gesagt.:


> Übrigens ist bzero veraltet, man sollte memset verwenden.


Danke. Habe es zu memset geändert.



deepthroat hat gesagt.:


> Und dein accept Aufruf ist etwas seltsam.


Habe ich noch garnicht drüber nachgedacht. Habe ich nun zu NULL geändert.

Danke erstmal für die Tipps!

Gruß


----------



## Bratkartoffel (19. Dezember 2011)

Hi,

bau in der Antwort noch den Header "Connection: close" ein und versuchs nochmal. Eventuell verwirrt es den Firefox, dass er eine persistente Verbindung anfrägt, diese dann aber einfach so nach der Antwort geschlossen wird.

Gruß
BK


----------



## huebstAr (19. Dezember 2011)

Hi,

meinst du NACH dem Senden der Datei einfach noch ein "Connection: close" rausschicken?
Oder soll ich es gleich im Kopf mit einbauen?

Gruß & Danke

€: Hm, wenn ich im Header das HTTP/1.1 auf HTTP/1.0 ändere geht es. Scheint was mit dem Standart zu tun zu haben.


----------



## Bratkartoffel (19. Dezember 2011)

Hi,

ja, wie ich schon sagte: Mit HTTP/1.1 sind persistente Verbindungen gekommen. Wenn der Browser also anfrägt, dass die Verbindung offen bleiben soll ("Connection: keep-alive") und du dann einfach die Verbindung trennst ohne dem Browser das vorher mitzuteilen ("Connection: close"), dann gibt der Browser natürlich nen Fehler.

Schicke also in der Antwort entweder im Header "Connection: close" mit, dann kannst du deine Antwort auch als HTTP/1.1 senden. Oder du lässt den Header weg und arbeitest dafür mit HTTP/1.0. Dürfte eigentlich egal sein, kommt halt darauf an wie weit du deinen Server später noch ausbauen willst und welche Features er in Zukunft noch bekommen soll.

Gruß
BK


----------

