Merge
This commit is contained in:
commit
8c5b748026
|
@ -650,6 +650,10 @@ HTTPRedirectHandler Objects
|
||||||
is the case, :exc:`HTTPError` is raised. See :rfc:`2616` for details of the
|
is the case, :exc:`HTTPError` is raised. See :rfc:`2616` for details of the
|
||||||
precise meanings of the various redirection codes.
|
precise meanings of the various redirection codes.
|
||||||
|
|
||||||
|
An :class:`HTTPError` exception raised as a security consideration if the
|
||||||
|
HTTPRedirectHandler is presented with a redirected url which is not an HTTP,
|
||||||
|
HTTPS or FTP url.
|
||||||
|
|
||||||
|
|
||||||
.. method:: HTTPRedirectHandler.redirect_request(req, fp, code, msg, hdrs, newurl)
|
.. method:: HTTPRedirectHandler.redirect_request(req, fp, code, msg, hdrs, newurl)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
import urllib.error
|
||||||
import http.client
|
import http.client
|
||||||
import email.message
|
import email.message
|
||||||
import io
|
import io
|
||||||
|
@ -206,6 +207,21 @@ Content-Type: text/html; charset=iso-8859-1
|
||||||
finally:
|
finally:
|
||||||
self.unfakehttp()
|
self.unfakehttp()
|
||||||
|
|
||||||
|
def test_invalid_redirect(self):
|
||||||
|
# urlopen() should raise IOError for many error codes.
|
||||||
|
self.fakehttp(b'''HTTP/1.1 302 Found
|
||||||
|
Date: Wed, 02 Jan 2008 03:03:54 GMT
|
||||||
|
Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
|
||||||
|
Location: file://guidocomputer.athome.com:/python/license
|
||||||
|
Connection: close
|
||||||
|
Content-Type: text/html; charset=iso-8859-1
|
||||||
|
''')
|
||||||
|
try:
|
||||||
|
self.assertRaises(urllib.error.HTTPError, urlopen,
|
||||||
|
"http://python.org/")
|
||||||
|
finally:
|
||||||
|
self.unfakehttp()
|
||||||
|
|
||||||
def test_empty_socket(self):
|
def test_empty_socket(self):
|
||||||
# urlopen() raises IOError if the underlying socket does not send any
|
# urlopen() raises IOError if the underlying socket does not send any
|
||||||
# data. (#1680230)
|
# data. (#1680230)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import urllib.request
|
||||||
# The proxy bypass method imported below has logic specific to the OSX
|
# The proxy bypass method imported below has logic specific to the OSX
|
||||||
# proxy config data structure but is testable on all platforms.
|
# proxy config data structure but is testable on all platforms.
|
||||||
from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
|
from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
|
||||||
|
import urllib.error
|
||||||
|
|
||||||
# XXX
|
# XXX
|
||||||
# Request
|
# Request
|
||||||
|
@ -1031,6 +1032,29 @@ class HandlerTests(unittest.TestCase):
|
||||||
self.assertEqual(count,
|
self.assertEqual(count,
|
||||||
urllib.request.HTTPRedirectHandler.max_redirections)
|
urllib.request.HTTPRedirectHandler.max_redirections)
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_redirect(self):
|
||||||
|
from_url = "http://example.com/a.html"
|
||||||
|
valid_schemes = ['http','https','ftp']
|
||||||
|
invalid_schemes = ['file','imap','ldap']
|
||||||
|
schemeless_url = "example.com/b.html"
|
||||||
|
h = urllib.request.HTTPRedirectHandler()
|
||||||
|
o = h.parent = MockOpener()
|
||||||
|
req = Request(from_url)
|
||||||
|
req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
|
||||||
|
|
||||||
|
for scheme in invalid_schemes:
|
||||||
|
invalid_url = scheme + '://' + schemeless_url
|
||||||
|
self.assertRaises(urllib.error.HTTPError, h.http_error_302,
|
||||||
|
req, MockFile(), 302, "Security Loophole",
|
||||||
|
MockHeaders({"location": invalid_url}))
|
||||||
|
|
||||||
|
for scheme in valid_schemes:
|
||||||
|
valid_url = scheme + '://' + schemeless_url
|
||||||
|
h.http_error_302(req, MockFile(), 302, "That's fine",
|
||||||
|
MockHeaders({"location": valid_url}))
|
||||||
|
self.assertEqual(o.req.get_full_url(), valid_url)
|
||||||
|
|
||||||
def test_cookie_redirect(self):
|
def test_cookie_redirect(self):
|
||||||
# cookies shouldn't leak into redirected requests
|
# cookies shouldn't leak into redirected requests
|
||||||
from http.cookiejar import CookieJar
|
from http.cookiejar import CookieJar
|
||||||
|
|
|
@ -545,6 +545,17 @@ class HTTPRedirectHandler(BaseHandler):
|
||||||
|
|
||||||
# fix a possible malformed URL
|
# fix a possible malformed URL
|
||||||
urlparts = urlparse(newurl)
|
urlparts = urlparse(newurl)
|
||||||
|
|
||||||
|
# For security reasons we don't allow redirection to anything other
|
||||||
|
# than http, https or ftp.
|
||||||
|
|
||||||
|
if not urlparts.scheme in ('http', 'https', 'ftp'):
|
||||||
|
raise HTTPError(newurl, code,
|
||||||
|
msg +
|
||||||
|
" - Redirection to url '%s' is not allowed" %
|
||||||
|
newurl,
|
||||||
|
headers, fp)
|
||||||
|
|
||||||
if not urlparts.path:
|
if not urlparts.path:
|
||||||
urlparts = list(urlparts)
|
urlparts = list(urlparts)
|
||||||
urlparts[2] = "/"
|
urlparts[2] = "/"
|
||||||
|
@ -1903,8 +1914,24 @@ class FancyURLopener(URLopener):
|
||||||
return
|
return
|
||||||
void = fp.read()
|
void = fp.read()
|
||||||
fp.close()
|
fp.close()
|
||||||
|
|
||||||
# In case the server sent a relative URL, join with original:
|
# In case the server sent a relative URL, join with original:
|
||||||
newurl = urljoin(self.type + ":" + url, newurl)
|
newurl = urljoin(self.type + ":" + url, newurl)
|
||||||
|
|
||||||
|
urlparts = urlparse(newurl)
|
||||||
|
|
||||||
|
# For security reasons, we don't allow redirection to anything other
|
||||||
|
# than http, https and ftp.
|
||||||
|
|
||||||
|
# We are using newer HTTPError with older redirect_internal method
|
||||||
|
# This older method will get deprecated in 3.3
|
||||||
|
|
||||||
|
if not urlparts.scheme in ('http', 'https', 'ftp'):
|
||||||
|
raise HTTPError(newurl, errcode,
|
||||||
|
errmsg +
|
||||||
|
" Redirection to url '%s' is not allowed." % newurl,
|
||||||
|
headers, fp)
|
||||||
|
|
||||||
return self.open(newurl)
|
return self.open(newurl)
|
||||||
|
|
||||||
def http_error_301(self, url, fp, errcode, errmsg, headers, data=None):
|
def http_error_301(self, url, fp, errcode, errmsg, headers, data=None):
|
||||||
|
|
|
@ -74,6 +74,9 @@ Library
|
||||||
- Issue #11666: let help() display named tuple attributes and methods
|
- Issue #11666: let help() display named tuple attributes and methods
|
||||||
that start with a leading underscore.
|
that start with a leading underscore.
|
||||||
|
|
||||||
|
- Issue #11662: Make urllib and urllib2 ignore redirections if the
|
||||||
|
scheme is not HTTP, HTTPS or FTP (CVE-2011-1521).
|
||||||
|
|
||||||
- Issue #5537: Fix time2isoz() and time2netscape() functions of
|
- Issue #5537: Fix time2isoz() and time2netscape() functions of
|
||||||
httplib.cookiejar for expiration year greater than 2038 on 32-bit systems.
|
httplib.cookiejar for expiration year greater than 2038 on 32-bit systems.
|
||||||
|
|
||||||
|
|
|
@ -1002,7 +1002,7 @@ static PyMethodDef deque_methods[] = {
|
||||||
PyDoc_STRVAR(deque_doc,
|
PyDoc_STRVAR(deque_doc,
|
||||||
"deque(iterable[, maxlen]) --> deque object\n\
|
"deque(iterable[, maxlen]) --> deque object\n\
|
||||||
\n\
|
\n\
|
||||||
Build an ordered collection accessible from endpoints only.");
|
Build an ordered collection with optimized access from its endpoints.");
|
||||||
|
|
||||||
static PyTypeObject deque_type = {
|
static PyTypeObject deque_type = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
PyVarObject_HEAD_INIT(NULL, 0)
|
||||||
|
|
Loading…
Reference in New Issue