Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pyinstaller support #384

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion run
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

import websockify

websockify.websocketproxy.websockify_init()
if __name__ == '__main__':
websockify.websocketproxy.websockify_init()
6 changes: 3 additions & 3 deletions tests/test_websockifyserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ class fake_create_default_context():
def __init__(self, purpose):
self.verify_mode = None
self.options = 0
def load_cert_chain(self, certfile, keyfile):
def load_cert_chain(self, certfile, keyfile, password):
pass
def set_default_verify_paths(self):
pass
Expand Down Expand Up @@ -310,7 +310,7 @@ class fake_create_default_context():
def __init__(self, purpose):
self.verify_mode = None
self.options = 0
def load_cert_chain(self, certfile, keyfile):
def load_cert_chain(self, certfile, keyfile, password):
pass
def set_default_verify_paths(self):
pass
Expand Down Expand Up @@ -351,7 +351,7 @@ class fake_create_default_context(object):
def __init__(self, purpose):
self.verify_mode = None
self._options = 0
def load_cert_chain(self, certfile, keyfile):
def load_cert_chain(self, certfile, keyfile, password):
pass
def set_default_verify_paths(self):
pass
Expand Down
102 changes: 102 additions & 0 deletions websockify.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# -*- mode: python -*-
# To be used with https://www.pyinstaller.org to build a "frozen" executable distribution
# Tested with pyinstaller 3.4, python 3.7.2, linux x86_64
# NOT tested with SSL

# Set to True to bring in numpy if available (increases output package size by ~45MB on linux64/python3.7).
# If False it will be left out
USE_NUMPY=True

# Get debug messages by pyinstaller bootloader
DEBUG=False

# Explicitly excluded modules
excludes = []

# It is possible to reduce the resulting package size (~3MB on linux64/python3.7)
# by excluding unused encodings.
# By default (as of pyinstaller 3.4/python 3.7) all encodings are pulled in:
# the following list can be used to reduce the encodings pulled in to the bare minimum.
# You should include the target platform encoding or call locale.setlocale(locale.LC_ALL, 'C')
# early in websockify_init()
#
# These are required:
# - 'encodings.base64_codec' This is required when payload is b64 encoded, don't exclude
# - 'encodings' Father package must also be included
# - 'encodings.aliases' Required, see initstdio() function in cPython sources
# - 'encodings.utf_8'
# - 'encodings.latin_1'
# - 'encodings.ascii' Required by some cascaded import from http
# - encodings.idna' Required by <I don't know>
# excludes.extend(('encodings.undefined', 'encodings.utf_32_be', 'encodings.utf_32',
# 'encodings.utf_16_le', 'encodings.utf_16_be', 'encodings.utf_16', 'encodings.utf_32_le',
# 'encodings.zlib_codec', 'encodings.euc_jis_2004', 'encodings.ptcp154', 'encodings.cp874',
# 'encodings.cp424',
# 'encodings.iso2022_jp_2', 'encodings.euc_jp', 'encodings.mac_arabic', 'encodings.shift_jis',
# 'encodings.utf_7', 'encodings.cp866', 'encodings.cp855', 'encodings.rot_13', 'encodings.cp1006',
# 'encodings.johab', 'encodings.cp865', 'encodings.mac_cyrillic', 'encodings.cp737', 'encodings.kz1048',
# 'encodings.cp1256', 'encodings.cp1252', 'encodings.hp_roman8', 'encodings.cp1026', 'encodings.iso8859_6',
# 'encodings.hz', 'encodings.shift_jisx0213', 'encodings.cp500', 'encodings.palmos', 'encodings.euc_jisx0213',
# 'encodings.cp864', 'encodings.cp875', 'encodings.mac_iceland', 'encodings.cp856', 'encodings.big5',
# 'encodings.iso2022_jp_ext', 'encodings.charmap', 'encodings.iso8859_7', 'encodings.cp852',
# 'encodings.mac_croatian', 'encodings.bz2_codec', 'encodings.cp863', 'encodings.iso8859_14',
# 'encodings.cp65001', 'encodings.cp1254', 'encodings.iso2022_jp_2004', 'encodings.cp932',
# 'encodings.raw_unicode_escape', 'encodings.mac_romanian', 'encodings.gb18030', 'encodings.cp1257',
# 'encodings.mac_latin2', 'encodings.iso2022_kr', 'encodings.shift_jis_2004', 'encodings.cp850',
# 'encodings.iso2022_jp_1', 'encodings.cp862', 'encodings.iso8859_15', 'encodings.hex_codec',
# 'encodings.cp857', 'encodings.iso8859_4', 'encodings.mac_roman', 'encodings.cp1250',
# 'encodings.iso8859_9', 'encodings.mbcs', 'encodings.mac_greek',
# 'encodings.cp1125', 'encodings.koi8_u', 'encodings.cp273', 'encodings.big5hkscs', 'encodings.cp1140',
# 'encodings.utf_8_sig', 'encodings.iso8859_13', 'encodings.tis_620', 'encodings.cp037',
# 'encodings.iso2022_jp_3', 'encodings.cp861', 'encodings.mac_farsi', 'encodings.iso8859_1',
# 'encodings.cp869', 'encodings.iso8859_8', 'encodings.unicode_internal',
# 'encodings.iso8859_3', 'encodings.cp720', 'encodings.koi8_r', 'encodings.cp437', 'encodings.cp858',
# 'encodings.euc_kr', 'encodings.iso8859_2', 'encodings.cp1251', 'encodings.cp950', 'encodings.gbk',
# 'encodings.cp775', 'encodings.unicode_escape', 'encodings.quopri_codec', 'encodings.cp860',
# 'encodings.koi8_t', 'encodings.uu_codec', 'encodings.cp1253', 'encodings.iso8859_5',
# 'encodings.mac_centeuro', 'encodings.iso8859_11', 'encodings.iso8859_16', 'encodings.iso8859_10',
# 'encodings.gb2312', 'encodings.iso2022_jp', 'encodings.mac_turkish',
# 'encodings.cp1255', 'encodings.cp949', 'encodings.cp1258', 'encodings.punycode'))

# Also some other modules may be safely left out (save ~2MB on linux64/python3.7)
# excludes.extend(('bz2', 'curses', 'decimal', 'grp', 'gzip', 'json', 'lzma', 'pdb', 'pkg_resources',
# 'plistlib', 'pyexpat', 'readline', 'termios', 'uuid', 'xml', 'zlib'))

block_cipher = None
CONSOLE=True

if not USE_NUMPY:
# Apparently unittes is required??? by numpy
excludes.extend(("numpy", "unittest"))

hiddenimports=[]

a = Analysis(
['run'],
pathex=[],
binaries=[],
datas=[("docs", "docs"),],
hiddenimports=hiddenimports,
hookspath=[],
runtime_hooks=[],
excludes=excludes,
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
# Must remain True or it will assume a single-file deploy
exclude_binaries=True,
name='websockify',
debug=DEBUG,
strip=False,
upx=False,
console=CONSOLE
)
coll = COLLECT(
exe, a.binaries, a.zipfiles, a.datas,
strip=False, upx=False, name='websockify'
)
8 changes: 5 additions & 3 deletions websockify/websocketproxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@

import signal, socket, optparse, time, os, sys, subprocess, logging, errno, ssl
try:
from socketserver import ForkingMixIn
from socketserver import ThreadingMixIn
except ImportError:
from SocketServer import ForkingMixIn
from SocketServer import ThreadingMixIn

try:
from http.server import HTTPServer
Expand Down Expand Up @@ -478,6 +478,8 @@ def websockify_init():
help="SSL certificate file")
parser.add_option("--key", default=None,
help="SSL key file (if separate from cert)")
parser.add_option("--key-password", default=None,
help="SSL key password")
parser.add_option("--ssl-only", action="store_true",
help="disallow non-encrypted client connections")
parser.add_option("--ssl-target", action="store_true",
Expand Down Expand Up @@ -724,7 +726,7 @@ def websockify_init():
server.start_server()


class LibProxyServer(ForkingMixIn, HTTPServer):
class LibProxyServer(ThreadingMixIn, HTTPServer):
"""
Just like WebSocketProxy, but uses standard Python SocketServer
framework.
Expand Down
8 changes: 3 additions & 5 deletions websockify/websockifyserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@
if sys.platform == 'win32':
# make sockets pickle-able/inheritable
import multiprocessing.reduction
# the multiprocesssing module behaves much differently on Windows,
# and we have yet to fix all the bugs
sys.exit("Windows is not supported at this time")

from websockify.websocket import WebSocket, WebSocketWantReadError, WebSocketWantWriteError
from websockify.websocketserver import WebSocketRequestHandlerMixIn
Expand Down Expand Up @@ -340,7 +337,7 @@ class Terminate(Exception):

def __init__(self, RequestHandlerClass, listen_fd=None,
listen_host='', listen_port=None, source_is_ipv6=False,
verbose=False, cert='', key='', ssl_only=None,
verbose=False, cert='', key='', key_password=None, ssl_only=None,
verify_client=False, cafile=None,
daemon=False, record='', web='', web_auth=False,
file_only=False,
Expand Down Expand Up @@ -380,6 +377,7 @@ def __init__(self, RequestHandlerClass, listen_fd=None,

# keyfile path must be None if not specified
self.key = None
self.key_password = key_password

# Make paths settings absolute
self.cert = os.path.abspath(cert)
Expand Down Expand Up @@ -577,7 +575,7 @@ def do_handshake(self, sock, address):
if self.ssl_ciphers is not None:
context.set_ciphers(self.ssl_ciphers)
context.options = self.ssl_options
context.load_cert_chain(certfile=self.cert, keyfile=self.key)
context.load_cert_chain(certfile=self.cert, keyfile=self.key, password=self.key_password)
if self.verify_client:
context.verify_mode = ssl.CERT_REQUIRED
if self.cafile:
Expand Down