Robert
Robert

Reputation: 1

C socket Webserver not displaying html in browser, only sending HTTP response

I am relatively new to C, and trying to play around with some code a professor gave me, and then modifying it since then, to help me along with a server project. I cant figure out how to actually be able to see the HTML in lynx, i just get the HTTP response. (i can curl it and see what I am trying to send, but the browser will not load the HTML body) I have been checking everything I can think of, but at this point I have to admit I don't know enough about HTTP responses and could use a step in the right direction as to where I stepped off the path.

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>

#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define BUFFER_SIZE 9999
#define HTTP_METHOD     "HTTP/1.1 "
#define HTTP__OK    "200 OK\r\n"
#define HTTP__NOT_FOUND "404 Not Found\r\n"
#define SERVER_NAME     "Server: ECE435\r\n"

/* Default port to listen on */
#define DEFAULT_PORT    8080 //modify port to listen on 8080

int main(int argc, char **argv) {

    int socket_fd,new_socket_fd;
    struct sockaddr_in server_addr, client_addr;
    int port=DEFAULT_PORT;
    int n;
    socklen_t client_len;
    char buffer[BUFFER_SIZE];

    printf("Starting server on port %d\n",port);

    /* Open a socket to listen on */
    /* AF_INET means an IPv4 connection */
    /* SOCK_STREAM means reliable two-way connection (TCP) */
    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd<0) {
        fprintf(stderr,"Error opening socket! %s\n",
            strerror(errno));
        exit(1);
    }

    /* Set up the server address to listen on */
    /* The memset stes the address to 0.0.0.0 which means */
    /* listen on any interface. */
    memset(&server_addr,0,sizeof(struct sockaddr_in));
    server_addr.sin_family=AF_INET;

    /* Convert the port we want to network byte order */
    server_addr.sin_port=htons(port);

    /* Bind to the port */
    if (bind(socket_fd, (struct sockaddr *) &server_addr,
        sizeof(server_addr)) <0) {
        fprintf(stderr,"Error binding! %s\n", strerror(errno));
        fprintf(stderr,"Probably in time wait, have to wait 60s if you ^C to close\n");
        exit(1);
    }

    /* Tell the server we want to listen on the port */
    /* Second argument is backlog, how many pending connections can */
    /* build up */
    listen(socket_fd,5);


wait_for_connection:


    /* Call accept to create a new file descriptor for an incoming */
    /* connection.  It takes the oldest one off the queue */
    /* We're blocking so it waits here until a connection happens */
    client_len=sizeof(client_addr);
    new_socket_fd = accept(socket_fd,
            (struct sockaddr *)&client_addr,&client_len);
    if (new_socket_fd<0) {
        fprintf(stderr,"Error accepting! %s\n",strerror(errno));
        exit(1);
    }

    while(1){
        /* Someone connected!  Let's try to read BUFFER_SIZE-1 bytes */
        memset( buffer, 0, BUFFER_SIZE );
        n = read( new_socket_fd, buffer, ( BUFFER_SIZE-1 ) );
        if (n==0){
            fprintf( stderr, "Connection to client lost\n\n" );
            break;
        }
        else if( n < 0 ){
            fprintf(stderr,"Error reading from socket %s\n",
                strerror(errno));
        }

        /* Print the message we received */
        printf("Message received: %s\n" ,buffer);


        const char *PATTERN1 = "GET /"; //first cut to make on buffer
        const char *PATTERN2 = " HTTP"; //second cut to make on buffer
        char *target = NULL; //variable to hold the slice we're taking
        char *start, *end;  //defining variables to hold start and end positions
        if ( start = strstr( buffer, PATTERN1 ) ){  //code to grab a slice of buffer
            start += strlen( PATTERN1 );        

        if ( end = strstr( start, PATTERN2 ) ){
            target = ( char * )malloc( end - start + 1 );
            memcpy( target, start, end - start );
            target[end - start] = '\0';
        }
    }
        if ( target ) printf( "Client requested: %s\n", target ); //code is working to this point. I can tell what file to get.

    time_t rawtime;
    struct tm info;
    time( &rawtime );
    struct tm * timeinfo;
    char timestamp[100];
    time_t now = time(0);
    struct tm tm = *gmtime(&now);
    strftime(timestamp, sizeof( timestamp ) , "%a, %d %b %Y %H:%M:%S %Z", &tm);
    //printf("Time is: [%s]\n", timestamp);

    struct stat file_info;      //define statistics structure for file info
    stat( target, &file_info ); //initiate file_info as the stat structure for target


    char send_client[9999];


    sprintf( send_client, "HTTP/1.0 %s%s\r\nServer: ECE435\r\nLast-Modified: Fri, 08 Sep 2017 04:31:47 GMT\r\nContent-Length: 85\r\nContent-Type: text/html\r\n\r\n", HTTP__OK, timestamp );

    char file_path[256]; //limited to 256 char for now
    sprintf( file_path, "./%s", target); //this is how you can combine char arrays: puts "./" + 'target' into 'file_path'   

    //int fd;

    //printf( "%ld\r\n" , file_info.st_size ); //this should print the File Size


    char source[BUFFER_SIZE + 1];
    FILE *fp = fopen( file_path, "r");
    if (fp != NULL) {
        size_t newLen = fread(source, sizeof(char), BUFFER_SIZE, fp);
        if (newLen == 0) {
            fputs("Error reading file", stderr);
        } else {
            source[newLen] = '\0'; /* Just to be safe. */
        }

        fclose(fp);
    }
        strcat( send_client, source);


    /* Send a response */
    printf( "\r\n%s\r\n" , send_client ); //print response before sending
    n = write( new_socket_fd, send_client , strlen(send_client) ) ;     
    if( n < 0 ){
        fprintf( stderr, "Error writing. %s\n", strerror(errno));
    }

}

close(new_socket_fd);

printf("Done connection, go back and wait for another\n\n");

goto wait_for_connection;

/* Try to avoid TIME_WAIT */
//  sleep(1);

/* Close the sockets */
close(socket_fd);

return 0;
}

Upvotes: 0

Views: 1790

Answers (1)

David Schwartz
David Schwartz

Reputation: 182743

    memset( buffer, 0, BUFFER_SIZE );
    n = read( new_socket_fd, buffer, ( BUFFER_SIZE-1 ) );
    if (n==0){
        fprintf( stderr, "Connection to client lost\n\n" );
        break;
    }
    else if( n < 0 ){
        fprintf(stderr,"Error reading from socket %s\n",
            strerror(errno));
    }

    /* Print the message we received */
    printf("Message received: %s\n" ,buffer);

When you call read on a TCP connection, you don't get a message. If you want to receive HTTP messages, you have to write code to do that. This is just broken.

sprintf( send_client, "HTTP/1.0 %s%s\r\nServer: ECE435\r\n"
   "Last-Modified: Fri, 08 Sep 2017 04:31:47 GMT\r\n"
   "Content-Length: 85\r\nContent-Type: text/html\r\n\r\n", HTTP__OK, timestamp );

Unless the file just happens to contain exactly 85 bytes, sending a "Content-Length" header is not a particulary good idea.

You have a while(1) loop that seems to be trying to receive multiple messages over a single connection. But there's no code to determine when you've actually received an HTTP request, so that's definitely not going to work.

The HTTP protocol is complicated and writing code to implement it correctly requires going through the standard and implementing everything that is required by the standard. This code doesn't do that and if it actually does work, it will be mostly by luck.

You may get away with just modifying the "Content-Length" header to have the correct length. But you're still violating lots of rules. For example, you could easily wind up sending more than one response to a single request because you do not ensure that read returned an entire HTTP request.

Upvotes: 1

Related Questions