Compare commits

...

44 Commits

Author SHA1 Message Date
Cory Benfield
c398ab0e7d v2.12.3 2016-12-01 10:48:35 +00:00
Cory Benfield
7d2dfa8684 Merge pull request #3738 from Lukasa/revert-exclusion-patch
Revert "Restrict URL preparation to HTTP/HTTPS"
2016-12-01 10:45:25 +00:00
Cory Benfield
6f659a4179 Tests for our URL handling. 2016-11-30 21:45:09 +00:00
Cory Benfield
402a55b647 Revert "Restrict URL preparation to HTTP/HTTPS"
This reverts commit 34af72c87d.
2016-11-30 21:19:31 +00:00
Cory Benfield
ca15d48087 v2.12.2 2016-11-30 12:38:26 +00:00
Cory Benfield
5c4549493b Merge pull request #3695 from nateprewitt/idna_bypass
idna bypass
2016-11-25 13:18:01 +00:00
Cory Benfield
36c9c8c3de Merge pull request #3718 from nsoranzo/master
Make Response.content() return None for an empty response
2016-11-24 13:35:37 +00:00
Nicola Soranzo
f897be58bf Make Response.content return None if raw is None
Add test.
2016-11-24 12:54:26 +00:00
Kenneth Reitz
dfad00a6e8 Update README.rst 2016-11-23 20:10:44 -05:00
Kenneth Reitz
d5e050da85 Update README.rst 2016-11-23 20:10:04 -05:00
Kenneth Reitz
1ec08bedd4 links 2016-11-23 20:00:33 -05:00
Kenneth Reitz
724ae1274e new logo :D
https://kennethreitz.org/tattoos
2016-11-23 19:58:18 -05:00
Nicola Soranzo
4f428228d7 Make Response.content() return None if status_code is None
Fix #3698.
2016-11-23 21:15:07 +00:00
Cory Benfield
ccabcf1fca Merge pull request #3717 from nateprewitt/streaming_docs
streaming doc clarification
2016-11-23 10:17:31 +00:00
Nate Prewitt
4f9d0e0455 streaming doc clarification 2016-11-21 14:17:28 -07:00
Cory Benfield
b9f1c448f7 Merge pull request #3673 from klimenko-forks/auth-unicode
Enable unicode in basic http auth
2016-11-21 19:27:39 +00:00
Cory Benfield
22ec73d71a Merge pull request #3713 from tiran/strict_http_protocol_check
Restrict URL preparation to HTTP/HTTPS
2016-11-21 19:13:56 +00:00
Dmitry Klimenko
005f93fd0f added new test, original test restored 2016-11-21 21:42:44 +03:00
Christian Heimes
34af72c87d Restrict URL preparation to HTTP/HTTPS
Requests treats all URLs starting with the string 'http' as HTTP URLs.
Preparation with IDNA breaks non-standard URIs like http+unix. Requests
now prepares only URLs with prefix http:// and https://.

Signed-off-by: Christian Heimes <christian@python.org>
2016-11-21 18:46:57 +01:00
Nate Prewitt
a83685ce00 modifying IDNA encoding check to allow fallback 2016-11-21 08:22:42 -07:00
Nate Prewitt
264f5bd5e1 adding unicode_is_ascii utility function 2016-11-21 08:22:41 -07:00
Nate Prewitt
d52e9b8c80 updated tests with IDNA encoded and IPv6 urls 2016-11-21 08:22:37 -07:00
Kenneth Reitz
268672ab33 Update sidebarlogo.html 2016-11-20 22:49:17 -05:00
Kenneth Reitz
3b956495c1 Update sidebarintro.html 2016-11-20 22:48:43 -05:00
Dmitry Klimenko
3b84be3c99 changed behavior of basic-http-auth test 2016-11-18 20:39:55 +03:00
Dmitry Klimenko
e15280e49d fixed: httpbin with unicode auth 2016-11-18 19:04:51 +03:00
Dmitry Klimenko
55dea233ce fixed some error 2016-11-18 15:19:43 +03:00
Dmitry Klimenko
4f0efdb77e unicode test for _basic_auth_str 2016-11-18 13:31:31 +03:00
Dmitry Klimenko
7c4821231f Fixed: httpbin doesn't support bytes 2016-11-18 13:14:08 +03:00
Dmitry Klimenko
bf3e960e15 fixed usage unicode string 2016-11-17 23:13:03 +03:00
Cory Benfield
53d4a1feee Merge pull request #3704 from afeld/patch-1
clarify that the `chunk_size` is optional when streaming to a file
2016-11-17 17:27:47 +00:00
Aidan Feldman
ed3ba3dbb8 correct backtick formatting 2016-11-17 12:26:19 -05:00
Dmitry Klimenko
37bde4b638 added unicode auth test 2016-11-17 20:22:32 +03:00
Aidan Feldman
5562c0f097 clarify that the chunk_size is optional when streaming to a file 2016-11-17 12:21:58 -05:00
Dmitry Klimenko
2185fac626 remove extra import 2016-11-17 19:52:13 +03:00
Dmitry Klimenko
329a5cfdd4 Order of type check 2016-11-17 19:50:53 +03:00
Kenneth Reitz
5b66b364a7 Merge pull request #3703 from kennethreitz/revert-3700-master
Revert "Adding 'import requests' to readme code snippet."
2016-11-17 10:53:38 -05:00
Kenneth Reitz
5f4d0d08de Revert "Adding 'import requests' to readme code snippet." 2016-11-17 10:53:33 -05:00
Rakib Hasan
7e138f945e Adding 'import requests' to readme code snippet. (#3700)
* added import requests to small demo
2016-11-17 08:23:57 +00:00
Cory Benfield
1e198f9115 Merge pull request #3697 from hussaintamboli/master
Fixed issue #3696. Added a test for it as well.
2016-11-16 18:32:59 +00:00
Hussain
be8b13e89b Added myself to AUTHORS 2016-11-16 23:33:42 +05:30
Hussain
0d7de50dbd Just lstrip instead of strip because trailing whitespace already works. 2016-11-16 23:26:48 +05:30
Hussain
248d3e9f0f Fixed issue #3696. Added a test for it as well. 2016-11-16 22:48:45 +05:30
Dmitry Klimenko
e514920e19 Unable unicode in basic http auth
Fixed the issue with unicode characters in basic http auth
2016-11-12 01:39:37 +03:00
15 changed files with 8365 additions and 2148 deletions

View File

@@ -172,3 +172,4 @@ Patches and Suggestions
- Brian Bamsch <bbamsch32@gmail.com> (`@bbamsch <https://github.com/bbamsch>`_)
- Om Prakash Kumar <omprakash070@gmail.com> (`@iamprakashom <https://github.com/iamprakashom>`_)
- Philipp Konrad <gardiac2002@gmail.com> (`@gardiac2002 <https://github.com/gardiac2002>`_)
- Hussain Tamboli <hussaintamboli18@gmail.com> (`@hussaintamboli <https://github.com/hussaintamboli>`_)

View File

@@ -3,6 +3,38 @@
Release History
---------------
2.12.3 (2016-12-01)
+++++++++++++++++++
**Bugfixes**
- Fixed regression from v2.12.1 for URLs with schemes that begin with "http".
These URLs have historically been processed as though they were HTTP-schemed
URLs, and so have had parameters added. This was removed in v2.12.2 in an
overzealous attempt to resolve problems with IDNA-encoding those URLs. This
change was reverted: the other fixes for IDNA-encoding have been judged to
be sufficient to return to the behaviour Requests had before v2.12.0.
2.12.2 (2016-11-30)
+++++++++++++++++++
**Bugfixes**
- Fixed several issues with IDNA-encoding URLs that are technically invalid but
which are widely accepted. Requests will now attempt to IDNA-encode a URL if
it can but, if it fails, and the host contains only ASCII characters, it will
be passed through optimistically. This will allow users to opt-in to using
IDNA2003 themselves if they want to, and will also allow technically invalid
but still common hostnames.
- Fixed an issue where URLs with leading whitespace would raise
``InvalidSchema`` errors.
- Fixed an issue where some URLs without the HTTP or HTTPS schemes would still
have HTTP URL preparation applied to them.
- Fixed an issue where Unicode strings could not be used in basic auth.
- Fixed an issue encountered by some Requests plugins where constructing a
Response object would cause ``Response.content`` to raise an
``AttributeError``.
2.12.1 (2016-11-16)
+++++++++++++++++++

View File

@@ -3,7 +3,7 @@ Requests: HTTP for Humans
.. image:: https://img.shields.io/pypi/v/requests.svg
:target: https://pypi.python.org/pypi/requests
Requests is the only *Non-GMO* HTTP library for Python, safe for human
consumption.
@@ -29,6 +29,10 @@ Behold, the power of Requests:
See `the similar code, sans Requests <https://gist.github.com/973705>`_.
.. image:: http://docs.python-requests.org/en/master/_static/requests-sidebar.png
:target: http://docs.python-requests.org/
Requests allows you to send *organic, grass-fed* HTTP/1.1 requests, without the
need for manual labor. There's no need to manually add query strings to your
URLs, or to form-encode your POST data. Keep-alive and HTTP connection pooling

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 299 KiB

View File

@@ -1,6 +1,6 @@
<p class="logo">
<a href="{{ pathto(master_doc) }}">
<img class="logo" src="{{ pathto('_static/requests-sidebar.png', 1) }}" title="Rezzy the Requests Sea Turtle"/>
<img class="logo" src="{{ pathto('_static/requests-sidebar.png', 1) }}" title="https://kennethreitz.org/tattoos"/>
</a>
</p>
@@ -21,7 +21,7 @@
allowtransparency="true" frameborder="0" scrolling="0" width="200" height="20"></iframe></p>
<p><a href="https://twitter.com/kennethreitz" class="twitter-follow-button" data-show-count="false">Follow @kennethreitz</a> <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script></p>
<p><a href="https://saythanks.io/to/kennethreitz">Say Thanks!</a></p>
<p><a href="http://tinyletter.com/kennethreitz">Join Mailing List</a>.</p>
<h3>Other Projects</h3>

View File

@@ -1,6 +1,6 @@
<p class="logo">
<a href="{{ pathto(master_doc) }}">
<img class="logo" src="{{ pathto('_static/requests-sidebar.png', 1) }}" title="Rezzy the Requests Sea Turtle"/>
<img class="logo" src="{{ pathto('_static/requests-sidebar.png', 1) }}" title="https://kennethreitz.org/tattoos"/>
</a>
</p>
<p>
@@ -19,6 +19,10 @@
<p><a href="http://tinyletter.com/kennethreitz">Join Mailing List</a>.</p>
<hr/>
<p>If you enjoy using this project, <a href="https://saythanks.io/to/kennethreitz">Say Thanks!</a></p>
<p><iframe src="http://ghbtns.com/github-btn.html?user=kennethreitz&type=follow&count=false"
allowtransparency="true" frameborder="0" scrolling="0" width="200" height="20"></iframe></p>

View File

@@ -178,13 +178,14 @@ In general, however, you should use a pattern like this to save what is being
streamed to a file::
with open(filename, 'wb') as fd:
for chunk in r.iter_content(chunk_size):
for chunk in r.iter_content(chunk_size=128):
fd.write(chunk)
Using ``Response.iter_content`` will handle a lot of what you would otherwise
have to handle when using ``Response.raw`` directly. When streaming a
download, the above is the preferred and recommended way to retrieve the
content.
content. Note that ``chunk_size`` can be freely adjusted to a number that
may better fit your use cases.
Custom Headers

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 863 KiB

View File

@@ -41,8 +41,8 @@ is at <http://python-requests.org>.
"""
__title__ = 'requests'
__version__ = '2.12.1'
__build__ = 0x021201
__version__ = '2.12.3'
__build__ = 0x021203
__author__ = 'Kenneth Reitz'
__license__ = 'Apache 2.0'
__copyright__ = 'Copyright 2016 Kenneth Reitz'

View File

@@ -8,7 +8,7 @@ Provides utility functions that are consumed internally by Requests
which depend on extremely few external helpers (such as compat)
"""
from .compat import is_py2, builtin_str
from .compat import is_py2, builtin_str, str
def to_native_string(string, encoding='ascii'):
@@ -25,3 +25,18 @@ def to_native_string(string, encoding='ascii'):
out = string.decode(encoding)
return out
def unicode_is_ascii(u_string):
"""Determine if unicode string only contains ASCII characters.
:param str u_string: unicode string to check. Must be unicode
and not Python 2 `str`.
:rtype: bool
"""
assert isinstance(u_string, str)
try:
u_string.encode('ascii')
return True
except UnicodeEncodeError:
return False

View File

@@ -27,9 +27,15 @@ CONTENT_TYPE_MULTI_PART = 'multipart/form-data'
def _basic_auth_str(username, password):
"""Returns a Basic Auth string."""
if isinstance(username, str):
username = username.encode('latin1')
if isinstance(password, str):
password = password.encode('latin1')
authstr = 'Basic ' + to_native_string(
b64encode(('%s:%s' % (username, password)).encode('latin1')).strip()
b64encode(b':'.join((username, password))).strip()
)
return authstr

View File

@@ -30,7 +30,7 @@ from .packages.urllib3.exceptions import (
from .exceptions import (
HTTPError, MissingSchema, InvalidURL, ChunkedEncodingError,
ContentDecodingError, ConnectionError, StreamConsumedError)
from ._internal_utils import to_native_string
from ._internal_utils import to_native_string, unicode_is_ascii
from .utils import (
guess_filename, get_auth_from_url, requote_uri,
stream_decode_response_unicode, to_key_val_list, parse_header_links,
@@ -343,6 +343,9 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
else:
url = unicode(url) if is_py2 else str(url)
# Remove leading whitespaces from url
url = url.lstrip()
# Don't do any URL preparation for non-HTTP schemes like `mailto`,
# `data` etc to work around exceptions from `url_parse`, which
# handles RFC 3986 only.
@@ -365,11 +368,17 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
if not host:
raise InvalidURL("Invalid URL %r: No host supplied" % url)
# Only want to apply IDNA to the hostname
# In general, we want to try IDNA encoding every hostname, as that
# allows users to automatically get the correct behaviour. However,
# were quite strict about IDNA encoding, so certain valid hostnames
# may fail to encode. On failure, we verify the hostname meets a
# minimum standard of only containing ASCII characters, and not starting
# with a wildcard (*), before allowing the unencoded hostname through.
try:
host = idna.encode(host, uts46=True).decode('utf-8')
except (UnicodeError, idna.IDNAError):
raise InvalidURL('URL has an invalid label.')
if not unicode_is_ascii(host) or host.startswith(u'*'):
raise InvalidURL('URL has an invalid label.')
# Carefully reconstruct the network location
netloc = auth or ''
@@ -766,7 +775,7 @@ class Response(object):
raise RuntimeError(
'The content for this response was already consumed')
if self.status_code == 0:
if self.status_code == 0 or self.raw is None:
self._content = None
else:
self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()

View File

@@ -140,6 +140,11 @@ class TestRequests:
data=u"ööö".encode("utf-8")).prepare()
assert isinstance(request.body, bytes)
def test_whitespaces_are_removed_from_url(self):
# Test for issue #3696
request = requests.Request('GET', ' http://example.com').prepare()
assert request.url == 'http://example.com/'
@pytest.mark.parametrize('scheme', ('http://', 'HTTP://', 'hTTp://', 'HttP://'))
def test_mixed_case_scheme_acceptable(self, httpbin, scheme):
s = requests.Session()
@@ -475,6 +480,20 @@ class TestRequests:
r = s.get(url)
assert r.status_code == 200
@pytest.mark.parametrize(
'username, password', (
('user', 'pass'),
(u'имя'.encode('utf-8'), u'пароль'.encode('utf-8')),
))
def test_set_basicauth(self, httpbin, username, password):
auth = (username, password)
url = httpbin('get')
r = requests.Request('GET', url, auth=auth)
p = r.prepare()
assert p.headers['Authorization'] == _basic_auth_str(username, password)
@pytest.mark.parametrize(
'url, exception', (
# Connecting to an unknown domain should raise a ConnectionError
@@ -1075,6 +1094,10 @@ class TestRequests:
total_seconds = ((td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6)
assert total_seconds > 0.0
def test_empty_response_has_content_none(self):
r = requests.Response()
assert r.content is None
def test_response_is_iterable(self):
r = requests.Response()
io = StringIO.StringIO('abc')
@@ -1568,10 +1591,15 @@ class TestRequests:
self._patch_adapter_gzipped_redirect(s, url)
s.get(url)
def test_basic_auth_str_is_always_native(self):
s = _basic_auth_str("test", "test")
@pytest.mark.parametrize(
'username, password, auth_str', (
('test', 'test', 'Basic dGVzdDp0ZXN0'),
(u'имя'.encode('utf-8'), u'пароль'.encode('utf-8'), 'Basic 0LjQvNGPOtC/0LDRgNC+0LvRjA=='),
))
def test_basic_auth_str_is_always_native(self, username, password, auth_str):
s = _basic_auth_str(username, password)
assert isinstance(s, builtin_str)
assert s == "Basic dGVzdDp0ZXN0"
assert s == auth_str
def test_requests_history_is_saved(self, httpbin):
r = requests.get(httpbin('redirect/5'))
@@ -2093,6 +2121,7 @@ class TestPreparingURLs(object):
(
('http://google.com', 'http://google.com/'),
(u'http://ジェーピーニック.jp', u'http://xn--hckqz9bzb1cyrb.jp/'),
(u'http://xn--n3h.net/', u'http://xn--n3h.net/'),
(
u'http://ジェーピーニック.jp'.encode('utf-8'),
u'http://xn--hckqz9bzb1cyrb.jp/'
@@ -2113,6 +2142,18 @@ class TestPreparingURLs(object):
u'http://Königsgäßchen.de/straße'.encode('utf-8'),
u'http://xn--knigsgchen-b4a3dun.de/stra%C3%9Fe'
),
(
b'http://xn--n3h.net/',
u'http://xn--n3h.net/'
),
(
b'http://[1200:0000:ab00:1234:0000:2552:7777:1313]:12345/',
u'http://[1200:0000:ab00:1234:0000:2552:7777:1313]:12345/'
),
(
u'http://[1200:0000:ab00:1234:0000:2552:7777:1313]:12345/',
u'http://[1200:0000:ab00:1234:0000:2552:7777:1313]:12345/'
)
)
)
def test_preparing_url(self, url, expected):
@@ -2127,9 +2168,81 @@ class TestPreparingURLs(object):
b"http://*",
u"http://*.google.com",
u"http://*",
u"http://☃.net/"
)
)
def test_preparing_bad_url(self, url):
r = requests.Request('GET', url=url)
with pytest.raises(requests.exceptions.InvalidURL):
r.prepare()
@pytest.mark.parametrize(
'input, expected',
(
(
b"http+unix://%2Fvar%2Frun%2Fsocket/path",
u"http+unix://%2fvar%2frun%2fsocket/path",
),
(
u"http+unix://%2Fvar%2Frun%2Fsocket/path",
u"http+unix://%2fvar%2frun%2fsocket/path",
),
(
b"mailto:user@example.org",
u"mailto:user@example.org",
),
(
u"mailto:user@example.org",
u"mailto:user@example.org",
),
(
b"data:SSDimaUgUHl0aG9uIQ==",
u"data:SSDimaUgUHl0aG9uIQ==",
)
)
)
def test_url_mutation(self, input, expected):
"""
This test validates that we correctly exclude some URLs from
preparation, and that we handle others. Specifically, it tests that
any URL whose scheme doesn't begin with "http" is left alone, and
those whose scheme *does* begin with "http" are mutated.
"""
r = requests.Request('GET', url=input)
p = r.prepare()
assert p.url == expected
@pytest.mark.parametrize(
'input, params, expected',
(
(
b"http+unix://%2Fvar%2Frun%2Fsocket/path",
{"key": "value"},
u"http+unix://%2fvar%2frun%2fsocket/path?key=value",
),
(
u"http+unix://%2Fvar%2Frun%2Fsocket/path",
{"key": "value"},
u"http+unix://%2fvar%2frun%2fsocket/path?key=value",
),
(
b"mailto:user@example.org",
{"key": "value"},
u"mailto:user@example.org",
),
(
u"mailto:user@example.org",
{"key": "value"},
u"mailto:user@example.org",
),
)
)
def test_parameters_for_nonstandard_schemes(self, input, params, expected):
"""
Setting paramters for nonstandard schemes is allowed if those schemes
begin with "http", and is forbidden otherwise.
"""
r = requests.Request('GET', url=input, params=params)
p = r.prepare()
assert p.url == expected

View File

@@ -17,6 +17,7 @@ from requests.utils import (
to_key_val_list, to_native_string,
unquote_header_value, unquote_unreserved,
urldefragauth, add_dict_to_cookiejar)
from requests._internal_utils import unicode_is_ascii
from .compat import StringIO, cStringIO
@@ -515,6 +516,7 @@ def test_should_bypass_proxies(url, expected, monkeypatch):
monkeypatch.setenv('NO_PROXY', '192.168.0.0/24,127.0.0.1,localhost.localdomain,172.16.1.1')
assert should_bypass_proxies(url) == expected
@pytest.mark.parametrize(
'cookiejar', (
compat.cookielib.CookieJar(),
@@ -529,3 +531,14 @@ def test_add_dict_to_cookiejar(cookiejar):
cj = add_dict_to_cookiejar(cookiejar, cookiedict)
cookies = dict((cookie.name, cookie.value) for cookie in cj)
assert cookiedict == cookies
@pytest.mark.parametrize(
'value, expected', (
(u'test', True),
(u'æíöû', False),
(u'ジェーピーニック', False),
)
)
def test_unicode_is_ascii(value, expected):
assert unicode_is_ascii(value) is expected