Compare commits

...

99 Commits

Author SHA1 Message Date
Ian Cordasco
ca66267d2c Add release notes for 2.6.2
Closes #2561
2015-04-23 11:29:10 -05:00
Ian Cordasco
73b9b6906d Update urllib3 to 7b82da0fa3a13514d11a863e379e7541d0ec46ef 2015-04-23 11:27:42 -05:00
Ian Cordasco
3880cf1255 Merge pull request #2556 from sigmavirus24/release/2.6.1
Prepare v2.6.1
2015-04-22 17:12:26 -05:00
Ian Cordasco
ae7c28eb8e Update notes for 2.6.1 2015-04-22 16:52:40 -05:00
Ian Cordasco
3e3fc7683c Remove VendorAlias meta_path hook 2015-04-22 16:26:14 -05:00
Cory Benfield
3d339ed7e6 Update urllib3 to 0b744993
(cherry picked from commit df63ee3e13672caa6b3256c6579fa85caefb2729)
2015-04-22 13:16:12 -05:00
Ian Cordasco
cfb9e66b04 Update history and version number for v2.6.1 2015-04-22 09:10:48 -05:00
Ian Cordasco
5fcd843eb2 Update urllib3 to 10b7a0fefa6596f47a9a6afc80f1f4d1ae950b66 2015-04-22 08:17:39 -05:00
Kenneth Reitz
1f0e5775f2 add betamax 2015-04-21 17:18:04 -04:00
Kenneth Reitz
4cfc5bcd96 add @sigmavirus42's blog post 2015-04-21 17:15:51 -04:00
Cory Benfield
b906c04a6f Merge pull request #2553 from sigmavirus24/bug/2552
Simplify PreparedRequest.prepare API
2015-04-21 06:59:55 +01:00
Ian Cordasco
35045e851a Simplify PreparedRequest.prepare API
Do not require that hooks be passed as an empty list to
PreparedRequest.prepare. In the event hooks is None in prepare or
prepare_hooks, use an empty list as a default.

Related to #2552
2015-04-20 20:13:58 -05:00
Kenneth Reitz
16eeee1436 and extensions 2015-04-17 08:52:47 -04:00
Kenneth Reitz
576e18a796 recommended packages and extensions 2015-04-17 08:51:02 -04:00
Kenneth Reitz
d0e64d32ba Merge pull request #2550 from Lukasa/recommended
Recommended packages.
2015-04-17 08:44:38 -04:00
Cory Benfield
a0d9e0bc57 Merge pull request #2504 from pvanderlinden/bug/2503-resolve-redirect-pass-all-arguments
fix resolve redirect to pass all original arguments
2015-04-16 06:57:56 +01:00
Kenneth Reitz
5a799dd0f5 Merge pull request #2546 from Lukasa/crystals
Keepers of the Three Crystals.
2015-04-14 14:03:08 -04:00
Cory Benfield
8cf5e67041 Recommended packages. 2015-04-13 11:39:23 -04:00
Ian Cordasco
a0632d8df0 Minor formatting change 2015-04-10 22:03:26 -05:00
Ian Cordasco
5478dd6271 Merge pull request #2547 from sh1buy/bug_2540
Fix MisssingSchema error message does not handle unicode input correctly #2540
2015-04-10 21:59:13 -05:00
sh1buy
599f834351 fix bug 2540 2015-04-11 03:29:21 +03:00
sh1buy
f02d0f9e79 Fix bug 2540 2015-04-11 01:41:02 +03:00
sh1buy
f89b5a5d90 fix bug 2540 2015-04-11 00:23:07 +03:00
Cory Benfield
0cd9f5855e Keepers of the Three Crystals. 2015-04-10 14:40:52 -04:00
Kenneth Reitz
ccc03b93ef Test 2015-04-10 13:22:14 -04:00
Kenneth Reitz
b0c008c593 Merge pull request #2536 from smiley/master
Document that "PreparedRequest.prepare_cookies" can only be called once
2015-04-06 18:29:17 -04:00
Cory Benfield
a57c87a459 Merge pull request #2535 from sigmavirus24/bug/2530
Fix build version number in metadata
2015-04-06 17:54:22 -04:00
Smiley Barry
e3c7b43fc9 #2532: Documented strange behaviour in "PreparedRequest.prepare_cookies", caused by cookielib. Also documented a workaround if absolutely necessary. 2015-04-06 21:00:51 +03:00
Ian Cordasco
956ec8321a Merge pull request #2427 from luozhaoyu/master
Bug fix: field uri in digest authentication should not be empty when enc...
2015-04-06 10:19:15 -05:00
Cory Benfield
0581f2c7d2 Merge pull request #2533 from sigmavirus24/bug/2465-2
Place VendorAlias first in meta_path
2015-04-06 07:19:15 -04:00
Cory Benfield
1ff9a05181 Merge pull request #2534 from sigmavirus24/bug/2527
Copy a PreparedRequest's CookieJar reliably
2015-04-06 07:15:55 -04:00
Ian Cordasco
36093e69c7 Copy a PreparedRequest's CookieJar reliably
When a PreparedRequests's cookie jar is not a RequestsCookieJar instance, it
will not have a "copy" method. By adding _copy_cookie_jar we can reliably copy
cookie jars so that we have an actual copy instead of the same instance on
different prepared requests.

This also updates the RequestsCookieJar.update logic to create copies of
cookies from the other jar.

Closes #2527
2015-04-05 21:49:52 -05:00
Ian Cordasco
dacf69a16d Fix build version number in metadata
Closes #2530
2015-04-05 21:49:10 -05:00
Ian Cordasco
1b5bfe681b Place VendorAlias first in meta_path
When other libraries or tools add items to the meta_path, we need to preempt
some of their import hooks to be sure modules can be properly found. This also
prevents problems importing built-in modules on Python 2 where it will first
attempt to import something like:

    requests.packages.chardet.sys

By placing our VendorAlias first, the above will fail and then it will fall
back to trying to import sys directly instead.

Closes #2465
2015-04-05 20:48:36 -05:00
Cory Benfield
18e678c1f8 Merge pull request #2531 from benjaminran/issue2062
Issue 2062: Updated custom header precedence info with .netrc example
2015-04-05 23:33:29 +01:00
benjaminran
1b1866934b updated custom header precedence info with .netrc example 2015-04-05 14:23:10 -07:00
Cory Benfield
d294de38c4 Merge pull request #2525 from benjaminran/issue2062
Issue 2062: Added custom header precedence info
2015-04-03 16:57:54 +01:00
benjaminran
898465756a added custom header precedence info 2015-04-03 07:58:42 -07:00
Kenneth Reitz
0ad075c430 Update index.rst 2015-03-31 12:44:50 -04:00
Ian Cordasco
460caf71a4 Merge pull request #2518 from deronnax/shorter_version_extraction
shorter and faster version extraction from __init__.py
2015-03-27 07:49:29 -05:00
Cory Benfield
452ba32edf Merge pull request #2497 from Lukasa/secprocess
Requests security release policy
2015-03-27 11:03:41 +00:00
Paul van der Linden
587eb193dd fix resolve redirect to pass all original arguments 2015-03-26 19:57:16 +00:00
deronnax
1145fe64a5 matching the version only at the begining of lines 2015-03-26 15:53:19 +01:00
deronnax
ce234d53a5 shorter and faster version extraction from __init__.py 2015-03-25 18:21:34 +01:00
Cory Benfield
e95e173b8c Merge pull request #2514 from kennethreitz/revert-2513-master
Revert "Minor Patch TypeError thrown"
2015-03-23 15:13:14 +00:00
Ian Cordasco
b2ce5be9d0 Revert "Minor Patch TypeError thrown" 2015-03-23 10:11:13 -05:00
Cory Benfield
a0f5776f35 Merge pull request #2513 from Montycarlo/master
Minor Patch TypeError thrown
2015-03-23 06:18:48 +00:00
Josh Brown
1b5317ea08 Minor Patch TypeError thrown 2015-03-23 16:01:48 +11:00
Ian Cordasco
8dda20f8e3 Merge pull request #2512 from Lukasa/elapsed
Expand on what 'elapsed' means.
2015-03-22 14:51:17 -05:00
Cory Benfield
54791d1970 Expand on what 'elapsed' means. 2015-03-21 16:27:21 +00:00
Cory Benfield
b7e3370762 'At least' 2015-03-18 21:40:03 +00:00
Cory Benfield
bedd2be0a7 Clarify that we ship patches early. 2015-03-18 21:27:20 +00:00
Cory Benfield
b974cd3741 Describe our new vulnerabilities process. 2015-03-17 20:07:28 +00:00
Cory Benfield
86f9b1616a Merge pull request #2501 from yasoob/master
Added myself to authors.rst
2015-03-16 20:31:09 +00:00
M.Yasoob Ullah Khalid ☺
dfa0a2925f added myself to authors.rst 2015-03-17 01:29:33 +05:00
M.Yasoob Ullah Khalid ☺
81d2d5535a Merge pull request #1 from kennethreitz/master
Only for me
2015-03-17 01:25:05 +05:00
Cory Benfield
cd3f7eb388 Merge pull request #2493 from yasoob/master
made the quickstart more reader friendly
2015-03-15 18:39:54 +00:00
M.Yasoob Ullah Khalid ☺
3711e04f37 edited the useragent string 2015-03-15 22:42:43 +05:00
Cory Benfield
8c6d82a244 Merge pull request #2496 from Lukasa/cve
Update 2.6.0 changelog with CVE number CVE-2015-2296
2015-03-15 11:50:51 +00:00
Cory Benfield
3385c78999 Update 2.6.0 changelog with CVE number. 2015-03-15 11:49:32 +00:00
M.Yasoob Ullah Khalid ☺
6e2f1eb402 made the quickstart more reader friendly. Closes #2418 2015-03-15 01:02:09 +05:00
Ian Cordasco
fa338da717 Merge pull request #2492 from sigmavirus24/release/v2.6.0
Bump version and add release notes for 2.6.0
2015-03-14 11:43:32 -05:00
Ian Cordasco
80a3e87bf3 Bump version and add release notes for 2.6.0 2015-03-14 11:42:38 -05:00
Ian Cordasco
bbbd9de6fd Merge pull request #2472 from scholer/master
Avoid data duplication when creating a Request with str/bytes/bytearray input
2015-03-14 07:43:17 -05:00
Ian Cordasco
e776bb2656 Merge pull request #2489 from Lukasa/cookiebad
Don't label cookies for the target domain.
2015-03-14 07:05:48 -05:00
Cory Benfield
f7c85685a8 Add explanatory comment for cookie change 2015-03-14 11:29:05 +00:00
Cory Benfield
8a2fd7ce6d Merge pull request #2486 from sigmavirus24/bug/2462
Extract version from requests/__init__.py instead of importing requests
2015-03-14 11:20:33 +00:00
Cory Benfield
76f7ce8a24 Merge pull request #2487 from ulope/return_type
Add return type field to entry-point docstrings
2015-03-14 11:19:12 +00:00
Ulrich Petri
573d460aa7 Add return type field to entry-point docstrings
Fixes: #2483
2015-03-14 10:49:32 +01:00
Cory Benfield
3bd8afbff2 Don't ascribe cookies to the target domain. 2015-03-14 08:49:55 +00:00
Ian Cordasco
1acc4992d4 Parse version number out of requests/__init__.py
With the new import machinery in requests/packages/__init__.py people
using `python setup.py test` will not be able to run the tests the first
time on a new environment. The VendorAlias logic breaks the import
machinery and the tests fail. By removing the import of requests in
setup.py, we avoid the issue where sys.meta_path continues to have the
version of VendorAlias from the import in setup.py.

Closes #2462
2015-03-13 21:47:29 -05:00
Cory Benfield
bc746e158c Merge pull request #2485 from sigmavirus24/bug/shazow/urllib3/567
Import urllib3's Retry location from the right place
2015-03-12 06:50:33 +00:00
Ian Cordasco
c4bd6ea150 Import urllib3's Retry location from the right place
Importing from urllib3's top-level location causes the namespace to be
urllib3.util.retry.Retry instead of
requests.packages.urllib3.util.retry.Retry. Without this fix, an using
requests with an un-vendored version of urllib3 will break when urllib3's
retry handling kicks in.

Closes shazow/urllib3#567
2015-03-11 20:52:12 -05:00
Ian Cordasco
9adaae6785 Merge pull request #2482 from sigmavirus24/update-urllib3
Update urllib3 to 43b5b2b452e4344374de7d08ececcca495079b8d
2015-03-11 09:52:11 -05:00
Ian Cordasco
a0790f37b7 Update urllib3 to 43b5b2b452e4344374de7d08ececcca495079b8d 2015-03-10 19:34:34 -05:00
Cory Benfield
14b653ab3c Merge pull request #2478 from plaes/iter-lines
Document Response.iter_lines() deficiencies
2015-03-07 10:03:42 +00:00
Priit Laes
4497a26c37 Document Response.iter_lines() reentrancy issues 2015-03-07 12:00:41 +02:00
Priit Laes
62200cb07e Add testcase to demonstrate r.iter_lines() reentrancy issue 2015-03-07 12:00:37 +02:00
Ian Cordasco
c53aa08cce Merge pull request #2429 from kennethreitz/sigmavirus24/docs/support
Update support documentation to be more accurate
2015-03-04 16:20:33 -06:00
Cory Benfield
bcfcd9f980 Add Lukasa's GPG key fingerprint. 2015-03-04 20:16:25 +00:00
Rasmus Scholer (TimelineX)
ec700a9a13 Avoid duplicating files data when creating a Request with str/bytes/bytearray in the files argument. 30-40% performance improvement. 2015-03-04 10:21:38 -05:00
Ian Cordasco
e7ac8ea0c1 Add PGP Key fingerprints 2015-03-04 08:11:39 -06:00
Ian Cordasco
39e49e5fb9 Merge pull request #2466 from sigmavirus24/bug/2465
Only add VendorAliases for vendored dependencies
2015-03-04 07:49:12 -06:00
Ian Cordasco
61f4faae70 Merge pull request #2468 from scholer/master
Support for bytearray when creating Request with files argument, just like str and bytes.
2015-03-03 14:01:31 -06:00
Rasmus Scholer (TimelineX)
1887f32b17 test_can_send_bytes_bytearray_objects_with_files test now uses string input, not float. 2015-03-03 14:37:39 -05:00
Rasmus Scholer (TimelineX)
326f77d57c Created test case for using bytes and bytearray objects with files argument to Request. 2015-03-03 03:41:00 +01:00
Rasmus Scholer (TimelineX)
11b12c3e07 models.RequestEncodingMixin._encode_files now takes bytearray as fp in addition to the currently supported bytes and str input. 2015-03-03 02:44:52 +01:00
Ian Cordasco
2669f0c0b1 Fix when packages are unvendored
When working these changes back upstream to pip, we realized that the
previous fix wasn't ideal since unvendoring the packages broke the
imports. For example, if urllib3 were unvendored, then the following
would fail:

    from requests.packages import urllib3
2015-02-28 23:04:24 -06:00
Ian Cordasco
9d8a57f2a2 Add a test to ensure the alias does not regress 2015-02-28 20:19:13 -06:00
Ian Cordasco
6ea3f2ada8 Only alias the imports for vendored dependencies
While discussion the issue, Donald Stufft (@dstufft) and I realized the
simplest solution is to simply add an alias per vendored dependency. The
resulting changes are simple and effective. It prevents the issue in
2.5.2 and 2.5.3 where the following would work:

    from requests.packages import webbrowser

This now appropriately raises an ImportError.

Closes #2465
2015-02-28 20:13:46 -06:00
Cory Benfield
461b740db6 Merge pull request #2459 from kennethreitz/release-notes/2.5.3
Update HISTORY and release version for 2.5.3
2015-02-24 16:32:15 +00:00
Ian Cordasco
628474d626 Update HISTORY and release version for 2.5.3 2015-02-24 10:30:17 -06:00
Cory Benfield
de674fc82c Merge pull request #2458 from kennethreitz/revert-2442-certs
Revert "Update certificate bundle."
2015-02-24 16:18:16 +00:00
Ian Cordasco
b58318163c Revert "Update certificate bundle." 2015-02-24 09:44:51 -06:00
Ian Cordasco
e644857877 Fix typo. Use smaller paragraphs. Add CVE list 2015-01-28 20:48:22 -06:00
Ian Cordasco
3a5e2b2f3d Add a missing comma 2015-01-28 08:58:43 -06:00
Ian Cordasco
02f852cc41 Add Cory's twitter account
Added some more detail to the Vulnerability section
2015-01-28 08:58:05 -06:00
Ian Cordasco
ff56e431ad Update support documentation to be more accurate
We were missing instructions to report security vulnerabilities,
and all of the documentation referred to Kenneth as the only
source of support. We were also missing a link to StackOverflow.
2015-01-28 08:16:05 -06:00
Zhaoyu Luo
fb1971778f Bug fix: field uri in digest authentication should not be empty when encounter http redirections 2015-01-25 18:11:22 -06:00
30 changed files with 1173 additions and 877 deletions

View File

@@ -1,14 +1,10 @@
Requests is written and maintained by Kenneth Reitz and
various contributors:
Development Lead
````````````````
- Kenneth Reitz <me@kennethreitz.org> `@kennethreitz <https://github.com/kennethreitz>`_
Core Contributors
`````````````````
Keepers of the Three Crystals
`````````````````````````````
- Kenneth Reitz <me@kennethreitz.org> `@kennethreitz <https://github.com/kennethreitz>`_, Keeper of the Master Crystal.
- Cory Benfield <cory@lukasa.co.uk> `@lukasa <https://github.com/lukasa>`_
- Ian Cordasco <graffatcolmingov@gmail.com> `@sigmavirus24 <https://github.com/sigmavirus24>`_
@@ -159,3 +155,6 @@ Patches and Suggestions
- Syed Suhail Ahmed <ssuhail.ahmed93@gmail.com> (`@syedsuhail <https://github.com/syedsuhail>`_)
- Scott Sadler (`@ssadler <https://github.com/ssadler>`_)
- Arthur Darcet (`@arthurdarcet <https://github.com/arthurdarcet>`_)
- Ulrich Petri (`@ulope <https://github.com/ulope>`_)
- Muhammad Yasoob Ullah Khalid <yasoob.khld@gmail.com> (`@yasoob <https://github.com/yasoob>`_)
- Paul van der Linden (`@pvanderlinden <https://github.com/pvanderlinden>`_)

View File

@@ -3,6 +3,74 @@
Release History
---------------
2.6.2 (2015-04-23)
++++++++++++++++++
**Bugfixes**
- Fix regression where compressed data that was sent as chunked data was not
properly decompressed. (#2561)
2.6.1 (2015-04-22)
++++++++++++++++++
**Bugfixes**
- Remove VendorAlias import machinery introduced in v2.5.2.
- Simplify the PreparedRequest.prepare API: We no longer require the user to
pass an empty list to the hooks keyword argument. (c.f. #2552)
- Resolve redirects now receives and forwards all of the original arguments to
the adapter. (#2503)
- Handle UnicodeDecodeErrors when trying to deal with a unicode URL that
cannot be encoded in ASCII. (#2540)
- Populate the parsed path of the URI field when performing Digest
Authentication. (#2426)
- Copy a PreparedRequest's CookieJar more reliably when it is not an instance
of RequestsCookieJar. (#2527)
2.6.0 (2015-03-14)
++++++++++++++++++
**Bugfixes**
- CVE-2015-2296: Fix handling of cookies on redirect. Previously a cookie
without a host value set would use the hostname for the redirected URL
exposing requests users to session fixation attacks and potentially cookie
stealing. This was disclosed privately by Matthew Daley of
`BugFuzz <https://bugfuzz.com>`_. This affects all versions of requests from
v2.1.0 to v2.5.3 (inclusive on both ends).
- Fix error when requests is an ``install_requires`` dependency and ``python
setup.py test`` is run. (#2462)
- Fix error when urllib3 is unbundled and requests continues to use the
vendored import location.
- Include fixes to ``urllib3``'s header handling.
- Requests' handling of unvendored dependencies is now more restrictive.
**Features and Improvements**
- Support bytearrays when passed as parameters in the ``files`` argument.
(#2468)
- Avoid data duplication when creating a request with ``str``, ``bytes``, or
``bytearray`` input to the ``files`` argument.
2.5.3 (2015-02-24)
++++++++++++++++++
**Bugfixes**
- Revert changes to our vendored certificate bundle. For more context see
(#2455, #2456, and http://bugs.python.org/issue23476)
2.5.2 (2015-02-23)
++++++++++++++++++

View File

@@ -8,6 +8,8 @@ Requests: HTTP for Humans
:target: https://pypi.python.org/pypi/requests
Requests is an Apache2 Licensed HTTP library, written in Python, for human
beings.

View File

@@ -40,8 +40,7 @@
<h3>Useful Links</h3>
<ul>
<li><a href="http://certifi.io/en/latest/">Certifi: Best CA Bundle</a></li>
<li><a href="https://github.com/sigmavirus24/requests-toolbelt">Requests-Toolbelt</a></li>
<li><a href="http://docs.python-requests.org/en/latest/community/recommended/">Recomended Packages and Extensions</a></li>
<p></p>

View File

@@ -30,3 +30,4 @@ Articles & Talks
- `Issac Kelly's 'Consuming Web APIs' talk <http://issackelly.github.com/Consuming-Web-APIs-with-Python-Talk/slides/slides.html>`_
- `Blog post about Requests via Yum <http://arunsag.wordpress.com/2011/08/17/new-package-python-requests-http-for-humans/>`_
- `Russian blog post introducing Requests <http://habrahabr.ru/blogs/python/126262/>`_
- `Sending JSON in Requests <http://www.coglib.com/~icordasc/blog/2014/11/sending-json-in-requests.html>`_

View File

@@ -0,0 +1,57 @@
.. _recommended:
Recommended Packages and Extensions
===================================
Requests has a great variety of powerful and useful third-party extensions.
This page provides an overview of some of the best of them.
Certifi CA Bundle
-----------------
`Certifi`_ is a carefully curated collection of Root Certificates for
validating the trustworthiness of SSL certificates while verifying the
identity of TLS hosts. It has been extracted from the Requests project.
.. _Certifi: http://certifi.io/en/latest/
CacheControl
------------
`CacheControl`_ is an extension that adds a full HTTP cache to Requests. This
makes your web requests substantially more efficient, and should be used
whenever you're making a lot of web requests.
.. _CacheControl: https://cachecontrol.readthedocs.org/en/latest/
Requests-Toolbelt
-----------------
`Requests-Toolbelt`_ is a collection of utilities that some users of Requests may desire,
but do not belong in Requests proper. This library is actively maintained
by members of the Requests core team, and reflects the functionality most
requested by users within the community.
.. _Requests-Toolbelt: http://toolbelt.readthedocs.org/en/latest/index.html
Requests-OAuthlib
-----------------
`requests-oauthlib`_ makes it possible to do the OAuth dance from Requests
automatically. This is useful for the large number of websites that use OAuth
to provide authentication. It also provides a lot of tweaks that handle ways
that specific OAuth providers differ from the standard specifications.
.. _requests-oauthlib: https://requests-oauthlib.readthedocs.org/en/latest/
Betamax
-------
`Betamax`_ records your HTTP interactions so the NSA does not have to.
A VCR imitation designed only for Python-Requests.
.. _betamax: https://github.com/sigmavirus24/betamax

View File

@@ -5,12 +5,21 @@ Support
If you have questions or issues about Requests, there are several options:
StackOverflow
-------------
If your question does not contain sensitive (possibly proprietary)
information or can be properly anonymized, please ask a question on
`StackOverflow <https://stackoverflow.com/questions/tagged/python-requests>`_
and use the tag ``python-requests``.
Send a Tweet
------------
If your question is less than 140 characters, feel free to send a tweet to
`@kennethreitz <http://twitter.com/kennethreitz>`_.
`@kennethreitz <https://twitter.com/kennethreitz>`_,
`@sigmavirus24 <https://twitter.com/sigmavirus24>`_, or
`@lukasaoz <https://twitter.com/lukasaoz>`_.
File an Issue
-------------
@@ -34,4 +43,9 @@ IRC
The official Freenode channel for Requests is
`#python-requests <irc://irc.freenode.net/python-requests>`_
I'm also available as **kennethreitz** on Freenode.
The core developers of requests are on IRC throughout the day.
You can find them in ``#python-requests`` as:
- kennethreitz
- lukasa
- sigmavirus24

View File

@@ -0,0 +1,105 @@
Vulnerability Disclosure
========================
If you think you have found a potential security vulnerability in requests,
please email `sigmavirus24 <mailto:graffatcolmingov@gmail.com>`_ and
`Lukasa <mailto:cory@lukasa.co.uk>`_ directly. **Do not file a public issue.**
Our PGP Key fingerprints are:
- 0161 BB7E B208 B5E0 4FDC 9F81 D9DA 0A04 9113 F853 (@sigmavirus24)
- 90DC AE40 FEA7 4B14 9B70 662D F25F 2144 EEC1 373D (@lukasa)
If English is not your first language, please try to describe the problem and
its impact to the best of your ability. For greater detail, please use your
native language and we will try our best to translate it using online services.
Please also include the code you used to find the problem and the shortest
amount of code necessary to reproduce it.
Please do not disclose this to anyone else. We will retrieve a CVE identifier
if necessary and give you full credit under whatever name or alias you provide.
We will only request an identifier when we have a fix and can publish it in a
release.
We will respect your privacy and will only publicize your involvement if you
grant us permission.
Process
-------
This following information discusses the process the requests project follows
in response to vulnerability disclosures. If you are disclosing a
vulnerability, this section of the documentation lets you know how we will
respond to your disclosure.
Timeline
~~~~~~~~
When you report an issue, one of the project members will respond to you within
two days *at the outside*. In most cases responses will be faster, usually
within 12 hours. This initial response will at the very least confirm receipt
of the report.
If we were able to rapidly reproduce the issue, the initial response will also
contain confirmation of the issue. If we are not, we will often ask for more
information about the reproduction scenario.
Our goal is to have a fix for any vulnerability released within two weeks of
the initial disclosure. This may potentially involve shipping an interim
release that simply disables function while a more mature fix can be prepared,
but will in the vast majority of cases mean shipping a complete release as soon
as possible.
Throughout the fix process we will keep you up to speed with how the fix is
progressing. Once the fix is prepared, we will notify you that we believe we
have a fix. Often we will ask you to confirm the fix resolves the problem in
your environment, especially if we are not confident of our reproduction
scenario.
At this point, we will prepare for the release. We will obtain a CVE number
if one is required, providing you with full credit for the discovery. We will
also decide on a planned release date, and let you know when it is. This
release date will *always* be on a weekday.
At this point we will reach out to our major downstream packagers to notify
them of an impending security-related patch so they can make arrangements. In
addition, these packagers will be provided with the intended patch ahead of
time, to ensure that they are able to promptly release their downstream
packages. Currently the list of people we actively contact *ahead of a public
release* is:
- Ralph Bean, Red Hat (@ralphbean)
- Daniele Tricoli, Debian (@eriol)
We will notify these individuals at least a week ahead of our planned release
date to ensure that they have sufficient time to prepare. If you believe you
should be on this list, please let one of the maintainers know at one of the
email addresses at the top of this article.
On release day, we will push the patch to our public repository, along with an
updated changelog that describes the issue and credits you. We will then issue
a PyPI release containing the patch.
At this point, we will publicise the release. This will involve mails to
mailing lists, Tweets, and all other communication mechanisms available to the
core team.
We will also explicitly mention which commits contain the fix to make it easier
for other distributors and users to easily patch their own versions of requests
if upgrading is not an option.
Previous CVEs
-------------
- Fixed in 2.6.0
- `CVE 2015-2296 <http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2015-2296>`_,
reported by Matthew Daley of `BugFuzz <https://bugfuzz.com/>`_.
- Fixed in 2.3.0
- `CVE 2014-1829 <http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2014-1829>`_
- `CVE 2014-1830 <http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2014-1830>`_

View File

@@ -48,7 +48,7 @@ Testimonials
Her Majesty's Government, Amazon, Google, Twilio, Runscope, Mozilla, Heroku,
PayPal, NPR, Obama for America, Transifex, Native Instruments, The Washington
Post, Twitter, SoundCloud, Kippt, Readability, Sony, and Federal US Institutions that prefer to be unnamed
use Requests internally. It has been downloaded over 23,000,000 times from PyPI.
use Requests internally. It has been downloaded over 40,000,000 times from PyPI.
**Armin Ronacher**
Requests is the perfect example how beautiful an API can be with the
@@ -114,8 +114,10 @@ Requests ecosystem and community.
:maxdepth: 1
community/faq
community/recommended
community/out-there.rst
community/support
community/vulnerabilities
community/updates
API Documentation

View File

@@ -399,6 +399,19 @@ set ``stream`` to ``True`` and iterate over the response with
if line:
print(json.loads(line))
.. warning::
:class:`~requests.Response.iter_lines()` is not reentrant safe.
Calling this method multiple times causes some of the received data
being lost. In case you need to call it from multiple places, use
the resulting iterator object instead::
lines = r.iter_lines()
# Save the first line for later or just skip it
first_line = next(lines)
for line in lines:
print(line)
.. _proxies:
Proxies

View File

@@ -186,10 +186,18 @@ For example, we didn't specify our content-type in the previous example::
>>> import json
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}
>>> headers = {'content-type': 'application/json'}
>>> headers = {'user-agent': 'my-app/0.0.1'}
>>> r = requests.post(url, data=json.dumps(payload), headers=headers)
>>> r = requests.get(url, headers=headers)
Note: Custom headers are given less precedence than more specific sources of information. For instance:
* Authorization headers will be overridden if credentials are passed via the ``auth`` parameter or are specified in a ``.netrc`` accessible in the environment.
* Authorization headers will be removed if you get redirected off-host.
* Proxy-Authorization headers will be overridden by proxy credentials provided in the URL.
* Content-Length headers will be overridden when we can determine the length of the content.
Furthermore, Requests does not change its behavior at all based on which custom headers are specified. The headers are simply passed on into the final request.
More complicated POST requests

View File

@@ -42,8 +42,8 @@ is at <http://python-requests.org>.
"""
__title__ = 'requests'
__version__ = '2.5.2'
__build__ = 0x020502
__version__ = '2.6.2'
__build__ = 0x020602
__author__ = 'Kenneth Reitz'
__license__ = 'Apache 2.0'
__copyright__ = 'Copyright 2015 Kenneth Reitz'

View File

@@ -11,10 +11,10 @@ and maintain connections.
import socket
from .models import Response
from .packages.urllib3 import Retry
from .packages.urllib3.poolmanager import PoolManager, proxy_from_url
from .packages.urllib3.response import HTTPResponse
from .packages.urllib3.util import Timeout as TimeoutSauce
from .packages.urllib3.util.retry import Retry
from .compat import urlparse, basestring
from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers,
prepend_scheme_if_needed, get_auth_from_url, urldefragauth)

View File

@@ -16,7 +16,6 @@ from . import sessions
def request(method, url, **kwargs):
"""Constructs and sends a :class:`Request <Request>`.
Returns :class:`Response <Response>` object.
:param method: method for the new :class:`Request` object.
:param url: URL for the new :class:`Request` object.
@@ -37,6 +36,8 @@ def request(method, url, **kwargs):
:param verify: (optional) if ``True``, the SSL cert will be verified. A CA_BUNDLE path can also be provided.
:param stream: (optional) if ``False``, the response content will be immediately downloaded.
:param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
:return: :class:`Response <Response>` object
:rtype: requests.Response
Usage::
@@ -55,10 +56,12 @@ def request(method, url, **kwargs):
def get(url, **kwargs):
"""Sends a GET request. Returns :class:`Response` object.
"""Sends a GET request.
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response
"""
kwargs.setdefault('allow_redirects', True)
@@ -66,10 +69,12 @@ def get(url, **kwargs):
def options(url, **kwargs):
"""Sends a OPTIONS request. Returns :class:`Response` object.
"""Sends a OPTIONS request.
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response
"""
kwargs.setdefault('allow_redirects', True)
@@ -77,10 +82,12 @@ def options(url, **kwargs):
def head(url, **kwargs):
"""Sends a HEAD request. Returns :class:`Response` object.
"""Sends a HEAD request.
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response
"""
kwargs.setdefault('allow_redirects', False)
@@ -88,44 +95,52 @@ def head(url, **kwargs):
def post(url, data=None, json=None, **kwargs):
"""Sends a POST request. Returns :class:`Response` object.
"""Sends a POST request.
:param url: URL for the new :class:`Request` object.
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
:param json: (optional) json data to send in the body of the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response
"""
return request('post', url, data=data, json=json, **kwargs)
def put(url, data=None, **kwargs):
"""Sends a PUT request. Returns :class:`Response` object.
"""Sends a PUT request.
:param url: URL for the new :class:`Request` object.
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response
"""
return request('put', url, data=data, **kwargs)
def patch(url, data=None, **kwargs):
"""Sends a PATCH request. Returns :class:`Response` object.
"""Sends a PATCH request.
:param url: URL for the new :class:`Request` object.
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response
"""
return request('patch', url, data=data, **kwargs)
def delete(url, **kwargs):
"""Sends a DELETE request. Returns :class:`Response` object.
"""Sends a DELETE request.
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response
"""
return request('delete', url, **kwargs)

View File

@@ -103,7 +103,8 @@ class HTTPDigestAuth(AuthBase):
# XXX not implemented yet
entdig = None
p_parsed = urlparse(url)
path = p_parsed.path
#: path is request-uri defined in RFC 2616 which should not be empty
path = p_parsed.path or "/"
if p_parsed.query:
path += '?' + p_parsed.query

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@ Compatibility code to be able to use `cookielib.CookieJar` with requests.
requests.utils imports from here, so be careful with imports.
"""
import copy
import time
import collections
from .compat import cookielib, urlparse, urlunparse, Morsel
@@ -302,7 +303,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
"""Updates this jar with cookies from another CookieJar or dict-like"""
if isinstance(other, cookielib.CookieJar):
for cookie in other:
self.set_cookie(cookie)
self.set_cookie(copy.copy(cookie))
else:
super(RequestsCookieJar, self).update(other)
@@ -359,6 +360,21 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
return new_cj
def _copy_cookie_jar(jar):
if jar is None:
return None
if hasattr(jar, 'copy'):
# We're dealing with an instane of RequestsCookieJar
return jar.copy()
# We're dealing with a generic CookieJar instance
new_jar = copy.copy(jar)
new_jar.clear()
for cookie in jar:
new_jar.set_cookie(copy.copy(cookie))
return new_jar
def create_cookie(name, value, **kwargs):
"""Make a cookie from underspecified parameters.

View File

@@ -15,7 +15,7 @@ from .hooks import default_hooks
from .structures import CaseInsensitiveDict
from .auth import HTTPBasicAuth
from .cookies import cookiejar_from_dict, get_cookie_header
from .cookies import cookiejar_from_dict, get_cookie_header, _copy_cookie_jar
from .packages.urllib3.fields import RequestField
from .packages.urllib3.filepost import encode_multipart_formdata
from .packages.urllib3.util import parse_url
@@ -143,12 +143,13 @@ class RequestEncodingMixin(object):
else:
fn = guess_filename(v) or k
fp = v
if isinstance(fp, str):
fp = StringIO(fp)
if isinstance(fp, bytes):
fp = BytesIO(fp)
rf = RequestField(name=k, data=fp.read(),
if isinstance(fp, (str, bytes, bytearray)):
fdata = fp
else:
fdata = fp.read()
rf = RequestField(name=k, data=fdata,
filename=fn, headers=fh)
rf.make_multipart(content_type=ft)
new_fields.append(rf)
@@ -319,7 +320,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
p.method = self.method
p.url = self.url
p.headers = self.headers.copy() if self.headers is not None else None
p._cookies = self._cookies.copy() if self._cookies is not None else None
p._cookies = _copy_cookie_jar(self._cookies)
p.body = self.body
p.hooks = self.hooks
return p
@@ -357,7 +358,8 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
if not scheme:
raise MissingSchema("Invalid URL {0!r}: No schema supplied. "
"Perhaps you meant http://{0}?".format(url))
"Perhaps you meant http://{0}?".format(
to_native_string(url, 'utf8')))
if not host:
raise InvalidURL("Invalid URL %r: No host supplied" % url)
@@ -500,7 +502,15 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
self.prepare_content_length(self.body)
def prepare_cookies(self, cookies):
"""Prepares the given HTTP cookie data."""
"""Prepares the given HTTP cookie data.
This function eventually generates a ``Cookie`` header from the
given cookies using cookielib. Due to cookielib's design, the header
will not be regenerated if it already exists, meaning this function
can only be called once for the life of the
:class:`PreparedRequest <PreparedRequest>` object. Any subsequent calls
to ``prepare_cookies`` will have no actual effect, unless the "Cookie"
header is removed beforehand."""
if isinstance(cookies, cookielib.CookieJar):
self._cookies = cookies
@@ -513,6 +523,10 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
def prepare_hooks(self, hooks):
"""Prepares the given hooks."""
# hooks can be passed as None to the prepare method and to this
# method. To prevent iterating over None, simply use an empty list
# if hooks is False-y
hooks = hooks or []
for event in hooks:
self.register_hook(event, hooks[event])
@@ -572,7 +586,11 @@ class Response(object):
self.cookies = cookiejar_from_dict({})
#: The amount of time elapsed between sending the request
#: and the arrival of the response (as a timedelta)
#: and the arrival of the response (as a timedelta).
#: This property specifically measures the time taken between sending
#: the first byte of the request and finishing parsing the headers. It
#: is therefore unaffected by consuming the response content or the
#: value of the ``stream`` keyword argument.
self.elapsed = datetime.timedelta(0)
#: The :class:`PreparedRequest <PreparedRequest>` object to which this
@@ -688,6 +706,8 @@ class Response(object):
"""Iterates over the response data, one line at a time. When
stream=True is set on the request, this avoids reading the
content at once into memory for large responses.
.. note:: This method is not reentrant safe.
"""
pending = None

View File

@@ -1,95 +1,3 @@
"""
Copyright (c) Donald Stufft, pip, and individual contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import absolute_import
import sys
class VendorAlias(object):
def __init__(self):
self._vendor_name = __name__
self._vendor_pkg = self._vendor_name + "."
def find_module(self, fullname, path=None):
if fullname.startswith(self._vendor_pkg):
return self
def load_module(self, name):
# Ensure that this only works for the vendored name
if not name.startswith(self._vendor_pkg):
raise ImportError(
"Cannot import %s, must be a subpackage of '%s'." % (
name, self._vendor_name,
)
)
# Check to see if we already have this item in sys.modules, if we do
# then simply return that.
if name in sys.modules:
return sys.modules[name]
# Check to see if we can import the vendor name
try:
# We do this dance here because we want to try and import this
# module without hitting a recursion error because of a bunch of
# VendorAlias instances on sys.meta_path
real_meta_path = sys.meta_path[:]
try:
sys.meta_path = [
m for m in sys.meta_path
if not isinstance(m, VendorAlias)
]
__import__(name)
module = sys.modules[name]
finally:
# Re-add any additions to sys.meta_path that were made while
# during the import we just did, otherwise things like
# requests.packages.urllib3.poolmanager will fail.
for m in sys.meta_path:
if m not in real_meta_path:
real_meta_path.append(m)
# Restore sys.meta_path with any new items.
sys.meta_path = real_meta_path
except ImportError:
# We can't import the vendor name, so we'll try to import the
# "real" name.
real_name = name[len(self._vendor_pkg):]
try:
__import__(real_name)
module = sys.modules[real_name]
except ImportError:
raise ImportError("No module named '%s'" % (name,))
# If we've gotten here we've found the module we're looking for, either
# as part of our vendored package, or as the real name, so we'll add
# it to sys.modules as the vendored name so that we don't have to do
# the lookup again.
sys.modules[name] = module
# Finally, return the loaded module
return module
sys.meta_path.append(VendorAlias())
from . import urllib3

View File

@@ -4,7 +4,7 @@ urllib3 - Thread-safe connection pooling and re-using.
__author__ = 'Andrey Petrov (andrey.petrov@shazow.net)'
__license__ = 'MIT'
__version__ = 'dev'
__version__ = '1.10.3'
from .connectionpool import (
@@ -55,9 +55,11 @@ def add_stderr_logger(level=logging.DEBUG):
del NullHandler
# Set security warning to always go off by default.
import warnings
# SecurityWarning's always go off by default.
warnings.simplefilter('always', exceptions.SecurityWarning)
# InsecurePlatformWarning's don't vary between requests, so we keep it default.
warnings.simplefilter('default', exceptions.InsecurePlatformWarning)
def disable_warnings(category=exceptions.HTTPWarning):
"""

View File

@@ -20,8 +20,6 @@ from .packages.six import iterkeys, itervalues, PY3
__all__ = ['RecentlyUsedContainer', 'HTTPHeaderDict']
MULTIPLE_HEADERS_ALLOWED = frozenset(['cookie', 'set-cookie', 'set-cookie2'])
_Null = object()
@@ -143,7 +141,10 @@ class HTTPHeaderDict(dict):
def __init__(self, headers=None, **kwargs):
dict.__init__(self)
if headers is not None:
self.extend(headers)
if isinstance(headers, HTTPHeaderDict):
self._copy_from(headers)
else:
self.extend(headers)
if kwargs:
self.extend(kwargs)
@@ -223,26 +224,23 @@ class HTTPHeaderDict(dict):
vals.append(val)
else:
# vals should be a tuple then, i.e. only one item so far
if key_lower in MULTIPLE_HEADERS_ALLOWED:
# Need to convert the tuple to list for further extension
_dict_setitem(self, key_lower, [vals[0], vals[1], val])
else:
_dict_setitem(self, key_lower, new_vals)
# Need to convert the tuple to list for further extension
_dict_setitem(self, key_lower, [vals[0], vals[1], val])
def extend(*args, **kwargs):
def extend(self, *args, **kwargs):
"""Generic import function for any type of header-like object.
Adapted version of MutableMapping.update in order to insert items
with self.add instead of self.__setitem__
"""
if len(args) > 2:
raise TypeError("update() takes at most 2 positional "
if len(args) > 1:
raise TypeError("extend() takes at most 1 positional "
"arguments ({} given)".format(len(args)))
elif not args:
raise TypeError("update() takes at least 1 argument (0 given)")
self = args[0]
other = args[1] if len(args) >= 2 else ()
other = args[0] if len(args) >= 1 else ()
if isinstance(other, Mapping):
if isinstance(other, HTTPHeaderDict):
for key, val in other.iteritems():
self.add(key, val)
elif isinstance(other, Mapping):
for key in other:
self.add(key, other[key])
elif hasattr(other, "keys"):
@@ -276,14 +274,17 @@ class HTTPHeaderDict(dict):
def __repr__(self):
return "%s(%s)" % (type(self).__name__, dict(self.itermerged()))
def copy(self):
clone = type(self)()
for key in self:
val = _dict_getitem(self, key)
def _copy_from(self, other):
for key in other:
val = _dict_getitem(other, key)
if isinstance(val, list):
# Don't need to convert tuples
val = list(val)
_dict_setitem(clone, key, val)
_dict_setitem(self, key, val)
def copy(self):
clone = type(self)()
clone._copy_from(self)
return clone
def iteritems(self):
@@ -303,17 +304,20 @@ class HTTPHeaderDict(dict):
return list(self.iteritems())
@classmethod
def from_httplib(cls, message, duplicates=('set-cookie',)): # Python 2
def from_httplib(cls, message): # Python 2
"""Read headers from a Python 2 httplib message object."""
ret = cls(message.items())
# ret now contains only the last header line for each duplicate.
# Importing with all duplicates would be nice, but this would
# mean to repeat most of the raw parsing already done, when the
# message object was created. Extracting only the headers of interest
# separately, the cookies, should be faster and requires less
# extra code.
for key in duplicates:
ret.discard(key)
for val in message.getheaders(key):
ret.add(key, val)
return ret
# python2.7 does not expose a proper API for exporting multiheaders
# efficiently. This function re-reads raw lines from the message
# object and extracts the multiheaders properly.
headers = []
for line in message.headers:
if line.startswith((' ', '\t')):
key, value = headers[-1]
headers[-1] = (key, value + '\r\n' + line.rstrip())
continue
key, value = line.split(':', 1)
headers.append((key, value.strip()))
return cls(headers)

View File

@@ -260,3 +260,5 @@ if ssl:
# Make a copy for testing.
UnverifiedHTTPSConnection = HTTPSConnection
HTTPSConnection = VerifiedHTTPSConnection
else:
HTTPSConnection = DummyConnection

View File

@@ -735,7 +735,6 @@ class HTTPSConnectionPool(HTTPConnectionPool):
% (self.num_connections, self.host))
if not self.ConnectionCls or self.ConnectionCls is DummyConnection:
# Platform-specific: Python without ssl
raise SSLError("Can't connect to HTTPS URL because the SSL "
"module is not available.")

View File

@@ -38,8 +38,6 @@ Module Variables
----------------
:var DEFAULT_SSL_CIPHER_LIST: The list of supported SSL/TLS cipher suites.
Default: ``ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:
ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS``
.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication
.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit)
@@ -85,22 +83,7 @@ _openssl_verify = {
+ OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
}
# A secure default.
# Sources for more information on TLS ciphers:
#
# - https://wiki.mozilla.org/Security/Server_Side_TLS
# - https://www.ssllabs.com/projects/best-practices/index.html
# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
#
# The general intent is:
# - Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE),
# - prefer ECDHE over DHE for better performance,
# - prefer any AES-GCM over any AES-CBC for better performance and security,
# - use 3DES as fallback which is secure but slow,
# - disable NULL authentication, MD5 MACs and DSS for security reasons.
DEFAULT_SSL_CIPHER_LIST = "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:" + \
"ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:" + \
"!aNULL:!MD5:!DSS"
DEFAULT_SSL_CIPHER_LIST = util.ssl_.DEFAULT_CIPHERS
orig_util_HAS_SNI = util.HAS_SNI
@@ -299,7 +282,9 @@ def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
try:
cnx.do_handshake()
except OpenSSL.SSL.WantReadError:
select.select([sock], [], [])
rd, _, _ = select.select([sock], [], [], sock.gettimeout())
if not rd:
raise timeout('select timed out')
continue
except OpenSSL.SSL.Error as e:
raise ssl.SSLError('bad handshake', e)

View File

@@ -157,3 +157,13 @@ class InsecureRequestWarning(SecurityWarning):
class SystemTimeWarning(SecurityWarning):
"Warned when system time is suspected to be wrong"
pass
class InsecurePlatformWarning(SecurityWarning):
"Warned when certain SSL configuration is not available on a platform."
pass
class ResponseNotChunked(ProtocolError, ValueError):
"Response needs to be chunked in order to read it as chunks."
pass

View File

@@ -1,9 +1,15 @@
try:
import http.client as httplib
except ImportError:
import httplib
import zlib
import io
from socket import timeout as SocketTimeout
from ._collections import HTTPHeaderDict
from .exceptions import ProtocolError, DecodeError, ReadTimeoutError
from .exceptions import (
ProtocolError, DecodeError, ReadTimeoutError, ResponseNotChunked
)
from .packages.six import string_types as basestring, binary_type, PY3
from .connection import HTTPException, BaseSSLError
from .util.response import is_fp_closed
@@ -117,8 +123,17 @@ class HTTPResponse(io.IOBase):
if hasattr(body, 'read'):
self._fp = body
if preload_content and not self._body:
self._body = self.read(decode_content=decode_content)
# Are we using the chunked-style of transfer encoding?
self.chunked = False
self.chunk_left = None
tr_enc = self.headers.get('transfer-encoding', '')
if tr_enc.lower() == "chunked":
self.chunked = True
# We certainly don't want to preload content when the response is chunked.
if not self.chunked:
if preload_content and not self._body:
self._body = self.read(decode_content=decode_content)
def get_redirect_location(self):
"""
@@ -157,6 +172,36 @@ class HTTPResponse(io.IOBase):
"""
return self._fp_bytes_read
def _init_decoder(self):
"""
Set-up the _decoder attribute if necessar.
"""
# Note: content-encoding value should be case-insensitive, per RFC 7230
# Section 3.2
content_encoding = self.headers.get('content-encoding', '').lower()
if self._decoder is None:
if content_encoding in self.CONTENT_DECODERS:
self._decoder = _get_decoder(content_encoding)
def _decode(self, data, decode_content, flush_decoder):
"""
Decode the data passed in and potentially flush the decoder.
"""
try:
if decode_content and self._decoder:
data = self._decoder.decompress(data)
except (IOError, zlib.error) as e:
content_encoding = self.headers.get('content-encoding', '').lower()
raise DecodeError(
"Received response with content-encoding: %s, but "
"failed to decode it." % content_encoding, e)
if flush_decoder and decode_content and self._decoder:
buf = self._decoder.decompress(binary_type())
data += buf + self._decoder.flush()
return data
def read(self, amt=None, decode_content=None, cache_content=False):
"""
Similar to :meth:`httplib.HTTPResponse.read`, but with two additional
@@ -178,12 +223,7 @@ class HTTPResponse(io.IOBase):
after having ``.read()`` the file object. (Overridden if ``amt`` is
set.)
"""
# Note: content-encoding value should be case-insensitive, per RFC 7230
# Section 3.2
content_encoding = self.headers.get('content-encoding', '').lower()
if self._decoder is None:
if content_encoding in self.CONTENT_DECODERS:
self._decoder = _get_decoder(content_encoding)
self._init_decoder()
if decode_content is None:
decode_content = self.decode_content
@@ -232,17 +272,7 @@ class HTTPResponse(io.IOBase):
self._fp_bytes_read += len(data)
try:
if decode_content and self._decoder:
data = self._decoder.decompress(data)
except (IOError, zlib.error) as e:
raise DecodeError(
"Received response with content-encoding: %s, but "
"failed to decode it." % content_encoding, e)
if flush_decoder and decode_content and self._decoder:
buf = self._decoder.decompress(binary_type())
data += buf + self._decoder.flush()
data = self._decode(data, decode_content, flush_decoder)
if cache_content:
self._body = data
@@ -269,11 +299,16 @@ class HTTPResponse(io.IOBase):
If True, will attempt to decode the body based on the
'content-encoding' header.
"""
while not is_fp_closed(self._fp):
data = self.read(amt=amt, decode_content=decode_content)
self._init_decoder()
if self.chunked:
for line in self.read_chunked(amt):
yield self._decode(line, decode_content, True)
else:
while not is_fp_closed(self._fp):
data = self.read(amt=amt, decode_content=decode_content)
if data:
yield data
if data:
yield data
@classmethod
def from_httplib(ResponseCls, r, **response_kw):
@@ -351,3 +386,59 @@ class HTTPResponse(io.IOBase):
else:
b[:len(temp)] = temp
return len(temp)
def read_chunked(self, amt=None):
# FIXME: Rewrite this method and make it a class with
# a better structured logic.
if not self.chunked:
raise ResponseNotChunked("Response is not chunked. "
"Header 'transfer-encoding: chunked' is missing.")
while True:
# First, we'll figure out length of a chunk and then
# we'll try to read it from socket.
if self.chunk_left is None:
line = self._fp.fp.readline()
line = line.decode()
# See RFC 7230: Chunked Transfer Coding.
i = line.find(';')
if i >= 0:
line = line[:i] # Strip chunk-extensions.
try:
self.chunk_left = int(line, 16)
except ValueError:
# Invalid chunked protocol response, abort.
self.close()
raise httplib.IncompleteRead(''.join(line))
if self.chunk_left == 0:
break
if amt is None:
chunk = self._fp._safe_read(self.chunk_left)
yield chunk
self._fp._safe_read(2) # Toss the CRLF at the end of the chunk.
self.chunk_left = None
elif amt < self.chunk_left:
value = self._fp._safe_read(amt)
self.chunk_left = self.chunk_left - amt
yield value
elif amt == self.chunk_left:
value = self._fp._safe_read(amt)
self._fp._safe_read(2) # Toss the CRLF at the end of the chunk.
self.chunk_left = None
yield value
else: # amt > self.chunk_left
yield self._fp._safe_read(self.chunk_left)
self._fp._safe_read(2) # Toss the CRLF at the end of the chunk.
self.chunk_left = None
# Chunk content ends with \r\n: discard it.
while True:
line = self._fp.fp.readline()
if not line:
# Some sites may not end with '\r\n'.
break
if line == b'\r\n':
break
# We read everything; close the "file".
self.release_conn()

View File

@@ -1,7 +1,7 @@
from binascii import hexlify, unhexlify
from hashlib import md5, sha1, sha256
from ..exceptions import SSLError
from ..exceptions import SSLError, InsecurePlatformWarning
SSLContext = None
@@ -9,9 +9,10 @@ HAS_SNI = False
create_default_context = None
import errno
import ssl
import warnings
try: # Test for SSL features
import ssl
from ssl import wrap_socket, CERT_NONE, PROTOCOL_SSLv23
from ssl import HAS_SNI # Has SNI?
except ImportError:
@@ -24,14 +25,24 @@ except ImportError:
OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000
OP_NO_COMPRESSION = 0x20000
try:
from ssl import _DEFAULT_CIPHERS
except ImportError:
_DEFAULT_CIPHERS = (
'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:'
'!eNULL:!MD5'
)
# A secure default.
# Sources for more information on TLS ciphers:
#
# - https://wiki.mozilla.org/Security/Server_Side_TLS
# - https://www.ssllabs.com/projects/best-practices/index.html
# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
#
# The general intent is:
# - Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE),
# - prefer ECDHE over DHE for better performance,
# - prefer any AES-GCM over any AES-CBC for better performance and security,
# - use 3DES as fallback which is secure but slow,
# - disable NULL authentication, MD5 MACs and DSS for security reasons.
DEFAULT_CIPHERS = (
'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:'
'!eNULL:!MD5'
)
try:
from ssl import SSLContext # Modern SSL?
@@ -39,7 +50,8 @@ except ImportError:
import sys
class SSLContext(object): # Platform-specific: Python 2 & 3.1
supports_set_ciphers = sys.version_info >= (2, 7)
supports_set_ciphers = ((2, 7) <= sys.version_info < (3,) or
(3, 2) <= sys.version_info)
def __init__(self, protocol_version):
self.protocol = protocol_version
@@ -69,6 +81,14 @@ except ImportError:
self.ciphers = cipher_suite
def wrap_socket(self, socket, server_hostname=None):
warnings.warn(
'A true SSLContext object is not available. This prevents '
'urllib3 from configuring SSL appropriately and may cause '
'certain SSL connections to fail. For more information, see '
'https://urllib3.readthedocs.org/en/latest/security.html'
'#insecureplatformwarning.',
InsecurePlatformWarning
)
kwargs = {
'keyfile': self.keyfile,
'certfile': self.certfile,
@@ -158,7 +178,7 @@ def resolve_ssl_version(candidate):
return candidate
def create_urllib3_context(ssl_version=None, cert_reqs=ssl.CERT_REQUIRED,
def create_urllib3_context(ssl_version=None, cert_reqs=None,
options=None, ciphers=None):
"""All arguments have the same meaning as ``ssl_wrap_socket``.
@@ -195,6 +215,9 @@ def create_urllib3_context(ssl_version=None, cert_reqs=ssl.CERT_REQUIRED,
"""
context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23)
# Setting the default here, as we may have no ssl module on import
cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs
if options is None:
options = 0
# SSLv2 is easily broken and is considered harmful and dangerous
@@ -208,7 +231,7 @@ def create_urllib3_context(ssl_version=None, cert_reqs=ssl.CERT_REQUIRED,
context.options |= options
if getattr(context, 'supports_set_ciphers', True): # Platform-specific: Python 2.6
context.set_ciphers(ciphers or _DEFAULT_CIPHERS)
context.set_ciphers(ciphers or DEFAULT_CIPHERS)
context.verify_mode = cert_reqs
if getattr(context, 'check_hostname', None) is not None: # Platform-specific: Python 3.2

View File

@@ -90,7 +90,7 @@ def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict):
class SessionRedirectMixin(object):
def resolve_redirects(self, resp, req, stream=False, timeout=None,
verify=True, cert=None, proxies=None):
verify=True, cert=None, proxies=None, **adapter_kwargs):
"""Receives a Response. Returns a generator of Responses."""
i = 0
@@ -171,7 +171,10 @@ class SessionRedirectMixin(object):
except KeyError:
pass
extract_cookies_to_jar(prepared_request._cookies, prepared_request, resp.raw)
# Extract any cookies sent on the response to the cookiejar
# in the new request. Because we've mutated our copied prepared
# request, use the old one that we haven't yet touched.
extract_cookies_to_jar(prepared_request._cookies, req, resp.raw)
prepared_request._cookies.update(self.cookies)
prepared_request.prepare_cookies(prepared_request._cookies)
@@ -190,6 +193,7 @@ class SessionRedirectMixin(object):
cert=cert,
proxies=proxies,
allow_redirects=False,
**adapter_kwargs
)
extract_cookies_to_jar(self.cookies, prepared_request, resp.raw)
@@ -557,10 +561,6 @@ class Session(SessionRedirectMixin):
# Set up variables needed for resolve_redirects and dispatching of hooks
allow_redirects = kwargs.pop('allow_redirects', True)
stream = kwargs.get('stream')
timeout = kwargs.get('timeout')
verify = kwargs.get('verify')
cert = kwargs.get('cert')
proxies = kwargs.get('proxies')
hooks = request.hooks
# Get the appropriate adapter to use
@@ -588,12 +588,7 @@ class Session(SessionRedirectMixin):
extract_cookies_to_jar(self.cookies, request, r.raw)
# Redirect resolving generator.
gen = self.resolve_redirects(r, request,
stream=stream,
timeout=timeout,
verify=verify,
cert=cert,
proxies=proxies)
gen = self.resolve_redirects(r, request, **kwargs)
# Resolve redirects if allowed.
history = [resp for resp in gen] if allow_redirects else []

View File

@@ -1,10 +1,9 @@
#!/usr/bin/env python
import os
import re
import sys
import requests
from codecs import open
try:
@@ -29,6 +28,14 @@ packages = [
requires = []
version = ''
with open('requests/__init__.py', 'r') as fd:
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]',
fd.read(), re.MULTILINE).group(1)
if not version:
raise RuntimeError('Cannot find version information')
with open('README.rst', 'r', 'utf-8') as f:
readme = f.read()
with open('HISTORY.rst', 'r', 'utf-8') as f:
@@ -36,7 +43,7 @@ with open('HISTORY.rst', 'r', 'utf-8') as f:
setup(
name='requests',
version=requests.__version__,
version=version,
description='Python HTTP for Humans.',
long_description=readme + '\n\n' + history,
author='Kenneth Reitz',
@@ -60,7 +67,6 @@ setup(
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4'
),
extras_require={
'security': ['pyOpenSSL', 'ndg-httpsclient', 'pyasn1'],

View File

@@ -935,6 +935,19 @@ class RequestsTestCase(unittest.TestCase):
assert 'multipart/form-data' in p.headers['Content-Type']
def test_can_send_bytes_bytearray_objects_with_files(self):
# Test bytes:
data = {'a': 'this is a string'}
files = {'b': b'foo'}
r = requests.Request('POST', httpbin('post'), data=data, files=files)
p = r.prepare()
assert 'multipart/form-data' in p.headers['Content-Type']
# Test bytearrays:
files = {'b': bytearray(b'foo')}
r = requests.Request('POST', httpbin('post'), data=data, files=files)
p = r.prepare()
assert 'multipart/form-data' in p.headers['Content-Type']
def test_can_send_file_object_with_non_string_filename(self):
f = io.BytesIO()
f.name = 2
@@ -1039,6 +1052,23 @@ class RequestsTestCase(unittest.TestCase):
assert 'application/json' in r.request.headers['Content-Type']
assert {'life': 42} == r.json()['json']
def test_response_iter_lines(self):
r = requests.get(httpbin('stream/4'), stream=True)
assert r.status_code == 200
it = r.iter_lines()
next(it)
assert len(list(it)) == 3
@pytest.mark.xfail
def test_response_iter_lines_reentrant(self):
"""Response.iter_lines() is not reentrant safe"""
r = requests.get(httpbin('stream/4'), stream=True)
assert r.status_code == 200
next(r.iter_lines())
assert len(list(r.iter_lines())) == 3
class TestContentEncodingDetection(unittest.TestCase):
@@ -1583,7 +1613,6 @@ def test_prepare_unicode_url():
p.prepare(
method='GET',
url=u('http://www.example.com/üniçø∂é'),
hooks=[]
)
assert_copy(p, p.copy())
@@ -1598,5 +1627,12 @@ def test_urllib3_retries():
with pytest.raises(RetryError):
s.get(httpbin('status/500'))
def test_vendor_aliases():
from requests.packages import urllib3
from requests.packages import chardet
with pytest.raises(ImportError):
from requests.packages import webbrowser
if __name__ == '__main__':
unittest.main()