kleiner Webserver in C

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

Kannst du die Telneteinagbe/ausgabe auch mal zeigen?

PS: content-length... :rolleyes:
 
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.

snapshot2.png
snapshot1.png

Was meinst Du mit Content-Length? Ist hier was falsch? Sehe da nun nichts >x
 
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.
 
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
 
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:
Code:
//

//----------------------------------------------------------------------------
// 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ß
 
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 :confused:
Wo ist das Problem?
 
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ß
 
...
Irgendwann heute schau ich mir den Apachesource an.
Ist zwar sehr viel komplexer, aber irgendwas muss der ja prinzipiell anders machen...
 
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ß
 
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:
Code:
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.

Übrigens ist bzero veraltet, man sollte memset verwenden.
Danke. Habe es zu memset geändert.

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ß
 
Zurück