Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd777b3d7e | ||
|
|
df272b7740 | ||
|
|
db108a19c8 | ||
|
|
c244f8ea87 | ||
|
|
f045979f8d | ||
|
|
3d59569264 | ||
|
|
5469291296 | ||
|
|
3b35f1c37d | ||
|
|
e813574497 | ||
|
|
e1e6255b48 | ||
|
|
1a9f0be6df | ||
|
|
d9ec7000db | ||
|
|
6b975cbd82 | ||
|
|
76be17b00a | ||
|
|
0cd6959f19 | ||
|
|
741fd3ded5 | ||
|
|
ff2b496e2d | ||
|
|
6a24eb6d20 | ||
|
|
e91ee0e246 | ||
|
|
ab8e43a196 | ||
|
|
c05b1bfca9 | ||
|
|
011f6dac82 | ||
|
|
f35363e584 | ||
|
|
c8d3dcb315 | ||
|
|
2ec1bdd0ab | ||
|
|
3d0a1eb90d | ||
|
|
65ec319f01 | ||
|
|
17dd3c0a76 | ||
|
|
3f84190a7b | ||
|
|
bea2060182 | ||
|
|
097121d214 | ||
|
|
21c9680a11 | ||
|
|
8d63577b78 | ||
|
|
2c2af651c4 | ||
|
|
13a6e02ccd | ||
|
|
025543b604 | ||
|
|
f32b86dba2 | ||
|
|
43477edc91 | ||
|
|
318ca102cd | ||
|
|
14c12fb151 | ||
|
|
3246fc088a | ||
|
|
45873e2a0a | ||
|
|
66339b21fa | ||
|
|
d8180f5dac | ||
|
|
48f59aa1f7 | ||
|
|
56c82c52b0 | ||
|
|
36485983ca | ||
|
|
6087015f1c | ||
|
|
5c92c72e2c | ||
|
|
4656c9b89b | ||
|
|
8370e66464 | ||
|
|
f9b7d92b91 | ||
|
|
c8a68334a7 | ||
|
|
953b234aff | ||
|
|
c9bee155c2 | ||
|
|
4291f76c99 | ||
|
|
82e6706722 | ||
|
|
af4fb8cedc | ||
|
|
c8fc19a779 | ||
|
|
012f0334ce | ||
|
|
0051837af4 | ||
|
|
8b7fcfb49a | ||
|
|
d22eaf96e2 | ||
|
|
373166d833 | ||
|
|
39fe0068aa | ||
|
|
1d1831ba40 | ||
|
|
3501ea4634 | ||
|
|
9968a10fcf | ||
|
|
768b175fee | ||
|
|
a17f5592f8 | ||
|
|
fbb8d32c4e |
11
.travis.yml
11
.travis.yml
@@ -1,11 +0,0 @@
|
||||
language: python
|
||||
python:
|
||||
- 2.6
|
||||
- 2.7
|
||||
- 3.3
|
||||
env: HTTPBIN_URL=http://httpbin.org/
|
||||
script: invoke test
|
||||
install:
|
||||
- pip install -r requirements.txt
|
||||
notifications:
|
||||
email: false
|
||||
@@ -135,4 +135,8 @@ Patches and Suggestions
|
||||
- David Pursehouse <david.pursehouse@gmail.com> @dpursehouse
|
||||
- Jon Parise
|
||||
- Alexander Karpinsky @homm86
|
||||
- Marc Schlaich @schlamar
|
||||
- Marc Schlaich @schlamar
|
||||
- Park Ilsu <daftonshady@gmail.com> @daftshady
|
||||
- Matt Spitz @mattspitz
|
||||
- Vikram Oberoi @voberoi
|
||||
- Can Ibanoglu <can.ibanoglu@gmail.com> @canibanoglu
|
||||
|
||||
15
HISTORY.rst
15
HISTORY.rst
@@ -3,6 +3,19 @@
|
||||
Release History
|
||||
---------------
|
||||
|
||||
|
||||
2.0.1 (2013-10-24)
|
||||
++++++++++++++++++
|
||||
|
||||
- Updated included CA Bundle with new mistrusts and automated process for the future
|
||||
- Added MD5-sess to Digest Auth
|
||||
- Accept per-file headers in multipart file POST messages.
|
||||
- Fixed: Don't send the full URL on CONNECT messages.
|
||||
- Fixed: Correctly lowercase a redirect scheme.
|
||||
- Fixed: Cookies not persisted when set via functional API.
|
||||
- Fixed: Translate urllib3 ProxyError into a requests ProxyError derived from ConnectionError.
|
||||
- Updated internal urllib3 and chardet.
|
||||
|
||||
2.0.0 (2013-09-24)
|
||||
++++++++++++++++++
|
||||
|
||||
@@ -42,7 +55,7 @@ Release History
|
||||
- Better handling of streaming downloads.
|
||||
- Retrieve environment proxies from more locations.
|
||||
- Minor cookies fixes.
|
||||
- Imroved redirect behaviour.
|
||||
- Improved redirect behaviour.
|
||||
- Improved streaming behaviour, particularly for compressed data.
|
||||
- Miscellaneous small Python 3 text encoding bugs.
|
||||
- ``.netrc`` no longer overrides explicit auth.
|
||||
|
||||
25
Makefile
Normal file
25
Makefile
Normal file
@@ -0,0 +1,25 @@
|
||||
init:
|
||||
pip install -r requirements.txt
|
||||
|
||||
test:
|
||||
py.test
|
||||
|
||||
ci: init
|
||||
py.test --junitxml=junit.xml
|
||||
|
||||
certs:
|
||||
curl http://ci.kennethreitz.org/job/ca-bundle/lastSuccessfulBuild/artifact/cacerts.pem -o requests/cacert.pem
|
||||
|
||||
deps: urllib3 charade
|
||||
|
||||
urllib3:
|
||||
rm -fr requests/packages/urllib3
|
||||
git clone https://github.com/shazow/urllib3.git
|
||||
mv urllib3/urllib3 requests/packages/
|
||||
rm -fr urllib3
|
||||
|
||||
charade:
|
||||
rm -fr requests/packages/charade
|
||||
git clone https://github.com/sigmavirus24/charade.git
|
||||
mv charade/charade requests/packages/
|
||||
rm -fr charade
|
||||
@@ -4,12 +4,13 @@ Requests: HTTP for Humans
|
||||
.. image:: https://badge.fury.io/py/requests.png
|
||||
:target: http://badge.fury.io/py/requests
|
||||
|
||||
.. image:: https://travis-ci.org/kennethreitz/requests.png?branch=master
|
||||
:target: https://travis-ci.org/kennethreitz/requests
|
||||
|
||||
.. image:: https://pypip.in/d/requests/badge.png
|
||||
:target: https://crate.io/packages/requests/
|
||||
|
||||
.. image:: http://ci.kennethreitz.org/buildStatus/icon?job=requests-trunk
|
||||
:target: http://ci.kennethreitz.org/job/requests-trunk/
|
||||
|
||||
|
||||
Requests is an Apache2 Licensed HTTP library, written in Python, for human
|
||||
beings.
|
||||
|
||||
|
||||
70
docs/api.rst
70
docs/api.rst
@@ -193,3 +193,73 @@ license ensures that contributions to Requests are also covered by the Apache
|
||||
.. _ISC: http://opensource.org/licenses/ISC
|
||||
.. _Apache 2.0: http://opensource.org/licenses/Apache-2.0
|
||||
|
||||
|
||||
Migrating to 2.x
|
||||
----------------
|
||||
|
||||
|
||||
Compared with the 1.0 release, there were relatively few backwards
|
||||
incompatible changes, but there are still a few issues to be aware of with
|
||||
this major release.
|
||||
|
||||
For more details on the changes in this release including new APIs, links
|
||||
to the relevant GitHub issues and some of the bug fixes, read Cory's blog_
|
||||
on the subject.
|
||||
|
||||
.. _blog: http://lukasa.co.uk/2013/09/Requests_20/
|
||||
|
||||
|
||||
API Changes
|
||||
~~~~~~~~~~~
|
||||
|
||||
* There were a couple changes to how Requests handles exceptions.
|
||||
``RequestException`` is now a subclass of ``IOError`` rather than
|
||||
``RuntimeError`` as that more accurately categorizes the type of error.
|
||||
In addition, an invalid URL escape sequence now raises a subclass of
|
||||
``RequestException`` rather than a ``ValueError``.
|
||||
|
||||
::
|
||||
|
||||
requests.get('http://%zz/') # raises requests.exceptions.InvalidURL
|
||||
|
||||
Lastly, ``httplib.IncompleteRead`` exceptions caused by incorrect chunked
|
||||
encoding will now raise a Requests ``ChunkedEncodingError`` instead.
|
||||
|
||||
* The proxy API has changed slightly. The scheme for a proxy URL is now
|
||||
required.
|
||||
|
||||
::
|
||||
|
||||
proxies = {
|
||||
"http": "10.10.1.10:3128", # use http://10.10.1.10:3128 instead
|
||||
}
|
||||
|
||||
# In requests 1.x, this was legal, in requests 2.x,
|
||||
# this raises requests.exceptions.MissingSchema
|
||||
requests.get("http://example.org", proxies=proxies)
|
||||
|
||||
|
||||
Behavioral Changes
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Keys in the ``headers`` dictionary are now native strings on all Python
|
||||
versions, i.e. bytestrings on Python 2 and unicode on Python 3. If the
|
||||
keys are not native strings (unicode on Python2 or bytestrings on Python 3)
|
||||
they will be converted to the native string type assuming UTF-8 encoding.
|
||||
|
||||
* Timeouts behave slightly differently. On streaming requests, the timeout
|
||||
only applies to the connection attempt. On regular requests, the timeout
|
||||
is applied to the connection process and downloading the full body.
|
||||
|
||||
::
|
||||
|
||||
tarball_url = 'https://github.com/kennethreitz/requests/tarball/master'
|
||||
|
||||
# One second timeout for the connection attempt
|
||||
# Unlimited time to download the tarball
|
||||
r = requests.get(tarball_url, stream=True, timeout=1)
|
||||
|
||||
# One second timeout for the connection attempt
|
||||
# Another full second timeout to download the tarball
|
||||
r = requests.get(tarball_url, timeout=1)
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ Let's persist some cookies across requests::
|
||||
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
|
||||
r = s.get("http://httpbin.org/cookies")
|
||||
|
||||
print r.text
|
||||
print(r.text)
|
||||
# '{"cookies": {"sessioncookie": "123456789"}}'
|
||||
|
||||
|
||||
@@ -48,13 +48,13 @@ All values that are contained within a session are directly available to you. Se
|
||||
Request and Response Objects
|
||||
----------------------------
|
||||
|
||||
Whenever a call is made to requests.*() you are doing two major things. First,
|
||||
you are constructing a ``Request`` object which will be sent off to a server
|
||||
to request or query some resource. Second, a ``Response`` object is generated
|
||||
once ``requests`` gets a response back from the server. The Response object
|
||||
contains all of the information returned by the server and also contains the
|
||||
``Request`` object you created originally. Here is a simple request to get some
|
||||
very important information from Wikipedia's servers::
|
||||
Whenever a call is made to ``requests.get()`` and friends you are doing two
|
||||
major things. First, you are constructing a ``Request`` object which will be
|
||||
sent off to a server to request or query some resource. Second, a ``Response``
|
||||
object is generated once ``requests`` gets a response back from the server.
|
||||
The Response object contains all of the information returned by the server and
|
||||
also contains the ``Request`` object you created originally. Here is a simple
|
||||
request to get some very important information from Wikipedia's servers::
|
||||
|
||||
>>> r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
|
||||
|
||||
@@ -275,8 +275,7 @@ Streaming Requests
|
||||
|
||||
With ``requests.Response.iter_lines()`` you can easily iterate over streaming
|
||||
APIs such as the `Twitter Streaming API <https://dev.twitter.com/docs/streaming-api>`_.
|
||||
|
||||
To use the Twitter Streaming API to track the keyword "requests"::
|
||||
Simply set ``stream`` to ``True`` and iterate over the response with ``iter_lines()``::
|
||||
|
||||
import json
|
||||
import requests
|
||||
@@ -305,7 +304,8 @@ If you need to use a proxy, you can configure individual requests with the
|
||||
|
||||
requests.get("http://example.org", proxies=proxies)
|
||||
|
||||
You can also configure proxies by environment variables ``HTTP_PROXY`` and ``HTTPS_PROXY``.
|
||||
You can also configure proxies by setting the environment variables
|
||||
``HTTP_PROXY`` and ``HTTPS_PROXY``.
|
||||
|
||||
::
|
||||
|
||||
@@ -321,6 +321,8 @@ To use HTTP Basic Auth with your proxy, use the `http://user:password@host/` syn
|
||||
"http": "http://user:pass@10.10.1.10:3128/",
|
||||
}
|
||||
|
||||
Note that proxy URLs must include the scheme.
|
||||
|
||||
Compliance
|
||||
----------
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ following code::
|
||||
|
||||
You can see that the URL has been correctly encoded by printing the URL::
|
||||
|
||||
>>> print r.url
|
||||
>>> print(r.url)
|
||||
http://httpbin.org/get?key2=value2&key1=value1
|
||||
|
||||
Note that any dictionary key whose value is ``None`` will not be added to the
|
||||
@@ -152,6 +152,18 @@ server, you can access ``r.raw``. If you want to do this, make sure you set
|
||||
>>> r.raw.read(10)
|
||||
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'
|
||||
|
||||
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):
|
||||
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.
|
||||
|
||||
|
||||
Custom Headers
|
||||
--------------
|
||||
@@ -339,8 +351,8 @@ parameter::
|
||||
Redirection and History
|
||||
-----------------------
|
||||
|
||||
Requests will automatically perform location redirection while using the GET
|
||||
and OPTIONS verbs.
|
||||
Requests will automatically perform location redirection for all verbs except
|
||||
HEAD.
|
||||
|
||||
GitHub redirects all HTTP requests to HTTPS. We can use the ``history`` method
|
||||
of the Response object to track redirection. Let's see what GitHub does::
|
||||
@@ -357,8 +369,8 @@ The :class:`Response.history` list contains the :class:`Request` objects that
|
||||
were created in order to complete the request. The list is sorted from the
|
||||
oldest to the most recent request.
|
||||
|
||||
If you're using GET or OPTIONS, you can disable redirection handling with the
|
||||
``allow_redirects`` parameter::
|
||||
If you're using GET, OPTIONS, POST, PUT, PATCH or DELETE, you can disable
|
||||
redirection handling with the ``allow_redirects`` parameter::
|
||||
|
||||
>>> r = requests.get('http://github.com', allow_redirects=False)
|
||||
>>> r.status_code
|
||||
@@ -366,8 +378,7 @@ If you're using GET or OPTIONS, you can disable redirection handling with the
|
||||
>>> r.history
|
||||
[]
|
||||
|
||||
If you're using POST, PUT, PATCH, DELETE or HEAD, you can enable
|
||||
redirection as well::
|
||||
If you're using HEAD, you can enable redirection as well::
|
||||
|
||||
>>> r = requests.post('http://github.com', allow_redirects=True)
|
||||
>>> r.url
|
||||
|
||||
@@ -23,7 +23,7 @@ usage:
|
||||
|
||||
>>> payload = dict(key1='value1', key2='value2')
|
||||
>>> r = requests.post("http://httpbin.org/post", data=payload)
|
||||
>>> print r.text
|
||||
>>> print(r.text)
|
||||
{
|
||||
...
|
||||
"form": {
|
||||
@@ -42,8 +42,8 @@ is at <http://python-requests.org>.
|
||||
"""
|
||||
|
||||
__title__ = 'requests'
|
||||
__version__ = '2.0.0'
|
||||
__build__ = 0x020000
|
||||
__version__ = '2.0.1'
|
||||
__build__ = 0x020001
|
||||
__author__ = 'Kenneth Reitz'
|
||||
__license__ = 'Apache 2.0'
|
||||
__copyright__ = 'Copyright 2013 Kenneth Reitz'
|
||||
|
||||
@@ -22,8 +22,9 @@ from .packages.urllib3.exceptions import MaxRetryError
|
||||
from .packages.urllib3.exceptions import TimeoutError
|
||||
from .packages.urllib3.exceptions import SSLError as _SSLError
|
||||
from .packages.urllib3.exceptions import HTTPError as _HTTPError
|
||||
from .packages.urllib3.exceptions import ProxyError as _ProxyError
|
||||
from .cookies import extract_cookies_to_jar
|
||||
from .exceptions import ConnectionError, Timeout, SSLError
|
||||
from .exceptions import ConnectionError, Timeout, SSLError, ProxyError
|
||||
from .auth import _basic_auth_str
|
||||
|
||||
DEFAULT_POOLBLOCK = False
|
||||
@@ -220,8 +221,8 @@ class HTTPAdapter(BaseAdapter):
|
||||
def request_url(self, request, proxies):
|
||||
"""Obtain the url to use when making the final request.
|
||||
|
||||
If the message is being sent through a proxy, the full URL has to be
|
||||
used. Otherwise, we should only use the path portion of the URL.
|
||||
If the message is being sent through a HTTP proxy, the full URL has to
|
||||
be used. Otherwise, we should only use the path portion of the URL.
|
||||
|
||||
This should not be called from user code, and is only exposed for use
|
||||
when subclassing the
|
||||
@@ -231,9 +232,10 @@ class HTTPAdapter(BaseAdapter):
|
||||
:param proxies: A dictionary of schemes to proxy URLs.
|
||||
"""
|
||||
proxies = proxies or {}
|
||||
proxy = proxies.get(urlparse(request.url).scheme)
|
||||
scheme = urlparse(request.url).scheme.lower()
|
||||
proxy = proxies.get(scheme)
|
||||
|
||||
if proxy:
|
||||
if proxy and scheme != 'https':
|
||||
url, _ = urldefrag(request.url)
|
||||
else:
|
||||
url = request.path_url
|
||||
@@ -353,6 +355,9 @@ class HTTPAdapter(BaseAdapter):
|
||||
except MaxRetryError as e:
|
||||
raise ConnectionError(e)
|
||||
|
||||
except _ProxyError as e:
|
||||
raise ProxyError(e)
|
||||
|
||||
except (_SSLError, _HTTPError) as e:
|
||||
if isinstance(e, _SSLError):
|
||||
raise SSLError(e)
|
||||
|
||||
7448
requests/cacert.pem
7448
requests/cacert.pem
File diff suppressed because it is too large
Load Diff
@@ -392,15 +392,21 @@ def morsel_to_cookie(morsel):
|
||||
return c
|
||||
|
||||
|
||||
def cookiejar_from_dict(cookie_dict, cookiejar=None):
|
||||
def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True):
|
||||
"""Returns a CookieJar from a key/value dictionary.
|
||||
|
||||
:param cookie_dict: Dict of key/values to insert into CookieJar.
|
||||
:param cookiejar: (optional) A cookiejar to add the cookies to.
|
||||
:param overwrite: (optional) If False, will not replace cookies
|
||||
already in the jar with new ones.
|
||||
"""
|
||||
if cookiejar is None:
|
||||
cookiejar = RequestsCookieJar()
|
||||
|
||||
if cookie_dict is not None:
|
||||
names_from_jar = [cookie.name for cookie in cookiejar]
|
||||
for name in cookie_dict:
|
||||
cookiejar.set_cookie(create_cookie(name, cookie_dict[name]))
|
||||
if overwrite or (name not in names_from_jar):
|
||||
cookiejar.set_cookie(create_cookie(name, cookie_dict[name]))
|
||||
|
||||
return cookiejar
|
||||
|
||||
@@ -27,6 +27,10 @@ class ConnectionError(RequestException):
|
||||
"""A Connection error occurred."""
|
||||
|
||||
|
||||
class ProxyError(ConnectionError):
|
||||
"""A proxy error occurred."""
|
||||
|
||||
|
||||
class SSLError(ConnectionError):
|
||||
"""An SSL error occurred."""
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ from .structures import CaseInsensitiveDict
|
||||
|
||||
from .auth import HTTPBasicAuth
|
||||
from .cookies import cookiejar_from_dict, get_cookie_header
|
||||
from .packages.urllib3.fields import RequestField
|
||||
from .packages.urllib3.filepost import encode_multipart_formdata
|
||||
from .packages.urllib3.util import parse_url
|
||||
from .exceptions import (
|
||||
@@ -90,7 +91,7 @@ class RequestEncodingMixin(object):
|
||||
"""Build the body for a multipart/form-data request.
|
||||
|
||||
Will successfully encode files when passed as a dict or a list of
|
||||
2-tuples. Order is retained if data is a list of 2-tuples but abritrary
|
||||
2-tuples. Order is retained if data is a list of 2-tuples but arbitrary
|
||||
if parameters are supplied as a dict.
|
||||
|
||||
"""
|
||||
@@ -119,11 +120,14 @@ class RequestEncodingMixin(object):
|
||||
for (k, v) in files:
|
||||
# support for explicit filename
|
||||
ft = None
|
||||
fh = None
|
||||
if isinstance(v, (tuple, list)):
|
||||
if len(v) == 2:
|
||||
fn, fp = v
|
||||
else:
|
||||
elif len(v) == 3:
|
||||
fn, fp, ft = v
|
||||
else:
|
||||
fn, fp, ft, fh = v
|
||||
else:
|
||||
fn = guess_filename(v) or k
|
||||
fp = v
|
||||
@@ -132,11 +136,10 @@ class RequestEncodingMixin(object):
|
||||
if isinstance(fp, bytes):
|
||||
fp = BytesIO(fp)
|
||||
|
||||
if ft:
|
||||
new_v = (fn, fp.read(), ft)
|
||||
else:
|
||||
new_v = (fn, fp.read())
|
||||
new_fields.append((k, new_v))
|
||||
rf = RequestField(name=k, data=fp.read(),
|
||||
filename=fn, headers=fh)
|
||||
rf.make_multipart(content_type=ft)
|
||||
new_fields.append(rf)
|
||||
|
||||
body, content_type = encode_multipart_formdata(new_fields)
|
||||
|
||||
@@ -274,7 +277,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
||||
|
||||
def prepare(self, method=None, url=None, headers=None, files=None,
|
||||
data=None, params=None, auth=None, cookies=None, hooks=None):
|
||||
"""Prepares the the entire request with the given parameters."""
|
||||
"""Prepares the entire request with the given parameters."""
|
||||
|
||||
self.prepare_method(method)
|
||||
self.prepare_url(url, params)
|
||||
@@ -295,7 +298,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
||||
p = PreparedRequest()
|
||||
p.method = self.method
|
||||
p.url = self.url
|
||||
p.headers = self.headers
|
||||
p.headers = self.headers.copy()
|
||||
p.body = self.body
|
||||
p.hooks = self.hooks
|
||||
return p
|
||||
@@ -575,7 +578,7 @@ class Response(object):
|
||||
raise ChunkedEncodingError(e)
|
||||
except AttributeError:
|
||||
# Standard file-like object.
|
||||
while 1:
|
||||
while True:
|
||||
chunk = self.raw.read(chunk_size)
|
||||
if not chunk:
|
||||
break
|
||||
@@ -687,7 +690,7 @@ class Response(object):
|
||||
encoding = guess_json_utf(self.content)
|
||||
if encoding is not None:
|
||||
return json.loads(self.content.decode(encoding), **kwargs)
|
||||
return json.loads(self.text or self.content, **kwargs)
|
||||
return json.loads(self.text, **kwargs)
|
||||
|
||||
@property
|
||||
def links(self):
|
||||
|
||||
@@ -30,3 +30,37 @@ def detect(aBuf):
|
||||
u.feed(aBuf)
|
||||
u.close()
|
||||
return u.result
|
||||
|
||||
def _description_of(path):
|
||||
"""Return a string describing the probable encoding of a file."""
|
||||
from charade.universaldetector import UniversalDetector
|
||||
|
||||
u = UniversalDetector()
|
||||
for line in open(path, 'rb'):
|
||||
u.feed(line)
|
||||
u.close()
|
||||
result = u.result
|
||||
if result['encoding']:
|
||||
return '%s: %s with confidence %s' % (path,
|
||||
result['encoding'],
|
||||
result['confidence'])
|
||||
else:
|
||||
return '%s: no result' % path
|
||||
|
||||
|
||||
def charade_cli():
|
||||
"""
|
||||
Script which takes one or more file paths and reports on their detected
|
||||
encodings
|
||||
|
||||
Example::
|
||||
|
||||
% chardetect.py somefile someotherfile
|
||||
somefile: windows-1252 with confidence 0.5
|
||||
someotherfile: ascii with confidence 1.0
|
||||
|
||||
"""
|
||||
from sys import argv
|
||||
for path in argv[1:]:
|
||||
print(_description_of(path))
|
||||
|
||||
7
requests/packages/charade/__main__.py
Normal file
7
requests/packages/charade/__main__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
'''
|
||||
support ';python -m charade <file1> [file2] ...' package execution syntax (2.7+)
|
||||
'''
|
||||
|
||||
from charade import charade_cli
|
||||
|
||||
charade_cli()
|
||||
@@ -169,7 +169,7 @@ class JapaneseContextAnalysis:
|
||||
def get_confidence(self):
|
||||
# This is just one way to calculate confidence. It works well for me.
|
||||
if self._mTotalRel > MINIMUM_DATA_THRESHOLD:
|
||||
return (self._mTotalRel - self._mRelSample[0]) / self._mTotalRel
|
||||
return float(self._mTotalRel - self._mRelSample[0]) / self._mTotalRel
|
||||
else:
|
||||
return DONT_KNOW
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ class Latin1Prober(CharSetProber):
|
||||
if total < 0.01:
|
||||
confidence = 0.0
|
||||
else:
|
||||
confidence = ((self._mFreqCounter[3] / total)
|
||||
confidence = ((float(self._mFreqCounter[3]) / total)
|
||||
- (self._mFreqCounter[1] * 20.0 / total))
|
||||
if confidence < 0.0:
|
||||
confidence = 0.0
|
||||
|
||||
@@ -74,12 +74,10 @@ class UniversalDetector:
|
||||
if aBuf[:3] == codecs.BOM:
|
||||
# EF BB BF UTF-8 with BOM
|
||||
self.result = {'encoding': "UTF-8", 'confidence': 1.0}
|
||||
elif aBuf[:4] == codecs.BOM_UTF32_LE:
|
||||
elif aBuf[:4] in (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE):
|
||||
# FF FE 00 00 UTF-32, little-endian BOM
|
||||
self.result = {'encoding': "UTF-32LE", 'confidence': 1.0}
|
||||
elif aBuf[:4] == codecs.BOM_UTF32_BE:
|
||||
# 00 00 FE FF UTF-32, big-endian BOM
|
||||
self.result = {'encoding': "UTF-32BE", 'confidence': 1.0}
|
||||
self.result = {'encoding': "UTF-32", 'confidence': 1.0}
|
||||
elif aBuf[:4] == b'\xFE\xFF\x00\x00':
|
||||
# FE FF 00 00 UCS-4, unusual octet order BOM (3412)
|
||||
self.result = {
|
||||
@@ -92,12 +90,10 @@ class UniversalDetector:
|
||||
'encoding': "X-ISO-10646-UCS-4-2143",
|
||||
'confidence': 1.0
|
||||
}
|
||||
elif aBuf[:2] == codecs.BOM_LE:
|
||||
elif aBuf[:2] == codecs.BOM_LE or aBuf[:2] == codecs.BOM_BE:
|
||||
# FF FE UTF-16, little endian BOM
|
||||
self.result = {'encoding': "UTF-16LE", 'confidence': 1.0}
|
||||
elif aBuf[:2] == codecs.BOM_BE:
|
||||
# FE FF UTF-16, big endian BOM
|
||||
self.result = {'encoding': "UTF-16BE", 'confidence': 1.0}
|
||||
self.result = {'encoding': "UTF-16", 'confidence': 1.0}
|
||||
|
||||
self._mGotData = True
|
||||
if self.result['encoding'] and (self.result['confidence'] > 0.0):
|
||||
|
||||
107
requests/packages/urllib3/connection.py
Normal file
107
requests/packages/urllib3/connection.py
Normal file
@@ -0,0 +1,107 @@
|
||||
# urllib3/connection.py
|
||||
# Copyright 2008-2013 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
|
||||
#
|
||||
# This module is part of urllib3 and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
import socket
|
||||
from socket import timeout as SocketTimeout
|
||||
|
||||
try: # Python 3
|
||||
from http.client import HTTPConnection, HTTPException
|
||||
except ImportError:
|
||||
from httplib import HTTPConnection, HTTPException
|
||||
|
||||
class DummyConnection(object):
|
||||
"Used to detect a failed ConnectionCls import."
|
||||
pass
|
||||
|
||||
try: # Compiled with SSL?
|
||||
ssl = None
|
||||
HTTPSConnection = DummyConnection
|
||||
|
||||
class BaseSSLError(BaseException):
|
||||
pass
|
||||
|
||||
try: # Python 3
|
||||
from http.client import HTTPSConnection
|
||||
except ImportError:
|
||||
from httplib import HTTPSConnection
|
||||
|
||||
import ssl
|
||||
BaseSSLError = ssl.SSLError
|
||||
|
||||
except (ImportError, AttributeError): # Platform-specific: No SSL.
|
||||
pass
|
||||
|
||||
from .exceptions import (
|
||||
ConnectTimeoutError,
|
||||
)
|
||||
from .packages.ssl_match_hostname import match_hostname
|
||||
from .util import (
|
||||
assert_fingerprint,
|
||||
resolve_cert_reqs,
|
||||
resolve_ssl_version,
|
||||
ssl_wrap_socket,
|
||||
)
|
||||
|
||||
class VerifiedHTTPSConnection(HTTPSConnection):
|
||||
"""
|
||||
Based on httplib.HTTPSConnection but wraps the socket with
|
||||
SSL certification.
|
||||
"""
|
||||
cert_reqs = None
|
||||
ca_certs = None
|
||||
ssl_version = None
|
||||
|
||||
def set_cert(self, key_file=None, cert_file=None,
|
||||
cert_reqs=None, ca_certs=None,
|
||||
assert_hostname=None, assert_fingerprint=None):
|
||||
|
||||
self.key_file = key_file
|
||||
self.cert_file = cert_file
|
||||
self.cert_reqs = cert_reqs
|
||||
self.ca_certs = ca_certs
|
||||
self.assert_hostname = assert_hostname
|
||||
self.assert_fingerprint = assert_fingerprint
|
||||
|
||||
def connect(self):
|
||||
# Add certificate verification
|
||||
try:
|
||||
sock = socket.create_connection(
|
||||
address=(self.host, self.port),
|
||||
timeout=self.timeout,
|
||||
)
|
||||
except SocketTimeout:
|
||||
raise ConnectTimeoutError(
|
||||
self, "Connection to %s timed out. (connect timeout=%s)" %
|
||||
(self.host, self.timeout))
|
||||
|
||||
resolved_cert_reqs = resolve_cert_reqs(self.cert_reqs)
|
||||
resolved_ssl_version = resolve_ssl_version(self.ssl_version)
|
||||
|
||||
if self._tunnel_host:
|
||||
self.sock = sock
|
||||
# Calls self._set_hostport(), so self.host is
|
||||
# self._tunnel_host below.
|
||||
self._tunnel()
|
||||
|
||||
# Wrap socket using verification with the root certs in
|
||||
# trusted_root_certs
|
||||
self.sock = ssl_wrap_socket(sock, self.key_file, self.cert_file,
|
||||
cert_reqs=resolved_cert_reqs,
|
||||
ca_certs=self.ca_certs,
|
||||
server_hostname=self.host,
|
||||
ssl_version=resolved_ssl_version)
|
||||
|
||||
if resolved_cert_reqs != ssl.CERT_NONE:
|
||||
if self.assert_fingerprint:
|
||||
assert_fingerprint(self.sock.getpeercert(binary_form=True),
|
||||
self.assert_fingerprint)
|
||||
elif self.assert_hostname is not False:
|
||||
match_hostname(self.sock.getpeercert(),
|
||||
self.assert_hostname or self.host)
|
||||
|
||||
|
||||
if ssl:
|
||||
HTTPSConnection = VerifiedHTTPSConnection
|
||||
@@ -10,13 +10,6 @@ import logging
|
||||
from socket import error as SocketError, timeout as SocketTimeout
|
||||
import socket
|
||||
|
||||
try: # Python 3
|
||||
from http.client import HTTPConnection, HTTPException
|
||||
from http.client import HTTP_PORT, HTTPS_PORT
|
||||
except ImportError:
|
||||
from httplib import HTTPConnection, HTTPException
|
||||
from httplib import HTTP_PORT, HTTPS_PORT
|
||||
|
||||
try: # Python 3
|
||||
from queue import LifoQueue, Empty, Full
|
||||
except ImportError:
|
||||
@@ -24,26 +17,6 @@ except ImportError:
|
||||
import Queue as _ # Platform-specific: Windows
|
||||
|
||||
|
||||
try: # Compiled with SSL?
|
||||
HTTPSConnection = object
|
||||
|
||||
class BaseSSLError(BaseException):
|
||||
pass
|
||||
|
||||
ssl = None
|
||||
|
||||
try: # Python 3
|
||||
from http.client import HTTPSConnection
|
||||
except ImportError:
|
||||
from httplib import HTTPSConnection
|
||||
|
||||
import ssl
|
||||
BaseSSLError = ssl.SSLError
|
||||
|
||||
except (ImportError, AttributeError): # Platform-specific: No SSL.
|
||||
pass
|
||||
|
||||
|
||||
from .exceptions import (
|
||||
ClosedPoolError,
|
||||
ConnectTimeoutError,
|
||||
@@ -51,23 +24,27 @@ from .exceptions import (
|
||||
HostChangedError,
|
||||
MaxRetryError,
|
||||
SSLError,
|
||||
TimeoutError,
|
||||
ReadTimeoutError,
|
||||
ProxyError,
|
||||
)
|
||||
from .packages.ssl_match_hostname import CertificateError, match_hostname
|
||||
from .packages.ssl_match_hostname import CertificateError
|
||||
from .packages import six
|
||||
from .connection import (
|
||||
DummyConnection,
|
||||
HTTPConnection, HTTPSConnection, VerifiedHTTPSConnection,
|
||||
HTTPException, BaseSSLError,
|
||||
)
|
||||
from .request import RequestMethods
|
||||
from .response import HTTPResponse
|
||||
from .util import (
|
||||
assert_fingerprint,
|
||||
get_host,
|
||||
is_connection_dropped,
|
||||
resolve_cert_reqs,
|
||||
resolve_ssl_version,
|
||||
ssl_wrap_socket,
|
||||
Timeout,
|
||||
)
|
||||
|
||||
|
||||
xrange = six.moves.xrange
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -75,70 +52,11 @@ log = logging.getLogger(__name__)
|
||||
_Default = object()
|
||||
|
||||
port_by_scheme = {
|
||||
'http': HTTP_PORT,
|
||||
'https': HTTPS_PORT,
|
||||
'http': 80,
|
||||
'https': 443,
|
||||
}
|
||||
|
||||
|
||||
## Connection objects (extension of httplib)
|
||||
|
||||
class VerifiedHTTPSConnection(HTTPSConnection):
|
||||
"""
|
||||
Based on httplib.HTTPSConnection but wraps the socket with
|
||||
SSL certification.
|
||||
"""
|
||||
cert_reqs = None
|
||||
ca_certs = None
|
||||
ssl_version = None
|
||||
|
||||
def set_cert(self, key_file=None, cert_file=None,
|
||||
cert_reqs=None, ca_certs=None,
|
||||
assert_hostname=None, assert_fingerprint=None):
|
||||
|
||||
self.key_file = key_file
|
||||
self.cert_file = cert_file
|
||||
self.cert_reqs = cert_reqs
|
||||
self.ca_certs = ca_certs
|
||||
self.assert_hostname = assert_hostname
|
||||
self.assert_fingerprint = assert_fingerprint
|
||||
|
||||
def connect(self):
|
||||
# Add certificate verification
|
||||
try:
|
||||
sock = socket.create_connection(
|
||||
address=(self.host, self.port),
|
||||
timeout=self.timeout)
|
||||
except SocketTimeout:
|
||||
raise ConnectTimeoutError(
|
||||
self, "Connection to %s timed out. (connect timeout=%s)" %
|
||||
(self.host, self.timeout))
|
||||
|
||||
resolved_cert_reqs = resolve_cert_reqs(self.cert_reqs)
|
||||
resolved_ssl_version = resolve_ssl_version(self.ssl_version)
|
||||
|
||||
if self._tunnel_host:
|
||||
self.sock = sock
|
||||
# Calls self._set_hostport(), so self.host is
|
||||
# self._tunnel_host below.
|
||||
self._tunnel()
|
||||
|
||||
# Wrap socket using verification with the root certs in
|
||||
# trusted_root_certs
|
||||
self.sock = ssl_wrap_socket(sock, self.key_file, self.cert_file,
|
||||
cert_reqs=resolved_cert_reqs,
|
||||
ca_certs=self.ca_certs,
|
||||
server_hostname=self.host,
|
||||
ssl_version=resolved_ssl_version)
|
||||
|
||||
if resolved_cert_reqs != ssl.CERT_NONE:
|
||||
if self.assert_fingerprint:
|
||||
assert_fingerprint(self.sock.getpeercert(binary_form=True),
|
||||
self.assert_fingerprint)
|
||||
elif self.assert_hostname is not False:
|
||||
match_hostname(self.sock.getpeercert(),
|
||||
self.assert_hostname or self.host)
|
||||
|
||||
|
||||
## Pool objects
|
||||
|
||||
class ConnectionPool(object):
|
||||
@@ -218,6 +136,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
|
||||
"""
|
||||
|
||||
scheme = 'http'
|
||||
ConnectionCls = HTTPConnection
|
||||
|
||||
def __init__(self, host, port=None, strict=False,
|
||||
timeout=Timeout.DEFAULT_TIMEOUT, maxsize=1, block=False,
|
||||
@@ -255,14 +174,14 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
|
||||
self.num_connections += 1
|
||||
log.info("Starting new HTTP connection (%d): %s" %
|
||||
(self.num_connections, self.host))
|
||||
|
||||
extra_params = {}
|
||||
if not six.PY3: # Python 2
|
||||
extra_params['strict'] = self.strict
|
||||
|
||||
return HTTPConnection(host=self.host, port=self.port,
|
||||
timeout=self.timeout.connect_timeout,
|
||||
**extra_params)
|
||||
|
||||
return self.ConnectionCls(host=self.host, port=self.port,
|
||||
timeout=self.timeout.connect_timeout,
|
||||
**extra_params)
|
||||
|
||||
def _get_conn(self, timeout=None):
|
||||
"""
|
||||
@@ -362,7 +281,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
|
||||
timeout_obj.start_connect()
|
||||
conn.timeout = timeout_obj.connect_timeout
|
||||
# conn.request() calls httplib.*.request, not the method in
|
||||
# request.py. It also calls makefile (recv) on the socket
|
||||
# urllib3.request. It also calls makefile (recv) on the socket.
|
||||
conn.request(method, url, **httplib_request_kw)
|
||||
except SocketTimeout:
|
||||
raise ConnectTimeoutError(
|
||||
@@ -371,11 +290,9 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
|
||||
|
||||
# Reset the timeout for the recv() on the socket
|
||||
read_timeout = timeout_obj.read_timeout
|
||||
log.debug("Setting read timeout to %s" % read_timeout)
|
||||
|
||||
# App Engine doesn't have a sock attr
|
||||
if hasattr(conn, 'sock') and \
|
||||
read_timeout is not None and \
|
||||
read_timeout is not Timeout.DEFAULT_TIMEOUT:
|
||||
if hasattr(conn, 'sock'):
|
||||
# In Python 3 socket.py will catch EAGAIN and return None when you
|
||||
# try and read into the file pointer created by http.client, which
|
||||
# instead raises a BadStatusLine exception. Instead of catching
|
||||
@@ -385,7 +302,10 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
|
||||
raise ReadTimeoutError(
|
||||
self, url,
|
||||
"Read timed out. (read timeout=%s)" % read_timeout)
|
||||
conn.sock.settimeout(read_timeout)
|
||||
if read_timeout is Timeout.DEFAULT_TIMEOUT:
|
||||
conn.sock.settimeout(socket.getdefaulttimeout())
|
||||
else: # None or a value
|
||||
conn.sock.settimeout(read_timeout)
|
||||
|
||||
# Receive the response from the server
|
||||
try:
|
||||
@@ -397,6 +317,16 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
|
||||
raise ReadTimeoutError(
|
||||
self, url, "Read timed out. (read timeout=%s)" % read_timeout)
|
||||
|
||||
except BaseSSLError as e:
|
||||
# Catch possible read timeouts thrown as SSL errors. If not the
|
||||
# case, rethrow the original. We need to do this because of:
|
||||
# http://bugs.python.org/issue10272
|
||||
if 'timed out' in str(e) or \
|
||||
'did not complete (read)' in str(e): # Python 2.6
|
||||
raise ReadTimeoutError(self, url, "Read timed out.")
|
||||
|
||||
raise
|
||||
|
||||
except SocketError as e: # Platform-specific: Python 2
|
||||
# See the above comment about EAGAIN in Python 3. In Python 2 we
|
||||
# have to specifically catch it and throw the timeout error
|
||||
@@ -404,8 +334,8 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
|
||||
raise ReadTimeoutError(
|
||||
self, url,
|
||||
"Read timed out. (read timeout=%s)" % read_timeout)
|
||||
raise
|
||||
|
||||
raise
|
||||
|
||||
# AppEngine doesn't have a version attr.
|
||||
http_version = getattr(conn, '_http_vsn_str', 'HTTP/?')
|
||||
@@ -559,24 +489,24 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
|
||||
|
||||
except Empty:
|
||||
# Timed out by queue
|
||||
raise ReadTimeoutError(
|
||||
self, url, "Read timed out, no pool connections are available.")
|
||||
|
||||
except SocketTimeout:
|
||||
# Timed out by socket
|
||||
raise ReadTimeoutError(self, url, "Read timed out.")
|
||||
raise EmptyPoolError(self, "No pool connections are available.")
|
||||
|
||||
except BaseSSLError as e:
|
||||
# SSL certificate error
|
||||
if 'timed out' in str(e) or \
|
||||
'did not complete (read)' in str(e): # Platform-specific: Python 2.6
|
||||
raise ReadTimeoutError(self, url, "Read timed out.")
|
||||
raise SSLError(e)
|
||||
|
||||
except CertificateError as e:
|
||||
# Name mismatch
|
||||
raise SSLError(e)
|
||||
|
||||
except TimeoutError as e:
|
||||
# Connection broken, discard.
|
||||
conn = None
|
||||
# Save the error off for retry logic.
|
||||
err = e
|
||||
|
||||
if retries == 0:
|
||||
raise
|
||||
|
||||
except (HTTPException, SocketError) as e:
|
||||
if isinstance(e, SocketError) and self.proxy is not None:
|
||||
raise ProxyError('Cannot connect to proxy. '
|
||||
@@ -639,6 +569,7 @@ class HTTPSConnectionPool(HTTPConnectionPool):
|
||||
"""
|
||||
|
||||
scheme = 'https'
|
||||
ConnectionCls = HTTPSConnection
|
||||
|
||||
def __init__(self, host, port=None,
|
||||
strict=False, timeout=None, maxsize=1,
|
||||
@@ -658,33 +589,33 @@ class HTTPSConnectionPool(HTTPConnectionPool):
|
||||
self.assert_hostname = assert_hostname
|
||||
self.assert_fingerprint = assert_fingerprint
|
||||
|
||||
def _prepare_conn(self, connection):
|
||||
def _prepare_conn(self, conn):
|
||||
"""
|
||||
Prepare the ``connection`` for :meth:`urllib3.util.ssl_wrap_socket`
|
||||
and establish the tunnel if proxy is used.
|
||||
"""
|
||||
|
||||
if isinstance(connection, VerifiedHTTPSConnection):
|
||||
connection.set_cert(key_file=self.key_file,
|
||||
cert_file=self.cert_file,
|
||||
cert_reqs=self.cert_reqs,
|
||||
ca_certs=self.ca_certs,
|
||||
assert_hostname=self.assert_hostname,
|
||||
assert_fingerprint=self.assert_fingerprint)
|
||||
connection.ssl_version = self.ssl_version
|
||||
if isinstance(conn, VerifiedHTTPSConnection):
|
||||
conn.set_cert(key_file=self.key_file,
|
||||
cert_file=self.cert_file,
|
||||
cert_reqs=self.cert_reqs,
|
||||
ca_certs=self.ca_certs,
|
||||
assert_hostname=self.assert_hostname,
|
||||
assert_fingerprint=self.assert_fingerprint)
|
||||
conn.ssl_version = self.ssl_version
|
||||
|
||||
if self.proxy is not None:
|
||||
# Python 2.7+
|
||||
try:
|
||||
set_tunnel = connection.set_tunnel
|
||||
set_tunnel = conn.set_tunnel
|
||||
except AttributeError: # Platform-specific: Python 2.6
|
||||
set_tunnel = connection._set_tunnel
|
||||
set_tunnel = conn._set_tunnel
|
||||
set_tunnel(self.host, self.port, self.proxy_headers)
|
||||
# Establish tunnel connection early, because otherwise httplib
|
||||
# would improperly set Host: header to proxy's IP:port.
|
||||
connection.connect()
|
||||
conn.connect()
|
||||
|
||||
return connection
|
||||
return conn
|
||||
|
||||
def _new_conn(self):
|
||||
"""
|
||||
@@ -694,28 +625,26 @@ class HTTPSConnectionPool(HTTPConnectionPool):
|
||||
log.info("Starting new HTTPS connection (%d): %s"
|
||||
% (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.")
|
||||
|
||||
actual_host = self.host
|
||||
actual_port = self.port
|
||||
if self.proxy is not None:
|
||||
actual_host = self.proxy.host
|
||||
actual_port = self.proxy.port
|
||||
|
||||
if not ssl: # Platform-specific: Python compiled without +ssl
|
||||
if not HTTPSConnection or HTTPSConnection is object:
|
||||
raise SSLError("Can't connect to HTTPS URL because the SSL "
|
||||
"module is not available.")
|
||||
connection_class = HTTPSConnection
|
||||
else:
|
||||
connection_class = VerifiedHTTPSConnection
|
||||
|
||||
extra_params = {}
|
||||
if not six.PY3: # Python 2
|
||||
extra_params['strict'] = self.strict
|
||||
connection = connection_class(host=actual_host, port=actual_port,
|
||||
timeout=self.timeout.connect_timeout,
|
||||
**extra_params)
|
||||
|
||||
return self._prepare_conn(connection)
|
||||
conn = self.ConnectionCls(host=actual_host, port=actual_port,
|
||||
timeout=self.timeout.connect_timeout,
|
||||
**extra_params)
|
||||
|
||||
return self._prepare_conn(conn)
|
||||
|
||||
|
||||
def connection_from_url(url, **kw):
|
||||
|
||||
@@ -26,6 +26,7 @@ import OpenSSL.SSL
|
||||
from pyasn1.codec.der import decoder as der_decoder
|
||||
from socket import _fileobject
|
||||
import ssl
|
||||
import select
|
||||
from cStringIO import StringIO
|
||||
|
||||
from .. import connectionpool
|
||||
@@ -336,6 +337,7 @@ def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
|
||||
try:
|
||||
cnx.do_handshake()
|
||||
except OpenSSL.SSL.WantReadError:
|
||||
select.select([sock], [], [])
|
||||
continue
|
||||
except OpenSSL.SSL.Error as e:
|
||||
raise ssl.SSLError('bad handshake', e)
|
||||
|
||||
@@ -80,14 +80,13 @@ class Timeout(object):
|
||||
:type read: integer, float, or None
|
||||
|
||||
:param total:
|
||||
The maximum amount of time to wait for an HTTP request to connect and
|
||||
return. This combines the connect and read timeouts into one. In the
|
||||
This combines the connect and read timeouts into one; the read timeout
|
||||
will be set to the time leftover from the connect attempt. In the
|
||||
event that both a connect timeout and a total are specified, or a read
|
||||
timeout and a total are specified, the shorter timeout will be applied.
|
||||
|
||||
Defaults to None.
|
||||
|
||||
|
||||
:type total: integer, float, or None
|
||||
|
||||
.. note::
|
||||
@@ -101,18 +100,23 @@ class Timeout(object):
|
||||
`total`.
|
||||
|
||||
In addition, the read and total timeouts only measure the time between
|
||||
read operations on the socket connecting the client and the server, not
|
||||
the total amount of time for the request to return a complete response.
|
||||
As an example, you may want a request to return within 7 seconds or
|
||||
fail, so you set the ``total`` timeout to 7 seconds. If the server
|
||||
sends one byte to you every 5 seconds, the request will **not** trigger
|
||||
time out. This case is admittedly rare.
|
||||
read operations on the socket connecting the client and the server,
|
||||
not the total amount of time for the request to return a complete
|
||||
response. For most requests, the timeout is raised because the server
|
||||
has not sent the first byte in the specified time. This is not always
|
||||
the case; if a server streams one byte every fifteen seconds, a timeout
|
||||
of 20 seconds will not ever trigger, even though the request will
|
||||
take several minutes to complete.
|
||||
|
||||
If your goal is to cut off any request after a set amount of wall clock
|
||||
time, consider having a second "watcher" thread to cut off a slow
|
||||
request.
|
||||
"""
|
||||
|
||||
#: A sentinel object representing the default timeout value
|
||||
DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT
|
||||
|
||||
def __init__(self, connect=_Default, read=_Default, total=None):
|
||||
def __init__(self, total=None, connect=_Default, read=_Default):
|
||||
self._connect = self._validate_timeout(connect, 'connect')
|
||||
self._read = self._validate_timeout(read, 'read')
|
||||
self.total = self._validate_timeout(total, 'total')
|
||||
@@ -372,7 +376,8 @@ def parse_url(url):
|
||||
|
||||
# Auth
|
||||
if '@' in url:
|
||||
auth, url = url.split('@', 1)
|
||||
# Last '@' denotes end of auth part
|
||||
auth, url = url.rsplit('@', 1)
|
||||
|
||||
# IPv6
|
||||
if url and url[0] == '[':
|
||||
@@ -386,10 +391,14 @@ def parse_url(url):
|
||||
if not host:
|
||||
host = _host
|
||||
|
||||
if not port.isdigit():
|
||||
raise LocationParseError("Failed to parse: %s" % url)
|
||||
|
||||
port = int(port)
|
||||
if port:
|
||||
# If given, ports must be integers.
|
||||
if not port.isdigit():
|
||||
raise LocationParseError("Failed to parse: %s" % url)
|
||||
port = int(port)
|
||||
else:
|
||||
# Blank ports are cool, too. (rfc3986#section-3.2.3)
|
||||
port = None
|
||||
|
||||
elif not host and url:
|
||||
host = url
|
||||
|
||||
@@ -12,7 +12,7 @@ import os
|
||||
from collections import Mapping
|
||||
from datetime import datetime
|
||||
|
||||
from .compat import cookielib, OrderedDict, urljoin, urlparse
|
||||
from .compat import cookielib, OrderedDict, urljoin, urlparse, urlunparse
|
||||
from .cookies import cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar
|
||||
from .models import Request, PreparedRequest
|
||||
from .hooks import default_hooks, dispatch_hook
|
||||
@@ -73,7 +73,7 @@ class SessionRedirectMixin(object):
|
||||
i = 0
|
||||
|
||||
# ((resp.status_code is codes.see_other))
|
||||
while (('location' in resp.headers and resp.status_code in REDIRECT_STATI)):
|
||||
while ('location' in resp.headers and resp.status_code in REDIRECT_STATI):
|
||||
prepared_request = req.copy()
|
||||
|
||||
resp.content # Consume socket so it can be released
|
||||
@@ -93,9 +93,10 @@ class SessionRedirectMixin(object):
|
||||
url = '%s:%s' % (parsed_rurl.scheme, url)
|
||||
|
||||
# The scheme should be lower case...
|
||||
if '://' in url:
|
||||
scheme, uri = url.split('://', 1)
|
||||
url = '%s://%s' % (scheme.lower(), uri)
|
||||
parsed = urlparse(url)
|
||||
parsed = (parsed.scheme.lower(), parsed.netloc, parsed.path,
|
||||
parsed.params, parsed.query, parsed.fragment)
|
||||
url = urlunparse(parsed)
|
||||
|
||||
# Facilitate non-RFC2616-compliant 'location' headers
|
||||
# (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource')
|
||||
@@ -322,6 +323,9 @@ class Session(SessionRedirectMixin):
|
||||
)
|
||||
prep = self.prepare_request(req)
|
||||
|
||||
# Add param cookies to session cookies
|
||||
self.cookies = cookiejar_from_dict(cookies, cookiejar=self.cookies, overwrite=False)
|
||||
|
||||
proxies = proxies or {}
|
||||
|
||||
# Gather clues from the surrounding environment.
|
||||
|
||||
@@ -12,6 +12,7 @@ that are also useful for external consumption.
|
||||
import cgi
|
||||
import codecs
|
||||
import collections
|
||||
import io
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
@@ -46,11 +47,21 @@ def dict_to_sequence(d):
|
||||
def super_len(o):
|
||||
if hasattr(o, '__len__'):
|
||||
return len(o)
|
||||
|
||||
if hasattr(o, 'len'):
|
||||
return o.len
|
||||
if hasattr(o, 'fileno'):
|
||||
return os.fstat(o.fileno()).st_size
|
||||
|
||||
if hasattr(o, 'fileno'):
|
||||
try:
|
||||
fileno = o.fileno()
|
||||
except io.UnsupportedOperation:
|
||||
pass
|
||||
else:
|
||||
return os.fstat(fileno).st_size
|
||||
|
||||
if hasattr(o, 'getvalue'):
|
||||
# e.g. BytesIO, cStringIO.StringI
|
||||
return len(o.getvalue())
|
||||
|
||||
def get_netrc_auth(url):
|
||||
"""Returns the Requests tuple auth for a given url from netrc."""
|
||||
|
||||
32
tasks.py
32
tasks.py
@@ -1,32 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import requests
|
||||
from invoke import run, task
|
||||
|
||||
@task
|
||||
def test():
|
||||
run('py.test', pty=True)
|
||||
|
||||
@task
|
||||
def deps():
|
||||
print('Vendoring urllib3...')
|
||||
|
||||
run('rm -fr requests/packages/urllib3')
|
||||
run('git clone https://github.com/shazow/urllib3.git')
|
||||
run('mv urllib3/urllib3 requests/packages/')
|
||||
run('rm -fr urllib3')
|
||||
|
||||
print('Vendoring Charade...')
|
||||
|
||||
run('rm -fr requests/packages/charade')
|
||||
run('git clone https://github.com/sigmavirus24/charade.git')
|
||||
run('mv charade/charade requests/packages/')
|
||||
run('rm -fr charade')
|
||||
|
||||
@task
|
||||
def certs():
|
||||
print('Grabbing latest CA Bundle...')
|
||||
r = requests.get('https://raw.github.com/kennethreitz/certifi/master/certifi/cacert.pem')
|
||||
|
||||
with open('requests/cacert.pem', 'w') as f:
|
||||
f.write(r.content)
|
||||
@@ -164,6 +164,12 @@ class RequestsTestCase(unittest.TestCase):
|
||||
s.get(httpbin('cookies/set?foo="bar:baz"'))
|
||||
self.assertTrue(s.cookies['foo'] == '"bar:baz"')
|
||||
|
||||
def test_cookie_persists_via_api(self):
|
||||
s = requests.session()
|
||||
r = s.get(httpbin('redirect/1'), cookies={'foo':'bar'})
|
||||
self.assertTrue('foo' in r.request.headers['Cookie'])
|
||||
self.assertTrue('foo' in r.history[0].request.headers['Cookie'])
|
||||
|
||||
def test_request_cookie_overrides_session_cookie(self):
|
||||
s = requests.session()
|
||||
s.cookies['foo'] = 'bar'
|
||||
@@ -867,5 +873,26 @@ class TestCaseInsensitiveDict(unittest.TestCase):
|
||||
self.assertEqual(frozenset(cid), keyset)
|
||||
|
||||
|
||||
class UtilsTestCase(unittest.TestCase):
|
||||
|
||||
def test_super_len_io_streams(self):
|
||||
""" Ensures that we properly deal with different kinds of IO streams. """
|
||||
# uses StringIO or io.StringIO (see import above)
|
||||
from io import BytesIO
|
||||
from requests.utils import super_len
|
||||
|
||||
self.assertEqual(super_len(StringIO.StringIO()), 0)
|
||||
self.assertEqual(super_len(StringIO.StringIO('with so much drama in the LBC')), 29)
|
||||
|
||||
self.assertEqual(super_len(BytesIO()), 0)
|
||||
self.assertEqual(super_len(BytesIO(b"it's kinda hard bein' snoop d-o-double-g")), 40)
|
||||
|
||||
try:
|
||||
import cStringIO
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
self.assertEqual(super_len(cStringIO.StringIO('but some how, some way...')), 25)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user