tags:

views:

350

answers:

4

I've got a basic HTTP client set up in C++, which works ok so far. It's for a school assignment, so there's lots more to do, but I'm having a problem.

I use the recv() function in a while loop, to repeatedly add pieces of the response to my response buffer, and then output that buffer each time. The problem is, at the end of each piece of the response, the HTTP Request is getting tacked on as well.

For example, the response will be a chunk of the page's source code, followed by "GET / HTTP/1.1...", followed by the next chunk, and then the "GET..." again, and so on.

Here's my relevant code:

 // Prepare request
char request[] = "HEAD /index.html HTTP/1.1\r\nHOST: www.google.com\r\nCONNECTION: close\r\n\r\n";

// Send request
len = send(sockfd, request, sizeof(request), 0);

// Write/output response
while (recv(sockfd, buf, sizeof(buf), 0) != 0)
{
 // Read & output response
 printf("%s", buf);
}
+4  A: 

The buffer isn't null terminated, which is required for strings in C++. When you see the "extra GET", you are seeing memory that you shouldn't be because the stdlib tried to print your buffer, but never found a '\0' character.

A quick fix is to force the buffer to be terminated:

int n = 1;
while (n > 0) {
    n = recv(sockfd, buf, sizeof(buf), 0);
    if (n > 0) {
        // null terminate the buffer so that we can print it
        buf[n] = '\0';

        // output response
        printf("%s", buf);
    }
}
Frank Krueger
Makes sense. Thanks!
Ishmael Smyrnow
A: 

recv does not add a \0 string terminator to the buffer recieved - it just works in raw binary. So your printf is running off the send of your buf buffer (and apparently ending up looking at your request buffer).

Either add a nul-terminator to the end of buf, or print the buffer one character at a time using putchar() (both of these approaches will make it necessary to store the value returned by recv()).

caf
A: 

The recv call will not null-terminate buf; instead, it will just provide you with the raw data received from the wire. You need to save the return value of recv, and then add a null-terminating byte yourself into buf before printing it. Consequentially, you can only ask for sizeof(buf)-1 bytes.

Martin v. Löwis
+1  A: 

I suspect it's because your buf is allocated in memory just below your request. When you call printf on the buffer, printf will print as much as it can before finding a NUL character (which marks the end of the string). If there isn't one, it'll go right on through into request. And generally, there won't be one, because recv is for receiving binary data and doesn't know that you want to treat its output a string.

One quick fix would be to limit the receive operation to sizeof(buf)-1, and to explicitly add the NUL terminator yourself, using the size of the returned data:

while ((nr = recv(sockfd, buf, sizeof(buf), 0)) > 0)
{
    buf[nr] = 0;
    ...
}

Of course, for this to (marginally) safe you need to be sure that you'll always receive printable data.

Edmund
Thanks for your explanation.
Ishmael Smyrnow