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.
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();