2

Symptom

I think, I messed up something, because both Mozilla Firefox and Google Chrome produce the same error: they don't receive the whole response the webserver sends them. CURL never misses, the last line of the quick-scrolling response is always "</html>".

Reason

The reason is, that I send response in more part:

    sendHeaders();  // is calls sendResponse with a fix header
    sendResponse(html_opening_part);
    for ( ...scan some data... ) {
        sendResponse(the_data);
    } // for
    sendResponse(html_closing_part)

The browsers stop receiving data between sendResponse() calls. Also, the webserver does not close() the socket, just at the end.

(Why I'm doing this way: the program I write is designed for non-linux system, it will run on an embedded computer. It has not too much memory, which is mostly occupied by lwIP stack. So, avoid collecting the - relativelly - huge webpage, I send it in parts. Browsers like it, no broken HTML occurred as under Linux.)

Environment

The platform is GNU/Linux (Ubuntu 32-bit with 3.0 kernel). My small webserver sends the stuff back to the client standard way:

    int sendResponse(char* data,int length) {

        int x = send(fd,data,length,MSG_NOSIGNAL);
        if (x == -1) {
            perror("this message never printed, so there's no error \n");
            if (errno == EPIPE) return 0;
            if (errno == ECONNRESET) return 0;

            ... panic() ... (never happened) ...

        } // if send()

    } // sendResponse()

And here's the fixed header I am using:

    sendResponse(
        "HTTP/1.0 200 OK\n"
        "Server: MyTinyWebServer\n"
        "Content-Type: text/html; charset=UTF-8\n"
        "Cache-Control: no-store, no-cache\n"
        "Pragma: no-cache\n"
        "Connection: close\n"
        "\n"
    );

Question

Is this normal? Do I have to send the whole response with a single send()? (Which I'm working on now, until a quick solution arrives.)

ern0
  • 3,074
  • 25
  • 40
  • You should check the return value of `close()` as well. It can detect errors that occurred after `send()` returns successfully. – Steve Jessop May 15 '12 at 09:28
  • Thx, I've checked, there's no error on *close()*. (As we could expect, *curl* works well.) – ern0 May 15 '12 at 10:04
  • well, you're looking for a difference between what happens with `curl` and what happens with the browser. If the browser had been causing an error on the socket before reading all the data, then that might have shown up in `close()` with the browser but not with curl. – Steve Jessop May 15 '12 at 11:30

2 Answers2

1

If you read RFC 2616, you'll see that you should be using CR+LF for the ends of lines.

Aside from that, open the browser developer tools to see the exact requests they are making. Use a tool like Netcat to duplicate the requests, then eliminate each header in turn until it starts working.

Jim
  • 72,985
  • 14
  • 101
  • 108
0

Gotcha!

As @Jim adviced, I've tried sending same headers with CURL, as Mozilla does: fail, broken pipe, etc. I've deleted half of headers: okay. I've added back one by one: fail. Deleted another half of headers: okay... So, there is error, only if header is too long. Bingo.

As I've said, there're very small amount of memory in the embedded device. So, I don't read the whole request header, only 256 bytes of them. I need only the GET params and "Host" header (even I don't need it really, just to perform redirects with the same "Host" instead of IP address).

So, if I don't recv() the whole request header, I can not send() back the whole response.

Thanks for your advices, dudes!

ern0
  • 3,074
  • 25
  • 40
  • Presumably the browser doesn't start reading the response until it has finished writing the request. By not reading the whole request you were blocking the browser's send, which means your send got blocked as soon as it had filled all available buffers. – Steve Jessop May 15 '12 at 11:34
  • Err, I found no other way to close this question. – ern0 May 19 '12 at 07:14