Finished up SSL.Connection compatibility. Backwards compatibility change: it used to be that you could just call close() on an ssl socket, but now you have to call shutdown() and then close(). This is in line with the normal OpenSSL behavior and means that we no longer penalize correctly-written clients. Fixed wsgi and api_test to reflect this changed assumption.
This commit is contained in:
@@ -233,12 +233,6 @@ class GreenSocket(object):
|
||||
if self.closed:
|
||||
return
|
||||
self.closed = True
|
||||
if self.is_secure:
|
||||
# *NOTE: This is not quite the correct SSL shutdown sequence.
|
||||
# We should actually be checking the return value of shutdown.
|
||||
# Note also that this is not the same as calling self.shutdown().
|
||||
self.fd.shutdown()
|
||||
|
||||
fn = self.close = self.fd.close
|
||||
try:
|
||||
res = fn(*args, **kw)
|
||||
@@ -362,10 +356,7 @@ class GreenSocket(object):
|
||||
return fn(*args, **kw)
|
||||
|
||||
def shutdown(self, *args, **kw):
|
||||
if self.is_secure:
|
||||
fn = self.shutdown = self.fd.sock_shutdown
|
||||
else:
|
||||
fn = self.shutdown = self.fd.shutdown
|
||||
fn = self.shutdown = self.fd.shutdown
|
||||
return fn(*args, **kw)
|
||||
|
||||
def settimeout(self, howlong):
|
||||
@@ -543,10 +534,69 @@ class GreenSSL(GreenSocket):
|
||||
"GreenSSL can only be constructed with an "\
|
||||
"OpenSSL Connection object")
|
||||
self.sock = self
|
||||
|
||||
def close(self):
|
||||
# *NOTE: in older versions of eventlet, we called shutdown() on SSL sockets
|
||||
# before closing them. That wasn't right because correctly-written clients
|
||||
# would have already called shutdown, and calling shutdown a second time
|
||||
# triggers unwanted bidirectional communication.
|
||||
super(GreenSSL, self).close()
|
||||
|
||||
def do_handshake(self):
|
||||
""" Perform an SSL handshake (usually called after renegotiate or one of
|
||||
set_accept_state or set_accept_state). This can raise the same exceptions as
|
||||
send and recv. """
|
||||
if self.act_non_blocking:
|
||||
return self.fd.do_handshake()
|
||||
while True:
|
||||
try:
|
||||
return self.fd.do_handshake()
|
||||
except util.SSL.WantReadError:
|
||||
trampoline(self.fd.fileno(),
|
||||
read=True,
|
||||
timeout=self.timeout,
|
||||
timeout_exc=socket.timeout)
|
||||
except util.SSL.WantWriteError:
|
||||
trampoline(self.fd.fileno(),
|
||||
write=True,
|
||||
timeout=self.timeout,
|
||||
timeout_exc=socket.timeout)
|
||||
|
||||
def dup(self):
|
||||
raise NotImplementedError("Dup not supported on SSL sockets")
|
||||
|
||||
def get_app_data(self, *args, **kw):
|
||||
fn = self.get_app_data = self.fd.get_app_data
|
||||
return fn(*args, **kw)
|
||||
|
||||
def set_app_data(self, *args, **kw):
|
||||
fn = self.set_app_data = self.fd.set_app_data
|
||||
return fn(*args, **kw)
|
||||
|
||||
def get_cipher_list(self, *args, **kw):
|
||||
fn = self.get_cipher_list = self.fd.get_cipher_list
|
||||
return fn(*args, **kw)
|
||||
|
||||
def get_context(self, *args, **kw):
|
||||
fn = self.get_context = self.fd.get_context
|
||||
return fn(*args, **kw)
|
||||
|
||||
def get_peer_certificate(self, *args, **kw):
|
||||
fn = self.get_peer_certificate = self.fd.get_peer_certificate
|
||||
return fn(*args, **kw)
|
||||
|
||||
def makefile(self, mode='r', bufsize=-1):
|
||||
raise NotImplementedError("Makefile not supported on SSL sockets")
|
||||
|
||||
def pending(self, *args, **kw):
|
||||
fn = self.pending = self.fd.pending
|
||||
return fn(*args, **kw)
|
||||
|
||||
def read(self, size):
|
||||
"""Works like a blocking call to SSL_read(), whose behavior is
|
||||
described here: http://www.openssl.org/docs/ssl/SSL_read.html"""
|
||||
if self.act_non_blocking:
|
||||
return self.fd.read(size)
|
||||
while True:
|
||||
try:
|
||||
return self.fd.read(size)
|
||||
@@ -565,12 +615,18 @@ class GreenSSL(GreenSocket):
|
||||
return ''
|
||||
|
||||
recv = read
|
||||
|
||||
def renegotiate(self, *args, **kw):
|
||||
fn = self.renegotiate = self.fd.renegotiate
|
||||
return fn(*args, **kw)
|
||||
|
||||
def write(self, data):
|
||||
"""Works like a blocking call to SSL_write(), whose behavior is
|
||||
described here: http://www.openssl.org/docs/ssl/SSL_write.html"""
|
||||
if not data:
|
||||
return 0 # calling SSL_write() with 0 bytes to be sent is undefined
|
||||
if self.act_non_blocking:
|
||||
return self.fd.write(data)
|
||||
while True:
|
||||
try:
|
||||
return self.fd.write(data)
|
||||
@@ -596,15 +652,55 @@ class GreenSSL(GreenSocket):
|
||||
tail = self.send(data)
|
||||
while tail < len(data):
|
||||
tail += self.send(data[tail:])
|
||||
|
||||
def set_accept_state(self, *args, **kw):
|
||||
fn = self.set_accept_state = self.fd.set_accept_state
|
||||
return fn(*args, **kw)
|
||||
|
||||
def dup(self):
|
||||
raise NotImplementedError("Dup not supported on SSL sockets")
|
||||
def set_connect_state(self, *args, **kw):
|
||||
fn = self.set_connect_state = self.fd.set_connect_state
|
||||
return fn(*args, **kw)
|
||||
|
||||
def shutdown(self):
|
||||
if self.act_non_blocking:
|
||||
return self.fd.shutdown()
|
||||
while True:
|
||||
try:
|
||||
return self.fd.shutdown()
|
||||
except util.SSL.WantReadError:
|
||||
trampoline(self.fd.fileno(),
|
||||
read=True,
|
||||
timeout=self.timeout,
|
||||
timeout_exc=socket.timeout)
|
||||
except util.SSL.WantWriteError:
|
||||
trampoline(self.fd.fileno(),
|
||||
write=True,
|
||||
timeout=self.timeout,
|
||||
timeout_exc=socket.timeout)
|
||||
|
||||
|
||||
def get_shutdown(self, *args, **kw):
|
||||
fn = self.get_shutdown = self.fd.get_shutdown
|
||||
return fn(*args, **kw)
|
||||
|
||||
def set_shutdown(self, *args, **kw):
|
||||
fn = self.set_shutdown = self.fd.set_shutdown
|
||||
return fn(*args, **kw)
|
||||
|
||||
def sock_shutdown(self, *args, **kw):
|
||||
fn = self.sock_shutdown = self.fd.sock_shutdown
|
||||
return fn(*args, **kw)
|
||||
|
||||
def state_string(self, *args, **kw):
|
||||
fn = self.state_string = self.fd.state_string
|
||||
return fn(*args, **kw)
|
||||
|
||||
def makefile(self, mode='r', bufsize=-1):
|
||||
raise NotImplementedError("Makefile not supported on SSL sockets")
|
||||
def want_read(self, *args, **kw):
|
||||
fn = self.want_read = self.fd.want_read
|
||||
return fn(*args, **kw)
|
||||
|
||||
def pending(self, *args, **kw):
|
||||
fn = self.pending = self.fd.pending
|
||||
def want_write(self, *args, **kw):
|
||||
fn = self.want_write = self.fd.want_write
|
||||
return fn(*args, **kw)
|
||||
|
||||
|
||||
|
@@ -358,6 +358,8 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
|
||||
def finish(self):
|
||||
BaseHTTPServer.BaseHTTPRequestHandler.finish(self)
|
||||
if self.connection.is_secure:
|
||||
self.connection.shutdown()
|
||||
self.connection.close()
|
||||
|
||||
|
||||
@@ -459,6 +461,8 @@ def server(sock, site,
|
||||
break
|
||||
finally:
|
||||
try:
|
||||
if sock.is_secure:
|
||||
sock.shutdown()
|
||||
sock.close()
|
||||
except socket.error, e:
|
||||
if e[0] != errno.EPIPE:
|
||||
|
@@ -21,6 +21,7 @@
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import socket
|
||||
from unittest import TestCase, main
|
||||
|
||||
from eventlet import api
|
||||
@@ -60,7 +61,7 @@ class TestApi(TestCase):
|
||||
def accept_once(listenfd):
|
||||
try:
|
||||
conn, addr = listenfd.accept()
|
||||
fd = conn.makeGreenFile()
|
||||
fd = conn.makefile()
|
||||
conn.close()
|
||||
fd.write('hello\n')
|
||||
fd.close()
|
||||
@@ -71,7 +72,7 @@ class TestApi(TestCase):
|
||||
api.spawn(accept_once, server)
|
||||
|
||||
client = api.connect_tcp(('127.0.0.1', server.getsockname()[1]))
|
||||
fd = client.makeGreenFile()
|
||||
fd = client.makefile()
|
||||
client.close()
|
||||
assert fd.readline() == 'hello\n'
|
||||
|
||||
@@ -84,9 +85,7 @@ class TestApi(TestCase):
|
||||
def accept_once(listenfd):
|
||||
try:
|
||||
conn, addr = listenfd.accept()
|
||||
fl = conn.makeGreenFile('w')
|
||||
fl.write('hello\r\n')
|
||||
fl.close()
|
||||
conn.write('hello\r\n')
|
||||
conn.close()
|
||||
finally:
|
||||
listenfd.close()
|
||||
@@ -98,10 +97,10 @@ class TestApi(TestCase):
|
||||
|
||||
client = util.wrap_ssl(
|
||||
api.connect_tcp(('127.0.0.1', server.getsockname()[1])))
|
||||
client = client.makeGreenFile()
|
||||
fd = socket._fileobject(client, 'rb', 8192)
|
||||
|
||||
assert client.readline() == 'hello\r\n'
|
||||
assert client.read() == ''
|
||||
assert fd.readline() == 'hello\r\n'
|
||||
assert fd.read() == ''
|
||||
client.close()
|
||||
|
||||
def test_server(self):
|
||||
|
Reference in New Issue
Block a user