Merge branch 'fix_invalid_tcp_close'

This commit is contained in:
Aldo Cortesi 2013-12-08 10:15:43 +13:00
commit ed74b62856
6 changed files with 16 additions and 33 deletions

View File

@ -283,32 +283,23 @@ def parse_init_http(line):
return method, url, httpversion return method, url, httpversion
def request_connection_close(httpversion, headers): def connection_close(httpversion, headers):
""" """
Checks the request to see if the client connection should be closed. Checks the message to see if the client connection should be closed according to RFC 2616 Section 8.1
""" """
# At first, check if we have an explicit Connection header.
if "connection" in headers: if "connection" in headers:
toks = get_header_tokens(headers, "connection") toks = get_header_tokens(headers, "connection")
if "close" in toks: if "close" in toks:
return True return True
elif "keep-alive" in toks: elif "keep-alive" in toks:
return False return False
# HTTP 1.1 connections are assumed to be persistent # If we don't have a Connection header, HTTP 1.1 connections are assumed to be persistent
if httpversion == (1, 1): if httpversion == (1, 1):
return False return False
return True return True
def response_connection_close(httpversion, headers):
"""
Checks the response to see if the client connection should be closed.
"""
if request_connection_close(httpversion, headers):
return True
elif (not has_chunked_encoding(headers)) and "content-length" in headers:
return False
return True
def read_http_body_request(rfile, wfile, headers, httpversion, limit): def read_http_body_request(rfile, wfile, headers, httpversion, limit):
""" """

View File

@ -235,6 +235,7 @@ class TCPClient:
try: try:
if self.ssl_established: if self.ssl_established:
self.connection.shutdown() self.connection.shutdown()
self.connection.sock_shutdown(socket.SHUT_WR)
else: else:
self.connection.shutdown(socket.SHUT_WR) self.connection.shutdown(socket.SHUT_WR)
#Section 4.2.2.13 of RFC 1122 tells us that a close() with any pending readable data could lead to an immediate RST being sent. #Section 4.2.2.13 of RFC 1122 tells us that a close() with any pending readable data could lead to an immediate RST being sent.
@ -302,6 +303,8 @@ class BaseHandler:
if request_client_cert: if request_client_cert:
def ver(*args): def ver(*args):
self.clientcert = certutils.SSLCert(args[1]) self.clientcert = certutils.SSLCert(args[1])
# Return true to prevent cert verification error
return True
ctx.set_verify(SSL.VERIFY_PEER, ver) ctx.set_verify(SSL.VERIFY_PEER, ver)
self.connection = SSL.Connection(ctx, self.connection) self.connection = SSL.Connection(ctx, self.connection)
self.ssl_established = True self.ssl_established = True
@ -338,6 +341,7 @@ class BaseHandler:
try: try:
if self.ssl_established: if self.ssl_established:
self.connection.shutdown() self.connection.shutdown()
self.connection.sock_shutdown(socket.SHUT_WR)
else: else:
self.connection.shutdown(socket.SHUT_WR) self.connection.shutdown(socket.SHUT_WR)
#Section 4.2.2.13 of RFC 1122 tells us that a close() with any pending readable data could lead to an immediate RST being sent. #Section 4.2.2.13 of RFC 1122 tells us that a close() with any pending readable data could lead to an immediate RST being sent.

View File

@ -52,7 +52,7 @@ class TServer(tcp.TCPServer):
self.last_handler = h self.last_handler = h
if self.ssl: if self.ssl:
cert = certutils.SSLCert.from_pem( cert = certutils.SSLCert.from_pem(
file(self.ssl["cert"], "r").read() file(self.ssl["cert"], "rb").read()
) )
if self.ssl["v3_only"]: if self.ssl["v3_only"]:
method = tcp.SSLv3_METHOD method = tcp.SSLv3_METHOD

View File

@ -65,7 +65,7 @@ def findPackages(path, dataExclude=[]):
return packages, package_data return packages, package_data
long_description = file("README").read() long_description = file("README","rb").read()
packages, package_data = findPackages("netlib") packages, package_data = findPackages("netlib")
setup( setup(
name = "netlib", name = "netlib",

View File

@ -38,28 +38,16 @@ def test_read_chunked():
tutils.raises("too large", http.read_chunked, 500, s, 2) tutils.raises("too large", http.read_chunked, 500, s, 2)
def test_request_connection_close(): def test_connection_close():
h = odict.ODictCaseless() h = odict.ODictCaseless()
assert http.request_connection_close((1, 0), h) assert http.connection_close((1, 0), h)
assert not http.request_connection_close((1, 1), h) assert not http.connection_close((1, 1), h)
h["connection"] = ["keep-alive"] h["connection"] = ["keep-alive"]
assert not http.request_connection_close((1, 1), h) assert not http.connection_close((1, 1), h)
h["connection"] = ["close"] h["connection"] = ["close"]
assert http.request_connection_close((1, 1), h) assert http.connection_close((1, 1), h)
def test_response_connection_close():
h = odict.ODictCaseless()
assert http.response_connection_close((1, 1), h)
h["content-length"] = [10]
assert not http.response_connection_close((1, 1), h)
h["connection"] = ["close"]
assert http.response_connection_close((1, 1), h)
def test_read_http_body_response(): def test_read_http_body_response():
h = odict.ODictCaseless() h = odict.ODictCaseless()

View File

@ -17,7 +17,7 @@ class TestPassManHtpasswd:
tutils.raises("invalid htpasswd", http_auth.PassManHtpasswd, s) tutils.raises("invalid htpasswd", http_auth.PassManHtpasswd, s)
def test_simple(self): def test_simple(self):
f = open(tutils.test_data.path("data/htpasswd")) f = open(tutils.test_data.path("data/htpasswd"),"rb")
pm = http_auth.PassManHtpasswd(f) pm = http_auth.PassManHtpasswd(f)
vals = ("basic", "test", "test") vals = ("basic", "test", "test")