Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Lib/_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,10 @@ def _finish_closing(self, _):
log.debug("Closed child socket %s not yet accepted", child, extra={"sock": self})
child.close()
else:
if self.incoming_head is not None:
if self.incoming_head is not _PEER_CLOSED:
self.incoming_head.release()
self.incoming_head = None
msgs = []
self.incoming.drainTo(msgs)
for msg in msgs:
Expand Down
41 changes: 35 additions & 6 deletions Lib/test/test_httplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import errno
import os
import tempfile
import urlparse

import unittest
TestCase = unittest.TestCase
Expand All @@ -22,6 +23,26 @@

HOST = test_support.HOST

def _external_https_connection(host, port=443, **kwargs):
proxy = _https_proxy()
if proxy is None:
return httplib.HTTPSConnection(host, port, **kwargs)
proxy_host, proxy_port = proxy
conn = httplib.HTTPSConnection(proxy_host, proxy_port, **kwargs)
conn.set_tunnel(host, port)
return conn

def _https_proxy():
for name in ('https_proxy', 'HTTPS_PROXY', 'http_proxy', 'HTTP_PROXY'):
proxy = os.environ.get(name)
if proxy:
if '://' not in proxy:
proxy = '//' + proxy
parsed = urlparse.urlparse(proxy)
if parsed.hostname:
return parsed.hostname, parsed.port or 80
return None

class FakeSocket:
def __init__(self, text, fileclass=StringIO.StringIO, host=None, port=None):
self.text = text
Expand Down Expand Up @@ -827,7 +848,7 @@ def test_networked(self):
import ssl
test_support.requires('network')
with test_support.transient_internet('self-signed.pythontest.net'):
h = httplib.HTTPSConnection('self-signed.pythontest.net', 443)
h = _external_https_connection('self-signed.pythontest.net', 443)
with self.assertRaises(ssl.SSLError) as exc_info:
h.request('GET', '/')
if test_support.is_jython:
Expand All @@ -840,18 +861,19 @@ def test_networked_noverification(self):
test_support.requires('network')
with test_support.transient_internet('self-signed.pythontest.net'):
context = ssl._create_stdlib_context()
h = httplib.HTTPSConnection('self-signed.pythontest.net', 443,
context=context)
h = _external_https_connection('self-signed.pythontest.net', 443,
context=context)
h.request('GET', '/')
resp = h.getresponse()
self.assertIn('nginx', resp.getheader('server'))

@test_support.system_must_validate_cert
def test_networked_trusted_by_default_cert(self):
# Default settings: requires a valid cert from a trusted CA
# www.pythontest.net intentionally uses a self-signed certificate.
test_support.requires('network')
with test_support.transient_internet('www.python.org'):
h = httplib.HTTPSConnection('www.python.org', 443)
h = _external_https_connection('www.python.org', 443)
h.request('GET', '/')
resp = h.getresponse()
content_type = resp.getheader('content-type')
Expand All @@ -865,7 +887,7 @@ def test_networked_good_cert(self):
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
h = _external_https_connection('self-signed.pythontest.net', 443, context=context)
h.request('GET', '/')
resp = h.getresponse()
server_string = resp.getheader('server')
Expand All @@ -879,7 +901,7 @@ def test_networked_bad_cert(self):
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations(CERT_localhost)
h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
h = _external_https_connection('self-signed.pythontest.net', 443, context=context)
with self.assertRaises(ssl.SSLError) as exc_info:
h.request('GET', '/')
if test_support.is_jython:
Expand Down Expand Up @@ -996,6 +1018,13 @@ def create_connection(address, timeout=None, source_address=None):

@test_support.reap_threads
def test_main(verbose=None):
if test_support.is_jython:
from java.util.logging import Logger, Level
# Netty logs noisy channel-initializer warnings when tests deliberately
# close localhost sockets in error paths.
Logger.getLogger("io.netty.channel.ChannelInitializer").setLevel(Level.SEVERE)
Logger.getLogger("io.netty.util.concurrent.DefaultPromise").setLevel(Level.OFF)

test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
HTTPTest, HTTPSTest, SourceAddressTest,
TunnelTests)
Expand Down
25 changes: 25 additions & 0 deletions Lib/test/test_os_jy.py
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,30 @@ def test_readlink_nonexistent(self):
self.assertEqual(cm.exception.filename, nonexistent_file)


class EnvironmentVarGuardTestCase(unittest.TestCase):

@unittest.skipUnless(getattr(os, '_name', os.name) == 'nt',
"Windows environment names are case-insensitive")
def test_case_insensitive_unset_restore(self):
lower = "jy_envguard_case_test"
upper = "JY_ENVGUARD_CASE_TEST"
had_value = lower in os.environ or upper in os.environ
original_value = os.environ.get(lower)
os.environ[lower] = "original"
try:
with test_support.EnvironmentVarGuard() as env:
env.unset(lower)
env.unset(upper)
self.assertEqual(os.environ.get(lower), "original")
self.assertEqual(os.environ.get(upper), "original")
finally:
if had_value:
os.environ[lower] = original_value
else:
if lower in os.environ:
del os.environ[lower]


def test_main():
test_support.run_unittest(
OSFileTestCase,
Expand All @@ -545,6 +569,7 @@ def test_main():
SystemTestCase,
LinkTestCase,
SymbolicLinkTestCase,
EnvironmentVarGuardTestCase,
)

if __name__ == '__main__':
Expand Down
8 changes: 5 additions & 3 deletions Lib/test/test_robotparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,12 +300,14 @@ class NetworkTestCase(unittest.TestCase):

def testPythonOrg(self):
support.requires('network')
with support.transient_internet('www.python.org'):
with support.transient_internet('www.pythontest.net'):
parser = robotparser.RobotFileParser(
"http://www.python.org/robots.txt")
"http://www.pythontest.net/robots.txt")
parser.read()
self.assertTrue(
parser.can_fetch("*", "http://www.python.org/robots.txt"))
parser.can_fetch("*", "http://www.pythontest.net/"))
self.assertFalse(
parser.can_fetch("*", "http://www.pythontest.net/no-robots-here/"))

def load_tests(loader, suite, pattern):
suite = unittest.makeSuite(NetworkTestCase)
Expand Down
42 changes: 42 additions & 0 deletions Lib/test/test_smtpnet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env python

import unittest
from test import test_support
import smtplib
import os

test_support.requires("network")


def _external_http_proxy_configured():
return any(os.environ.get(name) for name in (
'http_proxy', 'https_proxy', 'all_proxy',
'HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY'))

class SmtpSSLTest(unittest.TestCase):
testServer = 'smtp.gmail.com'
remotePort = 465

@unittest.skipIf(_external_http_proxy_configured(),
"external SMTP SSL tests require direct network access")
def test_connect(self):
test_support.get_attribute(smtplib, 'SMTP_SSL')
with test_support.transient_internet(self.testServer):
server = smtplib.SMTP_SSL(self.testServer, self.remotePort)
server.ehlo()
server.quit()

@unittest.skipIf(_external_http_proxy_configured(),
"external SMTP SSL tests require direct network access")
def test_connect_default_port(self):
test_support.get_attribute(smtplib, 'SMTP_SSL')
with test_support.transient_internet(self.testServer):
server = smtplib.SMTP_SSL(self.testServer)
server.ehlo()
server.quit()

def test_main():
test_support.run_unittest(SmtpSSLTest)

if __name__ == "__main__":
test_main()
35 changes: 33 additions & 2 deletions Lib/test/test_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

PORT = 50100
HOST = 'localhost'
UNREACHABLE_HOST = java.lang.System.getProperty(
'jython.test.socket.unreachableHost', '192.0.2.42')
MSG = 'Michael Gilfix was here\n'
EIGHT_BIT_MSG = 'Bh\xed Al\xe1in \xd3 Cinn\xe9ide anseo\n'
os_name = platform.java_ver()[3][0]
Expand Down Expand Up @@ -221,6 +223,16 @@ def clientSetUp(self):
self.cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.cli.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

def clientTearDown(self):
# Do not leave datagram channels for JVM finalization. On Windows,
# especially when regrtest is writing JUnit XML for the whole suite,
# delayed Netty socket cleanup can leave enough old selector/channel
# state around for the following threaded UDP tests to block forever
# waiting for a datagram that was sent by the client side.
self.cli.close()
self.cli = None
ThreadableTest.clientTearDown(self)

class SocketConnectedTest(ThreadedTCPSocketTest):

def __init__(self, methodName='runTest'):
Expand Down Expand Up @@ -1358,6 +1370,9 @@ def _testAcceptConnection(self):
def testBlockingConnect(self):
# Testing blocking connect
conn, addr = self.serv.accept()
# Close the accepted server-side socket explicitly. Relying on
# finalization to release the fixed test port can race later tests.
conn.close()

def _testBlockingConnect(self):
# Testing blocking connect
Expand Down Expand Up @@ -1480,6 +1495,9 @@ def testCloseFileDoesNotCloseSocket(self):
# This test is necessary on java/jython
msg = self.cli_conn.recv(1024)
self.assertEqual(msg, MSG)
# Close the accepted server-side socket explicitly. Relying on
# finalization to release the fixed test port can race later tests.
self.cli_conn.close()

def _testCloseFileDoesNotCloseSocket(self):
self.cli_file = self.serv_conn.makefile('wb')
Expand All @@ -1492,6 +1510,9 @@ def _testCloseFileDoesNotCloseSocket(self):
def testCloseSocketDoesNotCloseFile(self):
msg = self.cli_conn.recv(1024)
self.assertEqual(msg, MSG)
# Close the accepted server-side socket explicitly. Relying on
# finalization to release the fixed test port can race later tests.
self.cli_conn.close()

def _testCloseSocketDoesNotCloseFile(self):
self.cli_file = self.serv_conn.makefile('wb')
Expand Down Expand Up @@ -1537,6 +1558,9 @@ def testCloseDoesNotCloseOthers(self):

msg = self.cli_conn.recv(len('and ' + MSG))
self.assertEqual(msg, 'and ' + MSG)
# Close the accepted server-side socket explicitly. Relying on
# finalization to release the fixed test port can race later tests.
self.cli_conn.close()

def _testCloseDoesNotCloseOthers(self):
self.dup_conn1 = self.serv_conn.dup()
Expand Down Expand Up @@ -1731,7 +1755,7 @@ class TCPClientTimeoutTest(SocketTCPTest):
def testConnectTimeout(self):
cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cli.settimeout(0.1)
host = '192.0.2.42' # address in TEST-NET-1, guaranteed to not be routeable
host = UNREACHABLE_HOST
try:
cli.connect((host, 5000))
except socket.timeout, st:
Expand All @@ -1747,7 +1771,7 @@ def testConnectDefaultTimeout(self):
_saved_timeout = socket.getdefaulttimeout()
socket.setdefaulttimeout(0.1)
cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = '192.0.2.42' # address in TEST-NET-1, guaranteed to not be routeable
host = UNREACHABLE_HOST
try:
cli.connect((host, 5000))
except socket.timeout, st:
Expand Down Expand Up @@ -2599,6 +2623,13 @@ def setUp(self):
self.serverExplicitReady()
self.cli_conn, _ = self.serv.accept()

def tearDown(self):
# Close the accepted server-side socket explicitly. Relying on
# finalization to release the fixed test port can race the next test.
self.cli_conn.close()
self.cli_conn = None
SocketTCPTest.tearDown(self)

def clientSetUp(self):
self.cli = self.config_client()
self.cli.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Expand Down
29 changes: 27 additions & 2 deletions Lib/test/test_ssl_jy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# directly in the original, but this reduces the diff and ongoing merge effort

import errno
import os
import select
import socket
import ssl
Expand All @@ -15,6 +16,20 @@
from test.test_ssl import REMOTE_HOST, REMOTE_ROOT_CERT


def _errno_values(*names):
return tuple(getattr(errno, name) for name in names if hasattr(errno, name))


TRANSIENT_CONNECT_EX = _errno_values(
'ECONNREFUSED', 'EHOSTUNREACH', 'ENETUNREACH', 'ETIMEDOUT',
'EHOSTDOWN', 'ENETDOWN')


def _external_http_proxy_configured():
return any(os.environ.get(name) for name in (
'http_proxy', 'https_proxy', 'all_proxy',
'HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY'))


class BasicSocketTests(test.test_ssl.BasicSocketTests):
@unittest.skip("Jython does not have _ssl, therefore this test needs to be rewritten")
Expand Down Expand Up @@ -142,7 +157,14 @@ def test_subclass(self):
None


@unittest.skipIf(_external_http_proxy_configured(),
"external raw SSL socket tests require direct network access")
class NetworkedTests(test.test_ssl.NetworkedTests):
def _skip_if_remote_unreachable(self, rc):
if rc in TRANSIENT_CONNECT_EX:
self.skipTest("%s is not reachable from this environment" %
(REMOTE_HOST,))

def test_connect_ex(self):
# Issue #11326: check connect_ex() implementation
with support.transient_internet(REMOTE_HOST):
Expand All @@ -151,7 +173,9 @@ def test_connect_ex(self):
ca_certs=REMOTE_ROOT_CERT)
try:
# Jython, errno.EISCONN expected per earlier 2.x versions, not 0
self.assertEqual(errno.EISCONN, s.connect_ex((REMOTE_HOST, 443)))
rc = s.connect_ex((REMOTE_HOST, 443))
self._skip_if_remote_unreachable(rc)
self.assertEqual(errno.EISCONN, rc)
self.assertTrue(s.getpeercert())
finally:
s.close()
Expand All @@ -168,6 +192,7 @@ def test_non_blocking_connect_ex(self):
try:
s.setblocking(False)
rc = s.connect_ex((REMOTE_HOST, 443))
self._skip_if_remote_unreachable(rc)
# EWOULDBLOCK under Windows, EINPROGRESS elsewhere
# Jython added EALREADY, as in Jython connect may have already happened
self.assertIn(rc, (0, errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK))
Expand Down Expand Up @@ -200,6 +225,7 @@ def test_timeout_connect_ex(self):
try:
s.settimeout(0.0000001)
rc = s.connect_ex((REMOTE_HOST, 443))
self._skip_if_remote_unreachable(rc)
if rc == errno.EISCONN:
self.skipTest("REMOTE_HOST responded too quickly")
self.assertIn(rc, (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK))
Expand Down Expand Up @@ -229,4 +255,3 @@ def test_main(verbose=False):

if __name__ == "__main__":
test_main()

Loading