summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuel Gil Peyrot <linkmauve@linkmauve.fr>2015-06-12 01:36:56 +0100
committerEmmanuel Gil Peyrot <emmanuel.peyrot@collabora.com>2015-06-20 01:14:46 +0100
commit7bce1ecc8aeeb33bcf25474647aeb86245c71c1c (patch)
tree2a235379715b47ce8b1ac8946794e0b8733409d9
parentbbce16d526be4b427ed5144a7e3ffee5656abd23 (diff)
downloadslixmpp-7bce1ecc8aeeb33bcf25474647aeb86245c71c1c.tar.gz
slixmpp-7bce1ecc8aeeb33bcf25474647aeb86245c71c1c.tar.bz2
slixmpp-7bce1ecc8aeeb33bcf25474647aeb86245c71c1c.tar.xz
slixmpp-7bce1ecc8aeeb33bcf25474647aeb86245c71c1c.zip
Add a Cython version of slixmpp.stringprep, using libidn.
This makes the validation of a JID a *lot* faster.
-rwxr-xr-xsetup.py9
-rw-r--r--slixmpp/stringprep.pyx71
2 files changed, 80 insertions, 0 deletions
diff --git a/setup.py b/setup.py
index ca8be7f5..56fdc76e 100755
--- a/setup.py
+++ b/setup.py
@@ -13,6 +13,14 @@ try:
except ImportError:
from distutils.core import setup
+try:
+ from Cython.Build import cythonize
+except ImportError:
+ print('Cython not found, falling back to the slow stringprep module.')
+ ext_modules = None
+else:
+ ext_modules = cythonize('slixmpp/stringprep.pyx')
+
from run_tests import TestCommand
from slixmpp.version import __version__
@@ -43,6 +51,7 @@ setup(
license='MIT',
platforms=['any'],
packages=packages,
+ ext_modules=ext_modules,
requires=['aiodns', 'pyasn1', 'pyasn1_modules'],
classifiers=CLASSIFIERS,
cmdclass={'test': TestCommand}
diff --git a/slixmpp/stringprep.pyx b/slixmpp/stringprep.pyx
new file mode 100644
index 00000000..e17c62c3
--- /dev/null
+++ b/slixmpp/stringprep.pyx
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+# cython: language_level = 3
+# distutils: libraries = idn
+"""
+ slixmpp.stringprep
+ ~~~~~~~~~~~~~~~~~~~~~~~
+
+ This module wraps libidn’s stringprep and idna functions using Cython.
+
+ Part of Slixmpp: The Slick XMPP Library
+
+ :copyright: (c) 2015 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
+ :license: MIT, see LICENSE for more details
+"""
+
+from libc.stdlib cimport free
+
+
+# Those are Cython declarations for the C function we’ll be using.
+
+cdef extern from "stringprep.h" nogil:
+ int stringprep_profile(const char* in_, char** out, const char* profile, int flags)
+
+cdef extern from "idna.h" nogil:
+ int idna_to_ascii_8z(const char* in_, char** out, int flags)
+ int idna_to_unicode_8z8z(const char* in_, char** out, int flags)
+
+
+class StringprepError(Exception):
+ pass
+
+
+cdef str _stringprep(str in_, const char* profile):
+ """Python wrapper for libidn’s stringprep."""
+ cdef char* out
+ ret = stringprep_profile(in_.encode('utf-8'), &out, profile, 0)
+ if ret != 0:
+ raise StringprepError(ret)
+ unicode_out = out.decode('utf-8')
+ free(out)
+ return unicode_out
+
+def nodeprep(str node):
+ """The nodeprep profile of stringprep used to validate the local, or
+ username, portion of a JID."""
+ return _stringprep(node, 'Nodeprep')
+
+def resourceprep(str resource):
+ """The resourceprep profile of stringprep, which is used to validate the
+ resource portion of a JID."""
+ return _stringprep(resource, 'Resourceprep')
+
+def idna(str domain):
+ """The idna conversion functions, which are used to validate the domain
+ portion of a JID."""
+
+ cdef char* ascii_domain
+ cdef char* utf8_domain
+
+ ret = idna_to_ascii_8z(domain.encode('utf-8'), &ascii_domain, 0)
+ if ret != 0:
+ raise StringprepError(ret)
+
+ ret = idna_to_unicode_8z8z(ascii_domain, &utf8_domain, 0)
+ free(ascii_domain)
+ if ret != 0:
+ raise StringprepError(ret)
+
+ unicode_domain = utf8_domain.decode('utf-8')
+ free(utf8_domain)
+ return unicode_domain