Skip to content

fix(im): validate Content-Range for resource download chunks#1178

Open
xu91102 wants to merge 2 commits into
larksuite:mainfrom
xu91102:codex/fix-im-content-range-validation
Open

fix(im): validate Content-Range for resource download chunks#1178
xu91102 wants to merge 2 commits into
larksuite:mainfrom
xu91102:codex/fix-im-content-range-validation

Conversation

@xu91102
Copy link
Copy Markdown

@xu91102 xu91102 commented May 29, 2026

Summary

Fixes an integrity gap in im +messages-resources-download range downloads where later 206 Partial Content responses could return the wrong byte range while still matching the final byte count. The downloader now parses and validates Content-Range for the initial and subsequent chunks.

Changes

  • Add a concrete Content-Range parser that validates byte start, end, and total values.
  • Validate the initial range response against the probe request and every later chunk against the requested range.
  • Keep 200 OK single-stream downloads unchanged.
  • Tighten IM resource output path normalization so Unix-rooted paths such as /tmp/out.bin are rejected on Windows too.
  • Add unit coverage for malformed ranges, mismatched chunks, and platform-neutral path expectations.

Test Plan

  • Unit tests pass: go test ./shortcuts/im -run TestParseContentRange|TestDownloadIMResourceRangeChunksValidateContentRange|TestDownloadIMResourceToPathInitialRangeMustMatchRequest|TestDownloadIMResourceToPathHTTPClientError|TestNormalizeDownloadOutputPath|TestParseContentDispositionFilename|TestResolveIMResourceDownloadPath|TestDownloadIMResourceToPathRangeDownload|TestDownloadIMResourceToPathInvalidContentRange|TestDownloadIMResourceToPathRangeChunkFailureCleansOutput|TestDownloadIMResourceToPathRangeOverflowCleansOutput|TestDownloadIMResourceToPathRangeShortChunkSizeMismatch
  • Format check passes: gofmt -l shortcuts/im/im_messages_resources_download.go shortcuts/im/helpers_test.go shortcuts/im/helpers_network_test.go produced no output
  • Diff check passes: git diff --check
  • Full package tests: go test ./shortcuts/im was run on Windows but hit existing platform issues unrelated to this change: temp media files remained locked during cleanup, and TestValidateMediaFlagPath/absolute_path_rejected uses /etc/passwd, which is not absolute on Windows.
  • Manual local verification confirms the lark-cli im +messages-resources-download flow works as expected: not run; change is covered by focused HTTP stream unit tests.

Related Issues

  • None

Summary by CodeRabbit

  • Bug Fixes

    • Stricter validation of Content-Range and initial range probe to detect mismatched or malformed partial-content responses and chunk size mismatches.
    • Tighter output-path normalization rejecting absolute/invalid paths and trimming whitespace to avoid incorrect destinations.
  • Tests

    • Expanded tests covering initial-range checks, per-chunk Content-Range validation, chunk size mismatches, parsing edge cases, and path-normalization scenarios.

Review Change Stack

@github-actions github-actions Bot added domain/im PR touches the im domain size/M Single-domain feat or fix with limited business impact labels May 29, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 626870ec-dd79-4036-a3de-c48196836592

📥 Commits

Reviewing files that changed from the base of the PR and between 3ce5cec and 84137e9.

📒 Files selected for processing (3)
  • shortcuts/im/helpers_network_test.go
  • shortcuts/im/helpers_test.go
  • shortcuts/im/im_messages_resources_download.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • shortcuts/im/helpers_test.go
  • shortcuts/im/im_messages_resources_download.go

📝 Walkthrough

Walkthrough

This PR tightens IM ranged-downloads: adds content-range parsing/validation, enforces per-chunk byte-counts and per-response Content-Range checks (including initial probe), tightens output-path normalization, and adds integration tests for probe and chunk error cases.

Changes

Range Request Validation for IM Downloads

Layer / File(s) Summary
Content-Range parsing and validation contract
shortcuts/im/im_messages_resources_download.go, shortcuts/im/helpers_test.go
Adds contentRange struct with String(), parseContentRange, and validateContentRange; replaces parseTotalSize. TestParseContentRange covers valid and multiple malformed Content-Range forms.
Output path normalization
shortcuts/im/im_messages_resources_download.go, shortcuts/im/helpers_test.go
normalizeDownloadOutputPath trims input, rejects absolute paths (filepath.IsAbs or leading //\), cleans the path, and errors when result is ".". Tests updated to use filepath.Join and include a Windows-rooted path case.
Range chunk reader length & per-chunk validation
shortcuts/im/im_messages_resources_download.go
rangeChunkReader now tracks chunkWant/chunkRead, enforces exact per-chunk byte counts (errors on mismatch), and validates each 206 response Content-Range against expected start/end/total.
Initial 206 probe response validation
shortcuts/im/im_messages_resources_download.go
downloadIMResourceToPath parses/validates the initial 206 Content-Range (requires start==0 and expected end for probe chunk, consistent total) and initializes the reader with the validated total size.
Integration tests for probe & chunk scenarios
shortcuts/im/helpers_network_test.go
Adds TestDownloadIMResourceToPathInitialRangeMustMatchRequest, TestDownloadIMResourceRangeChunksValidateContentRange, TestDownloadIMResourceToPathRangeChunkLengthMismatch, plus imResourceRangeResponse helper; updates an existing short-chunk-size test expectation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • larksuite/cli#283: Related prior work on IM ranged download Content-Range handling and tests.
  • larksuite/cli#536: Related edits to downloadIMResourceToPath and Content-Range / download orchestration.

Suggested reviewers

  • jackie3927
  • YangJunzhou-01

Poem

🐰 I scope each range with careful care,
Bytes counted true, no header to spare.
Probe then chunk, they march in line,
Start, end, total — all align.
A hopping rabbit says: "Tests pass fine!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the main change: adding validation for Content-Range headers in resource download chunks, which is the core integrity fix described throughout the PR.
Description check ✅ Passed The description comprehensively covers all required template sections with specific details about the changes, thorough test plan documentation, and clear explanation of the fix.
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 unit tests (beta)
  • Create PR with unit tests

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
shortcuts/im/helpers_test.go (1)

562-569: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Cover the new Windows-rooted path branch here.

This table exercises /tmp/out.bin, but it never hits the new strings.HasPrefix(outputPath, "\\") rejection path. Adding a \tmp\out.bin case would lock in the regression this PR is trying to prevent on Windows.

Suggested test case
 	{name: "absolute path", fileKey: "file_123", outputPath: "/tmp/out.bin", wantErr: "absolute paths are not allowed"},
+	{name: "windows rooted path", fileKey: "file_123", outputPath: `\tmp\out.bin`, wantErr: "absolute paths are not allowed"},
 	{name: "parent escape", fileKey: "file_123", outputPath: "../out.bin", wantErr: "path cannot escape the current working directory"},
🤖 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 `@shortcuts/im/helpers_test.go` around lines 562 - 569, Add a test row to the
table in shortcuts/im/helpers_test.go that exercises the Windows-rooted path
branch by using outputPath set to `\tmp\out.bin` (e.g., {name: "Windows-rooted
path", fileKey: "file_123", outputPath: "\\tmp\\out.bin", wantErr: "absolute
paths are not allowed"}) so the strings.HasPrefix(outputPath, "\\") rejection
branch is covered; place it alongside the other cases that assert errors for
absolute/escaped paths.
🤖 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 `@shortcuts/im/im_messages_resources_download.go`:
- Around line 244-251: The code currently only validates the Content-Range
header via validateContentRange (using r.nextOffset, end, r.totalSize) but does
not verify the actual response body length, allowing corrupted writes; update
the download handling around the validateContentRange/resp.Body logic (the block
that calls validateContentRange and the similar logic at lines ~253-254) to
compute expectedLen = end - start + 1 (from the contentRange you validated),
read exactly expectedLen bytes from resp.Body (e.g., via io.ReadFull or io.CopyN
into the destination) and fail with an error (close resp.Body and return
output.ErrNetwork(...)) if fewer or more bytes are read (EOF/mismatch), and only
advance r.nextOffset after a successful exact-length write; apply the same
exact-length check to the initial probe body path as well.

---

Outside diff comments:
In `@shortcuts/im/helpers_test.go`:
- Around line 562-569: Add a test row to the table in
shortcuts/im/helpers_test.go that exercises the Windows-rooted path branch by
using outputPath set to `\tmp\out.bin` (e.g., {name: "Windows-rooted path",
fileKey: "file_123", outputPath: "\\tmp\\out.bin", wantErr: "absolute paths are
not allowed"}) so the strings.HasPrefix(outputPath, "\\") rejection branch is
covered; place it alongside the other cases that assert errors for
absolute/escaped paths.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7d40b66d-6137-48a2-b13a-d82f8e397d5c

📥 Commits

Reviewing files that changed from the base of the PR and between d126ea2 and 3ce5cec.

📒 Files selected for processing (3)
  • shortcuts/im/helpers_network_test.go
  • shortcuts/im/helpers_test.go
  • shortcuts/im/im_messages_resources_download.go

Comment thread shortcuts/im/im_messages_resources_download.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain/im PR touches the im domain size/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant