Skip to content

gh-86809: Add support for HTTP range requests - #24228

Open
DavidBord wants to merge 3 commits into
python:mainfrom
DavidBord:http-range-requests-bpo-42643
Open

DavidBord wants to merge 3 commits into
python:mainfrom
DavidBord:http-range-requests-bpo-42643

Conversation

@DavidBord

@DavidBord DavidBord commented Jan 16, 2021 •

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

This PR is stale because it has been open for 30 days with no activity.

@github-actions github-actions Bot added the stale Stale PR or inactive for long period of time. label Feb 16, 2021
@roolebo

roolebo commented Feb 20, 2021

Copy link
Copy Markdown

@DavidBord Thanks! I think built-in range support is going to be helpful

@stokito

stokito commented Feb 20, 2021

Copy link
Copy Markdown

It’s needed to resume downloads and this may significantly reduce load in some cases. That’s why even minimal busybox httpd has a support of Range requests

@github-actions github-actions Bot removed the stale Stale PR or inactive for long period of time. label Feb 21, 2021
@github-actions

Copy link
Copy Markdown

This PR is stale because it has been open for 30 days with no activity.

@github-actions github-actions Bot added the stale Stale PR or inactive for long period of time. label Mar 23, 2021
@chrisroat

Copy link
Copy Markdown

This is a most welcome update. Thank you @DavidBord

@imba-tjd

imba-tjd commented Feb 12, 2022 •

Copy link
Copy Markdown
Contributor

Personally I think it's fundamental to support Range: bytes=<range-start>- i.e. no <range-end>.

Others I think are OK.


I'm using a modified version of this patch in my program https://github.com/imba-tjd/qrsend. I will share info when I found defects.

Comment thread Lib/http/server.py Outdated
shutil.copyfileobj(source, outputfile)
if start_byte is not None and end_byte is not None:
source.seek(start_byte)
outputfile.write(source.read(end_byte))

@imba-tjd imba-tjd Apr 25, 2022 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Fatal error. When you use 2-5, the start_byte is 2 and end_byte is 5. Then you read(5).
The correct behavior is read(4), which is end_byte-start_byte+1. Though I won't suggest whether putting +1 here or previous place.

More importantly, read() will load all data into memory in a row before start writing. This has serious performance issue when resuming large file. I tried source.truncate() but it turns out an io.UnsupportedOperation.

Besides Content-Length needs changing too. So that new testing is recommended to be added, too.

@github-actions github-actions Bot removed the stale Stale PR or inactive for long period of time. label Aug 3, 2022
@muxator

muxator commented Apr 3, 2026

Copy link
Copy Markdown

Is there a way to help reviewing this PR? I'd like to help.

@imba-tjd

imba-tjd commented Apr 4, 2026 •

Copy link
Copy Markdown
Contributor

Is there a way to help reviewing this PR? I'd like to help.

There was another PR which was detailed discussed. However it seems to be deleted. Maybe it will be recoverd.

This PR is poorly implemented and can be closed IMO.

@GalaxySnail

Copy link
Copy Markdown
Contributor

You can use git fetch origin pull/118949/head:pr/118949 to get the code in #118949. The latest commit on this branch is 580aa14. And the latest archive on the Wayback Machine is https://web.archive.org/web/20250925083524/https://github.com/python/cpython/pull/118949.

@github-actions

Copy link
Copy Markdown

This PR is stale because it has been open for 30 days with no activity.

@github-actions github-actions Bot added the stale Stale PR or inactive for long period of time. label May 10, 2026
@DavidBord
DavidBord force-pushed the http-range-requests-bpo-42643 branch from 87935c0 to a89f588 Compare July 24, 2026 13:33
@DavidBord
DavidBord requested a review from AA-Turner as a code owner July 24, 2026 13:33
@DavidBord

Copy link
Copy Markdown
Author

I went through the review feedback on this PR.
I also went over GH-118949 and brought over the pieces that were valuable here.

@read-the-docs-community

read-the-docs-community Bot commented Jul 24, 2026 •

Copy link
Copy Markdown

@DavidBord
DavidBord force-pushed the http-range-requests-bpo-42643 branch from cd2dfba to 1aedfad Compare July 24, 2026 15:10
@github-actions github-actions Bot removed the stale Stale PR or inactive for long period of time. label Jul 26, 2026
@serhiy-storchaka serhiy-storchaka changed the title bpo-42643: Add support for HTTP range requests gh-86809: Add support for HTTP range requests Aug 12, 2026
@ambv

ambv commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

This PR is superseded by #118949, a newer open pull request for the same issue (gh-86809), and it no longer merges cleanly. Closing to cull the number of open pull requests. Do not reopen this pull request without getting a go-ahead from a triager or core developer.

Closing this was the wrong decision, closing #118949 instead and keeping this alive.

@ambv ambv closed this Oct 20, 2026
@ambv ambv reopened this Oct 20, 2026
@bedevere-app bedevere-app Bot added the type-feature A feature request or enhancement label Oct 20, 2026
@picnixz
picnixz self-requested a review October 20, 2026 23:39
Co-authored-by: Muse Code (Meta Muse Spark)

# Conflicts:
#	Doc/whatsnew/3.16.rst
#	Lib/http/server.py
@lyc8503

lyc8503 commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

I also went over #118949 and brought over the pieces that were valuable here.

Hi, I'm the author of #118949. Much more disscussion is done there. Maybe we should coauthor this if you took code pieces there?

There was another PR which was detailed discussed. However it seems to be deleted. Maybe it will be recoverd.

It's Microsoft somehow banning my GitHub account by mistake and took down that. Now it's back.

@picnixz

picnixz commented Oct 21, 2026

Copy link
Copy Markdown
Member

Yes, please credit the author of the other PR in both the commits and the NEWS/What's New entry.

@picnixz picnixz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I want to ask some questions:

  1. How much from your original work has been kept?
  2. How much did you take from the other PR?

AFAICT, the tests in this PR are better written, but the implementation itself is closer to what I wanted to have. In particular, I don't like the http_range keyword and the lack of documentation since we are adding new keyword parameters and expecting files to be seekable as well.

Please however address the credit attribution first because depending on how much was pulled from the other PR, I would rather have the other PR merged.

.. versionchanged:: 3.15
Added *extra_response_headers* parameter.

.. versionchanged:: 3.16

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
.. versionchanged:: 3.16
.. versionchanged:: next

Comment thread Doc/whatsnew/3.16.rst

* :class:`~http.server.SimpleHTTPRequestHandler` now supports HTTP
single-part range requests for files, as specified in :rfc:`9110#section-14`.
(Contributed by David Bord in :gh:`86809`.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
(Contributed by David Bord in :gh:`86809`.)
(Contributed by David Bord in :gh:`86809`.)

Please credit the other PR's author.

@lyc8503 Please indicate how you want to be credited here.

Comment thread Lib/http/server.py
Comment on lines +886 to +888
return None
else:
self._range = (start, end)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
return None
else:
self._range = (start, end)
return None
self._range = (start, end)

Comment thread Lib/http/server.py
if f:
try:
self.copyfile(f, self.wfile)
self.copyfile(f, self.wfile, http_range=self._range)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Personally, I would prefer that we have range=self._range rather than http_range, even if we are shadowing a built-in. The range itself can be given explicitly as it's simply a (start, end) pair.

Comment thread Lib/http/server.py
return path

def copyfile(self, source, outputfile):
def copyfile(self, source, outputfile, *, http_range=None):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You must document that this method has a new keyword argument now.

os.chmod(self.tempdir, 0o755)

@support.subTests(
'range_header,content_range,content_length,start,end',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
'range_header,content_range,content_length,start,end',
('range_header', 'content_range', 'content_length', 'start', 'end'),

Comment on lines +841 to +845
('bYtEs=2-5', 'bytes 2-5/30', '4', 2, 6),
('bytes=3-', 'bytes 3-29/30', '27', 3, None),
('bytes=-5', 'bytes 25-29/30', '5', 25, None),
('bytes=29-29', 'bytes 29-29/30', '1', 29, None),
('bytes=25-100', 'bytes 25-29/30', '5', 25, None),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For each param, please indicate what case exercises (using a # comment)

Comment on lines +889 to +890
self.assertEqual(response.getheader('content-range'), 'bytes */30')
self.assertEqual(response.getheader('content-length'), '0')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
self.assertEqual(response.getheader('content-range'), 'bytes */30')
self.assertEqual(response.getheader('content-length'), '0')
self.assertEqual(response.getheader('Content-Range'), 'bytes */30')
self.assertEqual(response.getheader('Content-Length'), '0')

Comment on lines +908 to +909
self.assertEqual(response.getheader('content-range'), 'bytes */0')
self.assertEqual(response.getheader('content-length'), '0')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
self.assertEqual(response.getheader('content-range'), 'bytes */0')
self.assertEqual(response.getheader('content-length'), '0')
self.assertEqual(response.getheader('Content-Range'), 'bytes */0')
self.assertEqual(response.getheader('Content-Length'), '0')

Comment on lines +1 to +2
SimpleHTTPRequestHandler now supports single-part HTTP range requests, as
specified in RFC 9110 section 14.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
SimpleHTTPRequestHandler now supports single-part HTTP range requests, as
specified in RFC 9110 section 14.
Added support for HTTP single-part range requests on files to
:class:`~http.server.SimpleHTTPRequestHandler`, as specified
in :rfc:`9110#section-14`.

@bedevere-app

bedevere-app Bot commented Oct 21, 2026

Copy link
Copy Markdown

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@picnixz

picnixz commented Oct 21, 2026

Copy link
Copy Markdown
Member

I looked at the commit history and despite the force push, the original PR's code is no longer the author's AFAICT. I can't find any tests either and thus I would rather have the other PR be altered with the tests this one brings. From a work perspective, the other PR made the work that I would like to see shipped.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting changes type-feature A feature request or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.