| 363 | |
| 364 | |
| 365 | int Perform(const Ref<DownloadInstance>& instance, const Request& request, Response& response) |
| 366 | { |
| 367 | int result = -1; |
| 368 | int retry = 0; |
| 369 | while (true) |
| 370 | { |
| 371 | response.response.statusCode = 0; |
| 372 | response.response.headers.clear(); |
| 373 | response.body.clear(); |
| 374 | response.error.clear(); |
| 375 | |
| 376 | if (getenv("BN_DEBUG_HTTP")) |
| 377 | { |
| 378 | LogDebug("> %s %s", request.m_method.c_str(), request.m_url.c_str()); |
| 379 | for (auto& header : request.m_headers) |
| 380 | { |
| 381 | LogDebug("> %s: %s", header.first.c_str(), header.second.c_str()); |
| 382 | } |
| 383 | LogDebug("> "); |
| 384 | if (!request.m_body.empty()) |
| 385 | { |
| 386 | for (size_t i = 0; i < request.m_body.size(); i += 1000) |
| 387 | { |
| 388 | LogDebug("> %.*s", (int)std::min(request.m_body.size() - i, (size_t)1000), request.m_body.data() + i); |
| 389 | } |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | RequestContext context {request, response}; |
| 394 | BNDownloadInstanceInputOutputCallbacks callbacks {}; |
| 395 | memset(&callbacks, 0, sizeof(BNDownloadInstanceInputOutputCallbacks)); |
| 396 | callbacks.readContext = &context; |
| 397 | callbacks.readCallback = &HttpReadCallback; |
| 398 | callbacks.writeContext = &context; |
| 399 | callbacks.writeCallback = &HttpWriteCallback; |
| 400 | result = instance->PerformCustomRequest( |
| 401 | request.m_method, request.m_url, request.m_headers, response.response, &callbacks); |
| 402 | if (getenv("BN_DEBUG_HTTP")) |
| 403 | { |
| 404 | LogDebug("* Function returned: %d", result); |
| 405 | } |
| 406 | if (result >= 0) |
| 407 | break; |
| 408 | |
| 409 | if (getenv("BN_DEBUG_HTTP")) |
| 410 | { |
| 411 | LogDebug("* Error: %s", instance->GetError().c_str()); |
| 412 | } |
| 413 | |
| 414 | // Request failed, grab its error and try again |
| 415 | response.error = instance->GetError(); |
| 416 | if (retry == HTTP_MAX_RETRIES || context.cancelled) |
| 417 | break; |
| 418 | size_t backoff = 1000 * HTTP_BACKOFF_FACTOR * (2 * pow(2, retry - 1)); |
| 419 | retry += 1; |
| 420 | LogWarn("Attempt %d to %s %s failed, trying again in %zums\n", retry, request.m_method.data(), |
| 421 | request.m_url.data(), backoff); |
| 422 | std::this_thread::sleep_for(std::chrono::milliseconds(backoff)); |