| 1797 | // --------------------------------------------------------------------------- |
| 1798 | |
| 1799 | static size_t pj_curl_read_range(PJ_CONTEXT *ctx, |
| 1800 | PROJ_NETWORK_HANDLE *raw_handle, |
| 1801 | unsigned long long offset, size_t size_to_read, |
| 1802 | void *buffer, size_t error_string_max_size, |
| 1803 | char *out_error_string, void *) { |
| 1804 | auto handle = reinterpret_cast<CurlFileHandle *>(raw_handle); |
| 1805 | auto hCurlHandle = handle->m_handle; |
| 1806 | |
| 1807 | double oldDelay = MIN_RETRY_DELAY_MS; |
| 1808 | std::string headers; |
| 1809 | std::string body; |
| 1810 | |
| 1811 | char szBuffer[128]; |
| 1812 | sqlite3_snprintf(sizeof(szBuffer), szBuffer, "%llu-%llu", offset, |
| 1813 | offset + size_to_read - 1); |
| 1814 | |
| 1815 | while (true) { |
| 1816 | CHECK_RET(ctx, curl_easy_setopt(hCurlHandle, CURLOPT_RANGE, szBuffer)); |
| 1817 | |
| 1818 | headers.clear(); |
| 1819 | headers.reserve(16 * 1024); |
| 1820 | CHECK_RET(ctx, |
| 1821 | curl_easy_setopt(hCurlHandle, CURLOPT_HEADERDATA, &headers)); |
| 1822 | CHECK_RET(ctx, curl_easy_setopt(hCurlHandle, CURLOPT_HEADERFUNCTION, |
| 1823 | pj_curl_write_func)); |
| 1824 | |
| 1825 | body.clear(); |
| 1826 | body.reserve(size_to_read); |
| 1827 | CHECK_RET(ctx, curl_easy_setopt(hCurlHandle, CURLOPT_WRITEDATA, &body)); |
| 1828 | CHECK_RET(ctx, curl_easy_setopt(hCurlHandle, CURLOPT_WRITEFUNCTION, |
| 1829 | pj_curl_write_func)); |
| 1830 | |
| 1831 | handle->m_szCurlErrBuf[0] = '\0'; |
| 1832 | |
| 1833 | curl_easy_perform(hCurlHandle); |
| 1834 | |
| 1835 | long response_code = 0; |
| 1836 | curl_easy_getinfo(hCurlHandle, CURLINFO_HTTP_CODE, &response_code); |
| 1837 | |
| 1838 | CHECK_RET(ctx, |
| 1839 | curl_easy_setopt(hCurlHandle, CURLOPT_WRITEDATA, nullptr)); |
| 1840 | CHECK_RET( |
| 1841 | ctx, curl_easy_setopt(hCurlHandle, CURLOPT_WRITEFUNCTION, nullptr)); |
| 1842 | |
| 1843 | if (response_code == 0 || response_code >= 300) { |
| 1844 | const double delay = |
| 1845 | GetNewRetryDelay(static_cast<int>(response_code), oldDelay, |
| 1846 | body.c_str(), handle->m_szCurlErrBuf); |
| 1847 | if (delay != 0 && delay < MAX_RETRY_DELAY_MS) { |
| 1848 | pj_log(ctx, PJ_LOG_TRACE, |
| 1849 | "Got a HTTP %ld error. Retrying in %d ms", response_code, |
| 1850 | static_cast<int>(delay)); |
| 1851 | sleep_ms(static_cast<int>(delay)); |
| 1852 | oldDelay = delay; |
| 1853 | } else { |
| 1854 | if (out_error_string) { |
| 1855 | if (handle->m_szCurlErrBuf[0]) { |
| 1856 | snprintf(out_error_string, error_string_max_size, "%s", |