c++socketsvectorbinarywinsock

HTTP over Winsock: fonts don't load until user presses "stop loading" button in their browser


When sending TTF files over HTTP, the font doesn't appear until the user manually presses the button to stop loading the page.

Let's use Inter font as an example. I read the file from disk to binary using vector<unsigned char>.

// Read file as binary
FILE* f;            // File handle
unsigned long flen; // File length in unsigned long because file length is always >= 0
             
f = fopen(c_internal_path, "rb"); // Open file in "r(ead)b(inary)" mode

if (!f) {   // If file not open print error to console and terminate function
    fprintf(stderr, "Unable to open file %s", c_internal_path); 
    http_code = 500;
    content = Util::stringToUCharVector(HTTP_ERROR_500);
}
else {
    fseek(f, 0, SEEK_END);
    flen = ftell(f);
    fseek(f, 0, SEEK_SET);

    content.resize(flen + 1); 
    std::fread(&content[0], flen, 1, f);

    fwrite(content.data(), 1, content.size(), stdout); // Write file contents to console
    fclose(f);

Then I take the data() of this vector and add it to the output stringstream:

// Compose HTTP response:
    std::ostringstream oss;
    oss << "HTTP/1.1 " << http_response.http_code << " OK\r\n";
    oss << "Cache-Control: no-cache, private\r\n";
    oss << "Content-Type: " << FHTTPMIME::MimeToString(mime_type) << "\r\n"; // use MimeToString() to convert enum MIME to string MIME
    oss << "Content-Length: " << http_response.content.size() << "\r\n"; // use size of 'content' vector<unsigned char>
    oss << "\r\n";
    oss << http_response.content.data(); // access vector data() for content char[]

We get a response like this:

HTTP/1.1 200 OK
Cache-Control: no-cache, private
Content-Type: font/ttf
Content-Length: 803385

<binary data of the file>

Then send the response to the client by:

// Convert ostringstream to string
    std::string output = oss.str();
    int size = output.size() + 1;

// Send 'output.c_str()' char* of size 'size' to 'clientSocket'
sendToClient(clientSocket, output.c_str(), size);

The size of the file is 803384 bytes. What can I be doing wrong in this situation for ttf font to not load properly?

I tried adding +1 to Content-Length and null-terminating ('\0') the binary vector, but nothing helped.

EDIT Everything works as intended for HTML, CSS, but not for TTF, JPG, JPEG, WEBP and so on, even though I use the correct MIME types.


Solution

  • Firstly, terminating NUL is not required for binary data (not string), so remove the extra byte.

    // content.resize(flen + 1);
    content.resize(flen);
    

    Secondly, passing unsigned char* to std::ostringstream via << operator makes it take only until first byte having value 0x00. You should use write function to explicitly specify the size of (binary) data.

    //oss << http_response.content.data();
    oss.write(reinterpret_cast<char*>(http_response.content.data()), http_response.content.size());
    

    Finally, remove another extra byte.

    //int size = output.size() + 1;
    int size = output.size();