Aran Bins Aran Bins - 2 years ago 107
HTTP Question

C Web Server, image not showing up on browser?

Currently trying to code a simple web server in C. Found a cool snippet online. Everything works aside from the image. I can't figure out why it doesn't show up on the browser. sendfile() returns 9109 (the size of the image).

I'm also a bit confused on what this code snippet is doing in terms of fork(). Why does it need to fork() at all? As well as why we close the client in the loop when there could be more requests coming in? Or is it that for every request, there's a new connection? Thanks in advance!

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sendfile.h>

char webpage[] =
"HTTP/1.1 200 Ok\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<!DOCTYPE html>\r\n"
"<html><head><title>Test Title</title>\r\n"
"<body>Hello World <img src='test.jpg'/></body>"
"</html>";

int main(int argc, char *argv[]){
struct sockaddr_in server_addr, client_addr;
socklen_t sin_len = sizeof(client_addr);
int fd_server, fd_client;
/* Storing the contents sent by the browser (a request) */
char buf[2048];
int fdimg;
int on = 1;

fd_server = socket(AF_INET, SOCK_STREAM, 0);
if(fd_server < 0){
perror("socket");
exit(1);
}

setsockopt(fd_server, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));

server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(8080);

if(bind(fd_server, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1){
perror("bind");
close(fd_server);
exit(1);
}

if(listen(fd_server, 10) == -1){
perror("listen");
close(fd_server);
exit(1);
}

while(1){
fd_client = accept(fd_server, (struct sockaddr *) &client_addr, &sin_len);

if(fd_client == -1){
perror("Connection failed...\n");
continue;
}

printf("Got client connection...\n");

if(!fork()){

/* Child process */

/* Close this as the client no longer needs it */
close(fd_server);
memset(buf, 0, 2048);
read(fd_client, buf, 2047); /* 2047 because of null char? */

/* Print the request on the console */
printf("%s\n", buf);

if(!strncmp(buf, "GET /test.jpg", 13)){
printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
fdimg = open("test.jpg", O_RDONLY);
int sent = sendfile(fd_client, fdimg, NULL, 10000);
printf("sent: %d", sent);
close(fdimg);
}
else{
write(fd_client, webpage, sizeof(webpage) - 1);
}

close(fd_client);
printf("closing connection...\n");
exit(0);
}

/* Parent process */
close(fd_client);


}


return 0;

}

Answer Source

This may be due to browser only allowing HTTP/0.9 on port 80.

The major difference between HTTP/0.9 and HTTP/1.1 is that the server sends a header before the data.

Try adding a HTTP/1.1 header to the image response:

char imageheader[] = 
"HTTP/1.1 200 Ok\r\n"
"Content-Type: image/jpeg\r\n\r\n";

// ....

if (!strncmp(buf, "GET /test.jpg", 13)) {
    printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    // Send header first: (Note, should loop in case of partial write or EINTR)
    write(fd_client, imageheader, sizeof(imageheader) - 1);
    // Send image content
    fdimg = open("test.jpg", O_RDONLY);
    int sent = sendfile(fd_client, fdimg, NULL, 10000);
    printf("sent: %d", sent);
    close(fdimg);
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download