porente
porente

Reputation: 443

http server response using sockets

My sockets server is receiving a GET request for an image, the image is 2MB so it doesn't fit in a single send(), this is what I am sending in the first send():

std::stringstream wsss;
wsss << "HTTP/1.1 200 OK\r\n" 
     << "Connection: keep-alive\r\n"
     << "Content-Type: image/x-icon\r\n"
     << "Content-Length: " << imageSize << "\r\n"
     << "\r\n";
wsss.write(imageData, imageSize);

Does every subsequent send() of this image needs the header fields? I am sending a .ico image, are the header fields correct?

Upvotes: 2

Views: 4513

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 596166

the image is 2MB so it doesn't fit in a single send()

send() is not guaranteed to send as many bytes as you ask it to send. It can send fewer bytes. Its return value tells you how many bytes it actually accepted for sending. So you should call send() in a loop until all bytes have been accepted. If you move this loop into its own reusable function, that will also allow you to send the icon data without having to first copy it into the std::stringstream.

Try something like this:

int sendData(int sckt, void *data, int datalen)
{
    unsigned char *pdata = (unsigned char *) data;
    int numSent;

    // send() can send fewer bytes than requested,
    // so call it in a loop until the specified data
    // has been sent in full...

    while (datalen > 0) {
      numSent = send(sckt, pdata, datalen, 0);
      if (numSent == -1) return -1;
      pdata += numSent;
      datalen -= numSent;
    }

    return 0;
}

std::stringstream wsss;
wsss << "HTTP/1.1 200 OK\r\n" 
     << "Connection: keep-alive\r\n"
     << "Content-Type: image/x-icon\r\n"
     << "Content-Length: " << imageSize << "\r\n"
     << "\r\n";

// do not append the image data to the stringstream...
//wsss.write(imageData, imageSize);

// send the headers first...
std::string headers = wsss.str();
int res = sendData(TheSocket, headers.c_str(), headers.size());
if (res == -1) ...

// now send the image data...
res = sendData(TheSocket, imageData, imageSize);
if (res == -1) ...

Does every subsequent send() of this image needs the header fields?

Every HTTP response to every HTTP request for the same image needs to send the same headers1. But every send() for any particular response does not need to repeat the headers, they only need to be sent once. Just keep sending whatever bytes have not been sent yet. That is why you have to pay attention to the return value of send() so you know how many bytes have been sent so far and how many bytes are still need to be sent.

I am sending a .ico image, are the header fields correct?

In general, yes1.


1: assuming that either:

  1. the client sent an HTTP 1.1 request without a Connection: close request header.

  2. the client sent an HTTP 1.0 request with a Connection: keep-alive request header.

Otherwise, your Connection: keep-alive header would be erroneous, you should be sending a Connection: close header instead, and then close the socket after sending the complete response.

Upvotes: 4

Related Questions