Commit a183ccfb authored by Jay Oster's avatar Jay Oster

Merge branch 'master' into bug/_py3k_acquire

parents 4b216d90 5f264dfb
...@@ -32,6 +32,13 @@ __all__ = ['get_hub', ...@@ -32,6 +32,13 @@ __all__ = ['get_hub',
'reinit'] 'reinit']
import sys
if sys.platform == 'win32':
import socket # trigger WSAStartup call
del socket
del sys
from gevent.hub import get_hub, iwait, wait, PYPY from gevent.hub import get_hub, iwait, wait, PYPY
from gevent.greenlet import Greenlet, joinall, killall from gevent.greenlet import Greenlet, joinall, killall
spawn = Greenlet.spawn spawn = Greenlet.spawn
......
import signal, subprocess, sys import signal, subprocess, sys, time
# On Linux this causes os.waitpid to fail with OSError as the OS has already # On Linux this causes os.waitpid to fail with OSError as the OS has already
# reaped our child process. The wait() passing the OSError on to the caller # reaped our child process. The wait() passing the OSError on to the caller
# and causing us to exit with an error is what we are testing against. # and causing us to exit with an error is what we are testing against.
signal.signal(signal.SIGCHLD, signal.SIG_IGN) signal.signal(signal.SIGCHLD, signal.SIG_IGN)
subprocess.Popen([sys.executable, '-c', 'print("albatross")']).wait() subprocess.Popen([sys.executable, '-c', 'print("albatross")']).wait()
# Also ensure poll() handles an errno.ECHILD appropriately.
p = subprocess.Popen([sys.executable, '-c', 'print("albatross")'])
num_polls = 0
while p.poll() is None:
# Waiting for the process to finish.
time.sleep(0.01) # Avoid being a CPU busy loop.
num_polls += 1
if num_polls > 3000:
raise RuntimeError('poll should have returned 0 within 30 seconds')
...@@ -7,9 +7,10 @@ import sys ...@@ -7,9 +7,10 @@ import sys
import time import time
import warnings import warnings
import errno import errno
import struct
from test import test_support from test import test_support
from test.test_support import TESTFN, run_unittest, unlink from test.test_support import TESTFN, run_unittest, unlink, HOST
from StringIO import StringIO from StringIO import StringIO
try: try:
...@@ -17,7 +18,6 @@ try: ...@@ -17,7 +18,6 @@ try:
except ImportError: except ImportError:
threading = None threading = None
HOST = test_support.HOST
class dummysocket: class dummysocket:
def __init__(self): def __init__(self):
...@@ -483,8 +483,9 @@ class TCPServer(asyncore.dispatcher): ...@@ -483,8 +483,9 @@ class TCPServer(asyncore.dispatcher):
return self.socket.getsockname()[:2] return self.socket.getsockname()[:2]
def handle_accept(self): def handle_accept(self):
sock, addr = self.accept() pair = self.accept()
self.handler(sock) if pair is not None:
self.handler(pair[0])
def handle_error(self): def handle_error(self):
raise raise
...@@ -703,6 +704,27 @@ class BaseTestAPI(unittest.TestCase): ...@@ -703,6 +704,27 @@ class BaseTestAPI(unittest.TestCase):
finally: finally:
sock.close() sock.close()
@unittest.skipUnless(threading, 'Threading required for this test.')
@test_support.reap_threads
def test_quick_connect(self):
# see: http://bugs.python.org/issue10340
server = TCPServer()
t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1, count=500))
t.start()
self.addCleanup(t.join)
for x in xrange(20):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(.2)
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
struct.pack('ii', 1, 0))
try:
s.connect(server.address)
except socket.error:
pass
finally:
s.close()
class TestAPI_UseSelect(BaseTestAPI): class TestAPI_UseSelect(BaseTestAPI):
use_poll = False use_poll = False
......
...@@ -15,9 +15,9 @@ try: ...@@ -15,9 +15,9 @@ try:
except ImportError: except ImportError:
ssl = None ssl = None
from unittest import TestCase from unittest import TestCase, SkipTest, skipUnless
from test import test_support from test import test_support
from test.test_support import HOST from test.test_support import HOST, HOSTv6
threading = test_support.import_module('threading') threading = test_support.import_module('threading')
...@@ -65,6 +65,7 @@ class DummyFTPHandler(asynchat.async_chat): ...@@ -65,6 +65,7 @@ class DummyFTPHandler(asynchat.async_chat):
self.last_received_data = '' self.last_received_data = ''
self.next_response = '' self.next_response = ''
self.rest = None self.rest = None
self.next_retr_data = RETR_DATA
self.push('220 welcome') self.push('220 welcome')
def collect_incoming_data(self, data): def collect_incoming_data(self, data):
...@@ -189,7 +190,7 @@ class DummyFTPHandler(asynchat.async_chat): ...@@ -189,7 +190,7 @@ class DummyFTPHandler(asynchat.async_chat):
offset = int(self.rest) offset = int(self.rest)
else: else:
offset = 0 offset = 0
self.dtp.push(RETR_DATA[offset:]) self.dtp.push(self.next_retr_data[offset:])
self.dtp.close_when_done() self.dtp.close_when_done()
self.rest = None self.rest = None
...@@ -203,6 +204,11 @@ class DummyFTPHandler(asynchat.async_chat): ...@@ -203,6 +204,11 @@ class DummyFTPHandler(asynchat.async_chat):
self.dtp.push(NLST_DATA) self.dtp.push(NLST_DATA)
self.dtp.close_when_done() self.dtp.close_when_done()
def cmd_setlongretr(self, arg):
# For testing. Next RETR will return long line.
self.next_retr_data = 'x' * int(arg)
self.push('125 setlongretr ok')
class DummyFTPServer(asyncore.dispatcher, threading.Thread): class DummyFTPServer(asyncore.dispatcher, threading.Thread):
...@@ -474,6 +480,14 @@ class TestFTPClass(TestCase): ...@@ -474,6 +480,14 @@ class TestFTPClass(TestCase):
def test_rmd(self): def test_rmd(self):
self.client.rmd('foo') self.client.rmd('foo')
def test_cwd(self):
dir = self.client.cwd('/foo')
self.assertEqual(dir, '250 cwd ok')
def test_mkd(self):
dir = self.client.mkd('/foo')
self.assertEqual(dir, '/foo')
def test_pwd(self): def test_pwd(self):
dir = self.client.pwd() dir = self.client.pwd()
self.assertEqual(dir, 'pwd ok') self.assertEqual(dir, 'pwd ok')
...@@ -550,11 +564,33 @@ class TestFTPClass(TestCase): ...@@ -550,11 +564,33 @@ class TestFTPClass(TestCase):
# IPv4 is in use, just make sure send_epsv has not been used # IPv4 is in use, just make sure send_epsv has not been used
self.assertEqual(self.server.handler.last_received_cmd, 'pasv') self.assertEqual(self.server.handler.last_received_cmd, 'pasv')
def test_line_too_long(self):
self.assertRaises(ftplib.Error, self.client.sendcmd,
'x' * self.client.maxline * 2)
def test_retrlines_too_long(self):
self.client.sendcmd('SETLONGRETR %d' % (self.client.maxline * 2))
received = []
self.assertRaises(ftplib.Error,
self.client.retrlines, 'retr', received.append)
def test_storlines_too_long(self):
f = StringIO.StringIO('x' * self.client.maxline * 2)
self.assertRaises(ftplib.Error, self.client.storlines, 'stor', f)
@skipUnless(socket.has_ipv6, "IPv6 not enabled")
class TestIPv6Environment(TestCase): class TestIPv6Environment(TestCase):
@classmethod
def setUpClass(cls):
try:
DummyFTPServer((HOST, 0), af=socket.AF_INET6)
except socket.error:
raise SkipTest("IPv6 not enabled")
def setUp(self): def setUp(self):
self.server = DummyFTPServer((HOST, 0), af=socket.AF_INET6) self.server = DummyFTPServer((HOSTv6, 0), af=socket.AF_INET6)
self.server.start() self.server.start()
self.client = ftplib.FTP() self.client = ftplib.FTP()
self.client.connect(self.server.host, self.server.port) self.client.connect(self.server.host, self.server.port)
...@@ -587,6 +623,7 @@ class TestIPv6Environment(TestCase): ...@@ -587,6 +623,7 @@ class TestIPv6Environment(TestCase):
retr() retr()
@skipUnless(ssl, "SSL not available")
class TestTLS_FTPClassMixin(TestFTPClass): class TestTLS_FTPClassMixin(TestFTPClass):
"""Repeat TestFTPClass tests starting the TLS layer for both control """Repeat TestFTPClass tests starting the TLS layer for both control
and data connections first. and data connections first.
...@@ -602,6 +639,7 @@ class TestTLS_FTPClassMixin(TestFTPClass): ...@@ -602,6 +639,7 @@ class TestTLS_FTPClassMixin(TestFTPClass):
self.client.prot_p() self.client.prot_p()
@skipUnless(ssl, "SSL not available")
class TestTLS_FTPClass(TestCase): class TestTLS_FTPClass(TestCase):
"""Specific TLS_FTP class tests.""" """Specific TLS_FTP class tests."""
...@@ -702,10 +740,10 @@ class TestTimeouts(TestCase): ...@@ -702,10 +740,10 @@ class TestTimeouts(TestCase):
def testTimeoutDefault(self): def testTimeoutDefault(self):
# default -- use global socket timeout # default -- use global socket timeout
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
try: try:
ftp = ftplib.FTP("localhost") ftp = ftplib.FTP(HOST)
finally: finally:
socket.setdefaulttimeout(None) socket.setdefaulttimeout(None)
self.assertEqual(ftp.sock.gettimeout(), 30) self.assertEqual(ftp.sock.gettimeout(), 30)
...@@ -714,13 +752,13 @@ class TestTimeouts(TestCase): ...@@ -714,13 +752,13 @@ class TestTimeouts(TestCase):
def testTimeoutNone(self): def testTimeoutNone(self):
# no timeout -- do not use global socket timeout # no timeout -- do not use global socket timeout
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
try: try:
ftp = ftplib.FTP("localhost", timeout=None) ftp = ftplib.FTP(HOST, timeout=None)
finally: finally:
socket.setdefaulttimeout(None) socket.setdefaulttimeout(None)
self.assertTrue(ftp.sock.gettimeout() is None) self.assertIsNone(ftp.sock.gettimeout())
self.evt.wait() self.evt.wait()
ftp.close() ftp.close()
...@@ -755,17 +793,9 @@ class TestTimeouts(TestCase): ...@@ -755,17 +793,9 @@ class TestTimeouts(TestCase):
def test_main(): def test_main():
tests = [TestFTPClass, TestTimeouts] tests = [TestFTPClass, TestTimeouts,
if socket.has_ipv6: TestIPv6Environment,
try: TestTLS_FTPClassMixin, TestTLS_FTPClass]
DummyFTPServer((HOST, 0), af=socket.AF_INET6)
except socket.error:
pass
else:
tests.append(TestIPv6Environment)
if ssl is not None:
tests.extend([TestTLS_FTPClassMixin, TestTLS_FTPClass])
thread_info = test_support.threading_setup() thread_info = test_support.threading_setup()
try: try:
......
...@@ -13,10 +13,12 @@ from test import test_support ...@@ -13,10 +13,12 @@ from test import test_support
HOST = test_support.HOST HOST = test_support.HOST
class FakeSocket: class FakeSocket:
def __init__(self, text, fileclass=StringIO.StringIO): def __init__(self, text, fileclass=StringIO.StringIO, host=None, port=None):
self.text = text self.text = text
self.fileclass = fileclass self.fileclass = fileclass
self.data = '' self.data = ''
self.host = host
self.port = port
def sendall(self, data): def sendall(self, data):
self.data += ''.join(data) self.data += ''.join(data)
...@@ -26,6 +28,9 @@ class FakeSocket: ...@@ -26,6 +28,9 @@ class FakeSocket:
raise httplib.UnimplementedFileMode() raise httplib.UnimplementedFileMode()
return self.fileclass(self.text) return self.fileclass(self.text)
def close(self):
pass
class EPipeSocket(FakeSocket): class EPipeSocket(FakeSocket):
def __init__(self, text, pipe_trigger): def __init__(self, text, pipe_trigger):
...@@ -90,12 +95,40 @@ class HeaderTests(TestCase): ...@@ -90,12 +95,40 @@ class HeaderTests(TestCase):
conn.request('POST', '/', body, headers) conn.request('POST', '/', body, headers)
self.assertEqual(conn._buffer.count[header.lower()], 1) self.assertEqual(conn._buffer.count[header.lower()], 1)
def test_content_length_0(self):
class ContentLengthChecker(list):
def __init__(self):
list.__init__(self)
self.content_length = None
def append(self, item):
kv = item.split(':', 1)
if len(kv) > 1 and kv[0].lower() == 'content-length':
self.content_length = kv[1].strip()
list.append(self, item)
# POST with empty body
conn = httplib.HTTPConnection('example.com')
conn.sock = FakeSocket(None)
conn._buffer = ContentLengthChecker()
conn.request('POST', '/', '')
self.assertEqual(conn._buffer.content_length, '0',
'Header Content-Length not set')
# PUT request with empty body
conn = httplib.HTTPConnection('example.com')
conn.sock = FakeSocket(None)
conn._buffer = ContentLengthChecker()
conn.request('PUT', '/', '')
self.assertEqual(conn._buffer.content_length, '0',
'Header Content-Length not set')
def test_putheader(self): def test_putheader(self):
conn = httplib.HTTPConnection('example.com') conn = httplib.HTTPConnection('example.com')
conn.sock = FakeSocket(None) conn.sock = FakeSocket(None)
conn.putrequest('GET','/') conn.putrequest('GET','/')
conn.putheader('Content-length',42) conn.putheader('Content-length',42)
self.assertTrue('Content-length: 42' in conn._buffer) self.assertIn('Content-length: 42', conn._buffer)
def test_ipv6host_header(self): def test_ipv6host_header(self):
# Default host header on IPv6 transaction should wrapped by [] if # Default host header on IPv6 transaction should wrapped by [] if
...@@ -125,6 +158,8 @@ class BasicTest(TestCase): ...@@ -125,6 +158,8 @@ class BasicTest(TestCase):
sock = FakeSocket(body) sock = FakeSocket(body)
resp = httplib.HTTPResponse(sock) resp = httplib.HTTPResponse(sock)
resp.begin() resp.begin()
self.assertEqual(resp.read(0), '') # Issue #20007
self.assertFalse(resp.isclosed())
self.assertEqual(resp.read(), 'Text') self.assertEqual(resp.read(), 'Text')
self.assertTrue(resp.isclosed()) self.assertTrue(resp.isclosed())
...@@ -138,7 +173,7 @@ class BasicTest(TestCase): ...@@ -138,7 +173,7 @@ class BasicTest(TestCase):
self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''') self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''')
def test_partial_reads(self): def test_partial_reads(self):
# if we have a lenght, the system knows when to close itself # if we have a length, the system knows when to close itself
# same behaviour than when we read the whole thing with read() # same behaviour than when we read the whole thing with read()
body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText" body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
sock = FakeSocket(body) sock = FakeSocket(body)
...@@ -149,6 +184,32 @@ class BasicTest(TestCase): ...@@ -149,6 +184,32 @@ class BasicTest(TestCase):
self.assertEqual(resp.read(2), 'xt') self.assertEqual(resp.read(2), 'xt')
self.assertTrue(resp.isclosed()) self.assertTrue(resp.isclosed())
def test_partial_reads_no_content_length(self):
# when no length is present, the socket should be gracefully closed when
# all data was read
body = "HTTP/1.1 200 Ok\r\n\r\nText"
sock = FakeSocket(body)
resp = httplib.HTTPResponse(sock)
resp.begin()
self.assertEqual(resp.read(2), 'Te')
self.assertFalse(resp.isclosed())
self.assertEqual(resp.read(2), 'xt')
self.assertEqual(resp.read(1), '')
self.assertTrue(resp.isclosed())
def test_partial_reads_incomplete_body(self):
# if the server shuts down the connection before the whole
# content-length is delivered, the socket is gracefully closed
body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
sock = FakeSocket(body)
resp = httplib.HTTPResponse(sock)
resp.begin()
self.assertEqual(resp.read(2), 'Te')
self.assertFalse(resp.isclosed())
self.assertEqual(resp.read(2), 'xt')
self.assertEqual(resp.read(1), '')
self.assertTrue(resp.isclosed())
def test_host_port(self): def test_host_port(self):
# Check invalid host_port # Check invalid host_port
...@@ -279,7 +340,7 @@ class BasicTest(TestCase): ...@@ -279,7 +340,7 @@ class BasicTest(TestCase):
resp = httplib.HTTPResponse(sock, method="GET") resp = httplib.HTTPResponse(sock, method="GET")
resp.begin() resp.begin()
self.assertEqual(resp.read(), 'Hello\r\n') self.assertEqual(resp.read(), 'Hello\r\n')
resp.close() self.assertTrue(resp.isclosed())
def test_incomplete_read(self): def test_incomplete_read(self):
sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n') sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
...@@ -293,10 +354,9 @@ class BasicTest(TestCase): ...@@ -293,10 +354,9 @@ class BasicTest(TestCase):
"IncompleteRead(7 bytes read, 3 more expected)") "IncompleteRead(7 bytes read, 3 more expected)")
self.assertEqual(str(i), self.assertEqual(str(i),
"IncompleteRead(7 bytes read, 3 more expected)") "IncompleteRead(7 bytes read, 3 more expected)")
self.assertTrue(resp.isclosed())
else: else:
self.fail('IncompleteRead expected') self.fail('IncompleteRead expected')
finally:
resp.close()
def test_epipe(self): def test_epipe(self):
sock = EPipeSocket( sock = EPipeSocket(
...@@ -349,6 +409,14 @@ class BasicTest(TestCase): ...@@ -349,6 +409,14 @@ class BasicTest(TestCase):
resp.begin() resp.begin()
self.assertRaises(httplib.LineTooLong, resp.read) self.assertRaises(httplib.LineTooLong, resp.read)
def test_early_eof(self):
# Test httpresponse with no \r\n termination,
body = "HTTP/1.1 200 Ok"
sock = FakeSocket(body)
resp = httplib.HTTPResponse(sock)
resp.begin()
self.assertEqual(resp.read(), '')
self.assertTrue(resp.isclosed())
class OfflineTest(TestCase): class OfflineTest(TestCase):
def test_responses(self): def test_responses(self):
...@@ -403,7 +471,7 @@ class TimeoutTest(TestCase): ...@@ -403,7 +471,7 @@ class TimeoutTest(TestCase):
HTTPConnection and into the socket. HTTPConnection and into the socket.
''' '''
# default -- use global socket timeout # default -- use global socket timeout
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
try: try:
httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT) httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT)
...@@ -414,7 +482,7 @@ class TimeoutTest(TestCase): ...@@ -414,7 +482,7 @@ class TimeoutTest(TestCase):
httpConn.close() httpConn.close()
# no timeout -- do not use global socket default # no timeout -- do not use global socket default
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
try: try:
httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT, httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT,
...@@ -463,9 +531,48 @@ class HTTPSTimeoutTest(TestCase): ...@@ -463,9 +531,48 @@ class HTTPSTimeoutTest(TestCase):
self.fail("Port incorrectly parsed: %s != %s" % (p, c.host)) self.fail("Port incorrectly parsed: %s != %s" % (p, c.host))
class TunnelTests(TestCase):
def test_connect(self):
response_text = (
'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
'HTTP/1.1 200 OK\r\n' # Reply to HEAD
'Content-Length: 42\r\n\r\n'
)
def create_connection(address, timeout=None, source_address=None):
return FakeSocket(response_text, host=address[0], port=address[1])
conn = httplib.HTTPConnection('proxy.com')
conn._create_connection = create_connection
# Once connected, we should not be able to tunnel anymore
conn.connect()
self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com')
# But if close the connection, we are good.
conn.close()
conn.set_tunnel('destination.com')
conn.request('HEAD', '/', '')
self.assertEqual(conn.sock.host, 'proxy.com')
self.assertEqual(conn.sock.port, 80)
self.assertTrue('CONNECT destination.com' in conn.sock.data)
self.assertTrue('Host: destination.com' in conn.sock.data)
self.assertTrue('Host: proxy.com' not in conn.sock.data)
conn.close()
conn.request('PUT', '/', '')
self.assertEqual(conn.sock.host, 'proxy.com')
self.assertEqual(conn.sock.port, 80)
self.assertTrue('CONNECT destination.com' in conn.sock.data)
self.assertTrue('Host: destination.com' in conn.sock.data)
def test_main(verbose=None): def test_main(verbose=None):
test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest, test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
HTTPSTimeoutTest, SourceAddressTest) HTTPSTimeoutTest, SourceAddressTest, TunnelTests)
if __name__ == '__main__': if __name__ == '__main__':
test_main() test_main()
...@@ -4,11 +4,6 @@ Written by Cody A.W. Somerville <cody-somerville@ubuntu.com>, ...@@ -4,11 +4,6 @@ Written by Cody A.W. Somerville <cody-somerville@ubuntu.com>,
Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest. Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest.
""" """
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
from CGIHTTPServer import CGIHTTPRequestHandler
import CGIHTTPServer
import os import os
import sys import sys
import re import re
...@@ -17,12 +12,17 @@ import shutil ...@@ -17,12 +12,17 @@ import shutil
import urllib import urllib
import httplib import httplib
import tempfile import tempfile
import unittest import unittest
import CGIHTTPServer
from StringIO import StringIO
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
from CGIHTTPServer import CGIHTTPRequestHandler
from StringIO import StringIO
from test import test_support from test import test_support
threading = test_support.import_module('threading') threading = test_support.import_module('threading')
...@@ -43,7 +43,7 @@ class SocketlessRequestHandler(SimpleHTTPRequestHandler): ...@@ -43,7 +43,7 @@ class SocketlessRequestHandler(SimpleHTTPRequestHandler):
self.end_headers() self.end_headers()
self.wfile.write(b'<html><body>Data</body></html>\r\n') self.wfile.write(b'<html><body>Data</body></html>\r\n')
def log_message(self, format, *args): def log_message(self, fmt, *args):
pass pass
...@@ -97,9 +97,9 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase): ...@@ -97,9 +97,9 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase):
self.handler = SocketlessRequestHandler() self.handler = SocketlessRequestHandler()
def send_typical_request(self, message): def send_typical_request(self, message):
input = StringIO(message) input_msg = StringIO(message)
output = StringIO() output = StringIO()
self.handler.rfile = input self.handler.rfile = input_msg
self.handler.wfile = output self.handler.wfile = output
self.handler.handle_one_request() self.handler.handle_one_request()
output.seek(0) output.seek(0)
...@@ -114,7 +114,7 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase): ...@@ -114,7 +114,7 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase):
def verify_http_server_response(self, response): def verify_http_server_response(self, response):
match = self.HTTPResponseMatch.search(response) match = self.HTTPResponseMatch.search(response)
self.assertTrue(match is not None) self.assertIsNotNone(match)
def test_http_1_1(self): def test_http_1_1(self):
result = self.send_typical_request('GET / HTTP/1.1\r\n\r\n') result = self.send_typical_request('GET / HTTP/1.1\r\n\r\n')
...@@ -189,7 +189,7 @@ class BaseHTTPServerTestCase(BaseTestCase): ...@@ -189,7 +189,7 @@ class BaseHTTPServerTestCase(BaseTestCase):
def test_request_line_trimming(self): def test_request_line_trimming(self):
self.con._http_vsn_str = 'HTTP/1.1\n' self.con._http_vsn_str = 'HTTP/1.1\n'
self.con.putrequest('GET', '/') self.con.putrequest('XYZBOGUS', '/')
self.con.endheaders() self.con.endheaders()
res = self.con.getresponse() res = self.con.getresponse()
self.assertEqual(res.status, 501) self.assertEqual(res.status, 501)
...@@ -216,8 +216,9 @@ class BaseHTTPServerTestCase(BaseTestCase): ...@@ -216,8 +216,9 @@ class BaseHTTPServerTestCase(BaseTestCase):
self.assertEqual(res.status, 501) self.assertEqual(res.status, 501)
def test_version_none(self): def test_version_none(self):
# Test that a valid method is rejected when not HTTP/1.x
self.con._http_vsn_str = '' self.con._http_vsn_str = ''
self.con.putrequest('PUT', '/') self.con.putrequest('CUSTOM', '/')
self.con.endheaders() self.con.endheaders()
res = self.con.getresponse() res = self.con.getresponse()
self.assertEqual(res.status, 400) self.assertEqual(res.status, 400)
...@@ -296,7 +297,7 @@ class SimpleHTTPServerTestCase(BaseTestCase): ...@@ -296,7 +297,7 @@ class SimpleHTTPServerTestCase(BaseTestCase):
os.chdir(self.cwd) os.chdir(self.cwd)
try: try:
shutil.rmtree(self.tempdir) shutil.rmtree(self.tempdir)
except: except OSError:
pass pass
finally: finally:
BaseTestCase.tearDown(self) BaseTestCase.tearDown(self)
...@@ -313,6 +314,9 @@ class SimpleHTTPServerTestCase(BaseTestCase): ...@@ -313,6 +314,9 @@ class SimpleHTTPServerTestCase(BaseTestCase):
#constructs the path relative to the root directory of the HTTPServer #constructs the path relative to the root directory of the HTTPServer
response = self.request(self.tempdir_name + '/test') response = self.request(self.tempdir_name + '/test')
self.check_status_and_reason(response, 200, data=self.data) self.check_status_and_reason(response, 200, data=self.data)
# check for trailing "/" which should return 404. See Issue17324
response = self.request(self.tempdir_name + '/test/')
self.check_status_and_reason(response, 404)
response = self.request(self.tempdir_name + '/') response = self.request(self.tempdir_name + '/')
self.check_status_and_reason(response, 200) self.check_status_and_reason(response, 200)
response = self.request(self.tempdir_name) response = self.request(self.tempdir_name)
...@@ -321,17 +325,16 @@ class SimpleHTTPServerTestCase(BaseTestCase): ...@@ -321,17 +325,16 @@ class SimpleHTTPServerTestCase(BaseTestCase):
self.check_status_and_reason(response, 404) self.check_status_and_reason(response, 404)
response = self.request('/' + 'ThisDoesNotExist' + '/') response = self.request('/' + 'ThisDoesNotExist' + '/')
self.check_status_and_reason(response, 404) self.check_status_and_reason(response, 404)
f = open(os.path.join(self.tempdir_name, 'index.html'), 'w') with open(os.path.join(self.tempdir_name, 'index.html'), 'w') as fp:
response = self.request('/' + self.tempdir_name + '/') response = self.request('/' + self.tempdir_name + '/')
self.check_status_and_reason(response, 200) self.check_status_and_reason(response, 200)
# chmod() doesn't work as expected on Windows, and filesystem
# chmod() doesn't work as expected on Windows, and filesystem # permissions are ignored by root on Unix.
# permissions are ignored by root on Unix. if os.name == 'posix' and os.geteuid() != 0:
if os.name == 'posix' and os.geteuid() != 0: os.chmod(self.tempdir, 0)
os.chmod(self.tempdir, 0) response = self.request(self.tempdir_name + '/')
response = self.request(self.tempdir_name + '/') self.check_status_and_reason(response, 404)
self.check_status_and_reason(response, 404) os.chmod(self.tempdir, 0755)
os.chmod(self.tempdir, 0755)
def test_head(self): def test_head(self):
response = self.request( response = self.request(
...@@ -393,6 +396,11 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -393,6 +396,11 @@ class CGIHTTPServerTestCase(BaseTestCase):
else: else:
self.pythonexe = sys.executable self.pythonexe = sys.executable
self.nocgi_path = os.path.join(self.parent_dir, 'nocgi.py')
with open(self.nocgi_path, 'w') as fp:
fp.write(cgi_file1 % self.pythonexe)
os.chmod(self.nocgi_path, 0777)
self.file1_path = os.path.join(self.cgi_dir, 'file1.py') self.file1_path = os.path.join(self.cgi_dir, 'file1.py')
with open(self.file1_path, 'w') as file1: with open(self.file1_path, 'w') as file1:
file1.write(cgi_file1 % self.pythonexe) file1.write(cgi_file1 % self.pythonexe)
...@@ -411,6 +419,7 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -411,6 +419,7 @@ class CGIHTTPServerTestCase(BaseTestCase):
os.chdir(self.cwd) os.chdir(self.cwd)
if self.pythonexe != sys.executable: if self.pythonexe != sys.executable:
os.remove(self.pythonexe) os.remove(self.pythonexe)
os.remove(self.nocgi_path)
os.remove(self.file1_path) os.remove(self.file1_path)
os.remove(self.file2_path) os.remove(self.file2_path)
os.rmdir(self.cgi_dir) os.rmdir(self.cgi_dir)
...@@ -418,41 +427,44 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -418,41 +427,44 @@ class CGIHTTPServerTestCase(BaseTestCase):
finally: finally:
BaseTestCase.tearDown(self) BaseTestCase.tearDown(self)
def test_url_collapse_path_split(self): def test_url_collapse_path(self):
# verify tail is the last portion and head is the rest on proper urls
test_vectors = { test_vectors = {
'': ('/', ''), '': '//',
'..': IndexError, '..': IndexError,
'/.//..': IndexError, '/.//..': IndexError,
'/': ('/', ''), '/': '//',
'//': ('/', ''), '//': '//',
'/\\': ('/', '\\'), '/\\': '//\\',
'/.//': ('/', ''), '/.//': '//',
'cgi-bin/file1.py': ('/cgi-bin', 'file1.py'), 'cgi-bin/file1.py': '/cgi-bin/file1.py',
'/cgi-bin/file1.py': ('/cgi-bin', 'file1.py'), '/cgi-bin/file1.py': '/cgi-bin/file1.py',
'a': ('/', 'a'), 'a': '//a',
'/a': ('/', 'a'), '/a': '//a',
'//a': ('/', 'a'), '//a': '//a',
'./a': ('/', 'a'), './a': '//a',
'./C:/': ('/C:', ''), './C:/': '/C:/',
'/a/b': ('/a', 'b'), '/a/b': '/a/b',
'/a/b/': ('/a/b', ''), '/a/b/': '/a/b/',
'/a/b/c/..': ('/a/b', ''), '/a/b/.': '/a/b/',
'/a/b/c/../d': ('/a/b', 'd'), '/a/b/c/..': '/a/b/',
'/a/b/c/../d/e/../f': ('/a/b/d', 'f'), '/a/b/c/../d': '/a/b/d',
'/a/b/c/../d/e/../../f': ('/a/b', 'f'), '/a/b/c/../d/e/../f': '/a/b/d/f',
'/a/b/c/../d/e/.././././..//f': ('/a/b', 'f'), '/a/b/c/../d/e/../../f': '/a/b/f',
'/a/b/c/../d/e/.././././..//f': '/a/b/f',
'../a/b/c/../d/e/.././././..//f': IndexError, '../a/b/c/../d/e/.././././..//f': IndexError,
'/a/b/c/../d/e/../../../f': ('/a', 'f'), '/a/b/c/../d/e/../../../f': '/a/f',
'/a/b/c/../d/e/../../../../f': ('/', 'f'), '/a/b/c/../d/e/../../../../f': '//f',
'/a/b/c/../d/e/../../../../../f': IndexError, '/a/b/c/../d/e/../../../../../f': IndexError,
'/a/b/c/../d/e/../../../../f/..': ('/', ''), '/a/b/c/../d/e/../../../../f/..': '//',
'/a/b/c/../d/e/../../../../f/../.': '//',
} }
for path, expected in test_vectors.iteritems(): for path, expected in test_vectors.iteritems():
if isinstance(expected, type) and issubclass(expected, Exception): if isinstance(expected, type) and issubclass(expected, Exception):
self.assertRaises(expected, self.assertRaises(expected,
CGIHTTPServer._url_collapse_path_split, path) CGIHTTPServer._url_collapse_path, path)
else: else:
actual = CGIHTTPServer._url_collapse_path_split(path) actual = CGIHTTPServer._url_collapse_path(path)
self.assertEqual(expected, actual, self.assertEqual(expected, actual,
msg='path = %r\nGot: %r\nWanted: %r' % msg='path = %r\nGot: %r\nWanted: %r' %
(path, actual, expected)) (path, actual, expected))
...@@ -462,6 +474,10 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -462,6 +474,10 @@ class CGIHTTPServerTestCase(BaseTestCase):
self.assertEqual(('Hello World\n', 'text/html', 200), self.assertEqual(('Hello World\n', 'text/html', 200),
(res.read(), res.getheader('Content-type'), res.status)) (res.read(), res.getheader('Content-type'), res.status))
def test_issue19435(self):
res = self.request('///////////nocgi.py/../cgi-bin/nothere.sh')
self.assertEqual(res.status, 404)
def test_post(self): def test_post(self):
params = urllib.urlencode({'spam' : 1, 'eggs' : 'python', 'bacon' : 123456}) params = urllib.urlencode({'spam' : 1, 'eggs' : 'python', 'bacon' : 123456})
headers = {'Content-type' : 'application/x-www-form-urlencoded'} headers = {'Content-type' : 'application/x-www-form-urlencoded'}
...@@ -495,6 +511,11 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -495,6 +511,11 @@ class CGIHTTPServerTestCase(BaseTestCase):
(res.read(), res.getheader('Content-type'), res.status)) (res.read(), res.getheader('Content-type'), res.status))
self.assertEqual(os.environ['SERVER_SOFTWARE'], signature) self.assertEqual(os.environ['SERVER_SOFTWARE'], signature)
def test_urlquote_decoding_in_cgi_check(self):
res = self.request('/cgi-bin%2ffile1.py')
self.assertEqual((b'Hello World\n', 'text/html', 200),
(res.read(), res.getheader('Content-type'), res.status))
class SimpleHTTPRequestHandlerTestCase(unittest.TestCase): class SimpleHTTPRequestHandlerTestCase(unittest.TestCase):
""" Test url parsing """ """ Test url parsing """
......
...@@ -43,6 +43,9 @@ class _TriggerThread(threading.Thread): ...@@ -43,6 +43,9 @@ class _TriggerThread(threading.Thread):
class BlockingTestMixin: class BlockingTestMixin:
def tearDown(self):
self.t = None
def do_blocking_test(self, block_func, block_args, trigger_func, trigger_args): def do_blocking_test(self, block_func, block_args, trigger_func, trigger_args):
self.t = _TriggerThread(trigger_func, trigger_args) self.t = _TriggerThread(trigger_func, trigger_args)
self.t.start() self.t.start()
...@@ -79,7 +82,7 @@ class BlockingTestMixin: ...@@ -79,7 +82,7 @@ class BlockingTestMixin:
self.fail("trigger thread ended but event never set") self.fail("trigger thread ended but event never set")
class BaseQueueTest(unittest.TestCase, BlockingTestMixin): class BaseQueueTest(BlockingTestMixin):
def setUp(self): def setUp(self):
self.cum = 0 self.cum = 0
self.cumlock = threading.Lock() self.cumlock = threading.Lock()
...@@ -191,13 +194,13 @@ class BaseQueueTest(unittest.TestCase, BlockingTestMixin): ...@@ -191,13 +194,13 @@ class BaseQueueTest(unittest.TestCase, BlockingTestMixin):
self.simple_queue_test(q) self.simple_queue_test(q)
class QueueTest(BaseQueueTest): class QueueTest(BaseQueueTest, unittest.TestCase):
type2test = Queue.Queue type2test = Queue.Queue
class LifoQueueTest(BaseQueueTest): class LifoQueueTest(BaseQueueTest, unittest.TestCase):
type2test = Queue.LifoQueue type2test = Queue.LifoQueue
class PriorityQueueTest(BaseQueueTest): class PriorityQueueTest(BaseQueueTest, unittest.TestCase):
type2test = Queue.PriorityQueue type2test = Queue.PriorityQueue
...@@ -222,7 +225,7 @@ class FailingQueue(Queue.Queue): ...@@ -222,7 +225,7 @@ class FailingQueue(Queue.Queue):
raise FailingQueueException, "You Lose" raise FailingQueueException, "You Lose"
return Queue.Queue._get(self) return Queue.Queue._get(self)
class FailingQueueTest(unittest.TestCase, BlockingTestMixin): class FailingQueueTest(BlockingTestMixin, unittest.TestCase):
def failing_queue_test(self, q): def failing_queue_test(self, q):
if not q.empty(): if not q.empty():
......
...@@ -49,6 +49,15 @@ class SelectTestCase(unittest.TestCase): ...@@ -49,6 +49,15 @@ class SelectTestCase(unittest.TestCase):
self.fail('Unexpected return values from select():', rfd, wfd, xfd) self.fail('Unexpected return values from select():', rfd, wfd, xfd)
p.close() p.close()
# Issue 16230: Crash on select resized list
def test_select_mutated(self):
a = []
class F:
def fileno(self):
del a[-1]
return sys.__stdout__.fileno()
a[:] = [F()] * 10
self.assertEqual(select.select([], a, []), ([], a[:5], []))
def test_main(): def test_main():
test_support.run_unittest(SelectTestCase) test_support.run_unittest(SelectTestCase)
......
...@@ -109,7 +109,7 @@ class InterProcessSignalTests(unittest.TestCase): ...@@ -109,7 +109,7 @@ class InterProcessSignalTests(unittest.TestCase):
# This wait should be interrupted by the signal's exception. # This wait should be interrupted by the signal's exception.
self.wait(child) self.wait(child)
time.sleep(1) # Give the signal time to be delivered. time.sleep(1) # Give the signal time to be delivered.
self.fail('HandlerBCalled exception not thrown') self.fail('HandlerBCalled exception not raised')
except HandlerBCalled: except HandlerBCalled:
self.assertTrue(self.b_called) self.assertTrue(self.b_called)
self.assertFalse(self.a_called) self.assertFalse(self.a_called)
...@@ -148,7 +148,7 @@ class InterProcessSignalTests(unittest.TestCase): ...@@ -148,7 +148,7 @@ class InterProcessSignalTests(unittest.TestCase):
# test-running process from all the signals. It then # test-running process from all the signals. It then
# communicates with that child process over a pipe and # communicates with that child process over a pipe and
# re-raises information about any exceptions the child # re-raises information about any exceptions the child
# throws. The real work happens in self.run_test(). # raises. The real work happens in self.run_test().
os_done_r, os_done_w = os.pipe() os_done_r, os_done_w = os.pipe()
with closing(os.fdopen(os_done_r)) as done_r, \ with closing(os.fdopen(os_done_r)) as done_r, \
closing(os.fdopen(os_done_w, 'w')) as done_w: closing(os.fdopen(os_done_w, 'w')) as done_w:
...@@ -227,6 +227,13 @@ class WindowsSignalTests(unittest.TestCase): ...@@ -227,6 +227,13 @@ class WindowsSignalTests(unittest.TestCase):
signal.signal(7, handler) signal.signal(7, handler)
class WakeupFDTests(unittest.TestCase):
def test_invalid_fd(self):
fd = test_support.make_bad_fd()
self.assertRaises(ValueError, signal.set_wakeup_fd, fd)
@unittest.skipIf(sys.platform == "win32", "Not valid on Windows") @unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
class WakeupSignalTests(unittest.TestCase): class WakeupSignalTests(unittest.TestCase):
TIMEOUT_FULL = 10 TIMEOUT_FULL = 10
...@@ -485,8 +492,9 @@ class ItimerTest(unittest.TestCase): ...@@ -485,8 +492,9 @@ class ItimerTest(unittest.TestCase):
def test_main(): def test_main():
test_support.run_unittest(BasicSignalTests, InterProcessSignalTests, test_support.run_unittest(BasicSignalTests, InterProcessSignalTests,
WakeupSignalTests, SiginterruptTest, WakeupFDTests, WakeupSignalTests,
ItimerTest, WindowsSignalTests) SiginterruptTest, ItimerTest,
WindowsSignalTests)
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -77,7 +77,7 @@ class GeneralTests(unittest.TestCase): ...@@ -77,7 +77,7 @@ class GeneralTests(unittest.TestCase):
smtp.close() smtp.close()
def testTimeoutDefault(self): def testTimeoutDefault(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
try: try:
smtp = smtplib.SMTP(HOST, self.port) smtp = smtplib.SMTP(HOST, self.port)
...@@ -87,13 +87,13 @@ class GeneralTests(unittest.TestCase): ...@@ -87,13 +87,13 @@ class GeneralTests(unittest.TestCase):
smtp.close() smtp.close()
def testTimeoutNone(self): def testTimeoutNone(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
try: try:
smtp = smtplib.SMTP(HOST, self.port, timeout=None) smtp = smtplib.SMTP(HOST, self.port, timeout=None)
finally: finally:
socket.setdefaulttimeout(None) socket.setdefaulttimeout(None)
self.assertTrue(smtp.sock.gettimeout() is None) self.assertIsNone(smtp.sock.gettimeout())
smtp.close() smtp.close()
def testTimeoutValue(self): def testTimeoutValue(self):
......
This diff is collapsed.
...@@ -8,6 +8,8 @@ import os ...@@ -8,6 +8,8 @@ import os
import select import select
import signal import signal
import socket import socket
import select
import errno
import tempfile import tempfile
import unittest import unittest
import SocketServer import SocketServer
...@@ -25,15 +27,21 @@ TEST_STR = "hello world\n" ...@@ -25,15 +27,21 @@ TEST_STR = "hello world\n"
HOST = test.test_support.HOST HOST = test.test_support.HOST
HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX") HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX")
requires_unix_sockets = unittest.skipUnless(HAVE_UNIX_SOCKETS,
'requires Unix sockets')
HAVE_FORKING = hasattr(os, "fork") and os.name != "os2" HAVE_FORKING = hasattr(os, "fork") and os.name != "os2"
requires_forking = unittest.skipUnless(HAVE_FORKING, 'requires forking')
def signal_alarm(n): def signal_alarm(n):
"""Call signal.alarm when it exists (i.e. not on Windows).""" """Call signal.alarm when it exists (i.e. not on Windows)."""
if hasattr(signal, 'alarm'): if hasattr(signal, 'alarm'):
signal.alarm(n) signal.alarm(n)
# Remember real select() to avoid interferences with mocking
_real_select = select.select
def receive(sock, n, timeout=20): def receive(sock, n, timeout=20):
r, w, x = select.select([sock], [], [], timeout) r, w, x = _real_select([sock], [], [], timeout)
if sock in r: if sock in r:
return sock.recv(n) return sock.recv(n)
else: else:
...@@ -53,7 +61,7 @@ if HAVE_UNIX_SOCKETS: ...@@ -53,7 +61,7 @@ if HAVE_UNIX_SOCKETS:
def simple_subprocess(testcase): def simple_subprocess(testcase):
pid = os.fork() pid = os.fork()
if pid == 0: if pid == 0:
# Don't throw an exception; it would be caught by the test harness. # Don't raise an exception; it would be caught by the test harness.
os._exit(72) os._exit(72)
yield None yield None
pid2, status = os.waitpid(pid, 0) pid2, status = os.waitpid(pid, 0)
...@@ -183,31 +191,33 @@ class SocketServerTest(unittest.TestCase): ...@@ -183,31 +191,33 @@ class SocketServerTest(unittest.TestCase):
SocketServer.StreamRequestHandler, SocketServer.StreamRequestHandler,
self.stream_examine) self.stream_examine)
if HAVE_FORKING: @requires_forking
def test_ForkingTCPServer(self): def test_ForkingTCPServer(self):
with simple_subprocess(self): with simple_subprocess(self):
self.run_server(SocketServer.ForkingTCPServer, self.run_server(SocketServer.ForkingTCPServer,
SocketServer.StreamRequestHandler,
self.stream_examine)
if HAVE_UNIX_SOCKETS:
def test_UnixStreamServer(self):
self.run_server(SocketServer.UnixStreamServer,
SocketServer.StreamRequestHandler, SocketServer.StreamRequestHandler,
self.stream_examine) self.stream_examine)
def test_ThreadingUnixStreamServer(self): @requires_unix_sockets
self.run_server(SocketServer.ThreadingUnixStreamServer, def test_UnixStreamServer(self):
self.run_server(SocketServer.UnixStreamServer,
SocketServer.StreamRequestHandler,
self.stream_examine)
@requires_unix_sockets
def test_ThreadingUnixStreamServer(self):
self.run_server(SocketServer.ThreadingUnixStreamServer,
SocketServer.StreamRequestHandler,
self.stream_examine)
@requires_unix_sockets
@requires_forking
def test_ForkingUnixStreamServer(self):
with simple_subprocess(self):
self.run_server(ForkingUnixStreamServer,
SocketServer.StreamRequestHandler, SocketServer.StreamRequestHandler,
self.stream_examine) self.stream_examine)
if HAVE_FORKING:
def test_ForkingUnixStreamServer(self):
with simple_subprocess(self):
self.run_server(ForkingUnixStreamServer,
SocketServer.StreamRequestHandler,
self.stream_examine)
def test_UDPServer(self): def test_UDPServer(self):
self.run_server(SocketServer.UDPServer, self.run_server(SocketServer.UDPServer,
SocketServer.DatagramRequestHandler, SocketServer.DatagramRequestHandler,
...@@ -218,32 +228,66 @@ class SocketServerTest(unittest.TestCase): ...@@ -218,32 +228,66 @@ class SocketServerTest(unittest.TestCase):
SocketServer.DatagramRequestHandler, SocketServer.DatagramRequestHandler,
self.dgram_examine) self.dgram_examine)
if HAVE_FORKING: @requires_forking
def test_ForkingUDPServer(self): def test_ForkingUDPServer(self):
with simple_subprocess(self): with simple_subprocess(self):
self.run_server(SocketServer.ForkingUDPServer, self.run_server(SocketServer.ForkingUDPServer,
SocketServer.DatagramRequestHandler, SocketServer.DatagramRequestHandler,
self.dgram_examine) self.dgram_examine)
@contextlib.contextmanager
def mocked_select_module(self):
"""Mocks the select.select() call to raise EINTR for first call"""
old_select = select.select
class MockSelect:
def __init__(self):
self.called = 0
def __call__(self, *args):
self.called += 1
if self.called == 1:
# raise the exception on first call
raise select.error(errno.EINTR, os.strerror(errno.EINTR))
else:
# Return real select value for consecutive calls
return old_select(*args)
select.select = MockSelect()
try:
yield select.select
finally:
select.select = old_select
def test_InterruptServerSelectCall(self):
with self.mocked_select_module() as mock_select:
pid = self.run_server(SocketServer.TCPServer,
SocketServer.StreamRequestHandler,
self.stream_examine)
# Make sure select was called again:
self.assertGreater(mock_select.called, 1)
# Alas, on Linux (at least) recvfrom() doesn't return a meaningful # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
# client address so this cannot work: # client address so this cannot work:
# if HAVE_UNIX_SOCKETS: # @requires_unix_sockets
# def test_UnixDatagramServer(self): # def test_UnixDatagramServer(self):
# self.run_server(SocketServer.UnixDatagramServer, # self.run_server(SocketServer.UnixDatagramServer,
# SocketServer.DatagramRequestHandler, # SocketServer.DatagramRequestHandler,
# self.dgram_examine) # self.dgram_examine)
# #
# def test_ThreadingUnixDatagramServer(self): # @requires_unix_sockets
# self.run_server(SocketServer.ThreadingUnixDatagramServer, # def test_ThreadingUnixDatagramServer(self):
# SocketServer.DatagramRequestHandler, # self.run_server(SocketServer.ThreadingUnixDatagramServer,
# self.dgram_examine) # SocketServer.DatagramRequestHandler,
# self.dgram_examine)
# #
# if HAVE_FORKING: # @requires_unix_sockets
# def test_ForkingUnixDatagramServer(self): # @requires_forking
# self.run_server(SocketServer.ForkingUnixDatagramServer, # def test_ForkingUnixDatagramServer(self):
# SocketServer.DatagramRequestHandler, # self.run_server(SocketServer.ForkingUnixDatagramServer,
# self.dgram_examine) # SocketServer.DatagramRequestHandler,
# self.dgram_examine)
@reap_threads @reap_threads
def test_shutdown(self): def test_shutdown(self):
......
...@@ -25,6 +25,7 @@ ssl = test_support.import_module("ssl") ...@@ -25,6 +25,7 @@ ssl = test_support.import_module("ssl")
HOST = test_support.HOST HOST = test_support.HOST
CERTFILE = None CERTFILE = None
SVN_PYTHON_ORG_ROOT_CERT = None SVN_PYTHON_ORG_ROOT_CERT = None
NULLBYTECERT = None
def handle_error(prefix): def handle_error(prefix):
exc_format = ' '.join(traceback.format_exception(*sys.exc_info())) exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
...@@ -95,12 +96,8 @@ class BasicSocketTests(unittest.TestCase): ...@@ -95,12 +96,8 @@ class BasicSocketTests(unittest.TestCase):
sys.stdout.write("\n RAND_status is %d (%s)\n" sys.stdout.write("\n RAND_status is %d (%s)\n"
% (v, (v and "sufficient randomness") or % (v, (v and "sufficient randomness") or
"insufficient randomness")) "insufficient randomness"))
try: self.assertRaises(TypeError, ssl.RAND_egd, 1)
ssl.RAND_egd(1) self.assertRaises(TypeError, ssl.RAND_egd, 'foo', 1)
except TypeError:
pass
else:
print "didn't raise TypeError"
ssl.RAND_add("this is a random string", 75.0) ssl.RAND_add("this is a random string", 75.0)
def test_parse_cert(self): def test_parse_cert(self):
...@@ -127,6 +124,35 @@ class BasicSocketTests(unittest.TestCase): ...@@ -127,6 +124,35 @@ class BasicSocketTests(unittest.TestCase):
('DNS', 'projects.forum.nokia.com')) ('DNS', 'projects.forum.nokia.com'))
) )
def test_parse_cert_CVE_2013_4238(self):
p = ssl._ssl._test_decode_cert(NULLBYTECERT)
if test_support.verbose:
sys.stdout.write("\n" + pprint.pformat(p) + "\n")
subject = ((('countryName', 'US'),),
(('stateOrProvinceName', 'Oregon'),),
(('localityName', 'Beaverton'),),
(('organizationName', 'Python Software Foundation'),),
(('organizationalUnitName', 'Python Core Development'),),
(('commonName', 'null.python.org\x00example.org'),),
(('emailAddress', 'python-dev@python.org'),))
self.assertEqual(p['subject'], subject)
self.assertEqual(p['issuer'], subject)
if ssl.OPENSSL_VERSION_INFO >= (0, 9, 8):
san = (('DNS', 'altnull.python.org\x00example.com'),
('email', 'null@python.org\x00user@example.org'),
('URI', 'http://null.python.org\x00http://example.org'),
('IP Address', '192.0.2.1'),
('IP Address', '2001:DB8:0:0:0:0:0:1\n'))
else:
# OpenSSL 0.9.7 doesn't support IPv6 addresses in subjectAltName
san = (('DNS', 'altnull.python.org\x00example.com'),
('email', 'null@python.org\x00user@example.org'),
('URI', 'http://null.python.org\x00http://example.org'),
('IP Address', '192.0.2.1'),
('IP Address', '<invalid>'))
self.assertEqual(p['subjectAltName'], san)
def test_DER_to_PEM(self): def test_DER_to_PEM(self):
with open(SVN_PYTHON_ORG_ROOT_CERT, 'r') as f: with open(SVN_PYTHON_ORG_ROOT_CERT, 'r') as f:
pem = f.read() pem = f.read()
...@@ -166,9 +192,8 @@ class BasicSocketTests(unittest.TestCase): ...@@ -166,9 +192,8 @@ class BasicSocketTests(unittest.TestCase):
self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)), self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
(s, t)) (s, t))
@test_support.requires_resource('network')
def test_ciphers(self): def test_ciphers(self):
if not test_support.is_resource_enabled('network'):
return
remote = ("svn.python.org", 443) remote = ("svn.python.org", 443)
with test_support.transient_internet(remote[0]): with test_support.transient_internet(remote[0]):
s = ssl.wrap_socket(socket.socket(socket.AF_INET), s = ssl.wrap_socket(socket.socket(socket.AF_INET),
...@@ -207,6 +232,13 @@ class BasicSocketTests(unittest.TestCase): ...@@ -207,6 +232,13 @@ class BasicSocketTests(unittest.TestCase):
self.assertRaises(socket.error, ss.send, b'x') self.assertRaises(socket.error, ss.send, b'x')
self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0)) self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0))
def test_unsupported_dtls(self):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.addCleanup(s.close)
with self.assertRaises(NotImplementedError) as cx:
ssl.wrap_socket(s, cert_reqs=ssl.CERT_NONE)
self.assertEqual(str(cx.exception), "only stream sockets are supported")
class NetworkedTests(unittest.TestCase): class NetworkedTests(unittest.TestCase):
...@@ -283,6 +315,34 @@ class NetworkedTests(unittest.TestCase): ...@@ -283,6 +315,34 @@ class NetworkedTests(unittest.TestCase):
finally: finally:
s.close() s.close()
def test_timeout_connect_ex(self):
# Issue #12065: on a timeout, connect_ex() should return the original
# errno (mimicking the behaviour of non-SSL sockets).
with test_support.transient_internet("svn.python.org"):
s = ssl.wrap_socket(socket.socket(socket.AF_INET),
cert_reqs=ssl.CERT_REQUIRED,
ca_certs=SVN_PYTHON_ORG_ROOT_CERT,
do_handshake_on_connect=False)
try:
s.settimeout(0.0000001)
rc = s.connect_ex(('svn.python.org', 443))
if rc == 0:
self.skipTest("svn.python.org responded too quickly")
self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
finally:
s.close()
def test_connect_ex_error(self):
with test_support.transient_internet("svn.python.org"):
s = ssl.wrap_socket(socket.socket(socket.AF_INET),
cert_reqs=ssl.CERT_REQUIRED,
ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
try:
self.assertEqual(errno.ECONNREFUSED,
s.connect_ex(("svn.python.org", 444)))
finally:
s.close()
@unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows") @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
def test_makefile_close(self): def test_makefile_close(self):
# Issue #5238: creating a file-like object with makefile() shouldn't # Issue #5238: creating a file-like object with makefile() shouldn't
...@@ -330,19 +390,24 @@ class NetworkedTests(unittest.TestCase): ...@@ -330,19 +390,24 @@ class NetworkedTests(unittest.TestCase):
def test_get_server_certificate(self): def test_get_server_certificate(self):
with test_support.transient_internet("svn.python.org"): with test_support.transient_internet("svn.python.org"):
pem = ssl.get_server_certificate(("svn.python.org", 443)) pem = ssl.get_server_certificate(("svn.python.org", 443),
ssl.PROTOCOL_SSLv23)
if not pem: if not pem:
self.fail("No server certificate on svn.python.org:443!") self.fail("No server certificate on svn.python.org:443!")
try: try:
pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE) pem = ssl.get_server_certificate(("svn.python.org", 443),
ssl.PROTOCOL_SSLv23,
ca_certs=CERTFILE)
except ssl.SSLError: except ssl.SSLError:
#should fail #should fail
pass pass
else: else:
self.fail("Got server certificate %s for svn.python.org!" % pem) self.fail("Got server certificate %s for svn.python.org!" % pem)
pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT) pem = ssl.get_server_certificate(("svn.python.org", 443),
ssl.PROTOCOL_SSLv23,
ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
if not pem: if not pem:
self.fail("No server certificate on svn.python.org:443!") self.fail("No server certificate on svn.python.org:443!")
if test_support.verbose: if test_support.verbose:
...@@ -354,7 +419,8 @@ class NetworkedTests(unittest.TestCase): ...@@ -354,7 +419,8 @@ class NetworkedTests(unittest.TestCase):
# SHA256 was added in OpenSSL 0.9.8 # SHA256 was added in OpenSSL 0.9.8
if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15): if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION) self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
# NOTE: https://sha256.tbs-internet.com is another possible test host self.skipTest("remote host needs SNI, only available on Python 3.2+")
# NOTE: https://sha2.hboeck.de is another possible test host
remote = ("sha256.tbs-internet.com", 443) remote = ("sha256.tbs-internet.com", 443)
sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem") sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
with test_support.transient_internet("sha256.tbs-internet.com"): with test_support.transient_internet("sha256.tbs-internet.com"):
...@@ -993,7 +1059,7 @@ else: ...@@ -993,7 +1059,7 @@ else:
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
...@@ -1337,15 +1403,21 @@ else: ...@@ -1337,15 +1403,21 @@ else:
def test_main(verbose=False): def test_main(verbose=False):
global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT, NOKIACERT global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT, NOKIACERT, NULLBYTECERT
CERTFILE = test_support.findfile("keycert.pem") CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
SVN_PYTHON_ORG_ROOT_CERT = test_support.findfile( "keycert.pem")
SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
os.path.dirname(__file__) or os.curdir,
"https_svn_python_org_root.pem") "https_svn_python_org_root.pem")
NOKIACERT = test_support.findfile("nokia.pem") NOKIACERT = os.path.join(os.path.dirname(__file__) or os.curdir,
"nokia.pem")
NULLBYTECERT = os.path.join(os.path.dirname(__file__) or os.curdir,
"nullbytecert.pem")
if (not os.path.exists(CERTFILE) or if (not os.path.exists(CERTFILE) or
not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT) or not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT) or
not os.path.exists(NOKIACERT)): not os.path.exists(NOKIACERT) or
not os.path.exists(NULLBYTECERT)):
raise test_support.TestFailed("Can't read certificate files!") raise test_support.TestFailed("Can't read certificate files!")
tests = [BasicTests, BasicSocketTests] tests = [BasicTests, BasicSocketTests]
......
This diff is collapsed.
...@@ -3,6 +3,7 @@ import telnetlib ...@@ -3,6 +3,7 @@ import telnetlib
import time import time
import Queue import Queue
import unittest
from unittest import TestCase from unittest import TestCase
from test import test_support from test import test_support
threading = test_support.import_module('threading') threading = test_support.import_module('threading')
...@@ -91,6 +92,14 @@ class GeneralTests(TestCase): ...@@ -91,6 +92,14 @@ class GeneralTests(TestCase):
self.assertEqual(telnet.sock.gettimeout(), 30) self.assertEqual(telnet.sock.gettimeout(), 30)
telnet.sock.close() telnet.sock.close()
def testGetters(self):
# Test telnet getter methods
telnet = telnetlib.Telnet(HOST, self.port, timeout=30)
t_sock = telnet.sock
self.assertEqual(telnet.get_socket(), t_sock)
self.assertEqual(telnet.fileno(), t_sock.fileno())
telnet.sock.close()
def _read_setUp(self): def _read_setUp(self):
self.evt = threading.Event() self.evt = threading.Event()
self.dataq = Queue.Queue() self.dataq = Queue.Queue()
...@@ -135,6 +144,28 @@ class ReadTests(TestCase): ...@@ -135,6 +144,28 @@ class ReadTests(TestCase):
self.assertEqual(data, want[0]) self.assertEqual(data, want[0])
self.assertEqual(telnet.read_all(), 'not seen') self.assertEqual(telnet.read_all(), 'not seen')
def test_read_until_with_poll(self):
"""Use select.poll() to implement telnet.read_until()."""
want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
self.dataq.put(want)
telnet = telnetlib.Telnet(HOST, self.port)
if not telnet._has_poll:
raise unittest.SkipTest('select.poll() is required')
telnet._has_poll = True
self.dataq.join()
data = telnet.read_until('match')
self.assertEqual(data, ''.join(want[:-2]))
def test_read_until_with_select(self):
"""Use select.select() to implement telnet.read_until()."""
want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
self.dataq.put(want)
telnet = telnetlib.Telnet(HOST, self.port)
telnet._has_poll = False
self.dataq.join()
data = telnet.read_until('match')
self.assertEqual(data, ''.join(want[:-2]))
def test_read_all_A(self): def test_read_all_A(self):
""" """
read_all() read_all()
...@@ -146,7 +177,6 @@ class ReadTests(TestCase): ...@@ -146,7 +177,6 @@ class ReadTests(TestCase):
self.dataq.join() self.dataq.join()
data = telnet.read_all() data = telnet.read_all()
self.assertEqual(data, ''.join(want[:-1])) self.assertEqual(data, ''.join(want[:-1]))
return
def _test_blocking(self, func): def _test_blocking(self, func):
self.dataq.put([self.block_long, EOF_sigil]) self.dataq.put([self.block_long, EOF_sigil])
...@@ -357,8 +387,75 @@ class OptionTests(TestCase): ...@@ -357,8 +387,75 @@ class OptionTests(TestCase):
self.assertEqual('', telnet.read_sb_data()) self.assertEqual('', telnet.read_sb_data())
nego.sb_getter = None # break the nego => telnet cycle nego.sb_getter = None # break the nego => telnet cycle
class ExpectTests(TestCase):
def setUp(self):
self.evt = threading.Event()
self.dataq = Queue.Queue()
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(10)
self.port = test_support.bind_port(self.sock)
self.thread = threading.Thread(target=server, args=(self.evt,self.sock,
self.dataq))
self.thread.start()
self.evt.wait()
def tearDown(self):
self.thread.join()
# use a similar approach to testing timeouts as test_timeout.py
# these will never pass 100% but make the fuzz big enough that it is rare
block_long = 0.6
block_short = 0.3
def test_expect_A(self):
"""
expect(expected, [timeout])
Read until the expected string has been seen, or a timeout is
hit (default is no timeout); may block.
"""
want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
self.dataq.put(want)
telnet = telnetlib.Telnet(HOST, self.port)
self.dataq.join()
(_,_,data) = telnet.expect(['match'])
self.assertEqual(data, ''.join(want[:-2]))
def test_expect_B(self):
# test the timeout - it does NOT raise socket.timeout
want = ['hello', self.block_long, 'not seen', EOF_sigil]
self.dataq.put(want)
telnet = telnetlib.Telnet(HOST, self.port)
self.dataq.join()
(_,_,data) = telnet.expect(['not seen'], self.block_short)
self.assertEqual(data, want[0])
self.assertEqual(telnet.read_all(), 'not seen')
def test_expect_with_poll(self):
"""Use select.poll() to implement telnet.expect()."""
want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
self.dataq.put(want)
telnet = telnetlib.Telnet(HOST, self.port)
if not telnet._has_poll:
raise unittest.SkipTest('select.poll() is required')
telnet._has_poll = True
self.dataq.join()
(_,_,data) = telnet.expect(['match'])
self.assertEqual(data, ''.join(want[:-2]))
def test_expect_with_select(self):
"""Use select.select() to implement telnet.expect()."""
want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
self.dataq.put(want)
telnet = telnetlib.Telnet(HOST, self.port)
telnet._has_poll = False
self.dataq.join()
(_,_,data) = telnet.expect(['match'])
self.assertEqual(data, ''.join(want[:-2]))
def test_main(verbose=None): def test_main(verbose=None):
test_support.run_unittest(GeneralTests, ReadTests, OptionTests) test_support.run_unittest(GeneralTests, ReadTests, OptionTests,
ExpectTests)
if __name__ == '__main__': if __name__ == '__main__':
test_main() test_main()
...@@ -7,7 +7,7 @@ import time ...@@ -7,7 +7,7 @@ import time
import sys import sys
import weakref import weakref
import lock_tests from test import lock_tests
NUMTASKS = 10 NUMTASKS = 10
NUMTRIPS = 3 NUMTRIPS = 3
...@@ -70,39 +70,35 @@ class ThreadRunningTests(BasicThreadTest): ...@@ -70,39 +70,35 @@ class ThreadRunningTests(BasicThreadTest):
thread.stack_size(0) thread.stack_size(0)
self.assertEqual(thread.stack_size(), 0, "stack_size not reset to default") self.assertEqual(thread.stack_size(), 0, "stack_size not reset to default")
if os.name not in ("nt", "os2", "posix"): @unittest.skipIf(os.name not in ("nt", "os2", "posix"), 'test meant for nt, os2, and posix')
return def test_nt_and_posix_stack_size(self):
tss_supported = True
try: try:
thread.stack_size(4096) thread.stack_size(4096)
except ValueError: except ValueError:
verbose_print("caught expected ValueError setting " verbose_print("caught expected ValueError setting "
"stack_size(4096)") "stack_size(4096)")
except thread.error: except thread.error:
tss_supported = False self.skipTest("platform does not support changing thread stack "
verbose_print("platform does not support changing thread stack " "size")
"size")
fail_msg = "stack_size(%d) failed - should succeed"
if tss_supported: for tss in (262144, 0x100000, 0):
fail_msg = "stack_size(%d) failed - should succeed" thread.stack_size(tss)
for tss in (262144, 0x100000, 0): self.assertEqual(thread.stack_size(), tss, fail_msg % tss)
thread.stack_size(tss) verbose_print("successfully set stack_size(%d)" % tss)
self.assertEqual(thread.stack_size(), tss, fail_msg % tss)
verbose_print("successfully set stack_size(%d)" % tss) for tss in (262144, 0x100000):
verbose_print("trying stack_size = (%d)" % tss)
for tss in (262144, 0x100000): self.next_ident = 0
verbose_print("trying stack_size = (%d)" % tss) self.created = 0
self.next_ident = 0 for i in range(NUMTASKS):
self.created = 0 self.newtask()
for i in range(NUMTASKS):
self.newtask() verbose_print("waiting for all tasks to complete")
self.done_mutex.acquire()
verbose_print("waiting for all tasks to complete") verbose_print("all tasks done")
self.done_mutex.acquire()
verbose_print("all tasks done") thread.stack_size(0)
thread.stack_size(0)
def test__count(self): def test__count(self):
# Test the _count() function. # Test the _count() function.
...@@ -131,6 +127,29 @@ class ThreadRunningTests(BasicThreadTest): ...@@ -131,6 +127,29 @@ class ThreadRunningTests(BasicThreadTest):
test_support.gc_collect() test_support.gc_collect()
self.assertEqual(thread._count(), orig) self.assertEqual(thread._count(), orig)
def test_save_exception_state_on_error(self):
# See issue #14474
def task():
started.release()
raise SyntaxError
def mywrite(self, *args):
try:
raise ValueError
except ValueError:
pass
real_write(self, *args)
c = thread._count()
started = thread.allocate_lock()
with test_support.captured_output("stderr") as stderr:
real_write = stderr.write
stderr.write = mywrite
started.acquire()
thread.start_new_thread(task, ())
started.acquire()
while thread._count() > c:
time.sleep(0.01)
self.assertIn("Traceback", stderr.getvalue())
class Barrier: class Barrier:
def __init__(self, num_threads): def __init__(self, num_threads):
......
# Very rudimentary test of threading module # Very rudimentary test of threading module
import test.test_support import test.test_support
from test.test_support import verbose from test.test_support import verbose, cpython_only
from test.script_helper import assert_python_ok
import random import random
import re import re
import sys import sys
...@@ -12,8 +14,12 @@ import unittest ...@@ -12,8 +14,12 @@ import unittest
import weakref import weakref
import os import os
import subprocess import subprocess
try:
import _testcapi
except ImportError:
_testcapi = None
import lock_tests from test import lock_tests
# A trivial mutable counter. # A trivial mutable counter.
class Counter(object): class Counter(object):
...@@ -123,9 +129,7 @@ class ThreadTests(BaseTestCase): ...@@ -123,9 +129,7 @@ class ThreadTests(BaseTestCase):
try: try:
threading.stack_size(262144) threading.stack_size(262144)
except thread.error: except thread.error:
if verbose: self.skipTest('platform does not support changing thread stack size')
print 'platform does not support changing thread stack size'
return
self.test_various_ops() self.test_various_ops()
threading.stack_size(0) threading.stack_size(0)
...@@ -136,9 +140,7 @@ class ThreadTests(BaseTestCase): ...@@ -136,9 +140,7 @@ class ThreadTests(BaseTestCase):
try: try:
threading.stack_size(0x100000) threading.stack_size(0x100000)
except thread.error: except thread.error:
if verbose: self.skipTest('platform does not support changing thread stack size')
print 'platform does not support changing thread stack size'
return
self.test_various_ops() self.test_various_ops()
threading.stack_size(0) threading.stack_size(0)
...@@ -166,9 +168,7 @@ class ThreadTests(BaseTestCase): ...@@ -166,9 +168,7 @@ class ThreadTests(BaseTestCase):
try: try:
import ctypes import ctypes
except ImportError: except ImportError:
if verbose: self.skipTest('requires ctypes')
print "test_PyThreadState_SetAsyncExc can't import ctypes"
return # can't do anything
set_async_exc = ctypes.pythonapi.PyThreadState_SetAsyncExc set_async_exc = ctypes.pythonapi.PyThreadState_SetAsyncExc
...@@ -275,9 +275,7 @@ class ThreadTests(BaseTestCase): ...@@ -275,9 +275,7 @@ class ThreadTests(BaseTestCase):
try: try:
import ctypes import ctypes
except ImportError: except ImportError:
if verbose: self.skipTest('requires ctypes')
print("test_finalize_with_runnning_thread can't import ctypes")
return # can't do anything
rc = subprocess.call([sys.executable, "-c", """if 1: rc = subprocess.call([sys.executable, "-c", """if 1:
import ctypes, sys, time, thread import ctypes, sys, time, thread
...@@ -417,6 +415,73 @@ class ThreadTests(BaseTestCase): ...@@ -417,6 +415,73 @@ class ThreadTests(BaseTestCase):
msg=('%d references still around' % msg=('%d references still around' %
sys.getrefcount(weak_raising_cyclic_object()))) sys.getrefcount(weak_raising_cyclic_object())))
@unittest.skipUnless(hasattr(os, 'fork'), 'test needs fork()')
def test_dummy_thread_after_fork(self):
# Issue #14308: a dummy thread in the active list doesn't mess up
# the after-fork mechanism.
code = """if 1:
import thread, threading, os, time
def background_thread(evt):
# Creates and registers the _DummyThread instance
threading.current_thread()
evt.set()
time.sleep(10)
evt = threading.Event()
thread.start_new_thread(background_thread, (evt,))
evt.wait()
assert threading.active_count() == 2, threading.active_count()
if os.fork() == 0:
assert threading.active_count() == 1, threading.active_count()
os._exit(0)
else:
os.wait()
"""
_, out, err = assert_python_ok("-c", code)
self.assertEqual(out, '')
self.assertEqual(err, '')
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
def test_is_alive_after_fork(self):
# Try hard to trigger #18418: is_alive() could sometimes be True on
# threads that vanished after a fork.
old_interval = sys.getcheckinterval()
# Make the bug more likely to manifest.
sys.setcheckinterval(10)
try:
for i in range(20):
t = threading.Thread(target=lambda: None)
t.start()
pid = os.fork()
if pid == 0:
os._exit(1 if t.is_alive() else 0)
else:
t.join()
pid, status = os.waitpid(pid, 0)
self.assertEqual(0, status)
finally:
sys.setcheckinterval(old_interval)
def test_BoundedSemaphore_limit(self):
# BoundedSemaphore should raise ValueError if released too often.
for limit in range(1, 10):
bs = threading.BoundedSemaphore(limit)
threads = [threading.Thread(target=bs.acquire)
for _ in range(limit)]
for t in threads:
t.start()
for t in threads:
t.join()
threads = [threading.Thread(target=bs.release)
for _ in range(limit)]
for t in threads:
t.start()
for t in threads:
t.join()
self.assertRaises(ValueError, bs.release)
class ThreadJoinOnShutdown(BaseTestCase): class ThreadJoinOnShutdown(BaseTestCase):
...@@ -641,6 +706,49 @@ class ThreadJoinOnShutdown(BaseTestCase): ...@@ -641,6 +706,49 @@ class ThreadJoinOnShutdown(BaseTestCase):
output = "end of worker thread\nend of main thread\n" output = "end of worker thread\nend of main thread\n"
self.assertScriptHasOutput(script, output) self.assertScriptHasOutput(script, output)
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
def test_6_daemon_threads(self):
# Check that a daemon thread cannot crash the interpreter on shutdown
# by manipulating internal structures that are being disposed of in
# the main thread.
script = """if True:
import os
import random
import sys
import time
import threading
thread_has_run = set()
def random_io():
'''Loop for a while sleeping random tiny amounts and doing some I/O.'''
while True:
in_f = open(os.__file__, 'rb')
stuff = in_f.read(200)
null_f = open(os.devnull, 'wb')
null_f.write(stuff)
time.sleep(random.random() / 1995)
null_f.close()
in_f.close()
thread_has_run.add(threading.current_thread())
def main():
count = 0
for _ in range(40):
new_thread = threading.Thread(target=random_io)
new_thread.daemon = True
new_thread.start()
count += 1
while len(thread_has_run) < count:
time.sleep(0.001)
# Trigger process shutdown
sys.exit(0)
main()
"""
rc, out, err = assert_python_ok('-c', script)
self.assertFalse(err)
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
def test_reinit_tls_after_fork(self): def test_reinit_tls_after_fork(self):
...@@ -665,6 +773,46 @@ class ThreadJoinOnShutdown(BaseTestCase): ...@@ -665,6 +773,46 @@ class ThreadJoinOnShutdown(BaseTestCase):
for t in threads: for t in threads:
t.join() t.join()
@cpython_only
@unittest.skipIf(_testcapi is None, "need _testcapi module")
def test_frame_tstate_tracing(self):
# Issue #14432: Crash when a generator is created in a C thread that is
# destroyed while the generator is still used. The issue was that a
# generator contains a frame, and the frame kept a reference to the
# Python state of the destroyed C thread. The crash occurs when a trace
# function is setup.
def noop_trace(frame, event, arg):
# no operation
return noop_trace
def generator():
while 1:
yield "genereator"
def callback():
if callback.gen is None:
callback.gen = generator()
return next(callback.gen)
callback.gen = None
old_trace = sys.gettrace()
sys.settrace(noop_trace)
try:
# Install a trace function
threading.settrace(noop_trace)
# Create a generator in a C thread which exits after the call
_testcapi.call_in_temporary_c_thread(callback)
# Call the generator in a different Python thread, check that the
# generator didn't keep a reference to the destroyed thread state
for test in range(3):
# The trace function is still called here
callback()
finally:
sys.settrace(old_trace)
class ThreadingExceptionTests(BaseTestCase): class ThreadingExceptionTests(BaseTestCase):
# A RuntimeError should be raised if Thread.start() is called # A RuntimeError should be raised if Thread.start() is called
......
...@@ -178,16 +178,19 @@ class TimeoutTestCase(unittest.TestCase): ...@@ -178,16 +178,19 @@ class TimeoutTestCase(unittest.TestCase):
"timeout (%g) is %g seconds more than expected (%g)" "timeout (%g) is %g seconds more than expected (%g)"
%(_delta, self.fuzz, _timeout)) %(_delta, self.fuzz, _timeout))
@unittest.skip('test not implemented')
def testSend(self): def testSend(self):
# Test send() timeout # Test send() timeout
# couldn't figure out how to test it # couldn't figure out how to test it
pass pass
@unittest.skip('test not implemented')
def testSendto(self): def testSendto(self):
# Test sendto() timeout # Test sendto() timeout
# couldn't figure out how to test it # couldn't figure out how to test it
pass pass
@unittest.skip('test not implemented')
def testSendall(self): def testSendall(self):
# Test sendall() timeout # Test sendall() timeout
# couldn't figure out how to test it # couldn't figure out how to test it
......
...@@ -222,6 +222,27 @@ Content-Type: text/html; charset=iso-8859-1 ...@@ -222,6 +222,27 @@ Content-Type: text/html; charset=iso-8859-1
finally: finally:
self.unfakehttp() self.unfakehttp()
def test_missing_localfile(self):
self.assertRaises(IOError, urllib.urlopen,
'file://localhost/a/missing/file.py')
fd, tmp_file = tempfile.mkstemp()
tmp_fileurl = 'file://localhost/' + tmp_file.replace(os.path.sep, '/')
self.assertTrue(os.path.exists(tmp_file))
try:
fp = urllib.urlopen(tmp_fileurl)
fp.close()
finally:
os.close(fd)
os.unlink(tmp_file)
self.assertFalse(os.path.exists(tmp_file))
self.assertRaises(IOError, urllib.urlopen, tmp_fileurl)
def test_ftp_nonexisting(self):
self.assertRaises(IOError, urllib.urlopen,
'ftp://localhost/not/existing/file.py')
def test_userpass_inurl(self): def test_userpass_inurl(self):
self.fakehttp('Hello!') self.fakehttp('Hello!')
try: try:
...@@ -768,6 +789,26 @@ class Utility_Tests(unittest.TestCase): ...@@ -768,6 +789,26 @@ class Utility_Tests(unittest.TestCase):
self.assertEqual(('user 2', 'ab'),urllib.splitpasswd('user 2:ab')) self.assertEqual(('user 2', 'ab'),urllib.splitpasswd('user 2:ab'))
self.assertEqual(('user+1', 'a+b'),urllib.splitpasswd('user+1:a+b')) self.assertEqual(('user+1', 'a+b'),urllib.splitpasswd('user+1:a+b'))
def test_splitport(self):
splitport = urllib.splitport
self.assertEqual(splitport('parrot:88'), ('parrot', '88'))
self.assertEqual(splitport('parrot'), ('parrot', None))
self.assertEqual(splitport('parrot:'), ('parrot', None))
self.assertEqual(splitport('127.0.0.1'), ('127.0.0.1', None))
self.assertEqual(splitport('parrot:cheese'), ('parrot:cheese', None))
def test_splitnport(self):
splitnport = urllib.splitnport
self.assertEqual(splitnport('parrot:88'), ('parrot', 88))
self.assertEqual(splitnport('parrot'), ('parrot', -1))
self.assertEqual(splitnport('parrot', 55), ('parrot', 55))
self.assertEqual(splitnport('parrot:'), ('parrot', -1))
self.assertEqual(splitnport('parrot:', 55), ('parrot', 55))
self.assertEqual(splitnport('127.0.0.1'), ('127.0.0.1', -1))
self.assertEqual(splitnport('127.0.0.1', 55), ('127.0.0.1', 55))
self.assertEqual(splitnport('parrot:cheese'), ('parrot', None))
self.assertEqual(splitnport('parrot:cheese', 55), ('parrot', None))
class URLopener_Tests(unittest.TestCase): class URLopener_Tests(unittest.TestCase):
"""Testcase to test the open method of URLopener class.""" """Testcase to test the open method of URLopener class."""
...@@ -791,7 +832,7 @@ class URLopener_Tests(unittest.TestCase): ...@@ -791,7 +832,7 @@ class URLopener_Tests(unittest.TestCase):
# Everywhere else they work ok, but on those machines, sometimes # Everywhere else they work ok, but on those machines, sometimes
# fail in one of the tests, sometimes in other. I have a linux, and # fail in one of the tests, sometimes in other. I have a linux, and
# the tests go ok. # the tests go ok.
# If anybody has one of the problematic enviroments, please help! # If anybody has one of the problematic environments, please help!
# . Facundo # . Facundo
# #
# def server(evt): # def server(evt):
...@@ -837,7 +878,7 @@ class URLopener_Tests(unittest.TestCase): ...@@ -837,7 +878,7 @@ class URLopener_Tests(unittest.TestCase):
# def testTimeoutNone(self): # def testTimeoutNone(self):
# # global default timeout is ignored # # global default timeout is ignored
# import socket # import socket
# self.assertTrue(socket.getdefaulttimeout() is None) # self.assertIsNone(socket.getdefaulttimeout())
# socket.setdefaulttimeout(30) # socket.setdefaulttimeout(30)
# try: # try:
# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, []) # ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
...@@ -849,7 +890,7 @@ class URLopener_Tests(unittest.TestCase): ...@@ -849,7 +890,7 @@ class URLopener_Tests(unittest.TestCase):
# def testTimeoutDefault(self): # def testTimeoutDefault(self):
# # global default timeout is used # # global default timeout is used
# import socket # import socket
# self.assertTrue(socket.getdefaulttimeout() is None) # self.assertIsNone(socket.getdefaulttimeout())
# socket.setdefaulttimeout(30) # socket.setdefaulttimeout(30)
# try: # try:
# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, []) # ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
......
...@@ -593,8 +593,8 @@ class OpenerDirectorTests(unittest.TestCase): ...@@ -593,8 +593,8 @@ class OpenerDirectorTests(unittest.TestCase):
self.assertIsInstance(args[0], Request) self.assertIsInstance(args[0], Request)
# response from opener.open is None, because there's no # response from opener.open is None, because there's no
# handler that defines http_open to handle it # handler that defines http_open to handle it
self.assertTrue(args[1] is None or if args[1] is not None:
isinstance(args[1], MockResponse)) self.assertIsInstance(args[1], MockResponse)
def sanepathname2url(path): def sanepathname2url(path):
...@@ -926,7 +926,8 @@ class HandlerTests(unittest.TestCase): ...@@ -926,7 +926,8 @@ class HandlerTests(unittest.TestCase):
MockHeaders({"location": to_url})) MockHeaders({"location": to_url}))
except urllib2.HTTPError: except urllib2.HTTPError:
# 307 in response to POST requires user OK # 307 in response to POST requires user OK
self.assertTrue(code == 307 and data is not None) self.assertEqual(code, 307)
self.assertIsNotNone(data)
self.assertEqual(o.req.get_full_url(), to_url) self.assertEqual(o.req.get_full_url(), to_url)
try: try:
self.assertEqual(o.req.get_method(), "GET") self.assertEqual(o.req.get_method(), "GET")
...@@ -1003,7 +1004,7 @@ class HandlerTests(unittest.TestCase): ...@@ -1003,7 +1004,7 @@ class HandlerTests(unittest.TestCase):
# cookies shouldn't leak into redirected requests # cookies shouldn't leak into redirected requests
from cookielib import CookieJar from cookielib import CookieJar
from test_cookielib import interact_netscape from test.test_cookielib import interact_netscape
cj = CookieJar() cj = CookieJar()
interact_netscape(cj, "http://www.example.com/", "spam=eggs") interact_netscape(cj, "http://www.example.com/", "spam=eggs")
...@@ -1108,12 +1109,30 @@ class HandlerTests(unittest.TestCase): ...@@ -1108,12 +1109,30 @@ class HandlerTests(unittest.TestCase):
self._test_basic_auth(opener, auth_handler, "Authorization", self._test_basic_auth(opener, auth_handler, "Authorization",
realm, http_handler, password_manager, realm, http_handler, password_manager,
"http://acme.example.com/protected", "http://acme.example.com/protected",
"http://acme.example.com/protected", "http://acme.example.com/protected"
) )
def test_basic_auth_with_single_quoted_realm(self): def test_basic_auth_with_single_quoted_realm(self):
self.test_basic_auth(quote_char="'") self.test_basic_auth(quote_char="'")
def test_basic_auth_with_unquoted_realm(self):
opener = OpenerDirector()
password_manager = MockPasswordManager()
auth_handler = urllib2.HTTPBasicAuthHandler(password_manager)
realm = "ACME Widget Store"
http_handler = MockHTTPHandler(
401, 'WWW-Authenticate: Basic realm=%s\r\n\r\n' % realm)
opener.add_handler(auth_handler)
opener.add_handler(http_handler)
msg = "Basic Auth Realm was unquoted"
with test_support.check_warnings((msg, UserWarning)):
self._test_basic_auth(opener, auth_handler, "Authorization",
realm, http_handler, password_manager,
"http://acme.example.com/protected",
"http://acme.example.com/protected"
)
def test_proxy_basic_auth(self): def test_proxy_basic_auth(self):
opener = OpenerDirector() opener = OpenerDirector()
ph = urllib2.ProxyHandler(dict(http="proxy.example.com:3128")) ph = urllib2.ProxyHandler(dict(http="proxy.example.com:3128"))
...@@ -1132,7 +1151,7 @@ class HandlerTests(unittest.TestCase): ...@@ -1132,7 +1151,7 @@ class HandlerTests(unittest.TestCase):
) )
def test_basic_and_digest_auth_handlers(self): def test_basic_and_digest_auth_handlers(self):
# HTTPDigestAuthHandler threw an exception if it couldn't handle a 40* # HTTPDigestAuthHandler raised an exception if it couldn't handle a 40*
# response (http://python.org/sf/1479302), where it should instead # response (http://python.org/sf/1479302), where it should instead
# return None to allow another handler (especially # return None to allow another handler (especially
# HTTPBasicAuthHandler) to handle the response. # HTTPBasicAuthHandler) to handle the response.
...@@ -1320,19 +1339,35 @@ class RequestTests(unittest.TestCase): ...@@ -1320,19 +1339,35 @@ class RequestTests(unittest.TestCase):
req = Request(url) req = Request(url)
self.assertEqual(req.get_full_url(), url) self.assertEqual(req.get_full_url(), url)
def test_HTTPError_interface(): def test_HTTPError_interface(self):
""" """
Issue 13211 reveals that HTTPError didn't implement the URLError Issue 13211 reveals that HTTPError didn't implement the URLError
interface even though HTTPError is a subclass of URLError. interface even though HTTPError is a subclass of URLError.
>>> err = urllib2.HTTPError(msg='something bad happened', url=None, code=None, hdrs=None, fp=None) >>> err = urllib2.HTTPError(msg='something bad happened', url=None, code=None, hdrs=None, fp=None)
>>> assert hasattr(err, 'reason') >>> assert hasattr(err, 'reason')
>>> err.reason >>> err.reason
'something bad happened' 'something bad happened'
""" """
def test_HTTPError_interface_call(self):
"""
Issue 15701= - HTTPError interface has info method available from URLError.
"""
err = urllib2.HTTPError(msg='something bad happened', url=None,
code=None, hdrs='Content-Length:42', fp=None)
self.assertTrue(hasattr(err, 'reason'))
assert hasattr(err, 'reason')
assert hasattr(err, 'info')
assert callable(err.info)
try:
err.info()
except AttributeError:
self.fail("err.info() failed")
self.assertEqual(err.info(), "Content-Length:42")
def test_main(verbose=None): def test_main(verbose=None):
import test_urllib2 from test import test_urllib2
test_support.run_doctest(test_urllib2, verbose) test_support.run_doctest(test_urllib2, verbose)
test_support.run_doctest(urllib2, verbose) test_support.run_doctest(urllib2, verbose)
tests = (TrivialTests, tests = (TrivialTests,
......
#!/usr/bin/env python
import urlparse import urlparse
import urllib2 import urllib2
import BaseHTTPServer import BaseHTTPServer
import unittest import unittest
import hashlib import hashlib
from test import test_support from test import test_support
mimetools = test_support.import_module('mimetools', deprecated=True) mimetools = test_support.import_module('mimetools', deprecated=True)
threading = test_support.import_module('threading') threading = test_support.import_module('threading')
...@@ -23,7 +23,7 @@ class LoopbackHttpServer(BaseHTTPServer.HTTPServer): ...@@ -23,7 +23,7 @@ class LoopbackHttpServer(BaseHTTPServer.HTTPServer):
# Set the timeout of our listening socket really low so # Set the timeout of our listening socket really low so
# that we can stop the server easily. # that we can stop the server easily.
self.socket.settimeout(0.1) self.socket.settimeout(1.0)
def get_request(self): def get_request(self):
"""BaseHTTPServer method, overridden.""" """BaseHTTPServer method, overridden."""
...@@ -33,7 +33,7 @@ class LoopbackHttpServer(BaseHTTPServer.HTTPServer): ...@@ -33,7 +33,7 @@ class LoopbackHttpServer(BaseHTTPServer.HTTPServer):
# It's a loopback connection, so setting the timeout # It's a loopback connection, so setting the timeout
# really low shouldn't affect anything, but should make # really low shouldn't affect anything, but should make
# deadlocks less likely to occur. # deadlocks less likely to occur.
request.settimeout(1.0) request.settimeout(10.0)
return (request, client_address) return (request, client_address)
...@@ -346,6 +346,12 @@ class TestUrlopen(BaseTestCase): ...@@ -346,6 +346,12 @@ class TestUrlopen(BaseTestCase):
for transparent redirection have been written. for transparent redirection have been written.
""" """
def setUp(self):
proxy_handler = urllib2.ProxyHandler({})
opener = urllib2.build_opener(proxy_handler)
urllib2.install_opener(opener)
super(TestUrlopen, self).setUp()
def start_server(self, responses): def start_server(self, responses):
handler = GetRequestHandler(responses) handler = GetRequestHandler(responses)
...@@ -481,6 +487,11 @@ class TestUrlopen(BaseTestCase): ...@@ -481,6 +487,11 @@ class TestUrlopen(BaseTestCase):
def test_bad_address(self): def test_bad_address(self):
# Make sure proper exception is raised when connecting to a bogus # Make sure proper exception is raised when connecting to a bogus
# address. # address.
# as indicated by the comment below, this might fail with some ISP,
# so we run the test only when -unetwork/-uall is specified to
# mitigate the problem a bit (see #17564)
test_support.requires('network')
self.assertRaises(IOError, self.assertRaises(IOError,
# Given that both VeriSign and various ISPs have in # Given that both VeriSign and various ISPs have in
# the past or are presently hijacking various invalid # the past or are presently hijacking various invalid
......
#!/usr/bin/env python
import unittest import unittest
from test import test_support from test import test_support
from test_urllib2 import sanepathname2url from test.test_urllib2 import sanepathname2url
import socket import socket
import urllib2 import urllib2
...@@ -80,13 +78,13 @@ class CloseSocketTest(unittest.TestCase): ...@@ -80,13 +78,13 @@ class CloseSocketTest(unittest.TestCase):
# underlying socket # underlying socket
# delve deep into response to fetch socket._socketobject # delve deep into response to fetch socket._socketobject
response = _urlopen_with_retry("http://www.python.org/") response = _urlopen_with_retry("http://www.example.com/")
abused_fileobject = response.fp abused_fileobject = response.fp
self.assertTrue(abused_fileobject.__class__ is socket._fileobject) self.assertIs(abused_fileobject.__class__, socket._fileobject)
httpresponse = abused_fileobject._sock httpresponse = abused_fileobject._sock
self.assertTrue(httpresponse.__class__ is httplib.HTTPResponse) self.assertIs(httpresponse.__class__, httplib.HTTPResponse)
fileobject = httpresponse.fp fileobject = httpresponse.fp
self.assertTrue(fileobject.__class__ is socket._fileobject) self.assertIs(fileobject.__class__, socket._fileobject)
self.assertTrue(not fileobject.closed) self.assertTrue(not fileobject.closed)
response.close() response.close()
...@@ -157,15 +155,15 @@ class OtherNetworkTests(unittest.TestCase): ...@@ -157,15 +155,15 @@ class OtherNetworkTests(unittest.TestCase):
## self._test_urls(urls, self._extra_handlers()+[bauth, dauth]) ## self._test_urls(urls, self._extra_handlers()+[bauth, dauth])
def test_urlwithfrag(self): def test_urlwithfrag(self):
urlwith_frag = "http://docs.python.org/glossary.html#glossary" urlwith_frag = "https://docs.python.org/2/glossary.html#glossary"
with test_support.transient_internet(urlwith_frag): with test_support.transient_internet(urlwith_frag):
req = urllib2.Request(urlwith_frag) req = urllib2.Request(urlwith_frag)
res = urllib2.urlopen(req) res = urllib2.urlopen(req)
self.assertEqual(res.geturl(), self.assertEqual(res.geturl(),
"http://docs.python.org/glossary.html#glossary") "https://docs.python.org/2/glossary.html#glossary")
def test_fileno(self): def test_fileno(self):
req = urllib2.Request("http://www.python.org") req = urllib2.Request("http://www.example.com")
opener = urllib2.build_opener() opener = urllib2.build_opener()
res = opener.open(req) res = opener.open(req)
try: try:
...@@ -252,15 +250,15 @@ class OtherNetworkTests(unittest.TestCase): ...@@ -252,15 +250,15 @@ class OtherNetworkTests(unittest.TestCase):
class TimeoutTest(unittest.TestCase): class TimeoutTest(unittest.TestCase):
def test_http_basic(self): def test_http_basic(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
url = "http://www.python.org" url = "http://www.example.com"
with test_support.transient_internet(url, timeout=None): with test_support.transient_internet(url, timeout=None):
u = _urlopen_with_retry(url) u = _urlopen_with_retry(url)
self.assertTrue(u.fp._sock.fp._sock.gettimeout() is None) self.assertIsNone(u.fp._sock.fp._sock.gettimeout())
def test_http_default_timeout(self): def test_http_default_timeout(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
url = "http://www.python.org" url = "http://www.example.com"
with test_support.transient_internet(url): with test_support.transient_internet(url):
socket.setdefaulttimeout(60) socket.setdefaulttimeout(60)
try: try:
...@@ -270,18 +268,18 @@ class TimeoutTest(unittest.TestCase): ...@@ -270,18 +268,18 @@ class TimeoutTest(unittest.TestCase):
self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 60) self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 60)
def test_http_no_timeout(self): def test_http_no_timeout(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
url = "http://www.python.org" url = "http://www.example.com"
with test_support.transient_internet(url): with test_support.transient_internet(url):
socket.setdefaulttimeout(60) socket.setdefaulttimeout(60)
try: try:
u = _urlopen_with_retry(url, timeout=None) u = _urlopen_with_retry(url, timeout=None)
finally: finally:
socket.setdefaulttimeout(None) socket.setdefaulttimeout(None)
self.assertTrue(u.fp._sock.fp._sock.gettimeout() is None) self.assertIsNone(u.fp._sock.fp._sock.gettimeout())
def test_http_timeout(self): def test_http_timeout(self):
url = "http://www.python.org" url = "http://www.example.com"
with test_support.transient_internet(url): with test_support.transient_internet(url):
u = _urlopen_with_retry(url, timeout=120) u = _urlopen_with_retry(url, timeout=120)
self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 120) self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 120)
...@@ -289,13 +287,13 @@ class TimeoutTest(unittest.TestCase): ...@@ -289,13 +287,13 @@ class TimeoutTest(unittest.TestCase):
FTP_HOST = "ftp://ftp.mirror.nl/pub/gnu/" FTP_HOST = "ftp://ftp.mirror.nl/pub/gnu/"
def test_ftp_basic(self): def test_ftp_basic(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
with test_support.transient_internet(self.FTP_HOST, timeout=None): with test_support.transient_internet(self.FTP_HOST, timeout=None):
u = _urlopen_with_retry(self.FTP_HOST) u = _urlopen_with_retry(self.FTP_HOST)
self.assertTrue(u.fp.fp._sock.gettimeout() is None) self.assertIsNone(u.fp.fp._sock.gettimeout())
def test_ftp_default_timeout(self): def test_ftp_default_timeout(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
with test_support.transient_internet(self.FTP_HOST): with test_support.transient_internet(self.FTP_HOST):
socket.setdefaulttimeout(60) socket.setdefaulttimeout(60)
try: try:
...@@ -305,14 +303,14 @@ class TimeoutTest(unittest.TestCase): ...@@ -305,14 +303,14 @@ class TimeoutTest(unittest.TestCase):
self.assertEqual(u.fp.fp._sock.gettimeout(), 60) self.assertEqual(u.fp.fp._sock.gettimeout(), 60)
def test_ftp_no_timeout(self): def test_ftp_no_timeout(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout(),)
with test_support.transient_internet(self.FTP_HOST): with test_support.transient_internet(self.FTP_HOST):
socket.setdefaulttimeout(60) socket.setdefaulttimeout(60)
try: try:
u = _urlopen_with_retry(self.FTP_HOST, timeout=None) u = _urlopen_with_retry(self.FTP_HOST, timeout=None)
finally: finally:
socket.setdefaulttimeout(None) socket.setdefaulttimeout(None)
self.assertTrue(u.fp.fp._sock.gettimeout() is None) self.assertIsNone(u.fp.fp._sock.gettimeout())
def test_ftp_timeout(self): def test_ftp_timeout(self):
with test_support.transient_internet(self.FTP_HOST): with test_support.transient_internet(self.FTP_HOST):
......
...@@ -39,9 +39,6 @@ class MockHandler(WSGIRequestHandler): ...@@ -39,9 +39,6 @@ class MockHandler(WSGIRequestHandler):
pass pass
def hello_app(environ,start_response): def hello_app(environ,start_response):
start_response("200 OK", [ start_response("200 OK", [
('Content-Type','text/plain'), ('Content-Type','text/plain'),
...@@ -62,27 +59,6 @@ def run_amock(app=hello_app, data="GET / HTTP/1.0\n\n"): ...@@ -62,27 +59,6 @@ def run_amock(app=hello_app, data="GET / HTTP/1.0\n\n"):
return out.getvalue(), err.getvalue() return out.getvalue(), err.getvalue()
def compare_generic_iter(make_it,match): def compare_generic_iter(make_it,match):
"""Utility to compare a generic 2.1/2.2+ iterator with an iterable """Utility to compare a generic 2.1/2.2+ iterator with an iterable
...@@ -120,10 +96,6 @@ def compare_generic_iter(make_it,match): ...@@ -120,10 +96,6 @@ def compare_generic_iter(make_it,match):
raise AssertionError("Too many items from .next()",it) raise AssertionError("Too many items from .next()",it)
class IntegrationTests(TestCase): class IntegrationTests(TestCase):
def check_hello(self, out, has_length=True): def check_hello(self, out, has_length=True):
...@@ -161,10 +133,6 @@ class IntegrationTests(TestCase): ...@@ -161,10 +133,6 @@ class IntegrationTests(TestCase):
) )
class UtilityTests(TestCase): class UtilityTests(TestCase):
def checkShift(self,sn_in,pi_in,part,sn_out,pi_out): def checkShift(self,sn_in,pi_in,part,sn_out,pi_out):
...@@ -187,7 +155,7 @@ class UtilityTests(TestCase): ...@@ -187,7 +155,7 @@ class UtilityTests(TestCase):
# Check existing value # Check existing value
env = {key:alt} env = {key:alt}
util.setup_testing_defaults(env) util.setup_testing_defaults(env)
self.assertTrue(env[key] is alt) self.assertIs(env[key], alt)
def checkCrossDefault(self,key,value,**kw): def checkCrossDefault(self,key,value,**kw):
util.setup_testing_defaults(kw) util.setup_testing_defaults(kw)
...@@ -201,11 +169,6 @@ class UtilityTests(TestCase): ...@@ -201,11 +169,6 @@ class UtilityTests(TestCase):
util.setup_testing_defaults(kw) util.setup_testing_defaults(kw)
self.assertEqual(util.request_uri(kw,query),uri) self.assertEqual(util.request_uri(kw,query),uri)
def checkFW(self,text,size,match): def checkFW(self,text,size,match):
def make_it(text=text,size=size): def make_it(text=text,size=size):
...@@ -224,7 +187,6 @@ class UtilityTests(TestCase): ...@@ -224,7 +187,6 @@ class UtilityTests(TestCase):
it.close() it.close()
self.assertTrue(it.filelike.closed) self.assertTrue(it.filelike.closed)
def testSimpleShifts(self): def testSimpleShifts(self):
self.checkShift('','/', '', '/', '') self.checkShift('','/', '', '/', '')
self.checkShift('','/x', 'x', '/x', '') self.checkShift('','/x', 'x', '/x', '')
...@@ -232,7 +194,6 @@ class UtilityTests(TestCase): ...@@ -232,7 +194,6 @@ class UtilityTests(TestCase):
self.checkShift('/a','/x/y', 'x', '/a/x', '/y') self.checkShift('/a','/x/y', 'x', '/a/x', '/y')
self.checkShift('/a','/x/', 'x', '/a/x', '/') self.checkShift('/a','/x/', 'x', '/a/x', '/')
def testNormalizedShifts(self): def testNormalizedShifts(self):
self.checkShift('/a/b', '/../y', '..', '/a', '/y') self.checkShift('/a/b', '/../y', '..', '/a', '/y')
self.checkShift('', '/../y', '..', '', '/y') self.checkShift('', '/../y', '..', '', '/y')
...@@ -246,7 +207,6 @@ class UtilityTests(TestCase): ...@@ -246,7 +207,6 @@ class UtilityTests(TestCase):
self.checkShift('/a/b', '/x//', 'x', '/a/b/x', '/') self.checkShift('/a/b', '/x//', 'x', '/a/b/x', '/')
self.checkShift('/a/b', '/.', None, '/a/b', '') self.checkShift('/a/b', '/.', None, '/a/b', '')
def testDefaults(self): def testDefaults(self):
for key, value in [ for key, value in [
('SERVER_NAME','127.0.0.1'), ('SERVER_NAME','127.0.0.1'),
...@@ -266,7 +226,6 @@ class UtilityTests(TestCase): ...@@ -266,7 +226,6 @@ class UtilityTests(TestCase):
]: ]:
self.checkDefault(key,value) self.checkDefault(key,value)
def testCrossDefaults(self): def testCrossDefaults(self):
self.checkCrossDefault('HTTP_HOST',"foo.bar",SERVER_NAME="foo.bar") self.checkCrossDefault('HTTP_HOST',"foo.bar",SERVER_NAME="foo.bar")
self.checkCrossDefault('wsgi.url_scheme',"https",HTTPS="on") self.checkCrossDefault('wsgi.url_scheme',"https",HTTPS="on")
...@@ -276,7 +235,6 @@ class UtilityTests(TestCase): ...@@ -276,7 +235,6 @@ class UtilityTests(TestCase):
self.checkCrossDefault('SERVER_PORT',"80",HTTPS="foo") self.checkCrossDefault('SERVER_PORT',"80",HTTPS="foo")
self.checkCrossDefault('SERVER_PORT',"443",HTTPS="on") self.checkCrossDefault('SERVER_PORT',"443",HTTPS="on")
def testGuessScheme(self): def testGuessScheme(self):
self.assertEqual(util.guess_scheme({}), "http") self.assertEqual(util.guess_scheme({}), "http")
self.assertEqual(util.guess_scheme({'HTTPS':"foo"}), "http") self.assertEqual(util.guess_scheme({'HTTPS':"foo"}), "http")
...@@ -284,13 +242,10 @@ class UtilityTests(TestCase): ...@@ -284,13 +242,10 @@ class UtilityTests(TestCase):
self.assertEqual(util.guess_scheme({'HTTPS':"yes"}), "https") self.assertEqual(util.guess_scheme({'HTTPS':"yes"}), "https")
self.assertEqual(util.guess_scheme({'HTTPS':"1"}), "https") self.assertEqual(util.guess_scheme({'HTTPS':"1"}), "https")
def testAppURIs(self): def testAppURIs(self):
self.checkAppURI("http://127.0.0.1/") self.checkAppURI("http://127.0.0.1/")
self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam") self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam")
self.checkAppURI("http://127.0.0.1/sp%E4m", SCRIPT_NAME="/sp\xe4m")
self.checkAppURI("http://spam.example.com:2071/", self.checkAppURI("http://spam.example.com:2071/",
HTTP_HOST="spam.example.com:2071", SERVER_PORT="2071") HTTP_HOST="spam.example.com:2071", SERVER_PORT="2071")
self.checkAppURI("http://spam.example.com/", self.checkAppURI("http://spam.example.com/",
...@@ -304,14 +259,19 @@ class UtilityTests(TestCase): ...@@ -304,14 +259,19 @@ class UtilityTests(TestCase):
def testReqURIs(self): def testReqURIs(self):
self.checkReqURI("http://127.0.0.1/") self.checkReqURI("http://127.0.0.1/")
self.checkReqURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam") self.checkReqURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam")
self.checkReqURI("http://127.0.0.1/sp%E4m", SCRIPT_NAME="/sp\xe4m")
self.checkReqURI("http://127.0.0.1/spammity/spam", self.checkReqURI("http://127.0.0.1/spammity/spam",
SCRIPT_NAME="/spammity", PATH_INFO="/spam") SCRIPT_NAME="/spammity", PATH_INFO="/spam")
self.checkReqURI("http://127.0.0.1/spammity/sp%E4m",
SCRIPT_NAME="/spammity", PATH_INFO="/sp\xe4m")
self.checkReqURI("http://127.0.0.1/spammity/spam;ham", self.checkReqURI("http://127.0.0.1/spammity/spam;ham",
SCRIPT_NAME="/spammity", PATH_INFO="/spam;ham") SCRIPT_NAME="/spammity", PATH_INFO="/spam;ham")
self.checkReqURI("http://127.0.0.1/spammity/spam;cookie=1234,5678", self.checkReqURI("http://127.0.0.1/spammity/spam;cookie=1234,5678",
SCRIPT_NAME="/spammity", PATH_INFO="/spam;cookie=1234,5678") SCRIPT_NAME="/spammity", PATH_INFO="/spam;cookie=1234,5678")
self.checkReqURI("http://127.0.0.1/spammity/spam?say=ni", self.checkReqURI("http://127.0.0.1/spammity/spam?say=ni",
SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni") SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni")
self.checkReqURI("http://127.0.0.1/spammity/spam?s%E4y=ni",
SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="s%E4y=ni")
self.checkReqURI("http://127.0.0.1/spammity/spam", 0, self.checkReqURI("http://127.0.0.1/spammity/spam", 0,
SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni") SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni")
...@@ -342,7 +302,7 @@ class HeaderTests(TestCase): ...@@ -342,7 +302,7 @@ class HeaderTests(TestCase):
self.assertEqual(Headers(test[:]).keys(), ['x']) self.assertEqual(Headers(test[:]).keys(), ['x'])
self.assertEqual(Headers(test[:]).values(), ['y']) self.assertEqual(Headers(test[:]).values(), ['y'])
self.assertEqual(Headers(test[:]).items(), test) self.assertEqual(Headers(test[:]).items(), test)
self.assertFalse(Headers(test).items() is test) # must be copy! self.assertIsNot(Headers(test).items(), test) # must be copy!
h=Headers([]) h=Headers([])
del h['foo'] # should not raise an error del h['foo'] # should not raise an error
...@@ -411,15 +371,6 @@ class TestHandler(ErrorHandler): ...@@ -411,15 +371,6 @@ class TestHandler(ErrorHandler):
raise # for testing, we want to see what's happening raise # for testing, we want to see what's happening
class HandlerTests(TestCase): class HandlerTests(TestCase):
def checkEnvironAttrs(self, handler): def checkEnvironAttrs(self, handler):
...@@ -460,7 +411,6 @@ class HandlerTests(TestCase): ...@@ -460,7 +411,6 @@ class HandlerTests(TestCase):
h=TestHandler(); h.setup_environ() h=TestHandler(); h.setup_environ()
self.assertEqual(h.environ['wsgi.url_scheme'],'http') self.assertEqual(h.environ['wsgi.url_scheme'],'http')
def testAbstractMethods(self): def testAbstractMethods(self):
h = BaseHandler() h = BaseHandler()
for name in [ for name in [
...@@ -469,7 +419,6 @@ class HandlerTests(TestCase): ...@@ -469,7 +419,6 @@ class HandlerTests(TestCase):
self.assertRaises(NotImplementedError, getattr(h,name)) self.assertRaises(NotImplementedError, getattr(h,name))
self.assertRaises(NotImplementedError, h._write, "test") self.assertRaises(NotImplementedError, h._write, "test")
def testContentLength(self): def testContentLength(self):
# Demo one reason iteration is better than write()... ;) # Demo one reason iteration is better than write()... ;)
...@@ -549,7 +498,6 @@ class HandlerTests(TestCase): ...@@ -549,7 +498,6 @@ class HandlerTests(TestCase):
"\r\n"+MSG) "\r\n"+MSG)
self.assertNotEqual(h.stderr.getvalue().find("AssertionError"), -1) self.assertNotEqual(h.stderr.getvalue().find("AssertionError"), -1)
def testHeaderFormats(self): def testHeaderFormats(self):
def non_error_app(e,s): def non_error_app(e,s):
...@@ -591,40 +539,28 @@ class HandlerTests(TestCase): ...@@ -591,40 +539,28 @@ class HandlerTests(TestCase):
(stdpat%(version,sw), h.stdout.getvalue()) (stdpat%(version,sw), h.stdout.getvalue())
) )
# This epilogue is needed for compatibility with the Python 2.5 regrtest module def testCloseOnError(self):
side_effects = {'close_called': False}
MSG = b"Some output has been sent"
def error_app(e,s):
s("200 OK",[])(MSG)
class CrashyIterable(object):
def __iter__(self):
while True:
yield b'blah'
raise AssertionError("This should be caught by handler")
def close(self):
side_effects['close_called'] = True
return CrashyIterable()
h = ErrorHandler()
h.run(error_app)
self.assertEqual(side_effects['close_called'], True)
def test_main(): def test_main():
test_support.run_unittest(__name__) test_support.run_unittest(__name__)
if __name__ == "__main__": if __name__ == "__main__":
test_main() test_main()
# the above lines intentionally left blank
...@@ -65,10 +65,6 @@ if PYPY: ...@@ -65,10 +65,6 @@ if PYPY:
# BUGS: # BUGS:
# https://bugs.pypy.org/issue1743
'test__real_greenlet.py',
'test__exc_info.py',
# in CPython we compile _semaphore.py with Cython to make its operation atomic # in CPython we compile _semaphore.py with Cython to make its operation atomic
# how to do atomic operations on PyPy? # how to do atomic operations on PyPy?
'test__threading_vs_settrace.py', 'test__threading_vs_settrace.py',
...@@ -86,7 +82,8 @@ if PYPY: ...@@ -86,7 +82,8 @@ if PYPY:
'test__refcount.py', 'test__refcount.py',
'test__server.py', 'test__server.py',
'test_subprocess.py', # test_executable_without_cwd 'test_subprocess.py', # test_executable_without_cwd
'FLAKY test___example_servers.py' 'FLAKY test___example_servers.py',
'FLAKY test_queue.py',
] ]
......
...@@ -11,7 +11,32 @@ TODO: store pid for each signal ...@@ -11,7 +11,32 @@ TODO: store pid for each signal
TODO: document file descriptor usage per loop TODO: document file descriptor usage per loop
TODO: store loop pid_t and compare isndie signal handler,store 1 for same, 2 for differign pid, clean up in loop_fork TODO: store loop pid_t and compare isndie signal handler,store 1 for same, 2 for differign pid, clean up in loop_fork
TODO: embed watchers need updating when fd changes TODO: embed watchers need updating when fd changes
TODO: document portbaility requirements for atomic pointer access TODO: document portability requirements for atomic pointer access
TODO: possible cb aliasing?
TODO: document requirements for function pointers and calling conventions.
4.19 Thu Sep 25 08:18:25 CEST 2014
- ev.h wasn't valid C++ anymore, which tripped compilers other than
clang, msvc or gcc (analyzed by Raphael 'kena' Poss). Unfortunately,
C++ doesn't support typedefs for function pointers fully, so the affected
declarations have to spell out the types each time.
- when not using autoconf, tighten the check for clock_gettime and related
functionality.
4.18 Fri Sep 5 17:55:26 CEST 2014
- events on files were not always generated properly with the
epoll backend (testcase by Assaf Inbal).
- mark event pipe fd as cloexec after a fork (analyzed by Sami Farin).
- (ecb) support m68k, m88k and sh (patch by Miod Vallat).
- use a reasonable fallback for EV_NSIG instead of erroring out
when we can't detect the signal set size.
- in the absence of autoconf, do not use the clock syscall
on glibc >= 2.17 (avoids the syscall AND -lrt on systems
doing clock_gettime in userspace).
- ensure extern "C" function pointers are used for externally-visible
loop callbacks (not watcher callbacks yet).
- (ecb) work around memory barriers and volatile apparently both being
broken in visual studio 2008 and later (analysed and patch by Nicolas Noble).
4.15 Fri Mar 1 12:04:50 CET 2013 4.15 Fri Mar 1 12:04:50 CET 2013
- destroying a non-default loop would stop the global waitpid - destroying a non-default loop would stop the global waitpid
...@@ -41,7 +66,7 @@ TODO: document portbaility requirements for atomic pointer access ...@@ -41,7 +66,7 @@ TODO: document portbaility requirements for atomic pointer access
- include sys/syscall.h instead of plain syscall.h. - include sys/syscall.h instead of plain syscall.h.
- check for io watcher loops in ev_verify, check for the most - check for io watcher loops in ev_verify, check for the most
common reported usage bug in ev_io_start. common reported usage bug in ev_io_start.
- chose socket vs. WSASocket at compiletime using EV_USE_WSASOCKET. - choose socket vs. WSASocket at compiletime using EV_USE_WSASOCKET.
- always use WSASend/WSARecv directly on windows, hoping that this - always use WSASend/WSARecv directly on windows, hoping that this
works in all cases (unlike read/write/send/recv...). works in all cases (unlike read/write/send/recv...).
- try to detect signals around a fork faster (test program by - try to detect signals around a fork faster (test program by
...@@ -50,7 +75,7 @@ TODO: document portbaility requirements for atomic pointer access ...@@ -50,7 +75,7 @@ TODO: document portbaility requirements for atomic pointer access
- rename ev::embed::set to ev::embed::set_embed to avoid clashing - rename ev::embed::set to ev::embed::set_embed to avoid clashing
the watcher base set (loop) method. the watcher base set (loop) method.
- rewrite the async/signal pipe logic to always keep a valid fd, which - rewrite the async/signal pipe logic to always keep a valid fd, which
simplifies (and hopefuly correctifies :) the race checking simplifies (and hopefully correctifies :) the race checking
on fork, at the cost of one extra fd. on fork, at the cost of one extra fd.
- add fat, msdos, jffs2, ramfs, ntfs and btrfs to the list of - add fat, msdos, jffs2, ramfs, ntfs and btrfs to the list of
inotify-supporting filesystems. inotify-supporting filesystems.
...@@ -252,7 +277,7 @@ TODO: document portbaility requirements for atomic pointer access ...@@ -252,7 +277,7 @@ TODO: document portbaility requirements for atomic pointer access
- implement ev_suspend and ev_resume. - implement ev_suspend and ev_resume.
- new EV_CUSTOM revents flag for use by applications. - new EV_CUSTOM revents flag for use by applications.
- add documentation section about priorities. - add documentation section about priorities.
- add a glossary to the dcoumentation. - add a glossary to the documentation.
- extend the ev_fork description slightly. - extend the ev_fork description slightly.
- optimize a jump out of call_pending. - optimize a jump out of call_pending.
......
All files in libev are All files in libev are
Copyright (c)2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann. Copyright (c)2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ timestamp='2008-01-23' ...@@ -8,7 +8,7 @@ timestamp='2008-01-23'
# This file is free software; you can redistribute it and/or modify it # This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by # under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, but # This program is distributed in the hope that it will be useful, but
......
...@@ -12,7 +12,7 @@ timestamp='2008-01-16' ...@@ -12,7 +12,7 @@ timestamp='2008-01-16'
# #
# This file is free software; you can redistribute it and/or modify # This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
......
This diff is collapsed.
This diff is collapsed.
...@@ -205,7 +205,7 @@ struct ev_loop; ...@@ -205,7 +205,7 @@ struct ev_loop;
/*****************************************************************************/ /*****************************************************************************/
#define EV_VERSION_MAJOR 4 #define EV_VERSION_MAJOR 4
#define EV_VERSION_MINOR 15 #define EV_VERSION_MINOR 19
/* eventmask, revents, events... */ /* eventmask, revents, events... */
enum { enum {
...@@ -658,8 +658,10 @@ EV_API_DECL void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval) EV_T ...@@ -658,8 +658,10 @@ EV_API_DECL void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval) EV_T
/* advanced stuff for threading etc. support, see docs */ /* advanced stuff for threading etc. support, see docs */
EV_API_DECL void ev_set_userdata (EV_P_ void *data) EV_THROW; EV_API_DECL void ev_set_userdata (EV_P_ void *data) EV_THROW;
EV_API_DECL void *ev_userdata (EV_P) EV_THROW; EV_API_DECL void *ev_userdata (EV_P) EV_THROW;
EV_API_DECL void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P)) EV_THROW; typedef void (*ev_loop_callback)(EV_P);
EV_API_DECL void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P) EV_THROW) EV_THROW; EV_API_DECL void ev_set_invoke_pending_cb (EV_P_ ev_loop_callback invoke_pending_cb) EV_THROW;
/* C++ doesn't allow the use of the ev_loop_callback typedef here, so we need to spell it out*/
EV_API_DECL void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P) EV_THROW, void (*acquire)(EV_P) EV_THROW) EV_THROW;
EV_API_DECL unsigned int ev_pending_count (EV_P) EV_THROW; /* number of pending events, if any */ EV_API_DECL unsigned int ev_pending_count (EV_P) EV_THROW; /* number of pending events, if any */
EV_API_DECL void ev_invoke_pending (EV_P); /* invoke all pending watchers */ EV_API_DECL void ev_invoke_pending (EV_P); /* invoke all pending watchers */
...@@ -730,7 +732,7 @@ EV_API_DECL void ev_resume (EV_P) EV_THROW; ...@@ -730,7 +732,7 @@ EV_API_DECL void ev_resume (EV_P) EV_THROW;
#endif #endif
/* stopping (enabling, adding) a watcher does nothing if it is already running */ /* stopping (enabling, adding) a watcher does nothing if it is already running */
/* stopping (disabling, deleting) a watcher does nothing unless its already running */ /* stopping (disabling, deleting) a watcher does nothing unless it's already running */
#if EV_PROTOTYPES #if EV_PROTOTYPES
/* feeds an event into a watcher as if the event actually occurred */ /* feeds an event into a watcher as if the event actually occurred */
......
...@@ -228,7 +228,10 @@ epoll_poll (EV_P_ ev_tstamp timeout) ...@@ -228,7 +228,10 @@ epoll_poll (EV_P_ ev_tstamp timeout)
if (anfds [fd].emask & EV_EMASK_EPERM && events) if (anfds [fd].emask & EV_EMASK_EPERM && events)
fd_event (EV_A_ fd, events); fd_event (EV_A_ fd, events);
else else
epoll_eperms [i] = epoll_eperms [--epoll_epermcnt]; {
epoll_eperms [i] = epoll_eperms [--epoll_epermcnt];
anfds [fd].emask = 0;
}
} }
} }
......
/* /*
* libev kqueue backend * libev kqueue backend
* *
* Copyright (c) 2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann <libev@schmorp.de> * Copyright (c) 2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann <libev@schmorp.de>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modifica- * Redistribution and use in source and binary forms, with or without modifica-
......
/* /*
* loop member variable declarations * loop member variable declarations
* *
* Copyright (c) 2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann <libev@schmorp.de> * Copyright (c) 2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann <libev@schmorp.de>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modifica- * Redistribution and use in source and binary forms, with or without modifica-
...@@ -194,9 +194,10 @@ VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */ ...@@ -194,9 +194,10 @@ VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */
VARx(unsigned int, loop_depth) /* #ev_run enters - #ev_run leaves */ VARx(unsigned int, loop_depth) /* #ev_run enters - #ev_run leaves */
VARx(void *, userdata) VARx(void *, userdata)
/* C++ doesn't support the ev_loop_callback typedef here. stinks. */
VAR (release_cb, void (*release_cb)(EV_P) EV_THROW) VAR (release_cb, void (*release_cb)(EV_P) EV_THROW)
VAR (acquire_cb, void (*acquire_cb)(EV_P) EV_THROW) VAR (acquire_cb, void (*acquire_cb)(EV_P) EV_THROW)
VAR (invoke_cb , void (*invoke_cb) (EV_P)) VAR (invoke_cb , ev_loop_callback invoke_cb)
#endif #endif
#undef VARx #undef VARx
......
...@@ -143,7 +143,7 @@ fail: ...@@ -143,7 +143,7 @@ fail:
#undef pipe #undef pipe
#define pipe(filedes) ev_pipe (filedes) #define pipe(filedes) ev_pipe (filedes)
#define EV_HAVE_EV_TIME 1 #define EV_HAVE_EV_TIME 1
ev_tstamp ev_tstamp
ev_time (void) ev_time (void)
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
# GNU Libtool is free software; you can redistribute it and/or modify # GNU Libtool is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# As a special exception to the GNU General Public License, # As a special exception to the GNU General Public License,
......
This diff is collapsed.
...@@ -32,6 +32,11 @@ define_re = re.compile(r'^#define\s+([a-zA-Z_]\w*)(\((?:[^,)]+,)*[^,)]+\))?\s+(. ...@@ -32,6 +32,11 @@ define_re = re.compile(r'^#define\s+([a-zA-Z_]\w*)(\((?:[^,)]+,)*[^,)]+\))?\s+(.
# Conditional directive: # Conditional directive:
condition_re = re.compile(r'^#(ifdef\s+.+|if\s+.+|else\s*|endif\s*)$') condition_re = re.compile(r'^#(ifdef\s+.+|if\s+.+|else\s*|endif\s*)$')
# cython header:
cython_header_re = re.compile(r'^/\* (generated by cython [^\s*]+)[^*]+\*/$', re.I)
#assert cython_header_re.match('/* Generated by Cython 0.21.1 */').group(1) == 'Generated by Cython 0.21.1'
#assert cython_header_re.match('/* Generated by Cython 0.19 on 55-555-555 */').group(1) == 'Generated by Cython 0.19'
def match_condition(line): def match_condition(line):
line = line.strip() line = line.strip()
...@@ -557,9 +562,9 @@ def postprocess_cython_output(filename, banner): ...@@ -557,9 +562,9 @@ def postprocess_cython_output(filename, banner):
input = open(filename) input = open(filename)
firstline = input.readline() firstline = input.readline()
if firstline.strip().lower().startswith('/* generated by cython ') and firstline.strip().endswith('*/'): m = cython_header_re.match(firstline.strip())
line = firstline.strip().split(' on ', 1)[0] if m:
result.append(line + ' */') result.append('/* %s */' % m.group(1))
else: else:
result.append(firstline) result.append(firstline)
...@@ -738,7 +743,7 @@ if __name__ == '__main__': ...@@ -738,7 +743,7 @@ if __name__ == '__main__':
options, args = parser.parse_args() options, args = parser.parse_args()
if len(args) != 1: if len(args) != 1:
sys.exit('Expected one argument, got %s' % len(args)) sys.exit('Expected one argument (filename), got %r' % args)
filename = args[0] filename = args[0]
if options.debug: if options.debug:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment