Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f6aa072d5f |
@@ -81,8 +81,13 @@ static _Thread_local ElArena _tl_arena = {NULL, 0, 0};
|
||||
static _Thread_local int _tl_arena_active = 0;
|
||||
|
||||
/* Binary-safe fs_read length — set by fs_read, consumed by http_send_response.
|
||||
* Allows serving PNGs and other binary files without strlen truncation. */
|
||||
* Allows serving PNGs and other binary files without strlen truncation.
|
||||
* _tl_fs_read_ptr records WHICH buffer that length belongs to: the length is only
|
||||
* valid when the handler returns that exact buffer (a raw file). A handler that
|
||||
* fs_reads then builds a different/longer response (e.g. wraps a file in JSON) must
|
||||
* be measured by strlen — otherwise the reply is truncated to the file's size. */
|
||||
static _Thread_local size_t _tl_fs_read_len = 0;
|
||||
static _Thread_local const char* _tl_fs_read_ptr = NULL;
|
||||
|
||||
static void el_arena_track(char* p) {
|
||||
if (!_tl_arena_active || !p) return;
|
||||
@@ -1558,11 +1563,15 @@ static void* http_worker(void* arg) {
|
||||
const char* rs = EL_CSTR(r);
|
||||
/* Copy response out BEFORE arena teardown.
|
||||
* For binary files, _tl_fs_read_len holds the real byte count —
|
||||
* use memcpy instead of strdup so null bytes are preserved. */
|
||||
size_t rlen = _tl_fs_read_len > 0 ? _tl_fs_read_len : (rs ? strlen(rs) : 0);
|
||||
* use memcpy instead of strdup so null bytes are preserved. But only
|
||||
* trust that count when the handler returned the fs_read buffer itself;
|
||||
* a wrapped/concatenated response must be measured by strlen. */
|
||||
int is_fs_body = (_tl_fs_read_len > 0 && rs == _tl_fs_read_ptr);
|
||||
size_t rlen = is_fs_body ? _tl_fs_read_len : (rs ? strlen(rs) : 0);
|
||||
response = malloc(rlen + 1);
|
||||
if (response && rs) { memcpy(response, rs, rlen); response[rlen] = '\0'; }
|
||||
else if (response) { response[0] = '\0'; }
|
||||
_tl_fs_read_len = is_fs_body ? rlen : 0; /* length http_send_response should use */
|
||||
} else {
|
||||
response = el_strdup_persist("el-runtime: no http handler registered");
|
||||
}
|
||||
@@ -1806,10 +1815,14 @@ static void* http_worker_v2(void* arg) {
|
||||
el_val_t hmap = http_build_headers_map(hdr_block ? hdr_block : "");
|
||||
el_val_t r = h(EL_STR(dispatch_method), EL_STR(path), hmap, EL_STR(body));
|
||||
const char* rs = EL_CSTR(r);
|
||||
size_t rlen = _tl_fs_read_len > 0 ? _tl_fs_read_len : (rs ? strlen(rs) : 0);
|
||||
/* Only trust fs_read's byte count when the handler returned that exact
|
||||
* buffer (raw binary file); otherwise measure the built response by strlen. */
|
||||
int is_fs_body = (_tl_fs_read_len > 0 && rs == _tl_fs_read_ptr);
|
||||
size_t rlen = is_fs_body ? _tl_fs_read_len : (rs ? strlen(rs) : 0);
|
||||
response = malloc(rlen + 1);
|
||||
if (response && rs) { memcpy(response, rs, rlen); response[rlen] = '\0'; }
|
||||
else if (response) { response[0] = '\0'; }
|
||||
_tl_fs_read_len = is_fs_body ? rlen : 0; /* length http_send_response should use */
|
||||
el_release(hmap);
|
||||
} else {
|
||||
response = el_strdup_persist(
|
||||
@@ -1926,6 +1939,7 @@ el_val_t http_response(el_val_t status, el_val_t headers_json, el_val_t body) {
|
||||
el_val_t fs_read(el_val_t pathv) {
|
||||
const char* path = EL_CSTR(pathv);
|
||||
_tl_fs_read_len = 0;
|
||||
_tl_fs_read_ptr = NULL;
|
||||
if (!path) return el_wrap_str(el_strdup(""));
|
||||
FILE* f = fopen(path, "rb");
|
||||
if (!f) return el_wrap_str(el_strdup(""));
|
||||
@@ -1937,6 +1951,7 @@ el_val_t fs_read(el_val_t pathv) {
|
||||
size_t got = fread(buf, 1, (size_t)sz, f);
|
||||
buf[got] = '\0';
|
||||
_tl_fs_read_len = got; /* store real byte count for binary-safe send */
|
||||
_tl_fs_read_ptr = buf; /* ...valid only if THIS buffer is the response body */
|
||||
fclose(f);
|
||||
return el_wrap_str(buf);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user