Skip to content

Commit

Permalink
[python] Fixed python.net.SslSocket when python-version >= 3.4 (#8401) (
Browse files Browse the repository at this point in the history
#11050)

* [python] Fixed python.net.SslSocket when python-version >= 3.4 (#8401)

The issue where SslSocket throws an exception is due to hostName being
null in wrap_socket.  This fix delays wrap_socket until after connect is
called, so we can pass a host in.

* added compilation flag to only run this for python

* removed sys.net.Host import; it was unused, and it caused issues on
non-sys targets

* fixed test to work across platforms (see comment in code)

fixed copy/paste error in code comments

* added gettimeout, getblocking, and getsockopt to
python.lib.socket.Socket
(also added overload of setsockopt to take an Int value)

updated Issue8401 to remove casts

* replaced eq with feq in test for settimeout values
  • Loading branch information
theJenix committed Mar 30, 2023
1 parent 1d33f29 commit a521f7a
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 6 deletions.
5 changes: 5 additions & 0 deletions std/python/_std/sys/net/Socket.hx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ private class SocketOutput extends haxe.io.Output {
__s = new PSocket();
}

function __rebuildIoStreams():Void {
input = new SocketInput(__s);
output = new SocketOutput(__s);
}

public function close():Void {
__s.close();
}
Expand Down
17 changes: 17 additions & 0 deletions std/python/lib/socket/Socket.hx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ extern class Socket {
**/
function getsockname():python.lib.socket.Address;

/**
Return the timeout for the socket or null if no timeout has been set.
**/
function gettimeout():Null<Float>;

/**
Gives a timeout after which blocking socket operations (such as reading and writing) will abort and throw an exception.
**/
Expand All @@ -90,14 +95,26 @@ extern class Socket {
**/
function waitForRead():Void;

/**
Return the current blocking mode of the socket.
**/
@:require(python_version >= 3.7)
function getblocking():Bool;

/**
Change the blocking mode of the socket. A blocking socket is the default behavior. A non-blocking socket will abort blocking operations immediately by throwing a haxe.io.Error.Blocked value.
**/
function setblocking(b:Bool):Void;

/**
Return the current value of the sockopt as an Int or a Bytes buffer (if buflen is specified).
**/
function getsockopt(family:Int, option:Int):Int;

/**
Change the value of the given socket option.
**/
@:overload(function(family:Int, option:Int, value:Int):Void {})
function setsockopt(family:Int, option:Int, value:Bool):Void;

function fileno():Int;
Expand Down
39 changes: 34 additions & 5 deletions std/python/net/SslSocket.hx
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@ package python.net;
import python.lib.Ssl;
import python.lib.ssl.Purpose;
import python.lib.socket.Socket as PSocket;
import python.lib.Socket in PSocketModule;
import sys.net.Host;

class SslSocket extends sys.net.Socket {
var hostName:String;
var _timeout:Null<Float> = null;
var _blocking:Null<Bool> = null;
var _fastSend:Null<Bool> = null;

override function __initSocket():Void {
function wrapSocketWithSslContext(hostName:String):Void {
#if (python_version >= 3.4)
var context = Ssl.create_default_context(Purpose.SERVER_AUTH);
#else
Expand All @@ -43,16 +46,42 @@ class SslSocket extends sys.net.Socket {
context.options |= Ssl.OP_NO_COMPRESSION;
#end
context.options |= Ssl.OP_NO_TLSv1 #if (python_version >= 3.4) | Ssl.OP_NO_TLSv1_1 #end; // python 3.4 | Ssl.OP_NO_TLSv1_1;
__s = new PSocket();
__s = context.wrap_socket(__s, false, true, true, this.hostName);
__s = context.wrap_socket(__s, false, true, true, hostName);
if (_timeout != null) {
super.setTimeout(_timeout);
}

if (_blocking != null) {
super.setBlocking(_blocking);
}

if (_fastSend != null) {
super.setFastSend(_fastSend);
}
__rebuildIoStreams();
}

public override function connect(host:Host, port:Int):Void {
this.hostName = host.host;
wrapSocketWithSslContext(host.host);
super.connect(host, port);
}

public override function bind(host:Host, port:Int):Void {
throw new haxe.exceptions.NotImplementedException();
}

public override function setTimeout(timeout:Float):Void {
_timeout = timeout;
super.setTimeout(_timeout);
}

public override function setBlocking(b:Bool):Void {
_blocking = b;
super.setBlocking(_blocking);
}

public override function setFastSend(b:Bool):Void {
_fastSend = b;
super.setFastSend(_fastSend);
}
}
2 changes: 2 additions & 0 deletions tests/runci/targets/Python.hx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ class Python {
runCommand("haxe", ["compile-python.hxml"].concat(args));
for (py in pys) {
runCommand(py, ["bin/unit.py"]);
// Additional test for python-version >= 3.4
runCommand(py, ["bin/unit34.py"]);
}

changeDirectory(sysDir);
Expand Down
11 changes: 10 additions & 1 deletion tests/unit/compile-python.hxml
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
compile-each.hxml

--each

--main unit.TestMain
-python bin/unit.py
-python bin/unit.py

--next

-D python-version=3.4
--main unit.TestMain
-python bin/unit34.py
50 changes: 50 additions & 0 deletions tests/unit/src/unit/issues/Issue8401.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package unit.issues;

class Issue8401 extends unit.Test {
#if python
function testNew() {
var sock = new python.net.SslSocket();
// With Issue8401, construction fails immediately; if we get this far, it's a pass
utest.Assert.pass();
}

@:access(python.net.SslSocket.__s)
@:access(python.net.SslSocket.wrapSocketWithSslContext)
function testTimeout() {
var sock = new python.net.SslSocket();
eq(null, sock.__s.gettimeout());
sock.setTimeout(500);
feq(500, sock.__s.gettimeout());
// This will change __s. Make sure we set the timeout properly.
sock.wrapSocketWithSslContext("127.0.0.1");
feq(500, sock.__s.gettimeout());
}

#if (python_verion >= 3.7)
@:access(python.net.SslSocket.__s)
@:access(python.net.SslSocket.wrapSocketWithSslContext)
function testBlocking() {
var sock = new python.net.SslSocket();
t(sock.__s.getblocking());
sock.setBlocking(false);
f(sock.__s.getblocking());
// This will change __s. Make sure we set the blocking flag properly.
sock.wrapSocketWithSslContext("127.0.0.1");
f(sock.__s.getblocking());
}
#end

@:access(python.net.SslSocket.__s)
@:access(python.net.SslSocket.wrapSocketWithSslContext)
function testFastSend() {
var sock = new python.net.SslSocket();
eq(0, sock.__s.getsockopt(python.lib.Socket.SOL_TCP, python.lib.Socket.TCP_NODELAY));
sock.setFastSend(true);
// NOTE: this number can vary per platform; non-zero means true/enabled
utest.Assert.notEquals(0, sock.__s.getsockopt(python.lib.Socket.SOL_TCP, python.lib.Socket.TCP_NODELAY));
// This will change __s. Make sure we set the sock opt properly.
sock.wrapSocketWithSslContext("127.0.0.1");
utest.Assert.notEquals(0, sock.__s.getsockopt(python.lib.Socket.SOL_TCP, python.lib.Socket.TCP_NODELAY));
}
#end
}

0 comments on commit a521f7a

Please sign in to comment.