Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CherryPy should handle If-Range's properly #1760

Open
wants to merge 24 commits into
base: main
Choose a base branch
from

Conversation

ian-otto
Copy link
Contributor

@ian-otto ian-otto commented Dec 2, 2018

What kind of change does this PR introduce?

  • bug fix
  • feature
  • docs update
  • tests/coverage improvement
  • refactoring
  • other

What is the related issue number (starting with #)

Fixes #1699

What is the current behavior? (You can also link to an open issue here)

#1699

What is the new behavior (if this is a feature change)?

In the presence of an If-Range header, CP will check if the time is before the current time, and if so, return the entire file as opposed to respecting the Range header. This is the RFC compliant way to handle this.

Other information:

Checklist:

  • I think the code is well written
  • I wrote good commit messages
  • I have squashed related commits together after the changes have been approved
  • Unit tests for the changes exist
  • Integration tests for the changes exist (if applicable)
  • I used the same coding conventions as the rest of the project
  • The new code doesn't generate linter offenses
  • Documentation reflects the changes
  • The PR relates to only one subject with a clear title
    and description in grammatically correct, complete sentences

@@ -174,7 +176,21 @@ def _serve_fileobj(fileobj, content_type, content_length, debug=False):
cherrypy.log(message, 'TOOLS.STATIC')
raise cherrypy.HTTPError(416, message)

if r:
IF_RANGE_IN_PAST = False
Copy link
Member

Choose a reason for hiding this comment

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

Since it's a variable and not a constant, you should use lowercase

# and the server sends back a 206 Partial Content answer with
# the appropriate body. If the condition is not fulfilled,
# the full resource is sent back, with a 200 OK status.
if datetime.datetime(*parsedate(request.headers.get('If-Range'))[:6]) \
Copy link
Member

Choose a reason for hiding this comment

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

We prefer wrapping clause with braces instead of escaping EOL

@ian-otto
Copy link
Contributor Author

ian-otto commented Dec 5, 2018

Thanks for cleaning this up for me, I'm still getting used to the coding conventions on this project, as well as my IDE doing things for me that don't match what the convention is!

@webknjaz
Copy link
Member

webknjaz commented Dec 5, 2018

No worries, just try to follow PEP8 + PEP257 at first :)

@@ -174,7 +176,22 @@ def _serve_fileobj(fileobj, content_type, content_length, debug=False):
cherrypy.log(message, 'TOOLS.STATIC')
raise cherrypy.HTTPError(416, message)

if r:
is_if_range_in_past = False
Copy link
Member

Choose a reason for hiding this comment

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

I think that this check would be moved before httputil.get_ranges() call, so that we could skip calling another heavy function.
Also, this whole check could be put into its own function (maybe in httputil) for readability.

@webknjaz
Copy link
Member

webknjaz commented Dec 6, 2018

It looks like flake8 made checks stricter so this will need to be fixed separately.

@cherrypy cherrypy deleted a comment Dec 6, 2018
@cherrypy cherrypy deleted a comment Dec 6, 2018
@cherrypy cherrypy deleted a comment Dec 6, 2018
cherrypy/lib/static.py Outdated Show resolved Hide resolved
# the appropriate body. If the condition is not fulfilled,
# the full resource is sent back, with a 200 OK status.
# Ref: https://tools.ietf.org/html/rfc7233#section-3.2
if datetime(*parsedate(if_range_header)[:6]) < datetime.now():
Copy link
Member

Choose a reason for hiding this comment

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

This will probably fail with E-Tag value:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Range

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll write a change for this. Do you think searching for exactly two double quotes will be enough for detecting ETAG vs Date? That's what I'm working with at the moment.

Copy link
Member

Choose a reason for hiding this comment

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

I'd probably go for try/except

Copy link
Member

Choose a reason for hiding this comment

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

And it should probably go to httputil module

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Migrated to httputil, and caught exception when there is an ETag instead of an httpdate. However, I treat the ETag as an always-fail condition as to my knowledge we don't support that yet? Correct me if I'm wrong.

Copy link
Member

Choose a reason for hiding this comment

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

It's actually supported in caching tool: https://github.com/cherrypy/cherrypy/search?q=expires&unscoped_q=expires&type=Code

And it just occurred to me that maybe this check should be done there, not in this module.

There's also a tool called expires + there's tests for etag as well.

Could you please explore this?

@webknjaz
Copy link
Member

webknjaz commented Jan 4, 2019

This pull request introduces 2 alerts when merging 2da1314 into e10b984 - view on LGTM.com

new alerts:

  • 2 for Unused import

Comment posted by LGTM.com

@ian-otto ian-otto changed the title CherryPy should handle If-Range's properly [WIP] CherryPy should handle If-Range's properly Jan 4, 2019
cherrypy/lib/httputil.py Outdated Show resolved Hide resolved
cherrypy/lib/httputil.py Outdated Show resolved Hide resolved
cherrypy/lib/httputil.py Outdated Show resolved Hide resolved
cherrypy/lib/static.py Outdated Show resolved Hide resolved
@ian-otto ian-otto changed the title [WIP] CherryPy should handle If-Range's properly CherryPy should handle If-Range's properly Apr 9, 2019
@webknjaz
Copy link
Member

webknjaz commented Apr 9, 2019

This pull request introduces 1 alert when merging 302c2d9 into b648977 - view on LGTM.com

new alerts:

  • 1 for Module is imported with 'import' and 'import from'

Comment posted by LGTM.com

cherrypy/lib/httputil.py Outdated Show resolved Hide resolved
cherrypy/lib/httputil.py Outdated Show resolved Hide resolved
cherrypy/lib/httputil.py Outdated Show resolved Hide resolved
cherrypy/lib/static.py Outdated Show resolved Hide resolved
webknjaz and others added 2 commits April 9, 2019 16:54
Co-Authored-By: duper51 <ianotto24@gmail.com>
Co-Authored-By: duper51 <ianotto24@gmail.com>
@webknjaz
Copy link
Member

This pull request introduces 1 alert when merging 64a52cc into b648977 - view on LGTM.com

new alerts:

  • 1 for Module is imported with 'import' and 'import from'

Comment posted by LGTM.com

@webknjaz
Copy link
Member

This pull request introduces 1 alert when merging 13e149b into b648977 - view on LGTM.com

new alerts:

  • 1 for Module is imported with 'import' and 'import from'

Comment posted by LGTM.com

cherrypy/lib/static.py Outdated Show resolved Hide resolved
cherrypy/lib/static.py Outdated Show resolved Hide resolved
cherrypy/lib/httputil.py Outdated Show resolved Hide resolved
@webknjaz
Copy link
Member

This pull request introduces 1 alert when merging ae98c9b into b648977 - view on LGTM.com

new alerts:

  • 1 for Module is imported with 'import' and 'import from'

Comment posted by LGTM.com

ensure old functionality is still present (logging parameter for non-requested byterange)
@@ -66,6 +67,29 @@ def protocol_from_http(protocol_str):
return int(protocol_str[5]), int(protocol_str[7])


def matches_if_range_check(if_range_header):
"""
Determines if an If-Range header is present and passes its conditions.
Copy link
Member

Choose a reason for hiding this comment

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

Imperative plz.

Suggested change
Determines if an If-Range header is present and passes its conditions.
Determine if an If-Range header conditions are fulfilled.

stop = content_length
r_len = stop - start
if_range_valid = httputil.matches_if_range_check(
request.headers.get('Range')
Copy link
Member

Choose a reason for hiding this comment

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

plz add a trailing comma here

Suggested change
request.headers.get('Range')
request.headers.get('Range'),

if if_range_valid:
r = httputil.get_ranges(
request.headers.get('Range'),
content_length
Copy link
Member

Choose a reason for hiding this comment

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

trailing comma plz

Suggested change
content_length
content_length,

@codecov
Copy link

codecov bot commented Apr 12, 2019

Codecov Report

Merging #1760 into master will increase coverage by 20.68%.
The diff coverage is 77.77%.

@@            Coverage Diff             @@
##           master   #1760       +/-   ##
==========================================
+ Coverage   60.32%     81%   +20.68%     
==========================================
  Files         104     104               
  Lines       18156   13654     -4502     
==========================================
+ Hits        10953   11061      +108     
+ Misses       7203    2593     -4610

@jaraco jaraco changed the base branch from master to main March 23, 2021 00:13
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.

CherryPy ignores "If-Range" HTTP request header
2 participants