Skip to content

Handle resume responses without Content-Range#27529

Open
KirtiRamchandani wants to merge 1 commit into
PowerShell:masterfrom
KirtiRamchandani:fix/webrequest-resume-missing-contentrange
Open

Handle resume responses without Content-Range#27529
KirtiRamchandani wants to merge 1 commit into
PowerShell:masterfrom
KirtiRamchandani:fix/webrequest-resume-missing-contentrange

Conversation

@KirtiRamchandani
Copy link
Copy Markdown

Problem

Invoke-WebRequest -Resume and Invoke-RestMethod -Resume can throw a NullReferenceException when a server responds to an already-complete range request with 416 Requested Range Not Satisfiable but omits the optional Content-Range header.

Fixes #23948.

Root Cause

The resume code dereferenced response.Content.Headers.ContentRange for every 416 response. RFC 9110 says a 416 response should include Content-Range, but it is not mandatory, and some servers omit it when the requested range starts at EOF.

Solution

  • Treat 416 responses without Content-Range as an already-complete resumed download.
  • Keep the existing retry-without-range behavior when Content-Range is present and shows the remote size differs from the local file size.
  • Add a WebListener endpoint that simulates 416 without Content-Range.
  • Add regression coverage for both Invoke-WebRequest and Invoke-RestMethod.

Tests

  • Reproduced the original NullReferenceException locally with a tiny HTTP server returning 416 without Content-Range.
  • Start-PSBuild -Configuration Debug -NoPSModuleRestore
  • Publish-PSTestTools
  • Manual WebListener verification for Invoke-WebRequest -Resume and Invoke-RestMethod -Resume against the new MissingContentRange endpoint.
  • git diff --check (only existing Windows line-ending notices)

Copilot AI review requested due to automatic review settings May 25, 2026 05:00
@KirtiRamchandani KirtiRamchandani requested a review from a team as a code owner May 25, 2026 05:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Updates PowerShell web cmdlets’ -Resume handling to tolerate non-compliant 416 RequestedRangeNotSatisfiable responses that omit Content-Range, treating them as “already complete”, and adds test coverage for this behavior.

Changes:

  • Add a WebListener endpoint that returns 416 without a Content-Range header when a Range request is made.
  • Refactor and harden resume-range handling in WebRequestPSCmdlet to avoid null dereferences and treat missing Content-Range as complete.
  • Add Pester tests for Invoke-WebRequest and Invoke-RestMethod validating the new -Resume behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
test/tools/WebListener/Controllers/ResumeController.cs Adds a new test endpoint to simulate 416 without Content-Range for range requests
test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 Adds regression tests for -Resume behavior when Content-Range is missing
src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs Refactors resume logic into helpers and treats missing Content-Range as “already complete”

Comment on lines +80 to +85
string rangeHeader;
if (TryGetRangeHeader(out rangeHeader))
{
Response.StatusCode = StatusCodes.Status416RequestedRangeNotSatisfiable;
return;
}
await Response.Body.WriteAsync(FileBytes, 0, FileBytes.Length);
}

public async void MissingContentRange()
Comment on lines +1742 to +1744
// RFC 9110 only says 416 responses SHOULD include Content-Range. Treat a missing
// header as an already-complete resume instead of failing with a null reference.
return contentRange is null || (contentRange.HasLength && contentRange.Length == _resumeFileSize);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Invoke-WebRequest with Request gives "Object reference not set to an instance of an object" if there was an HTTP redirect

2 participants