Add a Cython version of slixmpp.stringprep, using libidn.
This makes the validation of a JID a *lot* faster.
This commit is contained in:
parent
bbce16d526
commit
7bce1ecc8a
2 changed files with 80 additions and 0 deletions
9
setup.py
9
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}
|
||||
|
|
71
slixmpp/stringprep.pyx
Normal file
71
slixmpp/stringprep.pyx
Normal file
|
@ -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
|
Loading…
Reference in a new issue