views:

892

answers:

3

As an addition to my previous post on Creating a web server in pure C, I'm having some trouble with the Sending function. Here's two code snippets:

int Send(char *message)
{
        int length, bytes_sent;
        length = strlen(message);

        bytes_sent = send(connecting_socket, message, length, 0);

        return bytes_sent;
}

This code sends void * to the current socket. Works like a charm!

Now here comes the SendHTML

void SendHTML(char *Status_code, char *Content_Type, char *HTML)
{
        char *head = "\r\nHTTP/1.1 ";
        char *content_head = "\r\nContent-Type: ";
        char *server_head = "\r\nServer: PT06";
        char *length_head = "\r\nContent-Length: ";
        char *date_head = "\r\nDate: ";
        char *newline = "\r\n";
        char Content_Length[100];
        int content_length = strlen(HTML);

        sprintf(Content_Length, "%i", content_length);

        char *message = malloc((
                strlen(head) +
                strlen(content_head) +
                strlen(server_head) +
                strlen(length_head) +
                strlen(date_head) +
                strlen(newline) +
                strlen(Status_code) +
                strlen(Content_Type) +
                strlen(Content_Length) +
                content_length +
                sizeof(char)) * 2);

        if ( message != NULL )
        {
                time_t rawtime;

                time ( &rawtime );

                strcpy(message, head);

                strcat(message, Status_code);

                strcat(message, content_head);
                strcat(message, Content_Type);
                strcat(message, server_head);
                strcat(message, length_head);
                strcat(message, Content_Length);
                strcat(message, date_head);
                strcat(message, (char*)ctime(&rawtime));
                strcat(message, newline);
                strcat(message, HTML);

                Send(message);

                free(message);
        }     
}

If I were to add

Send("Oh end of HTML Sending eh?");

after Send(message) and before free(message), this isn't sent to the browser?

I figured this might be a HTTP 1.1 issue, does the RFC say that i can only do one Send? Does the browser Close the connection after it receives the first message?

How do I solve this so I could do the following:

SendHTML("200 OK", "text/plain", "HAaaaii!!");
Send("lolwut?");

This should result in the Browser showing:

HAaaaii!!lolwut?

+4  A: 

Since you're sending the content-length, the browser won't be accepting no more content after "HAaaaii!!" and therfore will interpret the "lolwut?" as a part of the answer of its next request, which will of course fail.

You could skip sending a content-length, but this would mean that you are not using keep-alive and therefore can't handle more than one request per TCP connection.

Handling more than one Request-Response exchange per TCP connection can greatly speed up browsing speed, since a normal web-page consists of several separate resources, each of which will have to be requested separately. And since establishing a TCP connection is takes at least 3 round trips, this would add an additional, unnecessary delay for each resource.

Joachim Sauer
That's not good, is it?
Filip Ekberg
+3  A: 

In your head variable, there should be no leading "\r\n". That's probably what's causing the problem. Also, when you're malloc'ing your message, you're not reserving enough space for the date+time (26 bytes according to the documentation for ctime(3)), so you're almost certainly overwriting your buffer and causing heap corruption.

If you want to start sending data before you know what the Content-Length is, you can instead use the chunked transfer encoding. The chunked transfer encoding says, "I'm going to keep giving you a bunch of data in chunks, and I can tell you how long each chunk is, but I don't know how many chunks there are until I'm done." For example, Google uses the chunked transfer encoding. Here's a trace of an HTTP request for the Google homepage, generated with cURL:

curl www.google.com --trace-ascii -
(Header snipped -- but no Content-Length header)

The data stream consists of the chunk size (in hexadecimal) followed by a CRLF, then the data bytes. In this case, there was only one chunk, but there could easily have been more. After the last chunk, a chunk size of 0 is transmitted, indicating the last chunk.

Adam Rosenfield
A: 

Do you add newline after each header?

You can test your application by using telnet, of course and see what's the output.

No, it's not required to have only one send. Assume streaming a 2GB file. It's simply not logical.

Mehrdad Afshari
Exactly my thoughts. Telnet gives me the correct stuff :)
Filip Ekberg