-
-
Notifications
You must be signed in to change notification settings - Fork 276
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
Query string ordering #354
Query string ordering #354
Conversation
5af46af
to
3ae809f
Compare
Codecov Report
@@ Coverage Diff @@
## master #354 +/- ##
==========================================
+ Coverage 94.59% 94.73% +0.13%
==========================================
Files 7 7
Lines 832 835 +3
==========================================
+ Hits 787 791 +4
+ Misses 45 44 -1
Continue to review full report at Codecov.
|
3ae809f
to
3819645
Compare
Sweet, thanks @ErwinJunge ! |
Unfortunately, this PR has caused a regression. In terms of the HTTP spec, the ordering of query string fields can be ignored, yes. However, consider this case: Suppose we have a dynamic field value that we want to use a regular expression for to match within httpretty:
The compiled regular expression is expecting a URL in that format with the query string fields in that order. This now fails to match because Line 1007 in dbe2c3a
Line 1137 in dbe2c3a
q1=v1&q2=my_dynamic_value&q3=v3 when the application code making the request is actually sending q3=v3&q2=my_dynamic_value&q1=v1 .
As a workaround, the regular expression could be rewritten to match the internally-modified alphabetical version, however this is not an ideal solution as it's an implementation detail. If query string fields in the
Notice that in this hypothetical solution, we can provide the regular expressions as individual values of the dict keys. The presence of the params kwarg would override match_querystring to True. HTTPretty would then match against the URI and params dict. Alternatively, perhaps the ideal solution with the least change to the interface would be to add another kwarg such as Otherwise, what's happening right now is misleading. |
I don't agree that this would count as a regression. In your own description you're already saying that what you're trying to depend on doesn't conform the the http spec. I'd argue a logical conclusion of would be that the way you're using a regex to match query params also isn't conformant to the http spec and therefore that's where the problem is. However, if you can come up with a way to modify the library to support your usecase without breaking existing tests I'm sure a PR would be welcomed. |
@ErwinJunge Sure, expecting the query string fields to be in the exact order specified in the test can be argued to be non-conformant, but it is a regression by definition. A regression is something that worked before and now doesn't. Like I mentioned in my previous comment, if the order is to be ignored, the query param fields should be passed as a dict in another kwarg for optimal parsing. This would be a breaking change, and unfortunately that is necessary here if being conformant is the top concern. It could be rolled out in phases to limit the impact, for example implementing the params dict kwarg solution and then raising a DeprecationWarning if somebody passes in query string fields. Here are some examples from Webmock, the library that inspired httpretty: Special handling of query string params is exactly how they have tackled this, supporting both a custom DSL in the URI field and a params hash. |
Actually, it looks like httpretty was inspired by FakeWeb rather than WebMock. FakeWeb has the exact same issue since its inception: chrisk/fakeweb#7 (comment) and the issue is still open after 11 years. |
Just because it something used to work and now doesn't doesn't make it a regression. It's only a regression if it was supposed to work before. In this case, relying on the ordering of query params wasn't supposed to work in the first place. The fact that it did just means you got lucky for a while. As an extreme example of this, I'd like to refer you to https://xkcd.com/1172/ Either way, I think your suggestion of passing query params in a dict should be possible to implement in a non-breaking way. If you make the params kwarg optional it should be possible to implement the parsing/matching in such a way that a dict of params works the way you described without breaking the existing functionality. |
@ErwinJunge That definition is more accurate, and makes the regression even easier to point out: There are two uses cases for the Suppose we have the following statements:
and
Notice the second is not a string but a regular expression argument as denoted by the Prior to this PR, in both of the above invocations of If the application for which the test case is built for decided to instead send Line 1124 in dbe2c3a
URIInfo object created from the application's incoming request: Line 632 in dbe2c3a
However, this solution handled only one of the two supported use cases: string inputs. If a regular expression is passed as a Line 1116 in dbe2c3a
If URIs are now being parsed and their query string fields reordered, then this needs to happen on both string and regular expression user inputs, otherwise this change would result in a regression, which is exactly what has happened here. If it is possible to reliably parse query strings that contain complicated regular expressions (like I do think that the optional kwarg solution is best. |
This fixes the test from #353 by always comparing ordered query strings