noamgot noamgot - 5 months ago 14
Linux Question

failure in sending image from http server to client

I'm implementing a simple http server in c code.
I connect to the server via firefox browser as a client, and write:

http://localhost:<port number>/<path to file>


now, I tried it for a simple text file and it works. however, when I try it with an image it doesn't work.
It is important to mention that a few days ago it did work, but I changed my code due to some notes I got from my TA, and now it doesnt' work...

I added some helper prints and saw that some of the data was sent, however at some point it gets stuck and doesn't send anymore.
my guess is that somehow the sending buffer is filled, but I make sure it is empty after sending is over... can you try to identify where is the problem?

#define BUF_SIZE 2048


int sendToClient(int clientFd, char *buf)
{
int bytesSent;
int totalSent = 0;
size_t notSent = strlen(buf);
while (notSent > 0)
{
if ((bytesSent = send(clientFd, buf + totalSent, notSent, 0)) < 0)
{
printf("send syscall failed: %s\n", strerror(errno));
return -1;
}
notSent -= bytesSent;
totalSent += bytesSent;
}
return totalSent;

}


void handleFile(int sockFd, char *path, struct stat *statBuf)
{
//the stat structure pointer is delivered as a parameter,
//it already contains info about the file we want to send
//sockFd is the client's socket file descriptor.
//path is the path to the file...

size_t totalBytesToSend = (size_t) statBuf->st_size;
int fd = open(path, O_RDONLY, 0777);
if (fd < 0)
{
printf("open syscall failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// sending some initial http stuff...
char buf[BUF_SIZE];
// zero buffer
memset(buf, 0, BUF_SIZE);

int bytesSent;
while (totalBytesToSend > 0)
{
if (read(fd, buf, BUF_SIZE) < 0)
{
printf("read syscall failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
//send buf to client
if ((bytesSent = sendToClient(sockFd, buf)) < 0)
{
exit(EXIT_FAILURE);
}
// data was sent - zero buf again
memset(buf, 0, BUF_SIZE);
totalBytesToSend -= bytesSent;
}
//close file & socket
close(fd);
close(sockFd);
}


Thanks!

Answer

The error is here: size_t notSent = strlen(buf);. You assume that the first null in the buffer marks the end of the data read from file. It makes sense for text files that should never contain a null byte, but it is a wrong assumption for binary files like image files. As they can contain null bytes, you will not transfer to the client all the bytes that were read from file, the worst case being if the first byte of the buffer is 0!

You must pass the number of bytes actually read from disk to the sendToClient function and use it. Never assume the a particular byte or sequence will never occur in a binary file...