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

Bugfix/query string #39

Merged
merged 24 commits into from
Aug 1, 2017
Merged

Bugfix/query string #39

merged 24 commits into from
Aug 1, 2017

Conversation

digitalresistor
Copy link

Fix for #38

@@ -874,14 +870,14 @@ def parse_request_uri(self, uri):
# If there's a scheme (and it must be http or https), then:
# http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query
# ]]
return parsed.scheme, parsed.netloc, parsed.path
return parsed.scheme, parsed.netloc, parsed.path, parsed.query
Copy link
Member

Choose a reason for hiding this comment

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

Could you please alter the docsrting of this method to match new behavior?

Copy link
Member

@webknjaz webknjaz left a comment

Choose a reason for hiding this comment

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

return at line 865 shall be updated as well, please also test this case as well as all other returns in if clauses

@digitalresistor
Copy link
Author

I can update the docstring and the return line as requested.

I will need help writing test cases for the rest of it, I don't see any unit tests for this piece of code to verify that it works as intended (unless I missed them in my grepping). I am not sure that a full on HTTP request will hit all of the points it currently attempts to support.

@digitalresistor
Copy link
Author

Docstring and return statement added.

@webknjaz
Copy link
Member

@bertjwregeer possible test cases to cover are uri in ['*', '/some_abs_uri', 'some_rel_uri']. Feel free to add 'em next to the one you already wrote. Thanks in advance :)

@digitalresistor
Copy link
Author

digitalresistor commented Jul 13, 2017

  • * is only valid in the case of an OPTIONS request, and can't be tested with a simple GET
  • relative_uri are never valid in the HTTP spec
  • absolute_path is already tested, since it is the default
  • absolute_uri is valid for a proxy and not for a general HTTP server and should be rejected unless the server is a proxy server.

See https://tools.ietf.org/html/rfc7230#section-5.3

I have added the tests, but I don't believe that getPage() will pass them through without modifying them by prepending a /.


Edit: Wow, it does...

@digitalresistor
Copy link
Author

I also noticed that this is false: https://github.com/bertjwregeer/cheroot/blob/791f126947bd9406fe5648a089be778106672544/cheroot/server.py#L722

Since the returned path from urlparse will have it's params stripped (at least for the last component), since it is parsed. You'll want to modify parse_request_uri to return those too. Since it is part of "parsed.params". See https://docs.python.org/2/library/urlparse.html

@digitalresistor
Copy link
Author

Actually Python recommends using urlsplit instead: https://docs.python.org/2/library/urlparse.html#urlparse.urlsplit since it will leave the path parameters alone for later processing.

@digitalresistor
Copy link
Author

Alright. I'm done.

Copy link
Contributor

@josephtate josephtate left a comment

Choose a reason for hiding this comment

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

LGTM

@webknjaz
Copy link
Member

Sorry, I'm at EuroPython currently. I'll check the changes ASAP once have some free time. ETA: this week.
If I fail to give you a feedback or release changes, please feel free to ping me on Monday.

P.S. Thank you for your efforts! You've done much more than I expected, I really appreciate this.

@josephtate
Copy link
Contributor

@webknjaz do you still have objections?

@webknjaz
Copy link
Member

Sorry, I wrote a few comments and forgot to hit publish button. Yes, there are a couple of nitpicks.


if scheme:
self.scheme = scheme
if method.upper() == 'OPTIONS' and not self.proxy:
Copy link
Member

Choose a reason for hiding this comment

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

According to RFC 2616 (section 5.1.1) and its successors RFC 7230 (section 3.1.1) and RFC 7231 (section 4.1) method names are case-sensitive and uppercase. Otherwise the request line is malicious and HTTP server must return 400 Bad Request.

Another nitpick: .upper() is being called 3 times for the most of requests, which should be avoided.

"""Initialize HTTP request container instance.

Args:
server (HTTPServer): web server object receiving this request
conn (HTTPConnection): HTTP connection object for this request

Kwargs:
proxy (Boolean): Whether this HTTPServer should behave as a PROXY
Copy link
Member

Choose a reason for hiding this comment

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

  1. Please use bool for type, because its actual builtin you refer to
  2. Please start the description with lowercase letter, because of the style used everywhere around
  3. I'd vote for proxy_mode var name (just a nitpick)

Kwargs:
proxy (Boolean): Whether this HTTPServer should behave as a PROXY
server for certain requests.
strict (Boolean): Whether we should return a 400 Bad Request when
Copy link
Member

Choose a reason for hiding this comment

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

Nit: strict_mode

@@ -628,6 +635,8 @@ def __init__(self, server, conn):
self.close_connection = self.__class__.close_connection
self.chunked_read = False
self.chunked_write = self.__class__.chunked_write
self.proxy = proxy
Copy link
Member

Choose a reason for hiding this comment

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

Naming this attribute is_proxy would be beneficial

Copy link
Member

Choose a reason for hiding this comment

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

(or is_proxy_mode etc.)

@digitalresistor
Copy link
Author

You have push permissions to the branch on my repo as a maintainer. Feel free to make those modifications and push there; or pull these changes into a local branch and fixup before pushing back to a new PR.

I already maintain Waitress, I really have no want or desire to maintain or spend even more time fixing yet another Python HTTP server.

@webknjaz
Copy link
Member

Deal, thanks for your contribution anyway :)

return False
path = b'%2F'.join(atoms)

if path[0] != b'/':
Copy link
Member

Choose a reason for hiding this comment

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

Wow! It turned out that path[0] returns int, not bytes, which is 47 for /, thus prepending / unconditionally.

(just a note)

Copy link
Member

Choose a reason for hiding this comment

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

Ref: PEP 358

.__getitem__(int | slice) -> int | bytes

@@ -598,12 +599,17 @@ class HTTPRequest(object):
A HeaderReader instance or compatible reader.
"""

def __init__(self, server, conn):
def __init__(self, server, conn, proxy_mode=False, strict_mode=True):
Copy link
Member

Choose a reason for hiding this comment

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

I'm not a fan of boolean parameters, especially when they represent a switch on behavior, because they often are limited in what they can describe and lead to branchy and unmaintainable code. Often it's better to use subclasses or handler functions or enumerated values to signal behavior. I'm not sure what's the best approach here without digging deeper, but I wanted to signal this potential issue.

Copy link
Member

Choose a reason for hiding this comment

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

I see your point, but currently I cannot suggest cleaner solution. So for now I'm going to merge this as is.

@webknjaz webknjaz merged commit 51c004a into cherrypy:master Aug 1, 2017
@webknjaz
Copy link
Member

webknjaz commented Aug 1, 2017

@bertjwregeer I've cut the tag v5.8.0, it will be available @ PYPI once this build succeeds.

@webknjaz
Copy link
Member

webknjaz commented Aug 5, 2017

JFI: merging this broke some things and integration with CherryPy, so this is going to be fixed.

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.

4 participants