Skip to content

DirectDownload has bounded timeouts but no hard owner cancellation contract

Summary

DirectDownload::DownloadUrlToFile now applies bounded WinInet timeouts and a total deadline, but the active call still relies on WinInet honoring those timeouts. The owner cannot actively cancel a stuck DNS/proxy/WPAD/certificate or blocking WinInet state by closing the active handles from shutdown.

This is a follow-up to BUG-096. It does not invalidate the bounded-timeout improvement, but the Beta 0.7.3 shutdown contract remains weaker than the surrounding worker lifetime fixes if background refresh owners cannot interrupt the active download.

Evidence

  • srchybrid/DirectDownload.cpp:79 sets a connect timeout on the session.
  • srchybrid/DirectDownload.cpp:124 sets send and receive timeout options on the request handle.
  • srchybrid/DirectDownload.cpp:137 checks the total deadline only between blocking InternetReadFile calls.
  • Background GeoLocation and IPFilter refresh workers still depend on this helper for network downloads.

Execution Plan

  1. Revalidate all current DirectDownload::DownloadUrlToFile callers and classify which are background refresh work that must respond to shutdown.
  2. Decide whether a hard cancellation handle belongs in DirectDownload options, the refresh worker context, or a narrow owner-owned active-download wrapper.
  3. Make active WinInet handles closeable from owner shutdown without double closing or racing normal worker cleanup.
  4. Preserve BUG-091 close-time failure handling and BUG-096 bounded-timeout behavior as the fallback when no explicit cancellation is requested.
  5. Ensure cancellation failure returns false, removes partial artifacts, and leaves refresh state reusable.
  6. Add a deterministic seam for a blocked send/read path where owner cancellation closes active handles.
  7. Validate GeoLocation/IPFilter refresh success, timeout failure, explicit cancellation, retry, and shutdown behavior.
  8. Validate Debug and Release x64 app builds through the supported workspace entrypoints.

Acceptance Criteria

  • Background refresh owners can actively cancel an in-flight direct download during shutdown or owner teardown.
  • WinInet handles have clear single-owner or synchronized close ownership.
  • Explicit cancellation and timeout failure both clean up partial artifacts and leave refresh state reusable.
  • Successful direct-download behavior, proxy behavior, and existing timeout bounds remain unchanged.
  • The item has commit evidence and targeted validation in this file before Beta 0.7.3.

Validation

  • Implemented in app commit 9d765e3 (BUG-100 add cancellable direct downloads).
  • DirectDownload::DownloadUrlToFile now accepts an optional CDownloadCancellation token. Background GeoLocation and IPFilter refresh owners keep that token and call Cancel() during teardown, which closes any registered WinInet session, connection, and request handles.
  • WinInet handle close ownership is synchronized through the cancellation token: normal cleanup closes only handles still registered to the worker, while cancellation consumes registered handles before closing them.
  • The existing three-argument DownloadUrlToFile behavior is preserved for callers without explicit cancellation; bounded connect/send/receive timeouts, total deadline behavior, proxy policy, close-time failure handling, and failed artifact deletion remain in place.
  • Validation:
  • python -m emule_workspace validate --workspace-root .
  • python -m emule_workspace build app --workspace-root . --config Debug --platform x64 --variant main
    • logs: workspaces\v0.72a\state\build-logs\20260508-110532
  • python -m emule_workspace build app --workspace-root . --config Release --platform x64 --variant main
    • logs: workspaces\v0.72a\state\build-logs\20260508-110552
  • Residual note: no dedicated DirectDownload blocked-WinInet seam exists yet, so cancellation was validated by ownership review plus Debug/Release app builds rather than an automated blocked send/read injection test.