Daeto
Daeto

Reputation: 480

C - sockets, separating data and http header?

I am trying to simulate client/server communication to send and receive files using sockets and http requests.

The client sends an http request to the server saying that they want to download a simple .txt file and the server sends the file data back to the client with an http response header.

However, the data written into the received text file also contains the http header information which it shouldn't.

How do I effectively separate the http header from the actual data?

Here's what the code looks like:

Server:

//receives an http header request from client saying they want to download a .txt file

bzero(buffer, 256);

sprintf(buffer, "HTTP/1.1 200 OK\r\n Date:%s\r\n Content-Type:%s\r\n Content-Length:%s\r\n\r\n", time, content, length);

data = write(incoming_socket, buffer, strlen(buffer)); // first sends an http response header

bzero(buffer, 256);

int data;

while((data = fread(buffer, sizeof(char), 256, fs)) > 0){

    if(send(cli_socket, buffer, strlen(buffer), 0) < 0){ // sends the actual file data to client in this while cycle 

        perror("ERROR: Could not send file.");
        break;
        exit(EXIT_FAILURE);
    }

    if (block_size < 256){

        if (ferror(fs)){

            perror("ERROR: Failed while sending data.");
            exit(EXIT_FAILURE);
        }

        bzero(buffer, 256);

        break;
    }

    bzero(buffer, 256);
}

Client:

bzero(buffer, 256);

data = read(client_socket, buffer, 256); // first receive the http header response 

bzero(buffer, 256);

while (1){

    data = recv(client_socket, buffer, 256, 0); // receive data

    fwrite(buffer, sizeof(char), data, fr); // write data into the file 

    bzero(buffer, 256);

    if (data == 0 || data < 256){

        fclose(fr);
        break;
    }

    if(data< 0){

        printf("failed while copyng file!\n");
        exit(1);
    }
}

However, this fills the .txt file with the http response as well, not just the data.

Now, I know that I should probably look for /r/n/r/n in the header response in order to separate the header and write just the actual data but, if someone could show me the best way to do this in my example with my particular buffer, I'd be very grateful!

Upvotes: 0

Views: 2665

Answers (1)

David Schwartz
David Schwartz

Reputation: 182753

Unfortunately, you've chosen a very compelex protocol to implement. Your only choice is to read the documentation for HTTP version 1.1 and follow the specification precisely. The documentation will tell you how to identify the end of the header. Note that you must support chunked encoding. It is required for HTTP 1.1 compliance.

But you've really chosen an H-bomb to kill an ant here. HTTP 1.1 is a complex, high-performance protocol and a terrible choice for just messing around transferring a file.

A few more mistakes:

if(send(cli_socket, buffer, strlen(buffer), 0) < 0){ // sends the actual file data to client in this while cycle 

The strlen function is only for C-style strings, not arbitrary data. The recv function returns the number of bytes read for a reason.

data = recv(client_socket, buffer, 256, 0); // receive data

fwrite(buffer, sizeof(char), file_block_size, fr); // write data into the file

Surely the number of bytes you write should be the number of bytes you read (which you helpfully stored in a variable, data, but didn't use), not some other number.

If you really want to make HTTP 1.1 client and server code, you really should start by thoroughly understanding both the HTTP 1.1 specification and example client and server code. But that's a terrible way to learn how to send and receive files because HTTP 1.1 is so complicated.

Upvotes: 2

Related Questions