Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-nbxmpp for openSUSE:Factory checked in at 2023-06-05 18:06:13 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-nbxmpp (Old) and /work/SRC/openSUSE:Factory/.python-nbxmpp.new.15902 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-nbxmpp" Mon Jun 5 18:06:13 2023 rev:42 rq:1089734 version:4.3.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-nbxmpp/python-nbxmpp.changes 2023-03-27 18:15:40.878916975 +0200 +++ /work/SRC/openSUSE:Factory/.python-nbxmpp.new.15902/python-nbxmpp.changes 2023-06-05 18:06:15.603010476 +0200 @@ -1,0 +2,18 @@ +Sun May 28 21:40:08 UTC 2023 - Alexei Sorokin <sor.ale...@meowr.ru> + +- Update to version 4.3.1: + * HTTP: Abort correctly on content overflow. + * Websocket: Always set peer certificate. + +------------------------------------------------------------------- +Fri May 26 19:23:13 UTC 2023 - Alexei Sorokin <sor.ale...@meowr.ru> + +- Update to version 4.3.0: + * Add option to force http1. + * Add method to generate XMPP IRIs. + * Lower log level for missing GSSAPI dependency. + * OMEMO: Add device id and namespace to OMEMOBundle. + * Donât delete session object in cleanup(). + * HTTP: Donât accept content encoding. + +------------------------------------------------------------------- Old: ---- python-nbxmpp-4.2.2.tar.bz2 New: ---- python-nbxmpp-4.3.1.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-nbxmpp.spec ++++++ --- /var/tmp/diff_new_pack.nDPoPr/_old 2023-06-05 18:06:16.671016783 +0200 +++ /var/tmp/diff_new_pack.nDPoPr/_new 2023-06-05 18:06:16.679016830 +0200 @@ -24,7 +24,7 @@ %endif %define _name nbxmpp Name: python-nbxmpp -Version: 4.2.2 +Version: 4.3.1 Release: 0 Summary: XMPP library by Gajim team License: GPL-3.0-or-later ++++++ python-nbxmpp-4.2.2.tar.bz2 -> python-nbxmpp-4.3.1.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/.gitlab-ci.yml new/python-nbxmpp-4.3.1/.gitlab-ci.yml --- old/python-nbxmpp-4.2.2/.gitlab-ci.yml 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/.gitlab-ci.yml 2023-05-28 23:18:18.000000000 +0200 @@ -4,6 +4,7 @@ - test - build - deploy + - publish test-pylint: stage: test @@ -58,7 +59,11 @@ exit_codes: - 100 script: - - release-helper nightly-check + - | + if [ "$FORCE_DEB_DEPLOY" != "true" ] + then + release-helper nightly-check + fi - > release-helper deploy-to-ftp \ --host=$FTP_HOST \ @@ -66,3 +71,17 @@ --password=$FTP_PASS \ --directory=debian/nbxmpp/"$(date +'%Y%m%d')" \ debian_build + +publish-release: + image: nbxmpp-publish:latest + stage: publish + dependencies: [] + rules: + - if: '$CI_COMMIT_TAG' + script: + - > + release-helper create-release \ + $CI_PROJECT_ID \ + $CI_RELEASE_TOKEN \ + --version=$CI_COMMIT_TAG \ + --tag=$CI_COMMIT_TAG diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/ChangeLog new/python-nbxmpp-4.3.1/ChangeLog --- old/python-nbxmpp-4.2.2/ChangeLog 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/ChangeLog 2023-05-28 23:18:18.000000000 +0200 @@ -1,3 +1,30 @@ +nbxmpp 4.3.1 (28 May 2023) + + Bug Fixes + + * HTTP: Abort correctly on content overflow + * Websocket: Always set peer certificate + +nbxmpp 4.3.0 (21 May 2023) + + New + + * Add option to force http1 + * Add method to generate XMPP IRIs + + Improvements + + * Lower log level for missing GSSAPI dependency + + Change + + * OMEMO: Add device id and namespace to OMEMOBundle + + Bug Fixes + + * Donât delete session object in cleanup() + * HTTP: Donât accept content encoding (#143) + nbxmpp 4.2.2 (25 Mar 2023) Bug Fixes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/__init__.py new/python-nbxmpp-4.3.1/nbxmpp/__init__.py --- old/python-nbxmpp-4.2.2/nbxmpp/__init__.py 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/nbxmpp/__init__.py 2023-05-28 23:18:18.000000000 +0200 @@ -3,4 +3,4 @@ from .protocol import * # pylint: disable=wrong-import-position -__version__: str = '4.2.2' +__version__: str = '4.3.1' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/const.py new/python-nbxmpp-4.3.1/nbxmpp/const.py --- old/python-nbxmpp-4.2.2/nbxmpp/const.py 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/nbxmpp/const.py 2023-05-28 23:18:18.000000000 +0200 @@ -462,6 +462,9 @@ CONTENT_OVERFLOW = 4 TIMEOUT = 5 + def __str__(self) -> str: + return self.name + MOODS = [ 'afraid', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/http.py new/python-nbxmpp-4.3.1/nbxmpp/http.py --- old/python-nbxmpp-4.2.2/nbxmpp/http.py 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/nbxmpp/http.py 2023-05-28 23:18:18.000000000 +0200 @@ -50,6 +50,7 @@ CHUNK_SIZE = 32768 DEFAULT_USER_AGENT = f'nbxmpp/{nbxmpp.__version__}' SIGNAL_ACTIONS = GObject.SignalFlags.RUN_LAST | GObject.SignalFlags.ACTION +MIN_SOUP_3_3_0 = Soup.check_version(3, 3, 0) class HTTPLogAdapter(logging.LoggerAdapter): @@ -59,10 +60,10 @@ class HTTPSession: def __init__(self, user_agent: str = DEFAULT_USER_AGENT) -> None: - self._session = Soup.Session() self._session.set_user_agent(user_agent) self._session.add_feature_by_type(Soup.ContentSniffer) + self._session.remove_feature_by_type(Soup.ContentDecoder) def get_soup_session(self) -> Soup.Session: return self._session @@ -73,8 +74,8 @@ self._session.set_proxy_resolver(resolver) - def create_request(self) -> HTTPRequest: - return HTTPRequest(self) + def create_request(self, force_http1: bool = False) -> HTTPRequest: + return HTTPRequest(self, force_http1=force_http1) class HTTPRequest(GObject.GObject): @@ -90,7 +91,10 @@ 'destroy': (SIGNAL_ACTIONS, None, ()), } - def __init__(self, session: HTTPSession) -> None: + def __init__(self, + session: HTTPSession, + force_http1: bool = False + ) -> None: GObject.GObject.__init__(self) self._log = HTTPLogAdapter(log, extra={'request': self}) @@ -126,6 +130,8 @@ self._emit_response_progress = False self._message = Soup.Message() + if MIN_SOUP_3_3_0: + self._message.set_force_http1(force_http1) self._user_data = None self._log.info('Created') @@ -278,6 +284,7 @@ self._message.connect('got-body', self._on_got_body) self._message.connect('restarted', self._on_restarted) self._message.connect('finished', self._on_finished) + self._message.connect('got-headers', self._on_got_headers) soup_session = self._session.get_soup_session() soup_session.send_async(self._message, @@ -301,6 +308,8 @@ def _on_timeout(self) -> None: self._timeout_reached = True + self._timeout_id = None + self._set_error(HTTPRequestError.TIMEOUT) self.cancel() def _on_response(self, @@ -308,6 +317,8 @@ result: Gio.AsyncResult ) -> None: + self._log.info('HTTP version: %s', + self._message.get_http_version().value_name) self._log.info('Request response received') try: self._input_stream = session.send_finish(result) @@ -343,6 +354,7 @@ def _on_bytes_read_result(self, input_stream: Gio.InputStream, result: Gio.AsyncResult) -> None: + try: data = input_stream.read_bytes_finish(result) except GLib.Error as error: @@ -360,10 +372,8 @@ self._finish_read() return - length = len(bytes_) - self._received_size += length - if self._received_size > self._response_content_length: - self._finish_read(HTTPRequestError.CONTENT_OVERFLOW) + self._received_size += len(bytes_) + if self._check_content_overflow(): return if self._output_stream is None: @@ -382,12 +392,7 @@ return self._read_async() - - if (self._emit_response_progress and - self._message.get_method() == 'GET'): - self.emit('response-progress', - self._received_size / self._response_content_length) - + self._emit_progress() def _finish_read(self, error: Optional[HTTPRequestError] = None) -> None: self._log.info('Finished reading') @@ -404,11 +409,7 @@ ) -> None: # Signal is only raised when there is content in the response - headers = message.get_response_headers() - - self._response_content_length = headers.get_content_length() - if content_type is None: # According to the docs, content_type is None when the sniffer # decides to trust the content-type sent by the server. @@ -416,14 +417,19 @@ self._response_content_type = content_type or '' - self._log.info('Sniffed: content-type: %s, content-length: %s', - self._response_content_type, - self._response_content_length) + self._log.info('Sniffed: content-type: %s', + self._response_content_type) self.emit('content-sniffed', self._response_content_length, self._response_content_type) + def _on_got_headers(self, message: Soup.Message) -> None: + headers = message.get_response_headers() + self._response_content_length = headers.get_content_length() + self._log.info('Got Headers: content-length: %s', + self._response_content_length) + def _on_got_body(self, _message: Soup.Message) -> None: # This signal tells us that the full body was received. # The `finished` signal is not a sure indicator if the message body @@ -432,11 +438,28 @@ self._log.info('Body received') self._body_received = True + def _emit_progress(self) -> None: + if not self._emit_response_progress: + return + + if not self._message.get_method() == 'GET': + return + + self.emit('response-progress', + self._received_size / self._response_content_length) + + def _check_content_overflow(self) -> bool: + if self._received_size > self._response_content_length: + self._finish_read(HTTPRequestError.CONTENT_OVERFLOW) + return True + return False + def _on_restarted(self, _message: Soup.Message) -> None: self._log.info('Restarted') self._body_received = False self._response_content_type = '' self._response_content_length = 0 + self._received_size = 0 def _on_finished(self, _message: Soup.Message) -> None: self._log.info('Message finished') @@ -469,14 +492,17 @@ self._set_complete() + def _set_error(self, error: HTTPRequestError) -> None: + self._log.info('Set Error: %s', error) + self._error = error + def _set_failed(self, error: HTTPRequestError) -> None: self._log.info('Set Failed: %s', error) self._is_finished = True - if self._timeout_reached: - self._timeout_id = None - self._error = HTTPRequestError.TIMEOUT - else: - self._error = error + + if self._error is None: + self._set_error(error) + self._close_all_streams() self.emit('finished') self._cleanup() @@ -516,7 +542,6 @@ self._message.run_dispose() del self._cancellable - del self._session del self._user_data if self._timeout_id is not None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/modules/omemo.py new/python-nbxmpp-4.3.1/nbxmpp/modules/omemo.py --- old/python-nbxmpp-4.2.2/nbxmpp/modules/omemo.py 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/nbxmpp/modules/omemo.py 2023-05-28 23:18:18.000000000 +0200 @@ -161,7 +161,7 @@ if not items: yield task.set_result(None) - yield _parse_bundle(items[0]) + yield _parse_bundle(items[0], device_id) def _parse_omemo_message(stanza): @@ -235,7 +235,7 @@ return OMEMOMessage(sid=sid, iv=iv, keys=keys, payload=payload) -def _parse_bundle(item): +def _parse_bundle(item, device_id): ''' <item id='current'> <bundle xmlns='eu.siacs.conversations.axolotl'> @@ -317,7 +317,9 @@ result['otpks'].append({'key': key, 'id': id_}) - return OMEMOBundle(**result) + return OMEMOBundle(**result, + device_id=device_id, + namespace=Namespace.OMEMO_TEMP) def _make_bundle(bundle): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/protocol.py new/python-nbxmpp-4.3.1/nbxmpp/protocol.py --- old/python-nbxmpp-4.2.2/nbxmpp/protocol.py 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/nbxmpp/protocol.py 2023-05-28 23:18:18.000000000 +0200 @@ -38,6 +38,12 @@ from gi.repository import GLib import idna +from nbxmpp.xmppiri import escape_ifragment +from nbxmpp.xmppiri import escape_inode +from nbxmpp.xmppiri import escape_ires +from nbxmpp.xmppiri import escape_ivalue +from nbxmpp.xmppiri import validate_ikey +from nbxmpp.xmppiri import validate_querytype from nbxmpp.simplexml import Node from nbxmpp.namespaces import Namespace from nbxmpp.stringprep import nodeprep @@ -315,6 +321,7 @@ STREAM_UNSUPPORTED_STANZA_TYPE = 'urn:ietf:params:xml:ns:xmpp-streams unsupported-stanza-type' ERR_FORBIDDEN = 'urn:ietf:params:xml:ns:xmpp-stanzas forbidden' + def isResultNode(node): """ Return true if the node is a positive reply @@ -768,6 +775,45 @@ return f'{localpart}@{self.domain}{domain_encoded}' return f'{localpart}@{self.domain}/{self.resource}{domain_encoded}' + def to_iri(self, + query: Optional[str | tuple[str, list[tuple[str, str]]]] = None, + fragment: Optional[str] = None + ) -> str: + + if self.localpart: + inode = escape_inode(self.localpart) + ipathxmpp = f'{inode}@{self.domain}' + else: + ipathxmpp = f'{self.domain}' + + if self.resource is not None: + ires = escape_ires(self.resource) + ipathxmpp = f'{ipathxmpp}/{ires}' + + iri = f'xmpp:{ipathxmpp}' + + if query is not None: + if isinstance(query, str): + querytype = query + queryparams = None + else: + querytype, queryparams = query + + iquerytype = validate_querytype(querytype) + iri += f'?{iquerytype}' + + if queryparams is not None: + for ikey, ivalue in queryparams: + ivalue = escape_ivalue(ivalue) + ikey = validate_ikey(ikey) + iri += f';{ikey}={ivalue}' + + if fragment is not None: + ifragment = escape_ifragment(fragment) + iri += f'#{ifragment}' + + return iri + def copy(self) -> JID: deprecation_warning('copy() is not needed, JID is immutable') return self diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/sasl.py new/python-nbxmpp-4.3.1/nbxmpp/sasl.py --- old/python-nbxmpp-4.2.2/nbxmpp/sasl.py 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/nbxmpp/sasl.py 2023-05-28 23:18:18.000000000 +0200 @@ -41,7 +41,7 @@ gssapi = __import__('gssapi') GSSAPI_AVAILABLE = True except (ImportError, OSError) as error: - log.warning('GSSAPI not available: %s', error) + log.info('GSSAPI not available: %s', error) GSSAPI_AVAILABLE = False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/structs.py new/python-nbxmpp-4.3.1/nbxmpp/structs.py --- old/python-nbxmpp-4.2.2/nbxmpp/structs.py 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/nbxmpp/structs.py 2023-05-28 23:18:18.000000000 +0200 @@ -732,6 +732,8 @@ spk_signature: bytes ik: bytes otpks: list[dict[str, str]] + device_id: int = -1 + namespace: str = Namespace.OMEMO_TEMP def pick_prekey(self) -> dict[str, str]: return random.SystemRandom().choice(self.otpks) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/websocket.py new/python-nbxmpp-4.3.1/nbxmpp/websocket.py --- old/python-nbxmpp-4.2.2/nbxmpp/websocket.py 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/nbxmpp/websocket.py 2023-05-28 23:18:18.000000000 +0200 @@ -52,6 +52,8 @@ message = Soup.Message.new('GET', self._address.uri) message.connect('accept-certificate', self._check_certificate) + message.connect('notify::tls-peer-certificate', + self._on_certificate_set) message.set_flags(Soup.MessageFlags.NO_REDIRECT) self._session.websocket_connect_async(message, None, @@ -105,6 +107,15 @@ self._cancellable.cancel() return False + def _on_certificate_set(self, message, _param): + if self._peer_certificate is not None: + return + + # If the cert has errors _check_certificate() will set the cert. + self._peer_certificate = message.props.tls_peer_certificate + self._peer_certificate_errors = convert_tls_error_flags( + message.props.tls_peer_certificate_errors) + def _on_websocket_message(self, _websocket, _type, message): data = message.get_data().decode() self._log_stanza(data) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/xmppiri.py new/python-nbxmpp-4.3.1/nbxmpp/xmppiri.py --- old/python-nbxmpp-4.2.2/nbxmpp/xmppiri.py 1970-01-01 01:00:00.000000000 +0100 +++ new/python-nbxmpp-4.3.1/nbxmpp/xmppiri.py 2023-05-28 23:18:18.000000000 +0200 @@ -0,0 +1,57 @@ + +import re +from gi.repository import GLib + + +# https://www.rfc-editor.org/rfc/rfc3987 + +ucschar = r'\xA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF'\ + r'\U00010000-\U0001FFFD\U00020000-\U0002FFFD\U00030000-\U0003FFFD'\ + r'\U00040000-\U0004FFFD\U00050000-\U0005FFFD\U00060000-\U0006FFFD'\ + r'\U00070000-\U0007FFFD\U00080000-\U0008FFFD\U00090000-\U0009FFFD'\ + r'\U000A0000-\U000AFFFD\U000B0000-\U000BFFFD\U000C0000-\U000CFFFD'\ + r'\U000D0000-\U000DFFFD\U000E1000-\U000EFFFD' +unreserved = r'A-Za-z0-9\-._~' +iunreserved = fr'{unreserved}{ucschar}' +subdelims = r"!$&'()*+,;=" + +# https://www.rfc-editor.org/rfc/rfc5122.html#section-2.2 +nodeallow = r"!$()*+,;=" +resallow = r"!$&'()*+,:;=" + +# ifragment without iunreserved and pct-encoded +reserved_chars_allowed_in_ifragment = subdelims + ":@" + "/?" + +rx_ikey = f'[{iunreserved}]*' +rx_iquerytype = f'[{iunreserved}]*' + + +def validate_ikey(ikey: str) -> str: + res = re.fullmatch(rx_ikey, ikey) + if res is None: + raise ValueError('Not allowed characters in key') + return ikey + + +def validate_querytype(querytype: str) -> str: + res = re.fullmatch(rx_iquerytype, querytype) + if res is None: + raise ValueError('Not allowed characters in querytype') + return querytype + + +def escape_ifragment(ifragment: str) -> str: + return GLib.Uri.escape_string( + ifragment, reserved_chars_allowed_in_ifragment, True) + + +def escape_ivalue(ivalue: str) -> str: + return GLib.Uri.escape_string(ivalue, None, True) + + +def escape_inode(inode: str) -> str: + return GLib.Uri.escape_string(inode, nodeallow, True) + + +def escape_ires(ires: str) -> str: + return GLib.Uri.escape_string(ires, resallow, True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/test/lib/util.py new/python-nbxmpp-4.3.1/test/lib/util.py --- old/python-nbxmpp-4.2.2/test/lib/util.py 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/test/lib/util.py 2023-05-28 23:18:18.000000000 +0200 @@ -1,3 +1,4 @@ +import sys import unittest from unittest.mock import Mock @@ -18,3 +19,29 @@ self.dispatcher.reset_parser() self.dispatcher.process_data(STREAM_START) + + +def raise_all_exceptions(func): + # Exceptions which are raised from async callbacks + # in GLib or GTK do not bubble up to the unittest + # This decorator catches all exceptions and raises them + # after the unittest + def func_wrapper(self, *args, **kwargs): + + exceptions = [] + + def on_hook(type_, value, tback): + exceptions.append((type_, value, tback)) + + orig_excepthook = sys.excepthook + sys.excepthook = on_hook + try: + result = func(self) + finally: + sys.excepthook = orig_excepthook + if exceptions: + tp, value, tb = exceptions[0] + raise tp(value).with_traceback(tb) + + return result + return func_wrapper diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/test/unit/test_http.py new/python-nbxmpp-4.3.1/test/unit/test_http.py --- old/python-nbxmpp-4.2.2/test/unit/test_http.py 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/test/unit/test_http.py 2023-05-28 23:18:18.000000000 +0200 @@ -1,9 +1,6 @@ -from time import time import tempfile import unittest -from unittest.mock import call from unittest.mock import Mock -from unittest.mock import patch import os from pathlib import Path @@ -12,6 +9,7 @@ from nbxmpp.const import HTTPRequestError from nbxmpp.http import HTTPSession +from test.lib.util import raise_all_exceptions SMALL_FILE_URL = 'https://gajim.org/downloads/ci/unittest_small_file' # 200 KB @@ -124,13 +122,11 @@ session = HTTPSession() request = session.create_request() - def _on_progress(req, progress): - self.assertIsInstance(progress, float) + def _on_start(req): req.cancel() callback_mock = Mock() - request.connect('starting-response-body', callback_mock.starting) - request.connect('response-progress', _on_progress) + request.connect('starting-response-body', _on_start) request.connect('finished', callback_mock.finished) request.connect('destroy', lambda *args: mainloop.quit()) request.send('GET', LARGE_FILE_URL, timeout=10) @@ -141,7 +137,6 @@ self.assertTrue(request.is_finished()) self.assertEqual(request.get_error(), HTTPRequestError.CANCELLED) - callback_mock.starting.assert_called() callback_mock.finished.assert_called() def test_download_failed_404(self): @@ -242,6 +237,30 @@ self.assertTrue(request4.is_finished()) self.assertTrue(request4.is_complete()) + @raise_all_exceptions + def test_content_overflow(self): + + mainloop = GLib.MainLoop() + + session = HTTPSession() + request = session.create_request() + + def _on_starting(req) -> None: + req._received_size = 100000000000 + + callback_mock = Mock() + request.connect('starting-response-body', _on_starting) + request.connect('finished', callback_mock.finished) + request.connect('destroy', lambda *args: mainloop.quit()) + request.send('GET', SMALL_FILE_URL, timeout=10) + + mainloop.run() + + self.assertTrue(request.is_finished()) + self.assertFalse(request.is_complete()) + self.assertEqual(request.get_error(), HTTPRequestError.CONTENT_OVERFLOW) + + callback_mock.finished.assert_called() if __name__ == '__main__': unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-4.2.2/test/unit/test_jid_parsing.py new/python-nbxmpp-4.3.1/test/unit/test_jid_parsing.py --- old/python-nbxmpp-4.2.2/test/unit/test_jid_parsing.py 2023-03-25 17:33:26.000000000 +0100 +++ new/python-nbxmpp-4.3.1/test/unit/test_jid_parsing.py 2023-05-28 23:18:18.000000000 +0200 @@ -189,3 +189,26 @@ # from_user_input does only support bare jids with self.assertRaises(Exception): JID.from_user_input(user_input) + + def test_jid_to_iri(self): + tests = [ + ('nasty!#$%()*+,-.;=?[\\]^_`{|}~n...@example.com', 'xmpp:nasty!%23$%25()*+,-.;=%3F%5B%5C%5D%5E_%60%7B%7C%7D~n...@example.com'), + ('n...@example.com/repulsive !#"$%&\'()*+,-./:;<=>?@[\\]^_`{|}~resource', 'xmpp:n...@example.com/repulsive%20!%23%22$%25&\'()*+,-.%2F:;%3C=%3E%3F%40%5B%5C%5D%5E_%60%7B%7C%7D~resource'), + ] + + for jid, iri in tests: + jid = JID.from_string(jid) + self.assertEqual(jid.to_iri(), iri) + + jid = JID.from_string('example-n...@example.com') + iri = jid.to_iri(('message', [('subject', 'Hello World')]), 'frag') + self.assertEqual(iri, 'xmpp:example-n...@example.com?message;subject=Hello%20World#frag') + + iri = jid.to_iri('message') + self.assertEqual(iri, 'xmpp:example-n...@example.com?message') + + iri = jid.to_iri(fragment='onlyfragment') + self.assertEqual(iri, 'xmpp:example-n...@example.com#onlyfragment') + + jid = JID.from_user_input('call me "ishmael"@example.com') + self.assertEqual(jid.to_iri(), 'xmpp:call%5c20me%5c20%5c22ishmael%5...@example.com')