-
Notifications
You must be signed in to change notification settings - Fork 23.7k
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
Required changes to support redirects on HTTP 307/308 #36809
Conversation
b9766c7
to
18c99fd
Compare
Here is a reproducer for the problem using urllib2: #!/usr/bin/python
from ansible.module_utils.urls import fetch_url
class AltModule():
params = dict(
follow_redirects='urllib2',
# follow_redirects='all',
)
tmpdir='/tmp'
module = AltModule()
resp, info = fetch_url(
module,
# 'http://httpstat.us/301',
# 'http://httpstat.us/307',
'http://httpstat.us/308',
force=True,
method='POST',
data='{"name": "Somewhere", "type": "wireless", "tags": "a_tag", "timeZone": "America/Chicago"}',
headers={
'Content-Type': 'application/json',
},
)
print(info['status'])
print(info['url']) On Python 2.7 this reproducer only seems to show the problem with HTTP 307 on urllib2. But shows the problem for both HTTP 307 and 308 on both urllib2 and all. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
follow_redirects=urllib2
should not be updated to support this. The specific purpose of follow_redirects=urllib2
is to work exactly how urllib2 works. When using follow_redirects=urllib2
the expected outcome is that an HTTPError
should be raised.
Any change to expand the accepted status codes should only happen to all
Hmm, that seems weird. urllib2 is lacking any support for HTTP 308 redirects (as HTTP 308 predates urllib2 since its RFC says April 2015) and doesn't support 307 with POST/PUT. https://github.com/python/cpython/blob/2.7/Lib/urllib2.py#L577 I don't see why anyone would want that honestly. And worse, urllib2 is the default method. https://stackoverflow.com/questions/42136829/whats-difference-between-http-301-and-308-status-codes Adding HTTP 307 and HTTP 308 support to urllib2 does not make sense either, but would have been to proper course of action. Won't fix Python 2.6 and highly unlikely for Python 2.7. That's why we are turning to this. Can you explain why urllib2 method needs to stay broken ? And why it is the default method ? |
I did some tests to check results. These were done with Python 3.5.4.
|
The This ensures that a request made with urllib2/urllib.request outside of ansible, and within ansible follow the same redirect rules.
A default value of |
18c99fd
to
4dc6140
Compare
@sivel The new implementation does what you want. Tested and verified for Thanks !
It actually doesn't allow all redirects. HTTP 307 and 308 remain broken for urllib2 after this revisited PR. |
@dagwieers thanks. I'll likely get back around this tomorrow. |
4dc6140
to
f55076d
Compare
lib/ansible/module_utils/urls.py
Outdated
|
||
return RequestWithMethod(newurl, | ||
method=method, | ||
headers=req.headers, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we are dropping newheaders
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No probably a left-over of reworking the code. It works fine for our test-cases because there's no rewrite of the URL.
lib/ansible/module_utils/urls.py
Outdated
newurl = newurl.replace(' ', '%20') | ||
newheaders = dict((k, v) for k, v in req.headers.items() | ||
if k.lower() not in ("content-length", "content-type")) | ||
if k.lower() not in ("content-length")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we modifying this line, and then not using it later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same answer as before.
So I have been looking at urllib3 (from v2.7) and urllib (from v3.6) and noticed that rewriting spaces and Content-Length is not performed in urllib3 and I wonder if that is necessary, or just an old work-around for broken servers ? |
@sivel Is this ready to be merged now ? |
I think the only thing left is tests. Integration tests will work to test the behavior of
|
Well, You need to test the actual request and see if the request used the proper method and did contain the payload. Otherwise the HTTP 307 error would not have been detected, as it did redirect to the correct location, but using the wrong method and no payload. Not sure if our current integration-testing methodology allow to test redirection + feedback about used method and payload. If you like I can add integration tests for all this based on https://httpstat.us/ and get this merged ASAP. Everything else will likely need infra adaptations. |
httpbin can be made to work the same way, by redirecting to I need to think on some other things as well. This fundamentally makes changes to allow the body to be redirected as well, which has never been the case before, and could result in unexpected and backwards incompatible changes for people. I think this need to be it's own, new, separate EDIT: Also, with respect to a unit test, I'd expect things to be mocked and inspected in typical unit test style, not actually making a request. |
@sivel Good luck creating 2 implementations for every bug in our code. The whole point of HTTP 307 and 308 using POST/PUT is to redo the request to the new URI (and not turning it into a GET without payload or returning 307/308). This did not work before. So anything depending on this to fail, would not be usable. There's no universe where causing a HTTP 200 (or a 307 or 308) and not actually redoing the request is correct. It's broken, can't work. That's why I don't understand why we wouldn't be fixing urllib2 too. Other HTTP clients don't have options for every incorrect behaviour of the past, regardless of someone was relying on the wrong behaviour. And in this case, you can't rely on the wrong behaviour, as it simply doesn't do anything you depend on. (You might as well NOT do the request...) |
de12e6e
to
9b3ff09
Compare
9b3ff09
to
50c5921
Compare
This is required if we want to ensure that ansible#36809 doesn't cause any important behavioral changes. This PR changes the uri module to support follow_redirects=urllib2 It also adds a better error message when the connection closes before any data was returned.
Everything looks good to me so far. It passes all of my recently added unit tests (with small manipulations due to using After this merges, I'll update my Thanks for all the work, and bearing with my review. |
rebuild_merge |
@sivel And thanks for persisting despite me not getting initially what you were saying... |
CI failures. Unrelated. I'll merge manually. |
This is required if we want to ensure that ansible#36809 doesn't cause any important behavioral changes. This PR changes the uri module to support follow_redirects=urllib2 It also adds a better error message when the connection closes before any data was returned.
* Required changes to support redirects on HTTP 307/308 This ensures HTTP 307 and 308 will redirect the request to the new location without modification. * Fix the unused newheaders reference * Be more compliant * Add integration tests for follow_redirects=all * Improve other tests for new behaviour * Make follow_redirects values more strict
SUMMARY
This PR includes fixes to
follow_redirects=all
:ISSUE TYPE
COMPONENT NAME
module_utils/urls.py
ANSIBLE VERSION
v2.5