| 2009 | #endif |
| 2010 | |
| 2011 | static size_t pj_emscripten_read_range(PJ_CONTEXT *ctx, |
| 2012 | PROJ_NETWORK_HANDLE *raw_handle, |
| 2013 | unsigned long long offset, |
| 2014 | size_t size_to_read, void *buffer, |
| 2015 | size_t error_string_max_size, |
| 2016 | char *out_error_string, void *) { |
| 2017 | auto handle = reinterpret_cast<EmscriptenFileHandle *>(raw_handle); |
| 2018 | |
| 2019 | double oldDelay = MIN_RETRY_DELAY_MS; |
| 2020 | |
| 2021 | char szBuffer[128]; |
| 2022 | sqlite3_snprintf(sizeof(szBuffer), szBuffer, "bytes=%llu-%llu", offset, |
| 2023 | offset + size_to_read - 1); |
| 2024 | |
| 2025 | // To work in the browser, we need to run the fetch part in Web Worker, |
| 2026 | // otherwise we cannot run it synchronous. (at least with my tests) |
| 2027 | // It is easier running all PROJ in the Web Worker (that is the test done). |
| 2028 | // Documentation says compiling with pthread flag is needed. |
| 2029 | // https://emscripten.org/docs/api_reference/fetch.html#synchronous-fetches |
| 2030 | // We encapsulate the code related to empscripten_fetch in a lamda. |
| 2031 | // Some tests running this lambda in a thread were partially successful. |
| 2032 | size_t real_read = 0; |
| 2033 | const std::string url = handle->m_url; |
| 2034 | auto fetching = [&]() { |
| 2035 | emscripten_fetch_t *fetch = nullptr; |
| 2036 | while (true) { |
| 2037 | |
| 2038 | emscripten_fetch_attr_t attr; |
| 2039 | emscripten_fetch_attr_init(&attr); |
| 2040 | strcpy(attr.requestMethod, "GET"); |
| 2041 | const char *requestHeaders[] = {"Range", szBuffer, nullptr}; |
| 2042 | attr.requestHeaders = requestHeaders; |
| 2043 | attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY | |
| 2044 | EMSCRIPTEN_FETCH_SYNCHRONOUS | |
| 2045 | EMSCRIPTEN_FETCH_REPLACE; |
| 2046 | if (fetch) { |
| 2047 | emscripten_fetch_close(fetch); |
| 2048 | } |
| 2049 | |
| 2050 | TRACE_FETCH("Pre-fetch, url: " << url << ", range: " << szBuffer); |
| 2051 | fetch = emscripten_fetch(&attr, url.c_str()); |
| 2052 | // emscripten_fetch_wait(fetch, -1); // This is deprecated |
| 2053 | TRACE_FETCH("Post-fetch"); |
| 2054 | |
| 2055 | if (!fetch) { |
| 2056 | snprintf(out_error_string, error_string_max_size, |
| 2057 | "Cannot init emscripten_fetch for url %s", |
| 2058 | url.c_str()); |
| 2059 | return; |
| 2060 | } |
| 2061 | const auto response_code = fetch->status; |
| 2062 | TRACE_FETCH("Received HTTP response code: " << response_code); |
| 2063 | if (response_code == 0 || response_code >= 300) { |
| 2064 | const double delay = |
| 2065 | GetNewRetryDelay(static_cast<int>(response_code), oldDelay, |
| 2066 | fetch->data, fetch->statusText); |
| 2067 | if (delay != 0 && delay < MAX_RETRY_DELAY_MS) { |
| 2068 | pj_log(ctx, PJ_LOG_TRACE, |