Browse Source

Merge pull request #1226 from floooh/issue1225/use-fetch-api

sokol_fetch.h: replace XMLHttpRequest with fetch api.
Andre Weissflog 6 months ago
parent
commit
4bc52a1694
2 changed files with 87 additions and 88 deletions
  1. 8 0
      CHANGELOG.md
  2. 79 88
      sokol_fetch.h

+ 8 - 0
CHANGELOG.md

@@ -1,5 +1,13 @@
 ## Updates
 ## Updates
 
 
+### 17-Mar-2025
+
+- sokol_fetch.h web: replace XMLHttpRequest with the more modern fetch API,
+  and fix some inconsistencies when checking the HTTP status code: all status
+  codes in the 200 range via `response.ok` now count as success.
+
+  PR: https://github.com/floooh/sokol/pull/1226
+
 ### 15-Mar-2025
 ### 15-Mar-2025
 
 
 Some general cleanup around vertex formats in sokol_gfx.h which fixes a couple
 Some general cleanup around vertex formats in sokol_gfx.h which fixes a couple

+ 79 - 88
sokol_fetch.h

@@ -229,7 +229,7 @@
             path or HTTP URL. The string will be copied into an internal data
             path or HTTP URL. The string will be copied into an internal data
             structure, and passed "as is" (apart from any required
             structure, and passed "as is" (apart from any required
             encoding-conversions) to fopen(), CreateFileW() or
             encoding-conversions) to fopen(), CreateFileW() or
-            XMLHttpRequest. The maximum length of the string is defined by
+            the html fetch API call. The maximum length of the string is defined by
             the SFETCH_MAX_PATH configuration define, the default is 1024 bytes
             the SFETCH_MAX_PATH configuration define, the default is 1024 bytes
             including the 0-terminator byte.
             including the 0-terminator byte.
 
 
@@ -316,7 +316,7 @@
 
 
         - requests dispatched to a channel are either forwarded into that
         - requests dispatched to a channel are either forwarded into that
         channel's worker thread (on native platforms), or cause an HTTP
         channel's worker thread (on native platforms), or cause an HTTP
-        request to be sent via an asynchronous XMLHttpRequest (on the web
+        request to be sent via an asynchronous fetch() call (on the web
         platform)
         platform)
 
 
         - for all requests which have finished their current IO operation a
         - for all requests which have finished their current IO operation a
@@ -1049,7 +1049,8 @@ typedef enum sfetch_error_t {
     SFETCH_ERROR_BUFFER_TOO_SMALL,
     SFETCH_ERROR_BUFFER_TOO_SMALL,
     SFETCH_ERROR_UNEXPECTED_EOF,
     SFETCH_ERROR_UNEXPECTED_EOF,
     SFETCH_ERROR_INVALID_HTTP_STATUS,
     SFETCH_ERROR_INVALID_HTTP_STATUS,
-    SFETCH_ERROR_CANCELLED
+    SFETCH_ERROR_CANCELLED,
+    SFETCH_ERROR_JS_OTHER,          // check browser console for detailed error info
 } sfetch_error_t;
 } sfetch_error_t;
 
 
 /* the response struct passed to the response callback */
 /* the response struct passed to the response callback */
@@ -1402,8 +1403,7 @@ static void _sfetch_log(sfetch_log_item_t log_item, uint32_t log_level, uint32_t
             const char* message = 0;
             const char* message = 0;
         #endif
         #endif
         _sfetch->desc.logger.func("sfetch", log_level, log_item, message, line_nr, filename, _sfetch->desc.logger.user_data);
         _sfetch->desc.logger.func("sfetch", log_level, log_item, message, line_nr, filename, _sfetch->desc.logger.user_data);
-    }
-    else {
+    } else {
         // for log level PANIC it would be 'undefined behaviour' to continue
         // for log level PANIC it would be 'undefined behaviour' to continue
         if (log_level == 0) {
         if (log_level == 0) {
             abort();
             abort();
@@ -1468,8 +1468,7 @@ _SOKOL_PRIVATE void _sfetch_path_copy(_sfetch_path_t* dst, const char* src) {
         strncpy(dst->buf, src, SFETCH_MAX_PATH);
         strncpy(dst->buf, src, SFETCH_MAX_PATH);
         #endif
         #endif
         dst->buf[SFETCH_MAX_PATH-1] = 0;
         dst->buf[SFETCH_MAX_PATH-1] = 0;
-    }
-    else {
+    } else {
         _sfetch_clear(dst->buf, SFETCH_MAX_PATH);
         _sfetch_clear(dst->buf, SFETCH_MAX_PATH);
     }
     }
 }
 }
@@ -1513,8 +1512,7 @@ _SOKOL_PRIVATE bool _sfetch_ring_init(_sfetch_ring_t* rb, uint32_t num_slots) {
     rb->buf = (uint32_t*) _sfetch_malloc_clear(queue_size);
     rb->buf = (uint32_t*) _sfetch_malloc_clear(queue_size);
     if (rb->buf) {
     if (rb->buf) {
         return true;
         return true;
-    }
-    else {
+    } else {
         _sfetch_ring_discard(rb);
         _sfetch_ring_discard(rb);
         return false;
         return false;
     }
     }
@@ -1535,8 +1533,7 @@ _SOKOL_PRIVATE uint32_t _sfetch_ring_count(const _sfetch_ring_t* rb) {
     uint32_t count;
     uint32_t count;
     if (rb->head >= rb->tail) {
     if (rb->head >= rb->tail) {
         count = rb->head - rb->tail;
         count = rb->head - rb->tail;
-    }
-    else {
+    } else {
         count = (rb->head + rb->num) - rb->tail;
         count = (rb->head + rb->num) - rb->tail;
     }
     }
     SOKOL_ASSERT(count < rb->num);
     SOKOL_ASSERT(count < rb->num);
@@ -1658,8 +1655,7 @@ _SOKOL_PRIVATE bool _sfetch_pool_init(_sfetch_pool_t* pool, uint32_t num_items)
             pool->free_slots[pool->free_top++] = i;
             pool->free_slots[pool->free_top++] = i;
         }
         }
         pool->valid = true;
         pool->valid = true;
-    }
-    else {
+    } else {
         /* allocation error */
         /* allocation error */
         _sfetch_pool_discard(pool);
         _sfetch_pool_discard(pool);
     }
     }
@@ -1675,8 +1671,7 @@ _SOKOL_PRIVATE uint32_t _sfetch_pool_item_alloc(_sfetch_pool_t* pool, const sfet
         _sfetch_item_init(&pool->items[slot_index], slot_id, request);
         _sfetch_item_init(&pool->items[slot_index], slot_id, request);
         pool->items[slot_index].state = _SFETCH_STATE_ALLOCATED;
         pool->items[slot_index].state = _SFETCH_STATE_ALLOCATED;
         return slot_id;
         return slot_id;
-    }
-    else {
+    } else {
         /* pool exhausted, return the 'invalid handle' */
         /* pool exhausted, return the 'invalid handle' */
         return _sfetch_make_id(0, 0);
         return _sfetch_make_id(0, 0);
     }
     }
@@ -1897,8 +1892,7 @@ _SOKOL_PRIVATE bool _sfetch_win32_utf8_to_wide(const char* src, wchar_t* dst, in
     if ((dst_needed > 0) && (dst_needed < dst_chars)) {
     if ((dst_needed > 0) && (dst_needed < dst_chars)) {
         MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, dst_chars);
         MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, dst_chars);
         return true;
         return true;
-    }
-    else {
+    } else {
         /* input string doesn't fit into destination buffer */
         /* input string doesn't fit into destination buffer */
         return false;
         return false;
     }
     }
@@ -1941,8 +1935,7 @@ _SOKOL_PRIVATE bool _sfetch_file_read(_sfetch_file_handle_t h, uint32_t offset,
         DWORD bytes_read = 0;
         DWORD bytes_read = 0;
         BOOL read_res = ReadFile(h, ptr, (DWORD)num_bytes, &bytes_read, NULL);
         BOOL read_res = ReadFile(h, ptr, (DWORD)num_bytes, &bytes_read, NULL);
         return read_res && (bytes_read == num_bytes);
         return read_res && (bytes_read == num_bytes);
-    }
-    else {
+    } else {
         return false;
         return false;
     }
     }
 }
 }
@@ -2104,8 +2097,7 @@ _SOKOL_PRIVATE void _sfetch_request_handler(_sfetch_t* ctx, uint32_t slot_id) {
         if ((buffer->ptr == 0) || (buffer->size == 0)) {
         if ((buffer->ptr == 0) || (buffer->size == 0)) {
             thread->error_code = SFETCH_ERROR_NO_BUFFER;
             thread->error_code = SFETCH_ERROR_NO_BUFFER;
             thread->failed = true;
             thread->failed = true;
-        }
-        else {
+        } else {
             /* open file if not happened yet */
             /* open file if not happened yet */
             if (!_sfetch_file_handle_valid(thread->file_handle)) {
             if (!_sfetch_file_handle_valid(thread->file_handle)) {
                 SOKOL_ASSERT(path->buf[0]);
                 SOKOL_ASSERT(path->buf[0]);
@@ -2114,8 +2106,7 @@ _SOKOL_PRIVATE void _sfetch_request_handler(_sfetch_t* ctx, uint32_t slot_id) {
                 thread->file_handle = _sfetch_file_open(path);
                 thread->file_handle = _sfetch_file_open(path);
                 if (_sfetch_file_handle_valid(thread->file_handle)) {
                 if (_sfetch_file_handle_valid(thread->file_handle)) {
                     thread->content_size = _sfetch_file_size(thread->file_handle);
                     thread->content_size = _sfetch_file_size(thread->file_handle);
-                }
-                else {
+                } else {
                     thread->error_code = SFETCH_ERROR_FILE_NOT_FOUND;
                     thread->error_code = SFETCH_ERROR_FILE_NOT_FOUND;
                     thread->failed = true;
                     thread->failed = true;
                 }
                 }
@@ -2128,22 +2119,19 @@ _SOKOL_PRIVATE void _sfetch_request_handler(_sfetch_t* ctx, uint32_t slot_id) {
                     if (thread->content_size <= buffer->size) {
                     if (thread->content_size <= buffer->size) {
                         bytes_to_read = thread->content_size;
                         bytes_to_read = thread->content_size;
                         read_offset = 0;
                         read_offset = 0;
-                    }
-                    else {
+                    } else {
                         /* provided buffer to small to fit entire file */
                         /* provided buffer to small to fit entire file */
                         thread->error_code = SFETCH_ERROR_BUFFER_TOO_SMALL;
                         thread->error_code = SFETCH_ERROR_BUFFER_TOO_SMALL;
                         thread->failed = true;
                         thread->failed = true;
                     }
                     }
-                }
-                else {
+                } else {
                     if (chunk_size <= buffer->size) {
                     if (chunk_size <= buffer->size) {
                         bytes_to_read = chunk_size;
                         bytes_to_read = chunk_size;
                         read_offset = thread->fetched_offset;
                         read_offset = thread->fetched_offset;
                         if ((read_offset + bytes_to_read) > thread->content_size) {
                         if ((read_offset + bytes_to_read) > thread->content_size) {
                             bytes_to_read = thread->content_size - read_offset;
                             bytes_to_read = thread->content_size - read_offset;
                         }
                         }
-                    }
-                    else {
+                    } else {
                         /* provided buffer to small to fit next chunk */
                         /* provided buffer to small to fit next chunk */
                         thread->error_code = SFETCH_ERROR_BUFFER_TOO_SMALL;
                         thread->error_code = SFETCH_ERROR_BUFFER_TOO_SMALL;
                         thread->failed = true;
                         thread->failed = true;
@@ -2153,8 +2141,7 @@ _SOKOL_PRIVATE void _sfetch_request_handler(_sfetch_t* ctx, uint32_t slot_id) {
                     if (_sfetch_file_read(thread->file_handle, read_offset, bytes_to_read, (void*)buffer->ptr)) {
                     if (_sfetch_file_read(thread->file_handle, read_offset, bytes_to_read, (void*)buffer->ptr)) {
                         thread->fetched_size = bytes_to_read;
                         thread->fetched_size = bytes_to_read;
                         thread->fetched_offset += bytes_to_read;
                         thread->fetched_offset += bytes_to_read;
-                    }
-                    else {
+                    } else {
                         thread->error_code = SFETCH_ERROR_UNEXPECTED_EOF;
                         thread->error_code = SFETCH_ERROR_UNEXPECTED_EOF;
                         thread->failed = true;
                         thread->failed = true;
                     }
                     }
@@ -2199,51 +2186,53 @@ _SOKOL_PRIVATE void* _sfetch_channel_thread_func(void* arg) {
 #if _SFETCH_PLATFORM_EMSCRIPTEN
 #if _SFETCH_PLATFORM_EMSCRIPTEN
 EM_JS(void, sfetch_js_send_head_request, (uint32_t slot_id, const char* path_cstr), {
 EM_JS(void, sfetch_js_send_head_request, (uint32_t slot_id, const char* path_cstr), {
     const path_str = UTF8ToString(path_cstr);
     const path_str = UTF8ToString(path_cstr);
-    const req = new XMLHttpRequest();
-    req.open('HEAD', path_str);
-    req.onreadystatechange = function() {
-        if (req.readyState == XMLHttpRequest.DONE) {
-            if (req.status == 200) {
-                const content_length = req.getResponseHeader('Content-Length');
-                __sfetch_emsc_head_response(slot_id, content_length);
-            }
-            else {
-                __sfetch_emsc_failed_http_status(slot_id, req.status);
+    fetch(path_str, { method: 'HEAD' }).then((response) => {
+        if (response.ok) {
+            const content_length = response.headers.get('Content-Length');
+            if (content_length === null) {
+                console.warn(`sokol_fetch.h: HEAD ${path_str} response has no Content-Length`);
+                __sfetch_emsc_failed_other(slot_id);
+            } else {
+                __sfetch_emsc_head_response(slot_id, Number(content_length));
             }
             }
+        } else {
+            __sfetch_emsc_failed_http_status(slot_id, response.status);
         }
         }
-    };
-    req.send();
+    }).catch((err) => {
+        console.error(`sokol_fetch.h: HEAD ${path_str} failed with: `, err);
+        __sfetch_emsc_failed_other(slot_id);
+    });
 })
 })
 
 
 /* if bytes_to_read != 0, a range-request will be sent, otherwise a normal request */
 /* if bytes_to_read != 0, a range-request will be sent, otherwise a normal request */
 EM_JS(void, sfetch_js_send_get_request, (uint32_t slot_id, const char* path_cstr, uint32_t offset, uint32_t bytes_to_read, void* buf_ptr, uint32_t buf_size), {
 EM_JS(void, sfetch_js_send_get_request, (uint32_t slot_id, const char* path_cstr, uint32_t offset, uint32_t bytes_to_read, void* buf_ptr, uint32_t buf_size), {
     const path_str = UTF8ToString(path_cstr);
     const path_str = UTF8ToString(path_cstr);
-    const req = new XMLHttpRequest();
-    req.open('GET', path_str);
-    req.responseType = 'arraybuffer';
-    const need_range_request = (bytes_to_read > 0);
-    if (need_range_request) {
-        req.setRequestHeader('Range', 'bytes='+offset+'-'+(offset+bytes_to_read-1));
-    }
-    req.onreadystatechange = function() {
-        if (req.readyState == XMLHttpRequest.DONE) {
-            if ((req.status == 206) || ((req.status == 200) && !need_range_request)) {
-                const u8_array = new Uint8Array(\x2F\x2A\x2A @type {!ArrayBuffer} \x2A\x2F (req.response));
-                const content_fetched_size = u8_array.length;
-                if (content_fetched_size <= buf_size) {
-                    HEAPU8.set(u8_array, buf_ptr);
-                    __sfetch_emsc_get_response(slot_id, bytes_to_read, content_fetched_size);
-                }
-                else {
+    const headers = new Headers();
+    const range_request = bytes_to_read > 0;
+    if (range_request) {
+        headers.append('Range', `bytes=${offset}-${offset+bytes_to_read-1}`);
+    }
+    fetch(path_str, { method: 'GET', headers }).then((response) => {
+        if (response.ok) {
+            response.arrayBuffer().then((data) => {
+                const u8_data = new Uint8Array(data);
+                if (u8_data.length <= buf_size) {
+                    HEAPU8.set(u8_data, buf_ptr);
+                    __sfetch_emsc_get_response(slot_id, bytes_to_read, u8_data.length);
+                } else {
                     __sfetch_emsc_failed_buffer_too_small(slot_id);
                     __sfetch_emsc_failed_buffer_too_small(slot_id);
                 }
                 }
-            }
-            else {
-                __sfetch_emsc_failed_http_status(slot_id, req.status);
-            }
+            }).catch((err) => {
+                console.error(`sokol_fetch.h: GET ${path_str} failed with: `, err);
+                __sfetch_emsc_failed_other(slot_id);
+            });
+        } else {
+            __sfetch_emsc_failed_http_status(slot_id, response.status);
         }
         }
-    };
-    req.send();
+    }).catch((err) => {
+        console.error(`sokol_fetch.h: GET ${path_str} failed with: `, err);
+        __sfetch_emsc_failed_other(slot_id);
+    });
 })
 })
 
 
 /*=== emscripten specific C helper functions =================================*/
 /*=== emscripten specific C helper functions =================================*/
@@ -2254,8 +2243,7 @@ void _sfetch_emsc_send_get_request(uint32_t slot_id, _sfetch_item_t* item) {
     if ((item->buffer.ptr == 0) || (item->buffer.size == 0)) {
     if ((item->buffer.ptr == 0) || (item->buffer.size == 0)) {
         item->thread.error_code = SFETCH_ERROR_NO_BUFFER;
         item->thread.error_code = SFETCH_ERROR_NO_BUFFER;
         item->thread.failed = true;
         item->thread.failed = true;
-    }
-    else {
+    } else {
         uint32_t offset = 0;
         uint32_t offset = 0;
         uint32_t bytes_to_read = 0;
         uint32_t bytes_to_read = 0;
         if (item->chunk_size > 0) {
         if (item->chunk_size > 0) {
@@ -2297,8 +2285,7 @@ EMSCRIPTEN_KEEPALIVE void _sfetch_emsc_get_response(uint32_t slot_id, uint32_t r
             item->thread.http_range_offset += range_fetched_size;
             item->thread.http_range_offset += range_fetched_size;
             if (item->chunk_size == 0) {
             if (item->chunk_size == 0) {
                 item->thread.finished = true;
                 item->thread.finished = true;
-            }
-            else if (item->thread.http_range_offset >= item->thread.content_size) {
+            } else if (item->thread.http_range_offset >= item->thread.content_size) {
                 item->thread.finished = true;
                 item->thread.finished = true;
             }
             }
             _sfetch_ring_enqueue(&ctx->chn[item->channel].user_outgoing, slot_id);
             _sfetch_ring_enqueue(&ctx->chn[item->channel].user_outgoing, slot_id);
@@ -2314,8 +2301,7 @@ EMSCRIPTEN_KEEPALIVE void _sfetch_emsc_failed_http_status(uint32_t slot_id, uint
         if (item) {
         if (item) {
             if (http_status == 404) {
             if (http_status == 404) {
                 item->thread.error_code = SFETCH_ERROR_FILE_NOT_FOUND;
                 item->thread.error_code = SFETCH_ERROR_FILE_NOT_FOUND;
-            }
-            else {
+            } else {
                 item->thread.error_code = SFETCH_ERROR_INVALID_HTTP_STATUS;
                 item->thread.error_code = SFETCH_ERROR_INVALID_HTTP_STATUS;
             }
             }
             item->thread.failed = true;
             item->thread.failed = true;
@@ -2338,6 +2324,19 @@ EMSCRIPTEN_KEEPALIVE void _sfetch_emsc_failed_buffer_too_small(uint32_t slot_id)
     }
     }
 }
 }
 
 
+EMSCRIPTEN_KEEPALIVE void _sfetch_emsc_failed_other(uint32_t slot_id) {
+    _sfetch_t* ctx = _sfetch_ctx();
+    if (ctx && ctx->valid) {
+        _sfetch_item_t* item = _sfetch_pool_item_lookup(&ctx->pool, slot_id);
+        if (item) {
+            item->thread.error_code = SFETCH_ERROR_JS_OTHER;
+            item->thread.failed = true;
+            item->thread.finished = true;
+            _sfetch_ring_enqueue(&ctx->chn[item->channel].user_outgoing, slot_id);
+        }
+    }
+}
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 } /* extern "C" */
 } /* extern "C" */
 #endif
 #endif
@@ -2353,15 +2352,13 @@ _SOKOL_PRIVATE void _sfetch_request_handler(_sfetch_t* ctx, uint32_t slot_id) {
                yet, need to send a HEAD request first
                yet, need to send a HEAD request first
              */
              */
             sfetch_js_send_head_request(slot_id, item->path.buf);
             sfetch_js_send_head_request(slot_id, item->path.buf);
-        }
-        else {
+        } else {
             /* otherwise, this is either a request to load the entire file, or
             /* otherwise, this is either a request to load the entire file, or
                to load the next streaming chunk
                to load the next streaming chunk
              */
              */
             _sfetch_emsc_send_get_request(slot_id, item);
             _sfetch_emsc_send_get_request(slot_id, item);
         }
         }
-    }
-    else {
+    } else {
         /* just move all other items (e.g. paused or cancelled)
         /* just move all other items (e.g. paused or cancelled)
            into the outgoing queue, so they won't get lost
            into the outgoing queue, so they won't get lost
         */
         */
@@ -2413,8 +2410,7 @@ _SOKOL_PRIVATE bool _sfetch_channel_init(_sfetch_channel_t* chn, _sfetch_t* ctx,
         _sfetch_thread_init(&chn->thread, _sfetch_channel_thread_func, chn);
         _sfetch_thread_init(&chn->thread, _sfetch_channel_thread_func, chn);
         #endif
         #endif
         return true;
         return true;
-    }
-    else {
+    } else {
         _sfetch_channel_discard(chn);
         _sfetch_channel_discard(chn);
         return false;
         return false;
     }
     }
@@ -2428,8 +2424,7 @@ _SOKOL_PRIVATE bool _sfetch_channel_send(_sfetch_channel_t* chn, uint32_t slot_i
     if (!_sfetch_ring_full(&chn->user_sent)) {
     if (!_sfetch_ring_full(&chn->user_sent)) {
         _sfetch_ring_enqueue(&chn->user_sent, slot_id);
         _sfetch_ring_enqueue(&chn->user_sent, slot_id);
         return true;
         return true;
-    }
-    else {
+    } else {
         _SFETCH_ERROR(SEND_QUEUE_FULL);
         _SFETCH_ERROR(SEND_QUEUE_FULL);
         return false;
         return false;
     }
     }
@@ -2554,8 +2549,7 @@ _SOKOL_PRIVATE void _sfetch_channel_dowork(_sfetch_channel_t* chn, _sfetch_pool_
         item->user.fetched_size = item->thread.fetched_size;
         item->user.fetched_size = item->thread.fetched_size;
         if (item->user.cancel) {
         if (item->user.cancel) {
             _sfetch_cancel_item(item);
             _sfetch_cancel_item(item);
-        }
-        else {
+        } else {
             item->user.error_code = item->thread.error_code;
             item->user.error_code = item->thread.error_code;
         }
         }
         if (item->thread.finished) {
         if (item->thread.finished) {
@@ -2564,8 +2558,7 @@ _SOKOL_PRIVATE void _sfetch_channel_dowork(_sfetch_channel_t* chn, _sfetch_pool_
         /* state transition */
         /* state transition */
         if (item->thread.failed) {
         if (item->thread.failed) {
             item->state = _SFETCH_STATE_FAILED;
             item->state = _SFETCH_STATE_FAILED;
-        }
-        else if (item->state == _SFETCH_STATE_FETCHING) {
+        } else if (item->state == _SFETCH_STATE_FETCHING) {
             item->state = _SFETCH_STATE_FETCHED;
             item->state = _SFETCH_STATE_FETCHED;
         }
         }
         _sfetch_invoke_response_callback(item);
         _sfetch_invoke_response_callback(item);
@@ -2576,8 +2569,7 @@ _SOKOL_PRIVATE void _sfetch_channel_dowork(_sfetch_channel_t* chn, _sfetch_pool_
         if (item->user.finished) {
         if (item->user.finished) {
             _sfetch_ring_enqueue(&chn->free_lanes, item->lane);
             _sfetch_ring_enqueue(&chn->free_lanes, item->lane);
             _sfetch_pool_item_free(pool, slot_id);
             _sfetch_pool_item_free(pool, slot_id);
-        }
-        else {
+        } else {
             _sfetch_ring_enqueue(&chn->user_incoming, slot_id);
             _sfetch_ring_enqueue(&chn->user_incoming, slot_id);
         }
         }
     }
     }
@@ -2775,8 +2767,7 @@ SOKOL_API_IMPL void* sfetch_unbind_buffer(sfetch_handle_t h) {
         item->buffer.ptr = 0;
         item->buffer.ptr = 0;
         item->buffer.size = 0;
         item->buffer.size = 0;
         return prev_buf_ptr;
         return prev_buf_ptr;
-    }
-    else {
+    } else {
         return 0;
         return 0;
     }
     }
 }
 }