Skip to content

fix(http): Try to fix HTTP 412 and ConnectionReset hard failure - #96

Merged
YueMiyuki merged 3 commits into
masterfrom
next-dev
Jun 3, 2026
Merged

fix(http): Try to fix HTTP 412 and ConnectionReset hard failure#96
YueMiyuki merged 3 commits into
masterfrom
next-dev

Conversation

@YueMiyuki

@YueMiyuki YueMiyuki commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Summary by cubic

Fixes failures on HTTP 412 and mid-stream connection resets. Small single-connection downloads reuse the successful range probe and auto-retry transient errors by resuming the .part file.

  • Bug Fixes
    • Reuse Range: bytes=0- with identity encoding and the range client for small files when a probe confirmed range support; avoids 412 on signed-URL CDNs (e.g. Quark).
    • Add in-place auto-retry for single-connection downloads (up to 5 attempts) on transient network errors (connection resets, body-read errors, timeouts); no retries for 4xx/5xx, cancellation, Cloudflare challenges, checksum errors, or stalls.
    • Improve diagnostics: log range-probe details; log request failures with redacted sensitive headers and bounded body snippets; restrict HTTP error classification to http/m3u8.

Written for commit 67e9199. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • More precise HTTP error classification to reduce incorrect failure handling.
    • Improved handling of HTTP error responses with safer diagnostic output.
  • Improvements

    • Single-connection downloads now auto-retry and resume interrupted transfers instead of failing immediately.
    • Enhanced logging for retry/resume decisions and key HTTP response details.
  • Tests

    • Added regression tests covering retry and resume behavior for single-connection downloads.

Copilot AI review requested due to automatic review settings June 3, 2026 11:32
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ec97fa96-12e8-4a9b-934e-c13c671a7318

📥 Commits

Reviewing files that changed from the base of the PR and between ad84ce4 and 67e9199.

📒 Files selected for processing (1)
  • src-tauri/risuko-engine/src/engine/http.rs

📝 Walkthrough

Walkthrough

Adds automatic in-place retry and resume for the single-connection fallback, reuses range-probe request shape for small files via a new force_range flag, centralizes transient-error classification, improves HTTP diagnostics and logging, and adds regression tests covering range reuse and mid-stream resets.

Changes

Single-Connection Download Retry and Range Reuse

Layer / File(s) Summary
Error classification refactoring
src-tauri/risuko-engine/src/engine/error_code.rs
HTTP-status classification in classify_error refactored into explicit conditional branches for statuses like 401/403/404/416/429/503, generic server errors, and redirects; behavior and returned ErrorCode values unchanged.
Retry budget and transient-error classifier
src-tauri/risuko-engine/src/engine/http.rs
Introduces SINGLE_MAX_RETRIES and updates single-stream docs/comments about outcome and chunk metadata.
Retry loop, force_range param, and run_single_download integration
src-tauri/risuko-engine/src/engine/http.rs
Wraps single-connection fallback in a retry loop that resumes from existing .part, forwards probe_confirmed_range as a force_range argument to run_single_download, and makes initial requests use Range: bytes=0- + Accept-Encoding: identity when forced.
Enhanced diagnostics and HTTP error logging
src-tauri/risuko-engine/src/engine/http.rs
Range-probe responses now log status and selected headers; piece-request >=400 handling redacts sensitive headers and captures a bounded response body snippet; single-connection >=400 warnings include force_range, response headers, and a 512-char body snippet.
Comments and small docs
src-tauri/risuko-engine/src/engine/http.rs
Various non-functional comment and documentation refinements (stream outcome, chunk meta, piece-queue behavior, client builders, parsing helpers, writer lifecycle).
Regression tests: Quark-style CDN and flaky TCP server
src-tauri/risuko-engine/tests/http_features.rs
Adds helper payload generator and two tests: (1) Quark-style CDN that rejects full GETs but serves Range to validate small-file range reuse; (2) flaky TCP server that truncates first response then requires Range to validate auto-retry/resume and final content integrity.

Sequence Diagram(s)

sequenceDiagram
  participant Engine
  participant RangeProbe
  participant SingleFallback
  participant RetryLoop
  participant Server

  Engine->>RangeProbe: probe_range_support()
  RangeProbe->>Server: HEAD/GET Range probe
  Server-->>RangeProbe: 206 + headers
  RangeProbe-->>Engine: Range supported

  Engine->>SingleFallback: decide single-fallback (size < threshold)
  SingleFallback->>RetryLoop: start (force_range = true)
  loop up to SINGLE_MAX_RETRIES
    RetryLoop->>Server: GET (Range: bytes=0- + Accept-Encoding: identity)
    alt transient failure
      Server-->>RetryLoop: connection reset / truncated
      RetryLoop->>SingleFallback: resume from .part and retry
    else success
      Server-->>RetryLoop: 206/200 + data
      RetryLoop-->>Engine: download complete
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • YueMiyuki/Risuko#90: Modifies the same HTTP download paths (probe_range_support, download_piece_stream, run_single_download) and adds Cloudflare diagnostics; closely related to transient-error/Cloudflare handling here.
  • YueMiyuki/Risuko#80: Overlaps on Cloudflare detection and related error-code handling adjusted in classify_error.

Poem

🐰 I nibble at retries when networks fray,
I hold the .part and stitch the frayed way,
If probes say "use range" for a payload small,
I ask bytes from zero and answer the call.
Hooray — the warren resumes and saves all!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main changes: fixing HTTP 412 and ConnectionReset issues through range-probe reuse and auto-retry logic for single-connection downloads.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added the next The "next" steps label Jun 3, 2026

This comment was marked as low quality.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src-tauri/risuko-engine/src/engine/http.rs (1)

1169-1187: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve range-request shape on stale-.part retry.

The stale-file recovery path falls back to &client with force_range=false, which can reintroduce the HTTP 412 failure this PR is fixing for Quark-style CDNs.

Suggested fix
-            run_single_download(
-                &client,
+            run_single_download(
+                single_client,
                 uri,
                 &part_path,
                 &headers,
                 total,
                 completed,
                 speed,
                 cancelled,
                 cancel_token,
                 &filename,
                 dir_path,
                 global_limiter,
                 task_limiter,
                 stall,
                 filename_was_url_derived,
-                false,
+                probe_confirmed_range,
             )
             .await
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/risuko-engine/src/engine/http.rs` around lines 1169 - 1187, The
stale-.part recovery path is calling run_single_download(&client, ..., false)
which forces force_range=false and can reintroduce HTTP 412 errors; change the
retry call in the stale-file branch to preserve the original range-request
behavior by forwarding the same force_range boolean used in the initial attempt
(or set it to true if the initial attempt used range requests) instead of
hardcoding false, and ensure you still pass the same client (&client) and all
other parameters to run_single_download so the retry maintains the same
range/request shape.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src-tauri/risuko-engine/src/engine/http.rs`:
- Around line 1892-1899: The warning log in the piece request handler currently
emits full response headers and a 256-char body snippet (variables header_dump,
body, snippet and the tracing::warn! call), which may leak sensitive data;
change this to avoid logging sensitive headers and body at warn level: redact or
filter out headers like "set-cookie", "authorization" and any cookies when
building the header summary (only include safe header names/values or a count),
do not include raw body snippets (instead log body length or a safe
hash/placeholder), and demote the message to debug/trace level (or keep only
status and range at warn). Update the tracing call that uses
range.to_range_header_value() accordingly so only non-sensitive, minimal info is
emitted.

In `@src-tauri/risuko-engine/tests/http_features.rs`:
- Around line 720-736: The test currently treats a missing Range header as
start.unwrap_or(0) so a retry with no resume range (start==None) still appears
as start=0 and passes; change the flaky-server handler around the start variable
(the code that sets let start = start.unwrap_or(0) and builds head) to detect a
missing Range explicitly and fail the request (return a non-resume/invalid
response) when a retry does not include a resume Range: i.e., do not default to
0—require start.is_some() for resume behavior and return an error or non-206
response when it's None so the test fails if the client does not send a Range on
retry; apply the same change in the other mirror block around lines handling
head (the second start/Content-Range block).

---

Outside diff comments:
In `@src-tauri/risuko-engine/src/engine/http.rs`:
- Around line 1169-1187: The stale-.part recovery path is calling
run_single_download(&client, ..., false) which forces force_range=false and can
reintroduce HTTP 412 errors; change the retry call in the stale-file branch to
preserve the original range-request behavior by forwarding the same force_range
boolean used in the initial attempt (or set it to true if the initial attempt
used range requests) instead of hardcoding false, and ensure you still pass the
same client (&client) and all other parameters to run_single_download so the
retry maintains the same range/request shape.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a8be329c-bf43-4b14-81ba-a0330506f227

📥 Commits

Reviewing files that changed from the base of the PR and between 4bfd9c4 and bcbc71c.

📒 Files selected for processing (3)
  • src-tauri/risuko-engine/src/engine/error_code.rs
  • src-tauri/risuko-engine/src/engine/http.rs
  • src-tauri/risuko-engine/tests/http_features.rs

Comment thread src-tauri/risuko-engine/src/engine/http.rs Outdated
Comment thread src-tauri/risuko-engine/tests/http_features.rs Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 3 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src-tauri/risuko-engine/src/engine/http.rs Outdated
Comment thread src-tauri/risuko-engine/src/engine/http.rs Outdated
Comment thread src-tauri/risuko-engine/src/engine/http.rs Outdated
Comment thread src-tauri/risuko-engine/tests/http_features.rs Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src-tauri/risuko-engine/src/engine/http.rs Outdated
@YueMiyuki YueMiyuki linked an issue Jun 3, 2026 that may be closed by this pull request
@YueMiyuki
YueMiyuki merged commit 47c83c4 into master Jun 3, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

next The "next" steps

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Download fail for specific tasks

2 participants