diff options
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> | 2015-06-12 01:36:56 +0100 |
---|---|---|
committer | Emmanuel Gil Peyrot <emmanuel.peyrot@collabora.com> | 2015-06-20 01:14:46 +0100 |
commit | 7bce1ecc8aeeb33bcf25474647aeb86245c71c1c (patch) | |
tree | 2a235379715b47ce8b1ac8946794e0b8733409d9 | |
parent | bbce16d526be4b427ed5144a7e3ffee5656abd23 (diff) | |
download | slixmpp-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-x | setup.py | 9 | ||||
-rw-r--r-- | slixmpp/stringprep.pyx | 71 |
2 files changed, 80 insertions, 0 deletions
@@ -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 |