mirror of
https://github.com/weechat/weechat.git
synced 2026-07-09 11:13:12 +02:00
relay: add support of websocket extension "permessage-deflate" (closes #1549)
This extension is used to compress and decompress websocket frames (using the DEFLATE algorithm, with zlib).
This commit is contained in:
@@ -19,6 +19,7 @@ New features::
|
||||
* core: use function util_strftimeval in evaluation of expression `date:xxx`
|
||||
* api: add support of specifier `%!` for timestamp in function util_strftimeval
|
||||
* relay: add "api" protocol (HTTP REST API), add option relay.look.display_clients, change option type relay.look.auto_open_buffer to string (issue #2066)
|
||||
* relay: add support of websocket extension "permessage-deflate" (issue #1549)
|
||||
|
||||
Bug fixes::
|
||||
|
||||
|
||||
+85
-84
@@ -396,90 +396,91 @@ WeeChat "core" is located in following directories:
|
||||
|
||||
[width="100%",cols="2m,3",options="header"]
|
||||
|===
|
||||
| Path/file | Description
|
||||
| tests/ | Root of tests.
|
||||
| tests.cpp | Program used to run all tests.
|
||||
| tests-record.cpp | Record and search in messages displayed.
|
||||
| scripts/ | Root of scripting API tests.
|
||||
| test-scripts.cpp | Program used to run the scripting API tests.
|
||||
| python/ | Python scripts to generate and run the scripting API tests.
|
||||
| testapigen.py | Python script generating scripts in all languages to test the scripting API.
|
||||
| testapi.py | Python script with scripting API tests, used by script testapigen.py.
|
||||
| unparse.py | Convert Python code to other languages, used by script testapigen.py.
|
||||
| unit/ | Root of unit tests.
|
||||
| test-plugins.cpp | Tests: plugins.
|
||||
| test-plugin-api-info.cpp | Tests: plugin API info functions.
|
||||
| test-plugin-config.cpp | Tests: plugin config functions.
|
||||
| core/ | Root of unit tests for core.
|
||||
| test-core-arraylist.cpp | Tests: arraylists.
|
||||
| test-core-calc.cpp | Tests: calculation of expressions.
|
||||
| test-core-command.cpp | Tests: commands.
|
||||
| test-core-config-file.cpp | Tests: configuration files.
|
||||
| test-core-crypto.cpp | Tests: cryptographic functions.
|
||||
| test-core-dir.cpp | Tests: directory/file functions.
|
||||
| test-core-eval.cpp | Tests: evaluation of expressions.
|
||||
| test-core-hashtble.cpp | Tests: hashtables.
|
||||
| test-core-hdata.cpp | Tests: hdata.
|
||||
| test-core-hook.cpp | Tests: hooks.
|
||||
| test-core-infolist.cpp | Tests: infolists.
|
||||
| test-core-list.cpp | Tests: lists.
|
||||
| test-core-network.cpp | Tests: network functions.
|
||||
| test-core-secure.cpp | Tests: secured data.
|
||||
| test-core-signal.cpp | Tests: signals.
|
||||
| test-core-string.cpp | Tests: strings.
|
||||
| test-core-url.cpp | Tests: URLs.
|
||||
| test-core-utf8.cpp | Tests: UTF-8.
|
||||
| test-core-util.cpp | Tests: utility functions.
|
||||
| test-core-sys.cpp | Tests: system functions.
|
||||
| hook/ | Root of unit tests for hooks.
|
||||
| test-hook-command.cpp | Tests: hooks "command".
|
||||
| gui/ | Root of unit tests for interfaces.
|
||||
| test-gui-bar-window.cpp | Tests: bar window functions.
|
||||
| test-gui-buffer.cpp | Tests: buffer functions.
|
||||
| test-gui-chat.cpp | Tests: chat functions.
|
||||
| test-gui-color.cpp | Tests: colors.
|
||||
| test-gui-filter.cpp | Tests: filters.
|
||||
| test-gui-input.cpp | Tests: input functions.
|
||||
| test-gui-key.cpp | Tests: keys.
|
||||
| test-gui-line.cpp | Tests: lines.
|
||||
| test-gui-nick.cpp | Tests: nicks.
|
||||
| plugins/ | Root of unit tests for plugins.
|
||||
| irc/ | Root of unit tests for IRC plugin.
|
||||
| test-irc-batch.cpp | Tests: IRC batched events.
|
||||
| test-irc-buffer.cpp | Tests: IRC buffers.
|
||||
| test-irc-channel.cpp | Tests: IRC channels.
|
||||
| test-irc-color.cpp | Tests: IRC colors.
|
||||
| test-irc-config.cpp | Tests: IRC configuration.
|
||||
| test-irc-ctcp.cpp | Tests: IRC CTCP.
|
||||
| test-irc-ignore.cpp | Tests: IRC ignores.
|
||||
| test-irc-info.cpp | Tests: IRC info.
|
||||
| test-irc-join.cpp | Tests: IRC join functions.
|
||||
| test-irc-list.cpp | Tests: IRC buffer for reply to /list command.
|
||||
| test-irc-message.cpp | Tests: IRC messages.
|
||||
| test-irc-mode.cpp | Tests: IRC modes.
|
||||
| test-irc-nick.cpp | Tests: IRC nicks.
|
||||
| test-irc-protocol.cpp | Tests: IRC protocol.
|
||||
| test-irc-sasl.cpp | Tests: SASL authentication with IRC protocol.
|
||||
| test-irc-server.cpp | Tests: IRC server.
|
||||
| test-irc-tag.cpp | Tests: IRC message tags.
|
||||
| logger/ | Root of unit tests for logger plugin.
|
||||
| test-logger.cpp | Tests: logger.
|
||||
| test-logger-backlog.cpp | Tests: logger backlog.
|
||||
| test-logger-tail.cpp | Tests: logger tail functions.
|
||||
| trigger/ | Root of unit tests for trigger plugin.
|
||||
| test-trigger.cpp | Tests: triggers.
|
||||
| test-trigger-config.cpp | Tests: trigger configuration.
|
||||
| typing/ | Root of unit tests for typing plugin.
|
||||
| test-typing.cpp | Tests: typing.
|
||||
| test-typing-status.cpp | Tests: typing status.
|
||||
| relay/ | Root of unit tests for Relay plugin.
|
||||
| test-relay-auth.cpp | Tests: clients authentication.
|
||||
| test-relay-http.cpp | Tests: HTTP functions for Relay plugin.
|
||||
| irc/ | Root of unit tests for Relay "irc" protocol.
|
||||
| test-relay-irc.cpp | Tests: Relay "irc" protocol.
|
||||
| xfer/ | Root of unit tests for Xfer plugin.
|
||||
| test-xfer-file.cpp | Tests: file functions.
|
||||
| test-xfer-network.cpp | Tests: network functions.
|
||||
| Path/file | Description
|
||||
| tests/ | Root of tests.
|
||||
| tests.cpp | Program used to run all tests.
|
||||
| tests-record.cpp | Record and search in messages displayed.
|
||||
| scripts/ | Root of scripting API tests.
|
||||
| test-scripts.cpp | Program used to run the scripting API tests.
|
||||
| python/ | Python scripts to generate and run the scripting API tests.
|
||||
| testapigen.py | Python script generating scripts in all languages to test the scripting API.
|
||||
| testapi.py | Python script with scripting API tests, used by script testapigen.py.
|
||||
| unparse.py | Convert Python code to other languages, used by script testapigen.py.
|
||||
| unit/ | Root of unit tests.
|
||||
| test-plugins.cpp | Tests: plugins.
|
||||
| test-plugin-api-info.cpp | Tests: plugin API info functions.
|
||||
| test-plugin-config.cpp | Tests: plugin config functions.
|
||||
| core/ | Root of unit tests for core.
|
||||
| test-core-arraylist.cpp | Tests: arraylists.
|
||||
| test-core-calc.cpp | Tests: calculation of expressions.
|
||||
| test-core-command.cpp | Tests: commands.
|
||||
| test-core-config-file.cpp | Tests: configuration files.
|
||||
| test-core-crypto.cpp | Tests: cryptographic functions.
|
||||
| test-core-dir.cpp | Tests: directory/file functions.
|
||||
| test-core-eval.cpp | Tests: evaluation of expressions.
|
||||
| test-core-hashtble.cpp | Tests: hashtables.
|
||||
| test-core-hdata.cpp | Tests: hdata.
|
||||
| test-core-hook.cpp | Tests: hooks.
|
||||
| test-core-infolist.cpp | Tests: infolists.
|
||||
| test-core-list.cpp | Tests: lists.
|
||||
| test-core-network.cpp | Tests: network functions.
|
||||
| test-core-secure.cpp | Tests: secured data.
|
||||
| test-core-signal.cpp | Tests: signals.
|
||||
| test-core-string.cpp | Tests: strings.
|
||||
| test-core-url.cpp | Tests: URLs.
|
||||
| test-core-utf8.cpp | Tests: UTF-8.
|
||||
| test-core-util.cpp | Tests: utility functions.
|
||||
| test-core-sys.cpp | Tests: system functions.
|
||||
| hook/ | Root of unit tests for hooks.
|
||||
| test-hook-command.cpp | Tests: hooks "command".
|
||||
| gui/ | Root of unit tests for interfaces.
|
||||
| test-gui-bar-window.cpp | Tests: bar window functions.
|
||||
| test-gui-buffer.cpp | Tests: buffer functions.
|
||||
| test-gui-chat.cpp | Tests: chat functions.
|
||||
| test-gui-color.cpp | Tests: colors.
|
||||
| test-gui-filter.cpp | Tests: filters.
|
||||
| test-gui-input.cpp | Tests: input functions.
|
||||
| test-gui-key.cpp | Tests: keys.
|
||||
| test-gui-line.cpp | Tests: lines.
|
||||
| test-gui-nick.cpp | Tests: nicks.
|
||||
| plugins/ | Root of unit tests for plugins.
|
||||
| irc/ | Root of unit tests for IRC plugin.
|
||||
| test-irc-batch.cpp | Tests: IRC batched events.
|
||||
| test-irc-buffer.cpp | Tests: IRC buffers.
|
||||
| test-irc-channel.cpp | Tests: IRC channels.
|
||||
| test-irc-color.cpp | Tests: IRC colors.
|
||||
| test-irc-config.cpp | Tests: IRC configuration.
|
||||
| test-irc-ctcp.cpp | Tests: IRC CTCP.
|
||||
| test-irc-ignore.cpp | Tests: IRC ignores.
|
||||
| test-irc-info.cpp | Tests: IRC info.
|
||||
| test-irc-join.cpp | Tests: IRC join functions.
|
||||
| test-irc-list.cpp | Tests: IRC buffer for reply to /list command.
|
||||
| test-irc-message.cpp | Tests: IRC messages.
|
||||
| test-irc-mode.cpp | Tests: IRC modes.
|
||||
| test-irc-nick.cpp | Tests: IRC nicks.
|
||||
| test-irc-protocol.cpp | Tests: IRC protocol.
|
||||
| test-irc-sasl.cpp | Tests: SASL authentication with IRC protocol.
|
||||
| test-irc-server.cpp | Tests: IRC server.
|
||||
| test-irc-tag.cpp | Tests: IRC message tags.
|
||||
| logger/ | Root of unit tests for logger plugin.
|
||||
| test-logger.cpp | Tests: logger.
|
||||
| test-logger-backlog.cpp | Tests: logger backlog.
|
||||
| test-logger-tail.cpp | Tests: logger tail functions.
|
||||
| trigger/ | Root of unit tests for trigger plugin.
|
||||
| test-trigger.cpp | Tests: triggers.
|
||||
| test-trigger-config.cpp | Tests: trigger configuration.
|
||||
| typing/ | Root of unit tests for typing plugin.
|
||||
| test-typing.cpp | Tests: typing.
|
||||
| test-typing-status.cpp | Tests: typing status.
|
||||
| relay/ | Root of unit tests for Relay plugin.
|
||||
| test-relay-auth.cpp | Tests: clients authentication.
|
||||
| test-relay-http.cpp | Tests: HTTP functions for Relay plugin.
|
||||
| test-relay-websocket.cpp | Tests: websocket functions for Relay plugin.
|
||||
| irc/ | Root of unit tests for Relay "irc" protocol.
|
||||
| test-relay-irc.cpp | Tests: Relay "irc" protocol.
|
||||
| xfer/ | Root of unit tests for Xfer plugin.
|
||||
| test-xfer-file.cpp | Tests: file functions.
|
||||
| test-xfer-network.cpp | Tests: network functions.
|
||||
|===
|
||||
|
||||
[[documentation_translations]]
|
||||
|
||||
+85
-84
@@ -398,90 +398,91 @@ Le cœur de WeeChat est situé dans les répertoires suivants :
|
||||
|
||||
[width="100%",cols="2m,3",options="header"]
|
||||
|===
|
||||
| Chemin/fichier | Description
|
||||
| tests/ | Racine des tests.
|
||||
| tests.cpp | Programme utilisé pour lancer tous les tests.
|
||||
| tests-record.cpp | Enregistrement et recherche dans les messages affichés.
|
||||
| scripts/ | Racine des tests de l'API script.
|
||||
| test-scripts.cpp | Programme utilisé pour lancer les tests de l'API script.
|
||||
| python/ | Scripts Python pour générer et lancer les tests de l'API script.
|
||||
| testapigen.py | Script Python générant des scripts dans tous les languages pour tester l'API script.
|
||||
| testapi.py | Script Python avec les tests API, utilisé par le script testapigen.py.
|
||||
| unparse.py | Conversion de code Python vers d'autres langages, utilisé par le script testapigen.py.
|
||||
| unit/ | Racine des tests unitaires.
|
||||
| test-plugins.cpp | Tests : extensions.
|
||||
| test-plugin-api-info.cpp | Tests : fonctions info de l'API extension.
|
||||
| test-plugin-config.cpp | Tests : fonctions config de l'extension.
|
||||
| core/ | Racine des tests unitaires pour le cœur.
|
||||
| test-core-arraylist.cpp | Tests : listes avec tableau (« arraylists »).
|
||||
| test-core-calc.cpp | Tests : calcul d'expressions.
|
||||
| test-core-command.cpp | Tests : commandes.
|
||||
| test-core-config-file.cpp | Tests : fichiers de configuration.
|
||||
| test-core-crypto.cpp | Tests : fonctions cryptographiques.
|
||||
| test-core-dir.cpp | Tests : répertoires/fichiers.
|
||||
| test-core-eval.cpp | Tests : évaluation d'expressions.
|
||||
| test-core-hashtble.cpp | Tests : tables de hachage.
|
||||
| test-core-hdata.cpp | Tests : hdata.
|
||||
| test-core-hook.cpp | Tests : hooks.
|
||||
| test-core-infolist.cpp | Tests : infolists.
|
||||
| test-core-list.cpp | Tests : listes.
|
||||
| test-core-network.cpp | Tests : fonctions réseau.
|
||||
| test-core-secure.cpp | Tests : données sécurisées.
|
||||
| test-core-signal.cpp | Tests : signaux.
|
||||
| test-core-string.cpp | Tests : chaînes.
|
||||
| test-core-url.cpp | Tests : URLs.
|
||||
| test-core-utf8.cpp | Tests : UTF-8.
|
||||
| test-core-util.cpp | Tests : fonctions utiles.
|
||||
| test-core-sys.cpp | Tests : fonctions système.
|
||||
| hook/ | Racine des tests pour les hooks.
|
||||
| test-hook-command.cpp | Tests : hooks "command".
|
||||
| gui/ | Racine des tests unitaires pour les interfaces.
|
||||
| test-gui-bar-window.cpp | Tests : fonctions de fenêtres de barre.
|
||||
| test-gui-buffer.cpp | Tests : fonctions de tampons.
|
||||
| test-gui-chat.cpp | Tests : fonctions de discussion.
|
||||
| test-gui-color.cpp | Tests : couleurs.
|
||||
| test-gui-filter.cpp | Tests : filtres.
|
||||
| test-gui-input.cpp | Tests : fonctions d'entrée.
|
||||
| test-gui-key.cpp | Tests : touches.
|
||||
| test-gui-line.cpp | Tests : lignes.
|
||||
| test-gui-nick.cpp | Tests : pseudos.
|
||||
| plugins/ | Racine des tests unitaires pour les extensions.
|
||||
| irc/ | Racine des tests unitaires pour l'extension IRC.
|
||||
| test-irc-batch.cpp | Tests : évènements batch IRC.
|
||||
| test-irc-buffer.cpp | Tests : tampons IRC.
|
||||
| test-irc-channel.cpp | Tests : canaux IRC.
|
||||
| test-irc-color.cpp | Tests : couleurs IRC.
|
||||
| test-irc-config.cpp | Tests : configuration IRC.
|
||||
| test-irc-ctcp.cpp | Tests : CTCP IRC.
|
||||
| test-irc-ignore.cpp | Tests : ignores IRC.
|
||||
| test-irc-info.cpp | Tests : infos IRC.
|
||||
| test-irc-join.cpp | Tests : fonctions de join IRC.
|
||||
| test-irc-list.cpp | Tests : tampon IRC pour la réponse à la commande /list.
|
||||
| test-irc-message.cpp | Tests : messages IRC.
|
||||
| test-irc-mode.cpp | Tests : modes IRC.
|
||||
| test-irc-nick.cpp | Tests : pseudos IRC.
|
||||
| test-irc-protocol.cpp | Tests : protocole IRC.
|
||||
| test-irc-sasl.cpp | Tests : authentification SASL avec le protocole IRC.
|
||||
| test-irc-server.cpp | Tests : serveur IRC.
|
||||
| test-irc-tag.cpp | Tests : étiquettes des messages IRC.
|
||||
| logger/ | Racine des tests unitaires pour l'extension logger.
|
||||
| test-logger.cpp | Tests : logger.
|
||||
| test-logger-backlog.cpp | Tests : backlog logger.
|
||||
| test-logger-tail.cpp | Tests : fonctions "tail".
|
||||
| trigger/ | Racine des tests unitaires pour l'extension trigger.
|
||||
| test-trigger.cpp | Tests : triggers.
|
||||
| test-trigger-config.cpp | Tests : configuration trigger.
|
||||
| typing/ | Racine des tests unitaires pour l'extension typing.
|
||||
| test-typing.cpp | Tests : typing.
|
||||
| test-typing-status.cpp | Tests : statut d'écriture.
|
||||
| relay/ | Racine des tests unitaires pour l'extension Relay.
|
||||
| test-relay-auth.cpp | Tests : authentification des clients.
|
||||
| test-relay-http.cpp | Tests : fonctions HTTP pour l'extension Relay.
|
||||
| irc/ | Racine des tests unitaires pour le protocole relay "irc".
|
||||
| test-relay-irc.cpp | Tests : Protocole relay "irc".
|
||||
| xfer/ | Racine des tests unitaires pour l'extension Xfer.
|
||||
| test-xfer-file.cpp | Tests : fonctions sur les fichiers.
|
||||
| test-xfer-network.cpp | Tests : fonctions réseau.
|
||||
| Chemin/fichier | Description
|
||||
| tests/ | Racine des tests.
|
||||
| tests.cpp | Programme utilisé pour lancer tous les tests.
|
||||
| tests-record.cpp | Enregistrement et recherche dans les messages affichés.
|
||||
| scripts/ | Racine des tests de l'API script.
|
||||
| test-scripts.cpp | Programme utilisé pour lancer les tests de l'API script.
|
||||
| python/ | Scripts Python pour générer et lancer les tests de l'API script.
|
||||
| testapigen.py | Script Python générant des scripts dans tous les languages pour tester l'API script.
|
||||
| testapi.py | Script Python avec les tests API, utilisé par le script testapigen.py.
|
||||
| unparse.py | Conversion de code Python vers d'autres langages, utilisé par le script testapigen.py.
|
||||
| unit/ | Racine des tests unitaires.
|
||||
| test-plugins.cpp | Tests : extensions.
|
||||
| test-plugin-api-info.cpp | Tests : fonctions info de l'API extension.
|
||||
| test-plugin-config.cpp | Tests : fonctions config de l'extension.
|
||||
| core/ | Racine des tests unitaires pour le cœur.
|
||||
| test-core-arraylist.cpp | Tests : listes avec tableau (« arraylists »).
|
||||
| test-core-calc.cpp | Tests : calcul d'expressions.
|
||||
| test-core-command.cpp | Tests : commandes.
|
||||
| test-core-config-file.cpp | Tests : fichiers de configuration.
|
||||
| test-core-crypto.cpp | Tests : fonctions cryptographiques.
|
||||
| test-core-dir.cpp | Tests : répertoires/fichiers.
|
||||
| test-core-eval.cpp | Tests : évaluation d'expressions.
|
||||
| test-core-hashtble.cpp | Tests : tables de hachage.
|
||||
| test-core-hdata.cpp | Tests : hdata.
|
||||
| test-core-hook.cpp | Tests : hooks.
|
||||
| test-core-infolist.cpp | Tests : infolists.
|
||||
| test-core-list.cpp | Tests : listes.
|
||||
| test-core-network.cpp | Tests : fonctions réseau.
|
||||
| test-core-secure.cpp | Tests : données sécurisées.
|
||||
| test-core-signal.cpp | Tests : signaux.
|
||||
| test-core-string.cpp | Tests : chaînes.
|
||||
| test-core-url.cpp | Tests : URLs.
|
||||
| test-core-utf8.cpp | Tests : UTF-8.
|
||||
| test-core-util.cpp | Tests : fonctions utiles.
|
||||
| test-core-sys.cpp | Tests : fonctions système.
|
||||
| hook/ | Racine des tests pour les hooks.
|
||||
| test-hook-command.cpp | Tests : hooks "command".
|
||||
| gui/ | Racine des tests unitaires pour les interfaces.
|
||||
| test-gui-bar-window.cpp | Tests : fonctions de fenêtres de barre.
|
||||
| test-gui-buffer.cpp | Tests : fonctions de tampons.
|
||||
| test-gui-chat.cpp | Tests : fonctions de discussion.
|
||||
| test-gui-color.cpp | Tests : couleurs.
|
||||
| test-gui-filter.cpp | Tests : filtres.
|
||||
| test-gui-input.cpp | Tests : fonctions d'entrée.
|
||||
| test-gui-key.cpp | Tests : touches.
|
||||
| test-gui-line.cpp | Tests : lignes.
|
||||
| test-gui-nick.cpp | Tests : pseudos.
|
||||
| plugins/ | Racine des tests unitaires pour les extensions.
|
||||
| irc/ | Racine des tests unitaires pour l'extension IRC.
|
||||
| test-irc-batch.cpp | Tests : évènements batch IRC.
|
||||
| test-irc-buffer.cpp | Tests : tampons IRC.
|
||||
| test-irc-channel.cpp | Tests : canaux IRC.
|
||||
| test-irc-color.cpp | Tests : couleurs IRC.
|
||||
| test-irc-config.cpp | Tests : configuration IRC.
|
||||
| test-irc-ctcp.cpp | Tests : CTCP IRC.
|
||||
| test-irc-ignore.cpp | Tests : ignores IRC.
|
||||
| test-irc-info.cpp | Tests : infos IRC.
|
||||
| test-irc-join.cpp | Tests : fonctions de join IRC.
|
||||
| test-irc-list.cpp | Tests : tampon IRC pour la réponse à la commande /list.
|
||||
| test-irc-message.cpp | Tests : messages IRC.
|
||||
| test-irc-mode.cpp | Tests : modes IRC.
|
||||
| test-irc-nick.cpp | Tests : pseudos IRC.
|
||||
| test-irc-protocol.cpp | Tests : protocole IRC.
|
||||
| test-irc-sasl.cpp | Tests : authentification SASL avec le protocole IRC.
|
||||
| test-irc-server.cpp | Tests : serveur IRC.
|
||||
| test-irc-tag.cpp | Tests : étiquettes des messages IRC.
|
||||
| logger/ | Racine des tests unitaires pour l'extension logger.
|
||||
| test-logger.cpp | Tests : logger.
|
||||
| test-logger-backlog.cpp | Tests : backlog logger.
|
||||
| test-logger-tail.cpp | Tests : fonctions "tail".
|
||||
| trigger/ | Racine des tests unitaires pour l'extension trigger.
|
||||
| test-trigger.cpp | Tests : triggers.
|
||||
| test-trigger-config.cpp | Tests : configuration trigger.
|
||||
| typing/ | Racine des tests unitaires pour l'extension typing.
|
||||
| test-typing.cpp | Tests : typing.
|
||||
| test-typing-status.cpp | Tests : statut d'écriture.
|
||||
| relay/ | Racine des tests unitaires pour l'extension Relay.
|
||||
| test-relay-auth.cpp | Tests : authentification des clients.
|
||||
| test-relay-http.cpp | Tests : fonctions HTTP pour l'extension Relay.
|
||||
| test-relay-websocket.cpp | Tests : fonctions websocket pour l'extension Relay.
|
||||
| irc/ | Racine des tests unitaires pour le protocole relay "irc".
|
||||
| test-relay-irc.cpp | Tests : Protocole relay "irc".
|
||||
| xfer/ | Racine des tests unitaires pour l'extension Xfer.
|
||||
| test-xfer-file.cpp | Tests : fonctions sur les fichiers.
|
||||
| test-xfer-network.cpp | Tests : fonctions réseau.
|
||||
|===
|
||||
|
||||
[[documentation_translations]]
|
||||
|
||||
+86
-84
@@ -428,143 +428,145 @@ WeeChat "core" は以下のディレクトリに配置されています:
|
||||
|
||||
[width="100%",cols="2m,3",options="header"]
|
||||
|===
|
||||
| パス/ファイル名 | 説明
|
||||
| tests/ | テスト用のルートディレクトリ
|
||||
| tests.cpp | 全テストの実行時に使われるプログラム
|
||||
| パス/ファイル名 | 説明
|
||||
| tests/ | テスト用のルートディレクトリ
|
||||
| tests.cpp | 全テストの実行時に使われるプログラム
|
||||
// TRANSLATION MISSING
|
||||
| tests-record.cpp | Record and search in messages displayed.
|
||||
| scripts/ | スクリプト API テスト用のルートディレクトリ
|
||||
| test-scripts.cpp | スクリプト API テストの実行時に使われるプログラム
|
||||
| python/ | スクリプト API テストを生成、実行する Python スクリプト
|
||||
| testapigen.py | スクリプト API のテスト時にすべての言語に関するスクリプトを生成する Python スクリプト
|
||||
| testapi.py | スクリプト API テスト時に使われる Python スクリプト (スクリプト testapigen.py から使われます)
|
||||
| unparse.py | Python コードを別の言語に変換 (スクリプト testapigen.py から使われます)
|
||||
| unit/ | 単体テスト用のルートディレクトリ
|
||||
| test-plugins.cpp | テスト: プラグイン
|
||||
| tests-record.cpp | Record and search in messages displayed.
|
||||
| scripts/ | スクリプト API テスト用のルートディレクトリ
|
||||
| test-scripts.cpp | スクリプト API テストの実行時に使われるプログラム
|
||||
| python/ | スクリプト API テストを生成、実行する Python スクリプト
|
||||
| testapigen.py | スクリプト API のテスト時にすべての言語に関するスクリプトを生成する Python スクリプト
|
||||
| testapi.py | スクリプト API テスト時に使われる Python スクリプト (スクリプト testapigen.py から使われます)
|
||||
| unparse.py | Python コードを別の言語に変換 (スクリプト testapigen.py から使われます)
|
||||
| unit/ | 単体テスト用のルートディレクトリ
|
||||
| test-plugins.cpp | テスト: プラグイン
|
||||
// TRANSLATION MISSING
|
||||
| test-plugin-api-info.cpp | Tests: plugin API info functions.
|
||||
| test-plugin-api-info.cpp | Tests: plugin API info functions.
|
||||
// TRANSLATION MISSING
|
||||
| test-plugin-config.cpp | Tests: plugin config functions.
|
||||
| core/ | core 向け単体テスト用のルートディレクトリ
|
||||
| test-core-arraylist.cpp | テスト: 配列リスト
|
||||
| test-plugin-config.cpp | Tests: plugin config functions.
|
||||
| core/ | core 向け単体テスト用のルートディレクトリ
|
||||
| test-core-arraylist.cpp | テスト: 配列リスト
|
||||
// TRANSLATION MISSING
|
||||
| test-core-calc.cpp | Tests: calculation of expressions.
|
||||
| test-core-calc.cpp | Tests: calculation of expressions.
|
||||
// TRANSLATION MISSING
|
||||
| test-core-command.cpp | Tests: commands.
|
||||
| test-core-command.cpp | Tests: commands.
|
||||
// TRANSLATION MISSING
|
||||
| test-core-config-file.cpp | Tests: configuration files.
|
||||
| test-core-config-file.cpp | Tests: configuration files.
|
||||
// TRANSLATION MISSING
|
||||
| test-core-crypto.cpp | Tests: cryptographic functions.
|
||||
| test-core-crypto.cpp | Tests: cryptographic functions.
|
||||
// TRANSLATION MISSING
|
||||
| test-core-dir.cpp | Tests: directory/file functions.
|
||||
| test-core-eval.cpp | テスト: 式の評価
|
||||
| test-core-hashtble.cpp | テスト: ハッシュテーブル
|
||||
| test-core-hdata.cpp | テスト: hdata
|
||||
| test-core-hook.cpp | テスト: フック
|
||||
| test-core-infolist.cpp | テスト: インフォリスト
|
||||
| test-core-list.cpp | テスト: リスト
|
||||
| test-core-dir.cpp | Tests: directory/file functions.
|
||||
| test-core-eval.cpp | テスト: 式の評価
|
||||
| test-core-hashtble.cpp | テスト: ハッシュテーブル
|
||||
| test-core-hdata.cpp | テスト: hdata
|
||||
| test-core-hook.cpp | テスト: フック
|
||||
| test-core-infolist.cpp | テスト: インフォリスト
|
||||
| test-core-list.cpp | テスト: リスト
|
||||
// TRANSLATION MISSING
|
||||
| test-core-network.cpp | Tests: network functions.
|
||||
| test-core-secure.cpp | テスト: データ保護
|
||||
| test-core-network.cpp | Tests: network functions.
|
||||
| test-core-secure.cpp | テスト: データ保護
|
||||
// TRANSLATION MISSING
|
||||
| test-core-signal.cpp | テスト: signals.
|
||||
| test-core-string.cpp | テスト: 文字列
|
||||
| test-core-url.cpp | テスト: URL
|
||||
| test-core-utf8.cpp | テスト: UTF-8
|
||||
| test-core-util.cpp | テスト: ユーティリティ関数
|
||||
| test-core-signal.cpp | テスト: signals.
|
||||
| test-core-string.cpp | テスト: 文字列
|
||||
| test-core-url.cpp | テスト: URL
|
||||
| test-core-utf8.cpp | テスト: UTF-8
|
||||
| test-core-util.cpp | テスト: ユーティリティ関数
|
||||
// TRANSLATION MISSING
|
||||
| test-core-sys.cpp | Tests: system functions.
|
||||
| test-core-sys.cpp | Tests: system functions.
|
||||
// TRANSLATION MISSING
|
||||
| hook/ | Root of unit tests for hooks.
|
||||
| hook/ | Root of unit tests for hooks.
|
||||
// TRANSLATION MISSING
|
||||
| test-hook-command.cpp | Tests: hooks "command".
|
||||
| gui/ | インターフェースの単体テストを収める最上位ディレクトリ
|
||||
| test-hook-command.cpp | Tests: hooks "command".
|
||||
| gui/ | インターフェースの単体テストを収める最上位ディレクトリ
|
||||
// TRANSLATION MISSING
|
||||
| test-gui-bar-window.cpp | Tests: bar window functions.
|
||||
| test-gui-bar-window.cpp | Tests: bar window functions.
|
||||
// TRANSLATION MISSING
|
||||
| test-gui-buffer.cpp | Tests: buffer functions.
|
||||
| test-gui-buffer.cpp | Tests: buffer functions.
|
||||
// TRANSLATION MISSING
|
||||
| test-gui-chat.cpp | Tests: chat functions.
|
||||
| test-gui-chat.cpp | Tests: chat functions.
|
||||
// TRANSLATION MISSING
|
||||
| test-gui-color.cpp | Tests: colors.
|
||||
| test-gui-color.cpp | Tests: colors.
|
||||
// TRANSLATION MISSING
|
||||
| test-gui-filter.cpp | Tests: filters.
|
||||
| test-gui-filter.cpp | Tests: filters.
|
||||
// TRANSLATION MISSING
|
||||
| test-gui-input.cpp | Tests: input functions.
|
||||
| test-gui-input.cpp | Tests: input functions.
|
||||
// TRANSLATION MISSING
|
||||
| test-gui-key.cpp | Tests: keys.
|
||||
| test-gui-line.cpp | テスト: 行
|
||||
| test-gui-key.cpp | Tests: keys.
|
||||
| test-gui-line.cpp | テスト: 行
|
||||
// TRANSLATION MISSING
|
||||
| test-gui-nick.cpp | テスト: nicks
|
||||
| plugins/ | プラグインの単体テストを収める最上位ディレクトリ
|
||||
| irc/ | IRC プラグインの単体テストを収める最上位ディレクトリ
|
||||
| test-gui-nick.cpp | テスト: nicks
|
||||
| plugins/ | プラグインの単体テストを収める最上位ディレクトリ
|
||||
| irc/ | IRC プラグインの単体テストを収める最上位ディレクトリ
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-batch.cpp | Tests: IRC batched events.
|
||||
| test-irc-batch.cpp | Tests: IRC batched events.
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-buffer.cpp | Tests: IRC buffers.
|
||||
| test-irc-buffer.cpp | Tests: IRC buffers.
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-channel.cpp | Tests: IRC channels.
|
||||
| test-irc-color.cpp | Tests: IRC colors.
|
||||
| test-irc-config.cpp | テスト: IRC 設定
|
||||
| test-irc-channel.cpp | Tests: IRC channels.
|
||||
| test-irc-color.cpp | Tests: IRC colors.
|
||||
| test-irc-config.cpp | テスト: IRC 設定
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-ctcp.cpp | Tests: IRC CTCP.
|
||||
| test-irc-ctcp.cpp | Tests: IRC CTCP.
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-ignore.cpp | Tests: IRC ignores.
|
||||
| test-irc-ignore.cpp | Tests: IRC ignores.
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-info.cpp | Tests: IRC info.
|
||||
| test-irc-info.cpp | Tests: IRC info.
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-join.cpp | Tests: IRC join functions.
|
||||
| test-irc-join.cpp | Tests: IRC join functions.
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-list.cpp | Tests: IRC buffer for reply to /list command.
|
||||
| test-irc-list.cpp | Tests: IRC buffer for reply to /list command.
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-message.cpp | Tests: IRC messages.
|
||||
| test-irc-message.cpp | Tests: IRC messages.
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-mode.cpp | Tests: IRC modes.
|
||||
| test-irc-mode.cpp | Tests: IRC modes.
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-nick.cpp | Tests: IRC nicks.
|
||||
| test-irc-protocol.cpp | テスト: IRC プロトコル
|
||||
| test-irc-nick.cpp | Tests: IRC nicks.
|
||||
| test-irc-protocol.cpp | テスト: IRC プロトコル
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-sasl.cpp | Tests: SASL authentication with IRC protocol.
|
||||
| test-irc-sasl.cpp | Tests: SASL authentication with IRC protocol.
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-server.cpp | Tests: IRC server.
|
||||
| test-irc-server.cpp | Tests: IRC server.
|
||||
// TRANSLATION MISSING
|
||||
| test-irc-tag.cpp | Tests: IRC message tags.
|
||||
| test-irc-tag.cpp | Tests: IRC message tags.
|
||||
// TRANSLATION MISSING
|
||||
| logger/ | Root of unit tests for logger plugin.
|
||||
| logger/ | Root of unit tests for logger plugin.
|
||||
// TRANSLATION MISSING
|
||||
| test-logger.cpp | Tests: logger.
|
||||
| test-logger.cpp | Tests: logger.
|
||||
// TRANSLATION MISSING
|
||||
| test-logger-backlog.cpp | Tests: logger backlog.
|
||||
| test-logger-backlog.cpp | Tests: logger backlog.
|
||||
// TRANSLATION MISSING
|
||||
| test-logger-tail.cpp | Tests: logger tail functions.
|
||||
| test-logger-tail.cpp | Tests: logger tail functions.
|
||||
// TRANSLATION MISSING
|
||||
| trigger/ | Root of unit tests for trigger plugin.
|
||||
| trigger/ | Root of unit tests for trigger plugin.
|
||||
// TRANSLATION MISSING
|
||||
| test-trigger.cpp | Tests: triggers.
|
||||
| test-trigger.cpp | Tests: triggers.
|
||||
// TRANSLATION MISSING
|
||||
| test-trigger-config.cpp | Tests: trigger configuration.
|
||||
| test-trigger-config.cpp | Tests: trigger configuration.
|
||||
// TRANSLATION MISSING
|
||||
| typing/ | Root of unit tests for typing plugin.
|
||||
| typing/ | Root of unit tests for typing plugin.
|
||||
// TRANSLATION MISSING
|
||||
| test-typing.cpp | Tests: typing.
|
||||
| test-typing.cpp | Tests: typing.
|
||||
// TRANSLATION MISSING
|
||||
| test-typing-status.cpp | Tests: typing status.
|
||||
| test-typing-status.cpp | Tests: typing status.
|
||||
// TRANSLATION MISSING
|
||||
| relay/ | Root of unit tests for Relay plugin.
|
||||
| relay/ | Root of unit tests for Relay plugin.
|
||||
// TRANSLATION MISSING
|
||||
| test-relay-auth.cpp | Tests: clients authentication.
|
||||
| test-relay-auth.cpp | Tests: clients authentication.
|
||||
// TRANSLATION MISSING
|
||||
| test-relay-http.cpp | Tests: HTTP functions for Relay plugin.
|
||||
| test-relay-http.cpp | Tests: HTTP functions for Relay plugin.
|
||||
// TRANSLATION MISSING
|
||||
| irc/ | Root of unit tests for Relay "irc" protocol.
|
||||
| test-relay-websocket.cpp | Tests: websocket functions for Relay plugin.
|
||||
// TRANSLATION MISSING
|
||||
| test-relay-irc.cpp | Tests: Relay "irc" protocol.
|
||||
| irc/ | Root of unit tests for Relay "irc" protocol.
|
||||
// TRANSLATION MISSING
|
||||
| xfer/ | Root of unit tests for Xfer plugin.
|
||||
| test-relay-irc.cpp | Tests: Relay "irc" protocol.
|
||||
// TRANSLATION MISSING
|
||||
| test-xfer-file.cpp | Tests: file functions.
|
||||
| xfer/ | Root of unit tests for Xfer plugin.
|
||||
// TRANSLATION MISSING
|
||||
| test-xfer-network.cpp | Tests: network functions.
|
||||
| test-xfer-file.cpp | Tests: file functions.
|
||||
// TRANSLATION MISSING
|
||||
| test-xfer-network.cpp | Tests: network functions.
|
||||
|===
|
||||
|
||||
[[documentation_translations]]
|
||||
|
||||
+86
-84
@@ -404,91 +404,93 @@ WeeChat „језгро” се налази у следећим директо
|
||||
|
||||
[width="100%", cols="2m,3", options="header"]
|
||||
|===
|
||||
| Путања/фајл | Опис
|
||||
| tests/ | Корен тестова.
|
||||
| tests.cpp | Програм који се користи за извршавање свих тестова.
|
||||
| tests-record.cpp | Бележење и претрага у приказаним порукама.
|
||||
| scripts/ | Корен тестова за API скриптовања.
|
||||
| test-scripts.cpp | Програм који се користи за извршавање тестова API скриптовања.
|
||||
| python/ | Python скрипте које генеришу и покрећу тестове API скриптовања.
|
||||
| testapigen.py | Python скрипта која генерише скрипте на свим језицима за тестирање API скриптовања.
|
||||
| testapi.py | Python скрипта са тестовима API скриптовања, користи је скрипта testapigen.py.
|
||||
| unparse.py | Конверзија Python кода у остале језике, користи је скрипта testapigen.py.
|
||||
| unit/ | Корен unit тестова.
|
||||
| test-plugins.cpp | Тестови: plugins.
|
||||
| test-plugin-api-info.cpp | Тестови: инфо функције API додатака.
|
||||
| test-plugin-config.cpp | Тестови: функције конфигурације додатка.
|
||||
| core/ | Корен unit тестова језгра.
|
||||
| test-core-arraylist.cpp | Тестови: arraylists.
|
||||
| test-core-calc.cpp | Тестови: калкулација израза.
|
||||
| test-core-command.cpp | Тестови: команде.
|
||||
| test-core-config-file.cpp | Тестови: конфигурациони фајлови.
|
||||
| test-core-crypto.cpp | Тестови: криптографске функције.
|
||||
| test-core-dir.cpp | Тестови: функције директоријума/фајла.
|
||||
| test-core-eval.cpp | Тестови: израчунавање израза.
|
||||
| test-core-hashtble.cpp | Тестови: hashtables.
|
||||
| test-core-hdata.cpp | Тестови: hdata.
|
||||
| test-core-hook.cpp | Тестови: куке.
|
||||
| test-core-infolist.cpp | Тестови: infolists.
|
||||
| test-core-list.cpp | Тестови: листе.
|
||||
| test-core-network.cpp | Тестови: мрежне функције.
|
||||
| test-core-secure.cpp | Тестови: обезбеђени подаци.
|
||||
| test-core-signal.cpp | Тестови: сигнали.
|
||||
| test-core-string.cpp | Тестови: стрингови.
|
||||
| test-core-url.cpp | Тестови: URL адресе.
|
||||
| test-core-utf8.cpp | Тестови: UTF-8.
|
||||
| test-core-util.cpp | Тестови: помоћне функције.
|
||||
| test-core-sys.cpp | Тестови: системске функције.
|
||||
| hook/ | Корен unit тестова за куке.
|
||||
| test-hook-command.cpp | Тестови: куке „command”.
|
||||
| gui/ | Корен unit тестова интерфејса.
|
||||
| test-gui-bar-window.cpp | Тестови: функције прозора траке.
|
||||
| test-gui-buffer.cpp | Тестови: бафер функције.
|
||||
| test-gui-chat.cpp | Тестови: чет функције.
|
||||
| test-gui-color.cpp | Тестови: боје.
|
||||
| test-gui-filter.cpp | Тестови: филтери.
|
||||
| test-gui-input.cpp | Тестови: улазне функкције.
|
||||
| test-gui-key.cpp | Тестови: тастери.
|
||||
| test-gui-line.cpp | Тестови: линије.
|
||||
| test-gui-nick.cpp | Тестови: надимци.
|
||||
| plugins/ | Корен unit тестова додатака.
|
||||
| irc/ | Корен unit тестова IRC додатка.
|
||||
| test-irc-batch.cpp | Тестови: IRC пакетни догађаји.
|
||||
| test-irc-buffer.cpp | Тестови: IRC бафери.
|
||||
| test-irc-channel.cpp | Тестови: IRC канали.
|
||||
| test-irc-color.cpp | Тестови: IRC боје.
|
||||
| test-irc-config.cpp | Тестови: IRC конфигурација.
|
||||
| test-irc-ctcp.cpp | Тестови: IRC CTCP.
|
||||
| test-irc-ignore.cpp | Тестови: IRC игнорисања.
|
||||
| test-irc-info.cpp | Тестови: IRC информације.
|
||||
| test-irc-join.cpp | Тестови: IRC функције приступања.
|
||||
| test-irc-list.cpp | Тестови: IRC бафер за одговор на /list команду.
|
||||
| test-irc-message.cpp | Тестови: IRC поруке.
|
||||
| test-irc-mode.cpp | Тестови: IRC режими.
|
||||
| test-irc-nick.cpp | Тестови: IRC надимци.
|
||||
| test-irc-protocol.cpp | Тестови: IRC протокол.
|
||||
| test-irc-sasl.cpp | Тестови: SASL аутентификација са IRC протоколом.
|
||||
| test-irc-server.cpp | Тестови: IRC сервер.
|
||||
| test-irc-tag.cpp | Тестови: IRC ознаке порука.
|
||||
| logger/ | Корен unit тестива за logger додатак.
|
||||
| test-logger.cpp | Тестови: logger.
|
||||
| test-logger-backlog.cpp | Тестови: logger заостатак.
|
||||
| test-logger-tail.cpp | Тестови: logger tail фунцкије.
|
||||
| trigger/ | Корен unit тестова за окидач додатак.
|
||||
| test-trigger.cpp | Тестови: окидачи.
|
||||
| test-trigger-config.cpp | Тестови: конфигурација окидача.
|
||||
| typing/ | Корен unit тестова за typing додатак.
|
||||
| test-typing.cpp | Тестови: typing.
|
||||
| test-typing-status.cpp | Тестови: typing статус.
|
||||
| relay/ | Корен unit тестова за Релеј додатак.
|
||||
| test-relay-auth.cpp | Тестови: аутентификација клијената.
|
||||
| Путања/фајл | Опис
|
||||
| tests/ | Корен тестова.
|
||||
| tests.cpp | Програм који се користи за извршавање свих тестова.
|
||||
| tests-record.cpp | Бележење и претрага у приказаним порукама.
|
||||
| scripts/ | Корен тестова за API скриптовања.
|
||||
| test-scripts.cpp | Програм који се користи за извршавање тестова API скриптовања.
|
||||
| python/ | Python скрипте које генеришу и покрећу тестове API скриптовања.
|
||||
| testapigen.py | Python скрипта која генерише скрипте на свим језицима за тестирање API скриптовања.
|
||||
| testapi.py | Python скрипта са тестовима API скриптовања, користи је скрипта testapigen.py.
|
||||
| unparse.py | Конверзија Python кода у остале језике, користи је скрипта testapigen.py.
|
||||
| unit/ | Корен unit тестова.
|
||||
| test-plugins.cpp | Тестови: plugins.
|
||||
| test-plugin-api-info.cpp | Тестови: инфо функције API додатака.
|
||||
| test-plugin-config.cpp | Тестови: функције конфигурације додатка.
|
||||
| core/ | Корен unit тестова језгра.
|
||||
| test-core-arraylist.cpp | Тестови: arraylists.
|
||||
| test-core-calc.cpp | Тестови: калкулација израза.
|
||||
| test-core-command.cpp | Тестови: команде.
|
||||
| test-core-config-file.cpp | Тестови: конфигурациони фајлови.
|
||||
| test-core-crypto.cpp | Тестови: криптографске функције.
|
||||
| test-core-dir.cpp | Тестови: функције директоријума/фајла.
|
||||
| test-core-eval.cpp | Тестови: израчунавање израза.
|
||||
| test-core-hashtble.cpp | Тестови: hashtables.
|
||||
| test-core-hdata.cpp | Тестови: hdata.
|
||||
| test-core-hook.cpp | Тестови: куке.
|
||||
| test-core-infolist.cpp | Тестови: infolists.
|
||||
| test-core-list.cpp | Тестови: листе.
|
||||
| test-core-network.cpp | Тестови: мрежне функције.
|
||||
| test-core-secure.cpp | Тестови: обезбеђени подаци.
|
||||
| test-core-signal.cpp | Тестови: сигнали.
|
||||
| test-core-string.cpp | Тестови: стрингови.
|
||||
| test-core-url.cpp | Тестови: URL адресе.
|
||||
| test-core-utf8.cpp | Тестови: UTF-8.
|
||||
| test-core-util.cpp | Тестови: помоћне функције.
|
||||
| test-core-sys.cpp | Тестови: системске функције.
|
||||
| hook/ | Корен unit тестова за куке.
|
||||
| test-hook-command.cpp | Тестови: куке „command”.
|
||||
| gui/ | Корен unit тестова интерфејса.
|
||||
| test-gui-bar-window.cpp | Тестови: функције прозора траке.
|
||||
| test-gui-buffer.cpp | Тестови: бафер функције.
|
||||
| test-gui-chat.cpp | Тестови: чет функције.
|
||||
| test-gui-color.cpp | Тестови: боје.
|
||||
| test-gui-filter.cpp | Тестови: филтери.
|
||||
| test-gui-input.cpp | Тестови: улазне функкције.
|
||||
| test-gui-key.cpp | Тестови: тастери.
|
||||
| test-gui-line.cpp | Тестови: линије.
|
||||
| test-gui-nick.cpp | Тестови: надимци.
|
||||
| plugins/ | Корен unit тестова додатака.
|
||||
| irc/ | Корен unit тестова IRC додатка.
|
||||
| test-irc-batch.cpp | Тестови: IRC пакетни догађаји.
|
||||
| test-irc-buffer.cpp | Тестови: IRC бафери.
|
||||
| test-irc-channel.cpp | Тестови: IRC канали.
|
||||
| test-irc-color.cpp | Тестови: IRC боје.
|
||||
| test-irc-config.cpp | Тестови: IRC конфигурација.
|
||||
| test-irc-ctcp.cpp | Тестови: IRC CTCP.
|
||||
| test-irc-ignore.cpp | Тестови: IRC игнорисања.
|
||||
| test-irc-info.cpp | Тестови: IRC информације.
|
||||
| test-irc-join.cpp | Тестови: IRC функције приступања.
|
||||
| test-irc-list.cpp | Тестови: IRC бафер за одговор на /list команду.
|
||||
| test-irc-message.cpp | Тестови: IRC поруке.
|
||||
| test-irc-mode.cpp | Тестови: IRC режими.
|
||||
| test-irc-nick.cpp | Тестови: IRC надимци.
|
||||
| test-irc-protocol.cpp | Тестови: IRC протокол.
|
||||
| test-irc-sasl.cpp | Тестови: SASL аутентификација са IRC протоколом.
|
||||
| test-irc-server.cpp | Тестови: IRC сервер.
|
||||
| test-irc-tag.cpp | Тестови: IRC ознаке порука.
|
||||
| logger/ | Корен unit тестива за logger додатак.
|
||||
| test-logger.cpp | Тестови: logger.
|
||||
| test-logger-backlog.cpp | Тестови: logger заостатак.
|
||||
| test-logger-tail.cpp | Тестови: logger tail фунцкије.
|
||||
| trigger/ | Корен unit тестова за окидач додатак.
|
||||
| test-trigger.cpp | Тестови: окидачи.
|
||||
| test-trigger-config.cpp | Тестови: конфигурација окидача.
|
||||
| typing/ | Корен unit тестова за typing додатак.
|
||||
| test-typing.cpp | Тестови: typing.
|
||||
| test-typing-status.cpp | Тестови: typing статус.
|
||||
| relay/ | Корен unit тестова за Релеј додатак.
|
||||
| test-relay-auth.cpp | Тестови: аутентификација клијената.
|
||||
// TRANSLATION MISSING
|
||||
| test-relay-http.cpp | Tests: HTTP functions for Relay plugin.
|
||||
| irc/ | Корен unit тестова за Релеј „irc” протокол.
|
||||
| test-relay-irc.cpp | Тестови: РЕлеј „irc” протокол.
|
||||
| xfer/ | Корен unit тестова за Xfer додатак.
|
||||
| test-xfer-file.cpp | Тестови: фајл функције.
|
||||
| test-xfer-network.cpp | Тестови: мрежне функције.
|
||||
| test-relay-http.cpp | Tests: HTTP functions for Relay plugin.
|
||||
// TRANSLATION MISSING
|
||||
| test-relay-websocket.cpp | Tests: websocket functions for Relay plugin.
|
||||
| irc/ | Корен unit тестова за Релеј „irc” протокол.
|
||||
| test-relay-irc.cpp | Тестови: РЕлеј „irc” протокол.
|
||||
| xfer/ | Корен unit тестова за Xfer додатак.
|
||||
| test-xfer-file.cpp | Тестови: фајл функције.
|
||||
| test-xfer-network.cpp | Тестови: мрежне функције.
|
||||
|===
|
||||
|
||||
[[documentation_translations]]
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "../relay.h"
|
||||
#include "../relay-client.h"
|
||||
#include "../relay-http.h"
|
||||
#include "../relay-websocket.h"
|
||||
#include "relay-api.h"
|
||||
#include "relay-api-msg.h"
|
||||
#include "relay-api-protocol.h"
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "../relay-client.h"
|
||||
#include "../relay-config.h"
|
||||
#include "../relay-http.h"
|
||||
#include "../relay-websocket.h"
|
||||
#include "relay-api.h"
|
||||
#include "relay-api-msg.h"
|
||||
#include "relay-api-protocol.h"
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "../weechat-plugin.h"
|
||||
#include "relay.h"
|
||||
@@ -549,6 +549,85 @@ relay_client_recv_text_buffer (struct t_relay_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads websocket frames.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_client_read_websocket_frames (struct t_relay_client *client,
|
||||
struct t_relay_websocket_frame *frames,
|
||||
int num_frames)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!frames || (num_frames <= 0))
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_frames; i++)
|
||||
{
|
||||
if (frames[i].payload_size == 0)
|
||||
{
|
||||
/*
|
||||
* When decoded length is 0, assume client sent a PONG frame.
|
||||
*
|
||||
* RFC 6455 Section 5.5.3:
|
||||
*
|
||||
* "A Pong frame MAY be sent unsolicited. This serves as a
|
||||
* unidirectional heartbeat. A response to an unsolicited
|
||||
* Pong frame is not expected."
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
switch (frames[i].opcode)
|
||||
{
|
||||
case RELAY_CLIENT_MSG_PING:
|
||||
/* print message in raw buffer */
|
||||
relay_raw_print (client, RELAY_CLIENT_MSG_PING,
|
||||
RELAY_RAW_FLAG_RECV | RELAY_RAW_FLAG_BINARY,
|
||||
frames[i].payload,
|
||||
frames[i].payload_size);
|
||||
/* answer with a PONG */
|
||||
relay_client_send (client,
|
||||
RELAY_CLIENT_MSG_PONG,
|
||||
frames[i].payload,
|
||||
frames[i].payload_size,
|
||||
NULL);
|
||||
break;
|
||||
case RELAY_CLIENT_MSG_CLOSE:
|
||||
/* print message in raw buffer */
|
||||
relay_raw_print (client, RELAY_CLIENT_MSG_CLOSE,
|
||||
RELAY_RAW_FLAG_RECV | RELAY_RAW_FLAG_BINARY,
|
||||
frames[i].payload,
|
||||
frames[i].payload_size);
|
||||
/* answer with a CLOSE */
|
||||
relay_client_send (client,
|
||||
RELAY_CLIENT_MSG_CLOSE,
|
||||
frames[i].payload,
|
||||
frames[i].payload_size,
|
||||
NULL);
|
||||
/* close the connection */
|
||||
relay_client_set_status (client, RELAY_STATUS_DISCONNECTED);
|
||||
/* ignore any other message after the close */
|
||||
return;
|
||||
default:
|
||||
if (frames[i].payload)
|
||||
{
|
||||
if ((client->websocket == RELAY_CLIENT_WEBSOCKET_INITIALIZING)
|
||||
|| (client->recv_data_type == RELAY_CLIENT_DATA_HTTP))
|
||||
{
|
||||
relay_http_recv (client, frames[i].payload);
|
||||
}
|
||||
else if ((client->recv_data_type == RELAY_CLIENT_DATA_TEXT_LINE)
|
||||
|| (client->recv_data_type == RELAY_CLIENT_DATA_TEXT_MULTILINE))
|
||||
{
|
||||
relay_client_recv_text (client, frames[i].payload);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads data from a client.
|
||||
*/
|
||||
@@ -557,10 +636,9 @@ int
|
||||
relay_client_recv_cb (const void *pointer, void *data, int fd)
|
||||
{
|
||||
struct t_relay_client *client;
|
||||
static char buffer[4096], decoded[8192 + 1];
|
||||
const char *ptr_buffer;
|
||||
int num_read, rc;
|
||||
unsigned long long decoded_length, length_buffer;
|
||||
static char buffer[4096];
|
||||
int i, num_read, rc, num_frames;
|
||||
struct t_relay_websocket_frame *frames;
|
||||
|
||||
/* make C compiler happy */
|
||||
(void) data;
|
||||
@@ -590,8 +668,6 @@ relay_client_recv_cb (const void *pointer, void *data, int fd)
|
||||
if (num_read > 0)
|
||||
{
|
||||
buffer[num_read] = '\0';
|
||||
ptr_buffer = buffer;
|
||||
length_buffer = num_read;
|
||||
|
||||
/*
|
||||
* if we are receiving the first message from client, check if it looks
|
||||
@@ -599,7 +675,7 @@ relay_client_recv_cb (const void *pointer, void *data, int fd)
|
||||
*/
|
||||
if (client->bytes_recv == 0)
|
||||
{
|
||||
if (relay_websocket_is_valid_http_get (client, buffer))
|
||||
if (relay_websocket_is_valid_http_get (client->protocol, buffer))
|
||||
{
|
||||
/*
|
||||
* web socket is just initializing for now, it's not accepted
|
||||
@@ -615,23 +691,12 @@ relay_client_recv_cb (const void *pointer, void *data, int fd)
|
||||
if (client->websocket == RELAY_CLIENT_WEBSOCKET_READY)
|
||||
{
|
||||
/* websocket used, decode message */
|
||||
rc = relay_websocket_decode_frame ((unsigned char *)buffer,
|
||||
frames = NULL;
|
||||
num_frames = 0;
|
||||
rc = relay_websocket_decode_frame (client,
|
||||
(unsigned char *)buffer,
|
||||
(unsigned long long)num_read,
|
||||
(unsigned char *)decoded,
|
||||
&decoded_length);
|
||||
if (decoded_length == 0)
|
||||
{
|
||||
/*
|
||||
* When decoded length is 0, assume client sent a PONG frame.
|
||||
*
|
||||
* RFC 6455 Section 5.5.3:
|
||||
*
|
||||
* "A Pong frame MAY be sent unsolicited. This serves as a
|
||||
* unidirectional heartbeat. A response to an unsolicited
|
||||
* Pong frame is not expected."
|
||||
*/
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
&frames, &num_frames);
|
||||
if (!rc)
|
||||
{
|
||||
/* error when decoding frame: close connection */
|
||||
@@ -646,22 +711,26 @@ relay_client_recv_cb (const void *pointer, void *data, int fd)
|
||||
relay_client_set_status (client, RELAY_STATUS_DISCONNECTED);
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
ptr_buffer = decoded;
|
||||
length_buffer = decoded_length;
|
||||
}
|
||||
|
||||
if ((client->websocket == RELAY_CLIENT_WEBSOCKET_INITIALIZING)
|
||||
|| (client->recv_data_type == RELAY_CLIENT_DATA_TEXT_LINE)
|
||||
|| (client->recv_data_type == RELAY_CLIENT_DATA_TEXT_MULTILINE)
|
||||
|| (client->recv_data_type == RELAY_CLIENT_DATA_HTTP))
|
||||
{
|
||||
/* websocket initializing or text/HTTP data for this client */
|
||||
relay_client_recv_text_buffer (client, ptr_buffer, length_buffer);
|
||||
relay_client_read_websocket_frames (client, frames, num_frames);
|
||||
for (i = 0; i < num_frames; i++)
|
||||
{
|
||||
if (frames[i].payload)
|
||||
free (frames[i].payload);
|
||||
}
|
||||
free (frames);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* receive buffer as-is (binary data) */
|
||||
/* currently, all supported protocols receive only text, no binary */
|
||||
if ((client->websocket == RELAY_CLIENT_WEBSOCKET_INITIALIZING)
|
||||
|| (client->recv_data_type == RELAY_CLIENT_DATA_HTTP))
|
||||
{
|
||||
relay_http_recv (client, buffer);
|
||||
}
|
||||
else if ((client->recv_data_type == RELAY_CLIENT_DATA_TEXT_LINE)
|
||||
|| (client->recv_data_type == RELAY_CLIENT_DATA_TEXT_MULTILINE))
|
||||
{
|
||||
relay_client_recv_text (client, buffer);
|
||||
}
|
||||
}
|
||||
relay_buffer_refresh (NULL);
|
||||
}
|
||||
@@ -1103,9 +1172,8 @@ relay_client_send (struct t_relay_client *client,
|
||||
WEBSOCKET_FRAME_OPCODE_TEXT : WEBSOCKET_FRAME_OPCODE_BINARY;
|
||||
break;
|
||||
}
|
||||
websocket_frame = relay_websocket_encode_frame (opcode, data,
|
||||
data_size,
|
||||
&length_frame);
|
||||
websocket_frame = relay_websocket_encode_frame (
|
||||
client, opcode, data, data_size, &length_frame);
|
||||
if (websocket_frame)
|
||||
{
|
||||
ptr_data = websocket_frame;
|
||||
@@ -1307,6 +1375,7 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
|
||||
new_client->hook_timer_handshake = NULL;
|
||||
new_client->gnutls_handshake_ok = 0;
|
||||
new_client->websocket = RELAY_CLIENT_WEBSOCKET_NOT_USED;
|
||||
new_client->ws_deflate = relay_websocket_deflate_alloc ();
|
||||
new_client->http_req = relay_http_request_alloc ();
|
||||
new_client->address = strdup ((address && address[0]) ?
|
||||
address : "local");
|
||||
@@ -1516,6 +1585,8 @@ relay_client_new_with_infolist (struct t_infolist *infolist)
|
||||
{
|
||||
struct t_relay_client *new_client;
|
||||
const char *str;
|
||||
Bytef *ptr_dict;
|
||||
int dict_size;
|
||||
|
||||
new_client = malloc (sizeof (*new_client));
|
||||
if (new_client)
|
||||
@@ -1533,6 +1604,46 @@ relay_client_new_with_infolist (struct t_infolist *infolist)
|
||||
new_client->hook_timer_handshake = NULL;
|
||||
new_client->gnutls_handshake_ok = 0;
|
||||
new_client->websocket = weechat_infolist_integer (infolist, "websocket");
|
||||
new_client->ws_deflate = relay_websocket_deflate_alloc ();
|
||||
new_client->ws_deflate->enabled = weechat_infolist_integer (infolist, "ws_deflate_enabled");
|
||||
new_client->ws_deflate->server_context_takeover = weechat_infolist_integer (infolist, "ws_deflate_server_context_takeover");
|
||||
new_client->ws_deflate->client_context_takeover = weechat_infolist_integer (infolist, "ws_deflate_client_context_takeover");
|
||||
new_client->ws_deflate->window_bits_deflate = weechat_infolist_integer (infolist, "ws_deflate_window_bits_deflate");
|
||||
new_client->ws_deflate->window_bits_inflate = weechat_infolist_integer (infolist, "ws_deflate_window_bits_inflate");
|
||||
new_client->ws_deflate->strm_deflate = NULL;
|
||||
new_client->ws_deflate->strm_inflate = NULL;
|
||||
if (weechat_infolist_search_var (infolist, "ws_deflate_strm_deflate_dict"))
|
||||
{
|
||||
ptr_dict = weechat_infolist_buffer (infolist, "ws_deflate_strm_deflate_dict", &dict_size);
|
||||
if (ptr_dict)
|
||||
{
|
||||
new_client->ws_deflate->strm_deflate = calloc (1, sizeof (*new_client->ws_deflate->strm_deflate));
|
||||
if (new_client->ws_deflate->strm_deflate)
|
||||
{
|
||||
if (relay_websocket_deflate_init_stream_deflate (new_client->ws_deflate))
|
||||
{
|
||||
deflateSetDictionary (new_client->ws_deflate->strm_deflate,
|
||||
ptr_dict, dict_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (weechat_infolist_search_var (infolist, "ws_deflate_strm_inflate_dict"))
|
||||
{
|
||||
ptr_dict = weechat_infolist_buffer (infolist, "ws_deflate_strm_inflate_dict", &dict_size);
|
||||
if (ptr_dict)
|
||||
{
|
||||
new_client->ws_deflate->strm_inflate = calloc (1, sizeof (*new_client->ws_deflate->strm_inflate));
|
||||
if (new_client->ws_deflate->strm_inflate)
|
||||
{
|
||||
if (relay_websocket_deflate_init_stream_inflate (new_client->ws_deflate))
|
||||
{
|
||||
inflateSetDictionary (new_client->ws_deflate->strm_inflate,
|
||||
ptr_dict, dict_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
new_client->http_req = relay_http_request_alloc ();
|
||||
new_client->address = strdup (weechat_infolist_string (infolist, "address"));
|
||||
str = weechat_infolist_string (infolist, "real_ip");
|
||||
@@ -1780,6 +1891,7 @@ relay_client_free (struct t_relay_client *client)
|
||||
free (client->nonce);
|
||||
if (client->hook_timer_handshake)
|
||||
weechat_unhook (client->hook_timer_handshake);
|
||||
relay_websocket_deflate_free (client->ws_deflate);
|
||||
relay_http_request_free (client->http_req);
|
||||
if (client->hook_fd)
|
||||
weechat_unhook (client->hook_fd);
|
||||
@@ -1881,6 +1993,8 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
|
||||
{
|
||||
struct t_infolist_item *ptr_item;
|
||||
char value[128];
|
||||
Bytef *dict;
|
||||
uInt dict_size;
|
||||
|
||||
if (!infolist || !client)
|
||||
return 0;
|
||||
@@ -1929,6 +2043,47 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_integer (ptr_item, "websocket", client->websocket))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_integer (ptr_item, "ws_deflate_enabled", client->ws_deflate->enabled))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_integer (ptr_item, "ws_deflate_server_context_takeover", client->ws_deflate->server_context_takeover))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_integer (ptr_item, "ws_deflate_client_context_takeover", client->ws_deflate->client_context_takeover))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_integer (ptr_item, "ws_deflate_window_bits_deflate", client->ws_deflate->window_bits_deflate))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_integer (ptr_item, "ws_deflate_window_bits_inflate", client->ws_deflate->window_bits_inflate))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_pointer (ptr_item, "ws_deflate_strm_deflate", client->ws_deflate->strm_deflate))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_pointer (ptr_item, "ws_deflate_strm_inflate", client->ws_deflate->strm_inflate))
|
||||
return 0;
|
||||
if (client->ws_deflate->strm_deflate || client->ws_deflate->strm_inflate)
|
||||
{
|
||||
/* save the deflate/inflate dictionary, as it's required after /upgrade */
|
||||
dict = malloc (32768);
|
||||
if (dict)
|
||||
{
|
||||
if (client->ws_deflate->strm_deflate)
|
||||
{
|
||||
if (deflateGetDictionary (client->ws_deflate->strm_deflate, dict, &dict_size) == Z_OK)
|
||||
{
|
||||
weechat_infolist_new_var_buffer (ptr_item,
|
||||
"ws_deflate_strm_deflate_dict",
|
||||
dict, dict_size);
|
||||
}
|
||||
}
|
||||
if (client->ws_deflate->strm_inflate)
|
||||
{
|
||||
if (inflateGetDictionary (client->ws_deflate->strm_inflate, dict, &dict_size) == Z_OK)
|
||||
{
|
||||
weechat_infolist_new_var_buffer (ptr_item,
|
||||
"ws_deflate_strm_inflate_dict",
|
||||
dict, dict_size);
|
||||
}
|
||||
}
|
||||
free (dict);
|
||||
}
|
||||
}
|
||||
if (!weechat_infolist_new_var_string (ptr_item, "address", client->address))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_string (ptr_item, "real_ip", client->real_ip))
|
||||
@@ -2015,7 +2170,8 @@ relay_client_print_log ()
|
||||
weechat_log_printf (" gnutls_sess . . . . . . . : 0x%lx", ptr_client->gnutls_sess);
|
||||
weechat_log_printf (" hook_timer_handshake. . . : 0x%lx", ptr_client->hook_timer_handshake);
|
||||
weechat_log_printf (" gnutls_handshake_ok . . . : 0x%lx", ptr_client->gnutls_handshake_ok);
|
||||
weechat_log_printf (" websocket . . . . . . . . : %d", ptr_client->websocket);
|
||||
weechat_log_printf (" websocket . . . . . . . . ; %d", ptr_client->websocket);
|
||||
relay_websocket_deflate_print_log (ptr_client->ws_deflate, "");
|
||||
relay_http_print_log (ptr_client->http_req);
|
||||
weechat_log_printf (" address . . . . . . . . . : '%s'", ptr_client->address);
|
||||
weechat_log_printf (" real_ip . . . . . . . . . : '%s'", ptr_client->real_ip);
|
||||
|
||||
@@ -108,6 +108,7 @@ struct t_relay_client
|
||||
struct t_hook *hook_timer_handshake; /* timer for doing gnutls handshake*/
|
||||
int gnutls_handshake_ok; /* 1 if handshake was done and OK */
|
||||
enum t_relay_client_websocket_status websocket; /* websocket status */
|
||||
struct t_relay_websocket_deflate *ws_deflate; /* websocket deflate data */
|
||||
struct t_relay_http_request *http_req; /* HTTP request */
|
||||
char *address; /* string with IP address */
|
||||
char *real_ip; /* real IP (X-Real-IP HTTP header) */
|
||||
|
||||
@@ -78,6 +78,11 @@ relay_http_request_reinit (struct t_relay_http_request *request)
|
||||
}
|
||||
weechat_hashtable_remove_all (request->headers);
|
||||
weechat_hashtable_remove_all (request->accept_encoding);
|
||||
if (request->ws_deflate)
|
||||
{
|
||||
relay_websocket_deflate_free (request->ws_deflate);
|
||||
request->ws_deflate = relay_websocket_deflate_alloc ();
|
||||
}
|
||||
request->content_length = 0;
|
||||
request->body_size = 0;
|
||||
if (request->body)
|
||||
@@ -122,6 +127,7 @@ relay_http_request_alloc ()
|
||||
WEECHAT_HASHTABLE_STRING,
|
||||
WEECHAT_HASHTABLE_STRING,
|
||||
NULL, NULL);
|
||||
new_request->ws_deflate = relay_websocket_deflate_alloc ();
|
||||
new_request->content_length = 0;
|
||||
new_request->body_size = 0;
|
||||
new_request->body = NULL;
|
||||
@@ -400,18 +406,12 @@ relay_http_parse_header (struct t_relay_http_request *request,
|
||||
/* if header is "Accept-Encoding", save the allowed encoding */
|
||||
if (strcmp (name_lower, "accept-encoding") == 0)
|
||||
{
|
||||
items = weechat_string_split (ptr_value, ",", NULL, 0, 0, &num_items);
|
||||
items = weechat_string_split (ptr_value, ",", " ", 0, 0, &num_items);
|
||||
if (items)
|
||||
{
|
||||
for (i = 0; i < num_items; i++)
|
||||
{
|
||||
pos = items[i];
|
||||
while (pos[0] == ' ')
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
weechat_hashtable_set (request->accept_encoding,
|
||||
pos, NULL);
|
||||
weechat_hashtable_set (request->accept_encoding, items[i], NULL);
|
||||
}
|
||||
weechat_string_free_split (items);
|
||||
}
|
||||
@@ -426,6 +426,13 @@ relay_http_parse_header (struct t_relay_http_request *request,
|
||||
request->content_length = (int)number;
|
||||
}
|
||||
|
||||
/*
|
||||
* if header is "Sec-WebSocket-Extensions", save supported websocket
|
||||
* extensions
|
||||
*/
|
||||
if (strcmp (name_lower, "sec-websocket-extensions") == 0)
|
||||
relay_websocket_parse_extensions (ptr_value, request->ws_deflate);
|
||||
|
||||
free (name);
|
||||
free (name_lower);
|
||||
|
||||
@@ -635,7 +642,7 @@ relay_http_process_websocket (struct t_relay_client *client)
|
||||
char *handshake;
|
||||
int rc;
|
||||
|
||||
rc = relay_websocket_client_handshake_valid (client);
|
||||
rc = relay_websocket_client_handshake_valid (client->http_req);
|
||||
|
||||
if (rc == -1)
|
||||
{
|
||||
@@ -712,7 +719,7 @@ relay_http_process_websocket (struct t_relay_client *client)
|
||||
}
|
||||
}
|
||||
|
||||
handshake = relay_websocket_build_handshake (client);
|
||||
handshake = relay_websocket_build_handshake (client->http_req);
|
||||
if (handshake)
|
||||
{
|
||||
relay_client_send (client,
|
||||
@@ -721,6 +728,8 @@ relay_http_process_websocket (struct t_relay_client *client)
|
||||
strlen (handshake), NULL);
|
||||
free (handshake);
|
||||
client->websocket = RELAY_CLIENT_WEBSOCKET_READY;
|
||||
memcpy (client->ws_deflate, client->http_req->ws_deflate,
|
||||
sizeof (*(client->ws_deflate)));
|
||||
if (client->protocol == RELAY_PROTOCOL_API)
|
||||
{
|
||||
/* "api" protocol uses JSON in input/output (multi-line text) */
|
||||
@@ -977,6 +986,7 @@ relay_http_compress (struct t_relay_http_request *request,
|
||||
dest = malloc (dest_size);
|
||||
if (dest)
|
||||
{
|
||||
memset (&strm, 0, sizeof (strm));
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
@@ -1252,7 +1262,7 @@ relay_http_print_log (struct t_relay_http_request *request)
|
||||
{
|
||||
int i;
|
||||
|
||||
weechat_log_printf (" [http_request]");
|
||||
weechat_log_printf (" http_request:");
|
||||
weechat_log_printf (" raw . . . . . . . . . . : '%s'",
|
||||
(request->raw) ? *(request->raw) : NULL);
|
||||
weechat_log_printf (" status. . . . . . . . . : %d", request->status);
|
||||
@@ -1278,6 +1288,7 @@ relay_http_print_log (struct t_relay_http_request *request)
|
||||
request->accept_encoding,
|
||||
weechat_hashtable_get_string (request->accept_encoding,
|
||||
"keys_values"));
|
||||
relay_websocket_deflate_print_log (request->ws_deflate, " ");
|
||||
weechat_log_printf (" content_length. . . . . : %d", request->content_length);
|
||||
weechat_log_printf (" body_size . . . . . . . : %d", request->body_size);
|
||||
weechat_log_printf (" body. . . . . . . . . . : '%s'", request->body);
|
||||
|
||||
@@ -61,6 +61,7 @@ struct t_relay_http_request
|
||||
struct t_hashtable *headers; /* HTTP headers for websocket */
|
||||
/* and API protocol */
|
||||
struct t_hashtable *accept_encoding; /* allowed encoding for response */
|
||||
struct t_relay_websocket_deflate *ws_deflate; /* websocket deflate data */
|
||||
int content_length; /* value of header "Content-Length" */
|
||||
int body_size; /* size of HTTP body read so far */
|
||||
char *body; /* HTTP body (can be NULL) */
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "../weechat-plugin.h"
|
||||
#include "relay.h"
|
||||
@@ -39,6 +40,120 @@
|
||||
#define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
|
||||
|
||||
/*
|
||||
* Allocates a t_relay_websocket_deflate structure.
|
||||
*/
|
||||
|
||||
struct t_relay_websocket_deflate *
|
||||
relay_websocket_deflate_alloc ()
|
||||
{
|
||||
struct t_relay_websocket_deflate *new_ws_deflate;
|
||||
|
||||
new_ws_deflate = (struct t_relay_websocket_deflate *)malloc (sizeof (*new_ws_deflate));
|
||||
if (!new_ws_deflate)
|
||||
return NULL;
|
||||
|
||||
new_ws_deflate->enabled = 0;
|
||||
new_ws_deflate->server_context_takeover = 0;
|
||||
new_ws_deflate->server_context_takeover = 0;
|
||||
new_ws_deflate->window_bits_deflate = 0;
|
||||
new_ws_deflate->window_bits_inflate = 0;
|
||||
new_ws_deflate->strm_deflate = NULL;
|
||||
new_ws_deflate->strm_inflate = NULL;
|
||||
|
||||
return new_ws_deflate;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes stream for deflate (compression).
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK
|
||||
* 0: error
|
||||
*/
|
||||
|
||||
int
|
||||
relay_websocket_deflate_init_stream_deflate (struct t_relay_websocket_deflate *ws_deflate)
|
||||
{
|
||||
int rc, compression, compression_level;
|
||||
|
||||
compression = weechat_config_integer (relay_config_network_compression);
|
||||
|
||||
/* convert % to zlib compression level (1-9) */
|
||||
compression_level = (((compression - 1) * 9) / 100) + 1;
|
||||
|
||||
rc = deflateInit2 (
|
||||
ws_deflate->strm_deflate,
|
||||
compression_level,
|
||||
Z_DEFLATED, /* method */
|
||||
-1 * ws_deflate->window_bits_deflate,
|
||||
8, /* memLevel */
|
||||
Z_DEFAULT_STRATEGY); /* strategy */
|
||||
|
||||
return (rc == Z_OK) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees a deflate stream in a deflate structure.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_websocket_deflate_free_stream_deflate (struct t_relay_websocket_deflate *ws_deflate)
|
||||
{
|
||||
if (ws_deflate->strm_deflate)
|
||||
{
|
||||
deflateEnd (ws_deflate->strm_deflate);
|
||||
free (ws_deflate->strm_deflate);
|
||||
ws_deflate->strm_deflate = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes stream for inflate (decompression).
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK
|
||||
* 0: error
|
||||
*/
|
||||
|
||||
int
|
||||
relay_websocket_deflate_init_stream_inflate (struct t_relay_websocket_deflate *ws_deflate)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = inflateInit2 (ws_deflate->strm_inflate,
|
||||
-1 * ws_deflate->window_bits_inflate);
|
||||
|
||||
return (rc == Z_OK) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees an inflate stream in a deflate structure.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_websocket_deflate_free_stream_inflate (struct t_relay_websocket_deflate *ws_deflate)
|
||||
{
|
||||
if (ws_deflate->strm_inflate)
|
||||
{
|
||||
inflateEnd (ws_deflate->strm_inflate);
|
||||
free (ws_deflate->strm_inflate);
|
||||
ws_deflate->strm_inflate = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees a websocket deflate structure.
|
||||
*/
|
||||
|
||||
void
|
||||
relay_websocket_deflate_free (struct t_relay_websocket_deflate *ws_deflate)
|
||||
{
|
||||
relay_websocket_deflate_free_stream_deflate (ws_deflate);
|
||||
relay_websocket_deflate_free_stream_inflate (ws_deflate);
|
||||
free (ws_deflate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if a message is a HTTP GET with resource "/weechat" (for weechat
|
||||
* protocol) or "/api" (for api protocol).
|
||||
@@ -49,15 +164,18 @@
|
||||
*/
|
||||
|
||||
int
|
||||
relay_websocket_is_valid_http_get (struct t_relay_client *client,
|
||||
relay_websocket_is_valid_http_get (enum t_relay_protocol protocol,
|
||||
const char *message)
|
||||
{
|
||||
char string[128];
|
||||
int length;
|
||||
|
||||
if (!message)
|
||||
return 0;
|
||||
|
||||
/* the message must start with "GET /weechat" or "GET /api" */
|
||||
snprintf (string, sizeof (string),
|
||||
"GET /%s", relay_protocol_string[client->protocol]);
|
||||
"GET /%s", relay_protocol_string[protocol]);
|
||||
length = strlen (string);
|
||||
|
||||
if (strncmp (message, string, length) != 0)
|
||||
@@ -122,25 +240,28 @@ relay_websocket_is_valid_http_get (struct t_relay_client *client,
|
||||
*/
|
||||
|
||||
int
|
||||
relay_websocket_client_handshake_valid (struct t_relay_client *client)
|
||||
relay_websocket_client_handshake_valid (struct t_relay_http_request *request)
|
||||
{
|
||||
const char *value;
|
||||
|
||||
if (!request || !request->headers)
|
||||
return -1;
|
||||
|
||||
/* check if we have header "Upgrade" with value "websocket" */
|
||||
value = weechat_hashtable_get (client->http_req->headers, "upgrade");
|
||||
value = weechat_hashtable_get (request->headers, "upgrade");
|
||||
if (!value)
|
||||
return -1;
|
||||
if (weechat_strcasecmp (value, "websocket") != 0)
|
||||
return -1;
|
||||
|
||||
/* check if we have header "Sec-WebSocket-Key" with non-empty value */
|
||||
value = weechat_hashtable_get (client->http_req->headers, "sec-websocket-key");
|
||||
value = weechat_hashtable_get (request->headers, "sec-websocket-key");
|
||||
if (!value || !value[0])
|
||||
return -1;
|
||||
|
||||
if (relay_config_regex_websocket_allowed_origins)
|
||||
{
|
||||
value = weechat_hashtable_get (client->http_req->headers, "origin");
|
||||
value = weechat_hashtable_get (request->headers, "origin");
|
||||
if (!value || !value[0])
|
||||
return -2;
|
||||
if (regexec (relay_config_regex_websocket_allowed_origins, value, 0,
|
||||
@@ -154,6 +275,89 @@ relay_websocket_client_handshake_valid (struct t_relay_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses websocket extensions (header "Sec-WebSocket-Extensions").
|
||||
*
|
||||
* Header is for example:
|
||||
* Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
|
||||
*/
|
||||
|
||||
void
|
||||
relay_websocket_parse_extensions (const char *extensions,
|
||||
struct t_relay_websocket_deflate *ws_deflate)
|
||||
{
|
||||
char **exts, **params, **items, *error;
|
||||
int i, j, num_exts, num_params, num_items;
|
||||
long number;
|
||||
|
||||
if (!extensions || !ws_deflate)
|
||||
return;
|
||||
|
||||
exts = weechat_string_split (extensions, ",", " ", 0, 0, &num_exts);
|
||||
if (!exts)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_exts; i++)
|
||||
{
|
||||
params = weechat_string_split (exts[i], ";", " ", 0, 0, &num_params);
|
||||
if (params && (num_params >= 1)
|
||||
&& (strcmp (params[0], "permessage-deflate") == 0))
|
||||
{
|
||||
ws_deflate->enabled = 1;
|
||||
ws_deflate->server_context_takeover = 1;
|
||||
ws_deflate->client_context_takeover = 1;
|
||||
ws_deflate->window_bits_deflate = 15;
|
||||
ws_deflate->window_bits_inflate = 15;
|
||||
for (j = 1; j < num_params; j++)
|
||||
{
|
||||
items = weechat_string_split (params[j], "=", " ", 0, 0, &num_items);
|
||||
if (items && (num_items >= 1))
|
||||
{
|
||||
if (strcmp (items[0], "server_no_context_takeover") == 0)
|
||||
{
|
||||
ws_deflate->server_context_takeover = 0;
|
||||
}
|
||||
else if (strcmp (items[0], "client_no_context_takeover") == 0)
|
||||
{
|
||||
ws_deflate->client_context_takeover = 0;
|
||||
}
|
||||
else if ((strcmp (items[0], "server_max_window_bits") == 0)
|
||||
|| (strcmp (items[0], "client_max_window_bits") == 0))
|
||||
{
|
||||
number = 15;
|
||||
if (num_items >= 2)
|
||||
{
|
||||
error = NULL;
|
||||
number = strtol (items[1], &error, 10);
|
||||
if (error && !error[0])
|
||||
{
|
||||
if (number < 8)
|
||||
number = 8;
|
||||
else if (number > 15)
|
||||
number = 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
number = 15;
|
||||
}
|
||||
}
|
||||
if (strcmp (items[0], "server_max_window_bits") == 0)
|
||||
ws_deflate->window_bits_deflate = (int)number;
|
||||
else
|
||||
ws_deflate->window_bits_inflate = (int)number;
|
||||
}
|
||||
}
|
||||
if (items)
|
||||
weechat_string_free_split (items);
|
||||
}
|
||||
}
|
||||
if (params)
|
||||
weechat_string_free_split (params);
|
||||
}
|
||||
|
||||
weechat_string_free_split (exts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Builds the handshake that will be returned to client, to initialize and use
|
||||
* the websocket.
|
||||
@@ -168,13 +372,17 @@ relay_websocket_client_handshake_valid (struct t_relay_client *client)
|
||||
*/
|
||||
|
||||
char *
|
||||
relay_websocket_build_handshake (struct t_relay_client *client)
|
||||
relay_websocket_build_handshake (struct t_relay_http_request *request)
|
||||
{
|
||||
const char *sec_websocket_key;
|
||||
char *key, sec_websocket_accept[128], handshake[1024], hash[160 / 8];
|
||||
char *key, sec_websocket_accept[128], handshake[4096], hash[160 / 8];
|
||||
char sec_websocket_extensions[512];
|
||||
int length, hash_size;
|
||||
|
||||
sec_websocket_key = weechat_hashtable_get (client->http_req->headers,
|
||||
if (!request)
|
||||
return NULL;
|
||||
|
||||
sec_websocket_key = weechat_hashtable_get (request->headers,
|
||||
"sec-websocket-key");
|
||||
if (!sec_websocket_key || !sec_websocket_key[0])
|
||||
return NULL;
|
||||
@@ -204,20 +412,135 @@ relay_websocket_build_handshake (struct t_relay_client *client)
|
||||
|
||||
free (key);
|
||||
|
||||
if (request->ws_deflate->enabled)
|
||||
{
|
||||
snprintf (
|
||||
sec_websocket_extensions, sizeof (sec_websocket_extensions),
|
||||
"Sec-WebSocket-Extensions: permessage-deflate; "
|
||||
"%s"
|
||||
"%s"
|
||||
"server_max_window_bits=%d; "
|
||||
"client_max_window_bits=%d\r\n",
|
||||
(!request->ws_deflate->server_context_takeover) ? "server_no_context_takeover; " : "",
|
||||
(!request->ws_deflate->client_context_takeover) ? "client_no_context_takeover; " : "",
|
||||
request->ws_deflate->window_bits_deflate,
|
||||
request->ws_deflate->window_bits_inflate);
|
||||
}
|
||||
else
|
||||
{
|
||||
sec_websocket_extensions[0] = '\0';
|
||||
}
|
||||
|
||||
/* build the handshake (it will be sent as-is to client) */
|
||||
snprintf (handshake, sizeof (handshake),
|
||||
"HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: %s\r\n"
|
||||
"%s"
|
||||
"\r\n",
|
||||
sec_websocket_accept);
|
||||
sec_websocket_accept,
|
||||
sec_websocket_extensions);
|
||||
|
||||
return strdup (handshake);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes a websocket frame.
|
||||
* Decompresses a decoded and compressed websocket frame compressed with
|
||||
* "deflate" (when websocket extension "permessage-deflate" is enabled).
|
||||
*
|
||||
* A final '\0' is added after the decompressed data (the size_decompressed
|
||||
* does not count this final '\0').
|
||||
*
|
||||
* Returns pointer to decompressed data, NULL if error.
|
||||
*/
|
||||
|
||||
char *
|
||||
relay_websocket_inflate (const void *data, size_t size, z_stream *strm,
|
||||
size_t *size_decompressed)
|
||||
{
|
||||
int rc;
|
||||
unsigned char append_bytes[4] = { 0x00, 0x00, 0xFF, 0xFF };
|
||||
Bytef *data2, *dest, *dest2;
|
||||
uLongf size2, dest_size;
|
||||
|
||||
if (!data || (size == 0) || !strm || !size_decompressed)
|
||||
return NULL;
|
||||
|
||||
dest = NULL;
|
||||
|
||||
*size_decompressed = 0;
|
||||
|
||||
/* append "0x00 0x00 0xFF 0xFF" to data */
|
||||
size2 = size + sizeof (append_bytes);
|
||||
data2 = malloc (size2);
|
||||
if (!data2)
|
||||
goto error;
|
||||
memcpy (data2, data, size);
|
||||
memcpy (data2 + size, append_bytes, sizeof (append_bytes));
|
||||
|
||||
/* estimate the decompressed size, by default 10 * size */
|
||||
dest_size = 10 * size2;
|
||||
dest = malloc (dest_size);
|
||||
if (!dest)
|
||||
goto error;
|
||||
|
||||
strm->avail_in = (uInt)size2;
|
||||
strm->next_in = (Bytef *)data2;
|
||||
strm->total_in = 0;
|
||||
|
||||
strm->avail_out = (uInt)dest_size;
|
||||
strm->next_out = (Bytef *)dest;
|
||||
strm->total_out = 0;
|
||||
|
||||
/* loop until we manage to decompress whole data in dest */
|
||||
while (1)
|
||||
{
|
||||
rc = inflate (strm, Z_SYNC_FLUSH);
|
||||
if ((rc == Z_STREAM_END) || (rc == Z_OK))
|
||||
{
|
||||
/* data successfully decompressed */
|
||||
*size_decompressed = strm->total_out;
|
||||
break;
|
||||
}
|
||||
else if (rc == Z_BUF_ERROR)
|
||||
{
|
||||
strm->avail_out += dest_size;
|
||||
dest_size *= 2;
|
||||
dest2 = realloc (dest, dest_size);
|
||||
if (!dest2)
|
||||
goto error;
|
||||
dest = dest2;
|
||||
strm->next_out = dest + strm->total_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* any other error is fatal */
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
dest2 = realloc (dest, *size_decompressed + 1);
|
||||
if (!dest2)
|
||||
goto error;
|
||||
dest = dest2;
|
||||
dest[*size_decompressed] = '\0';
|
||||
if (data2)
|
||||
free (data2);
|
||||
return (char *)dest;
|
||||
|
||||
error:
|
||||
if (data2)
|
||||
free (data2);
|
||||
if (dest)
|
||||
free (dest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes a websocket frame and return a list of frames in "*frames" (each
|
||||
* frame is first decompressed if "permessage-deflate" websocket extension
|
||||
* is used).
|
||||
*
|
||||
* Returns:
|
||||
* 1: frame decoded successfully
|
||||
@@ -225,20 +548,42 @@ relay_websocket_build_handshake (struct t_relay_client *client)
|
||||
*/
|
||||
|
||||
int
|
||||
relay_websocket_decode_frame (const unsigned char *buffer,
|
||||
relay_websocket_decode_frame (struct t_relay_client *client,
|
||||
const unsigned char *buffer,
|
||||
unsigned long long buffer_length,
|
||||
unsigned char *decoded,
|
||||
unsigned long long *decoded_length)
|
||||
struct t_relay_websocket_frame **frames,
|
||||
int *num_frames)
|
||||
{
|
||||
unsigned long long i, index_buffer, length_frame_size, length_frame;
|
||||
unsigned char opcode;
|
||||
size_t size_decompressed;
|
||||
char *payload_decompressed;
|
||||
struct t_relay_websocket_frame *frames2, *ptr_frame;
|
||||
|
||||
if (!buffer || !frames || !num_frames)
|
||||
return 0;
|
||||
|
||||
*frames = NULL;
|
||||
*num_frames = 0;
|
||||
|
||||
*decoded_length = 0;
|
||||
index_buffer = 0;
|
||||
|
||||
/* loop to decode all frames in message */
|
||||
while (index_buffer + 1 < buffer_length)
|
||||
{
|
||||
(*num_frames)++;
|
||||
|
||||
frames2 = realloc (*frames, sizeof (**frames) * (*num_frames));
|
||||
if (!frames2)
|
||||
return 0;
|
||||
*frames = frames2;
|
||||
|
||||
ptr_frame = &((*frames)[*num_frames - 1]);
|
||||
|
||||
ptr_frame->opcode = 0;
|
||||
ptr_frame->payload_size = 0;
|
||||
ptr_frame->payload = NULL;
|
||||
|
||||
opcode = buffer[index_buffer] & 15;
|
||||
|
||||
/*
|
||||
@@ -276,20 +621,19 @@ relay_websocket_decode_frame (const unsigned char *buffer,
|
||||
}
|
||||
index_buffer += 4;
|
||||
|
||||
/* copy opcode in decoded data */
|
||||
/* save opcode */
|
||||
switch (opcode)
|
||||
{
|
||||
case WEBSOCKET_FRAME_OPCODE_PING:
|
||||
decoded[*decoded_length] = RELAY_CLIENT_MSG_PING;
|
||||
ptr_frame->opcode = RELAY_CLIENT_MSG_PING;
|
||||
break;
|
||||
case WEBSOCKET_FRAME_OPCODE_CLOSE:
|
||||
decoded[*decoded_length] = RELAY_CLIENT_MSG_CLOSE;
|
||||
ptr_frame->opcode = RELAY_CLIENT_MSG_CLOSE;
|
||||
break;
|
||||
default:
|
||||
decoded[*decoded_length] = RELAY_CLIENT_MSG_STANDARD;
|
||||
ptr_frame->opcode = RELAY_CLIENT_MSG_STANDARD;
|
||||
break;
|
||||
}
|
||||
*decoded_length += 1;
|
||||
|
||||
/* decode data using masks */
|
||||
if ((length_frame > buffer_length)
|
||||
@@ -297,18 +641,98 @@ relay_websocket_decode_frame (const unsigned char *buffer,
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr_frame->payload = malloc (length_frame + 1);
|
||||
if (!ptr_frame->payload)
|
||||
return 0;
|
||||
ptr_frame->payload_size = length_frame;
|
||||
|
||||
/* fill payload */
|
||||
for (i = 0; i < length_frame; i++)
|
||||
{
|
||||
decoded[*decoded_length + i] = (int)((unsigned char)buffer[index_buffer + i]) ^ masks[i % 4];
|
||||
ptr_frame->payload[i] = (int)((unsigned char)buffer[index_buffer + i]) ^ masks[i % 4];
|
||||
}
|
||||
decoded[*decoded_length + length_frame] = '\0';
|
||||
*decoded_length += length_frame + 1;
|
||||
ptr_frame->payload[length_frame] = '\0';
|
||||
|
||||
/*
|
||||
* decompress data if frame is not empty and if "permessage-deflate"
|
||||
* is enabled
|
||||
*/
|
||||
if ((length_frame > 0) && client->ws_deflate->enabled)
|
||||
{
|
||||
if (!client->ws_deflate->strm_inflate)
|
||||
{
|
||||
client->ws_deflate->strm_inflate = calloc (
|
||||
1, sizeof (*client->ws_deflate->strm_inflate));
|
||||
if (!client->ws_deflate->strm_inflate)
|
||||
return 0;
|
||||
if (!relay_websocket_deflate_init_stream_inflate (client->ws_deflate))
|
||||
return 0;
|
||||
}
|
||||
payload_decompressed = relay_websocket_inflate (
|
||||
ptr_frame->payload,
|
||||
ptr_frame->payload_size,
|
||||
client->ws_deflate->strm_inflate,
|
||||
&size_decompressed);
|
||||
if (!payload_decompressed)
|
||||
return 0;
|
||||
free (ptr_frame->payload);
|
||||
ptr_frame->payload = payload_decompressed;
|
||||
ptr_frame->payload_size = size_decompressed;
|
||||
if (!client->ws_deflate->client_context_takeover)
|
||||
relay_websocket_deflate_free_stream_inflate (client->ws_deflate);
|
||||
}
|
||||
|
||||
index_buffer += length_frame;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compresses data to send in a websocket frame (when websocket extension
|
||||
* "permessage-deflate" is enabled).
|
||||
*
|
||||
* Returns pointer to compressed data, NULL if error.
|
||||
*/
|
||||
|
||||
char *
|
||||
relay_websocket_deflate (const void *data, size_t size, z_stream *strm,
|
||||
size_t *size_compressed)
|
||||
{
|
||||
int rc;
|
||||
uLongf dest_size;
|
||||
Bytef *dest;
|
||||
|
||||
if (!data || (size == 0) || !strm || !size_compressed)
|
||||
return NULL;
|
||||
|
||||
*size_compressed = 0;
|
||||
|
||||
dest_size = compressBound (size);
|
||||
dest = malloc (dest_size);
|
||||
if (!dest)
|
||||
return NULL;
|
||||
|
||||
strm->avail_in = (uInt)size;
|
||||
strm->next_in = (Bytef *)data;
|
||||
strm->total_in = 0;
|
||||
|
||||
strm->avail_out = (uInt)dest_size;
|
||||
strm->next_out = (Bytef *)dest;
|
||||
strm->total_out = 0;
|
||||
|
||||
rc = deflate (strm, Z_SYNC_FLUSH);
|
||||
if ((rc == Z_STREAM_END) || (rc == Z_OK))
|
||||
{
|
||||
*size_compressed = strm->total_out;
|
||||
return (char *)dest;
|
||||
}
|
||||
|
||||
free (dest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encodes data in a websocket frame.
|
||||
*
|
||||
@@ -319,56 +743,132 @@ relay_websocket_decode_frame (const unsigned char *buffer,
|
||||
*/
|
||||
|
||||
char *
|
||||
relay_websocket_encode_frame (int opcode,
|
||||
const char *buffer,
|
||||
unsigned long long length,
|
||||
relay_websocket_encode_frame (struct t_relay_client *client,
|
||||
int opcode,
|
||||
const char *payload,
|
||||
unsigned long long payload_size,
|
||||
unsigned long long *length_frame)
|
||||
{
|
||||
const char *ptr_data;
|
||||
char *payload_compressed;
|
||||
size_t size_compressed;
|
||||
unsigned char *frame;
|
||||
unsigned long long index;
|
||||
unsigned long long index, data_size;
|
||||
|
||||
*length_frame = 0;
|
||||
|
||||
frame = malloc (length + 10);
|
||||
ptr_data = payload;
|
||||
data_size = payload_size;
|
||||
|
||||
payload_compressed = NULL;
|
||||
size_compressed = 0;
|
||||
|
||||
/*
|
||||
* compress data if payload is not empty and if "permessage-deflate"
|
||||
* is enabled
|
||||
*/
|
||||
if (((opcode == WEBSOCKET_FRAME_OPCODE_TEXT)
|
||||
|| (opcode == WEBSOCKET_FRAME_OPCODE_BINARY))
|
||||
&& (payload_size > 0)
|
||||
&& client->ws_deflate->enabled)
|
||||
{
|
||||
if (!client->ws_deflate->strm_deflate)
|
||||
{
|
||||
client->ws_deflate->strm_deflate = calloc (
|
||||
1, sizeof (*client->ws_deflate->strm_deflate));
|
||||
if (!client->ws_deflate->strm_deflate)
|
||||
return NULL;
|
||||
if (!relay_websocket_deflate_init_stream_deflate (client->ws_deflate))
|
||||
return NULL;
|
||||
}
|
||||
payload_compressed = relay_websocket_deflate (
|
||||
payload,
|
||||
payload_size,
|
||||
client->ws_deflate->strm_deflate,
|
||||
&size_compressed);
|
||||
if (!payload_compressed)
|
||||
return NULL;
|
||||
ptr_data = payload_compressed;
|
||||
data_size = size_compressed;
|
||||
if ((data_size > 4)
|
||||
&& ((unsigned char)ptr_data[data_size - 4] == 0x00)
|
||||
&& ((unsigned char)ptr_data[data_size - 3] == 0x00)
|
||||
&& ((unsigned char)ptr_data[data_size - 2] == 0xFF)
|
||||
&& ((unsigned char)ptr_data[data_size - 1] == 0xFF))
|
||||
{
|
||||
data_size -= 4;
|
||||
}
|
||||
if (!client->ws_deflate->server_context_takeover)
|
||||
relay_websocket_deflate_free_stream_deflate (client->ws_deflate);
|
||||
/* set bit RSV1: indicate permessage-deflate compressed data */
|
||||
opcode |= 0x40;
|
||||
}
|
||||
|
||||
frame = malloc (data_size + 10);
|
||||
if (!frame)
|
||||
{
|
||||
if (payload_compressed)
|
||||
free (payload_compressed);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
frame[0] = 0x80;
|
||||
frame[0] |= opcode;
|
||||
|
||||
if (length <= 125)
|
||||
if (data_size <= 125)
|
||||
{
|
||||
/* length on one byte */
|
||||
frame[1] = length;
|
||||
frame[1] = data_size;
|
||||
index = 2;
|
||||
}
|
||||
else if (length <= 65535)
|
||||
else if (data_size <= 65535)
|
||||
{
|
||||
/* length on 2 bytes */
|
||||
frame[1] = 126;
|
||||
frame[2] = (length >> 8) & 0xFF;
|
||||
frame[3] = length & 0xFF;
|
||||
frame[2] = (data_size >> 8) & 0xFF;
|
||||
frame[3] = data_size & 0xFF;
|
||||
index = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* length on 8 bytes */
|
||||
frame[1] = 127;
|
||||
frame[2] = (length >> 56) & 0xFF;
|
||||
frame[3] = (length >> 48) & 0xFF;
|
||||
frame[4] = (length >> 40) & 0xFF;
|
||||
frame[5] = (length >> 32) & 0xFF;
|
||||
frame[6] = (length >> 24) & 0xFF;
|
||||
frame[7] = (length >> 16) & 0xFF;
|
||||
frame[8] = (length >> 8) & 0xFF;
|
||||
frame[9] = length & 0xFF;
|
||||
frame[2] = (data_size >> 56) & 0xFF;
|
||||
frame[3] = (data_size >> 48) & 0xFF;
|
||||
frame[4] = (data_size >> 40) & 0xFF;
|
||||
frame[5] = (data_size >> 32) & 0xFF;
|
||||
frame[6] = (data_size >> 24) & 0xFF;
|
||||
frame[7] = (data_size >> 16) & 0xFF;
|
||||
frame[8] = (data_size >> 8) & 0xFF;
|
||||
frame[9] = data_size & 0xFF;
|
||||
index = 10;
|
||||
}
|
||||
|
||||
/* copy buffer after length */
|
||||
memcpy (frame + index, buffer, length);
|
||||
/* copy buffer after data_size */
|
||||
memcpy (frame + index, ptr_data, data_size);
|
||||
|
||||
*length_frame = index + length;
|
||||
*length_frame = index + data_size;
|
||||
|
||||
if (payload_compressed)
|
||||
free (payload_compressed);
|
||||
|
||||
return (char *)frame;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints websocket deflate data in WeeChat log file (usually for crash dump).
|
||||
*/
|
||||
|
||||
void
|
||||
relay_websocket_deflate_print_log (struct t_relay_websocket_deflate *ws_deflate,
|
||||
const char *prefix)
|
||||
{
|
||||
weechat_log_printf ("%s ws_deflate:", prefix);
|
||||
weechat_log_printf ("%s enabled . . . . . . . . : %d", prefix, ws_deflate->enabled);
|
||||
weechat_log_printf ("%s server_context_takeover : %d", prefix, ws_deflate->server_context_takeover);
|
||||
weechat_log_printf ("%s client_context_takeover : %d", prefix, ws_deflate->client_context_takeover);
|
||||
weechat_log_printf ("%s window_bits_deflate . . : %d", prefix, ws_deflate->window_bits_deflate);
|
||||
weechat_log_printf ("%s window_bits_inflate . . : %d", prefix, ws_deflate->window_bits_inflate);
|
||||
weechat_log_printf ("%s strm_deflate. . . . . . : 0x%lx", prefix, ws_deflate->strm_deflate);
|
||||
weechat_log_printf ("%s strm_inflate. . . . . . : 0x%lx", prefix, ws_deflate->strm_inflate);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#ifndef WEECHAT_PLUGIN_RELAY_WEBSOCKET_H
|
||||
#define WEECHAT_PLUGIN_RELAY_WEBSOCKET_H
|
||||
|
||||
#include "relay.h"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#define WEBSOCKET_FRAME_OPCODE_CONTINUATION 0x00
|
||||
#define WEBSOCKET_FRAME_OPCODE_TEXT 0x01
|
||||
#define WEBSOCKET_FRAME_OPCODE_BINARY 0x02
|
||||
@@ -27,17 +31,50 @@
|
||||
#define WEBSOCKET_FRAME_OPCODE_PING 0x09
|
||||
#define WEBSOCKET_FRAME_OPCODE_PONG 0x0A
|
||||
|
||||
extern int relay_websocket_is_valid_http_get (struct t_relay_client *client,
|
||||
struct t_relay_client;
|
||||
struct t_relay_http_request;
|
||||
|
||||
struct t_relay_websocket_deflate
|
||||
{
|
||||
int enabled; /* 1 if permessage-deflate is enabled*/
|
||||
int server_context_takeover; /* context takeover for server */
|
||||
int client_context_takeover; /* context takeover for client */
|
||||
int window_bits_deflate; /* window bits for server (comp.) */
|
||||
/* ("server_max_window_bits") */
|
||||
int window_bits_inflate; /* window bits for client (decomp.) */
|
||||
/* ("client_max_window_bits") */
|
||||
z_stream *strm_deflate; /* stream for deflate (compression) */
|
||||
z_stream *strm_inflate; /* stream for inflate (decompression)*/
|
||||
};
|
||||
|
||||
struct t_relay_websocket_frame
|
||||
{
|
||||
int opcode; /* frame opcode */
|
||||
int payload_size; /* size of payload */
|
||||
char *payload; /* payload */
|
||||
};
|
||||
|
||||
extern struct t_relay_websocket_deflate *relay_websocket_deflate_alloc ();
|
||||
extern int relay_websocket_deflate_init_stream_deflate (struct t_relay_websocket_deflate *ws_deflate);
|
||||
extern int relay_websocket_deflate_init_stream_inflate (struct t_relay_websocket_deflate *ws_deflate);
|
||||
extern void relay_websocket_deflate_free (struct t_relay_websocket_deflate *ws_deflate);
|
||||
extern int relay_websocket_is_valid_http_get (enum t_relay_protocol protocol,
|
||||
const char *message);
|
||||
extern int relay_websocket_client_handshake_valid (struct t_relay_client *client);
|
||||
extern char *relay_websocket_build_handshake (struct t_relay_client *client);
|
||||
extern int relay_websocket_decode_frame (const unsigned char *buffer,
|
||||
extern int relay_websocket_client_handshake_valid (struct t_relay_http_request *request);
|
||||
extern void relay_websocket_parse_extensions (const char *extensions,
|
||||
struct t_relay_websocket_deflate *ws_deflate);
|
||||
extern char *relay_websocket_build_handshake (struct t_relay_http_request *request);
|
||||
extern int relay_websocket_decode_frame (struct t_relay_client *client,
|
||||
const unsigned char *buffer,
|
||||
unsigned long long length,
|
||||
unsigned char *decoded,
|
||||
unsigned long long *decoded_length);
|
||||
extern char *relay_websocket_encode_frame (int opcode,
|
||||
const char *buffer,
|
||||
unsigned long long length,
|
||||
struct t_relay_websocket_frame **frames,
|
||||
int *num_frames);
|
||||
extern char *relay_websocket_encode_frame (struct t_relay_client *client,
|
||||
int opcode,
|
||||
const char *payload,
|
||||
unsigned long long payload_size,
|
||||
unsigned long long *length_frame);
|
||||
extern void relay_websocket_deflate_print_log (struct t_relay_websocket_deflate *ws_deflate,
|
||||
const char *prefix);
|
||||
|
||||
#endif /* WEECHAT_PLUGIN_RELAY_WEBSOCKET_H */
|
||||
|
||||
@@ -108,6 +108,7 @@ if (ENABLE_RELAY)
|
||||
list(APPEND LIB_WEECHAT_UNIT_TESTS_PLUGINS_SRC
|
||||
unit/plugins/relay/test-relay-auth.cpp
|
||||
unit/plugins/relay/test-relay-http.cpp
|
||||
unit/plugins/relay/test-relay-websocket.cpp
|
||||
unit/plugins/relay/irc/test-relay-irc.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -34,6 +34,7 @@ extern "C"
|
||||
#include "src/core/wee-string.h"
|
||||
#include "src/plugins/relay/relay-config.h"
|
||||
#include "src/plugins/relay/relay-http.h"
|
||||
#include "src/plugins/relay/relay-websocket.h"
|
||||
#include "src/plugins/weechat-plugin.h"
|
||||
|
||||
extern char *relay_http_url_decode (const char *url);
|
||||
@@ -89,6 +90,14 @@ TEST(RelayHttp, AllocReinitFree)
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
CHECK(request->accept_encoding);
|
||||
LONGS_EQUAL(0, request->accept_encoding->items_count);
|
||||
CHECK(request->ws_deflate);
|
||||
LONGS_EQUAL(0, request->ws_deflate->enabled);
|
||||
LONGS_EQUAL(0, request->ws_deflate->server_context_takeover);
|
||||
LONGS_EQUAL(0, request->ws_deflate->server_context_takeover);
|
||||
LONGS_EQUAL(0, request->ws_deflate->window_bits_deflate);
|
||||
LONGS_EQUAL(0, request->ws_deflate->window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, request->ws_deflate->strm_deflate);
|
||||
POINTERS_EQUAL(NULL, request->ws_deflate->strm_inflate);
|
||||
LONGS_EQUAL(0, request->content_length);
|
||||
LONGS_EQUAL(0, request->body_size);
|
||||
POINTERS_EQUAL(NULL, request->body);
|
||||
@@ -102,6 +111,7 @@ TEST(RelayHttp, AllocReinitFree)
|
||||
request->http_version = strdup ("HTTP/1.1");
|
||||
hashtable_set (request->headers, "x-test", "value");
|
||||
hashtable_set (request->accept_encoding, "gzip", "");
|
||||
request->ws_deflate->enabled = 1;
|
||||
request->content_length = 100;
|
||||
request->body_size = 16;
|
||||
request->body = (char *)malloc (16);
|
||||
@@ -123,6 +133,14 @@ TEST(RelayHttp, AllocReinitFree)
|
||||
LONGS_EQUAL(0, request->headers->items_count);
|
||||
CHECK(request->accept_encoding);
|
||||
LONGS_EQUAL(0, request->accept_encoding->items_count);
|
||||
CHECK(request->ws_deflate);
|
||||
LONGS_EQUAL(0, request->ws_deflate->enabled);
|
||||
LONGS_EQUAL(0, request->ws_deflate->server_context_takeover);
|
||||
LONGS_EQUAL(0, request->ws_deflate->server_context_takeover);
|
||||
LONGS_EQUAL(0, request->ws_deflate->window_bits_deflate);
|
||||
LONGS_EQUAL(0, request->ws_deflate->window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, request->ws_deflate->strm_deflate);
|
||||
POINTERS_EQUAL(NULL, request->ws_deflate->strm_inflate);
|
||||
LONGS_EQUAL(0, request->content_length);
|
||||
LONGS_EQUAL(0, request->body_size);
|
||||
POINTERS_EQUAL(NULL, request->body);
|
||||
@@ -477,6 +495,29 @@ TEST(RelayHttp, ParseHeader)
|
||||
LONGS_EQUAL(1, request->headers->items_count);
|
||||
LONGS_EQUAL(123, request->content_length);
|
||||
free (request);
|
||||
|
||||
/* websocket request */
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
relay_http_parse_method_path (request, "GET /api HTTP/1.1");
|
||||
relay_http_parse_header (
|
||||
request,
|
||||
"Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits");
|
||||
LONGS_EQUAL(RELAY_HTTP_HEADERS, request->status);
|
||||
STRCMP_EQUAL(
|
||||
"GET /api HTTP/1.1\n"
|
||||
"Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\n",
|
||||
*(request->raw));
|
||||
LONGS_EQUAL(1, request->headers->items_count);
|
||||
CHECK(request->ws_deflate);
|
||||
LONGS_EQUAL(1, request->ws_deflate->enabled);
|
||||
LONGS_EQUAL(1, request->ws_deflate->server_context_takeover);
|
||||
LONGS_EQUAL(1, request->ws_deflate->server_context_takeover);
|
||||
LONGS_EQUAL(15, request->ws_deflate->window_bits_deflate);
|
||||
LONGS_EQUAL(15, request->ws_deflate->window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, request->ws_deflate->strm_deflate);
|
||||
POINTERS_EQUAL(NULL, request->ws_deflate->strm_inflate);
|
||||
free (request);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,415 @@
|
||||
/*
|
||||
* test-relay-websocket.cpp - test websocket functions
|
||||
*
|
||||
* Copyright (C) 2024 Sébastien Helleu <flashcode@flashtux.org>
|
||||
*
|
||||
* This file is part of WeeChat, the extensible chat client.
|
||||
*
|
||||
* WeeChat is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WeeChat is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with WeeChat. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CppUTest/TestHarness.h"
|
||||
|
||||
#include "tests/tests.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
#include "src/core/wee-config-file.h"
|
||||
#include "src/core/wee-hashtable.h"
|
||||
#include "src/plugins/relay/relay-config.h"
|
||||
#include "src/plugins/relay/relay-http.h"
|
||||
#include "src/plugins/relay/relay-websocket.h"
|
||||
|
||||
extern void relay_websocket_deflate_free_stream_deflate (struct t_relay_websocket_deflate *ws_deflate);
|
||||
extern void relay_websocket_deflate_free_stream_inflate (struct t_relay_websocket_deflate *ws_deflate);
|
||||
extern char *relay_websocket_deflate (const void *data, size_t size, z_stream *strm,
|
||||
size_t *size_compressed);
|
||||
extern char *relay_websocket_inflate (const void *data, size_t size, z_stream *strm,
|
||||
size_t *size_decompressed);
|
||||
}
|
||||
|
||||
TEST_GROUP(RelayWebsocket)
|
||||
{
|
||||
};
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_websocket_deflate_alloc
|
||||
* relay_websocket_deflate_init_stream_deflate
|
||||
* relay_websocket_deflate_free_stream_deflate
|
||||
* relay_websocket_deflate_init_stream_inflate
|
||||
* relay_websocket_deflate_free_stream_inflate
|
||||
* relay_websocket_deflate_free
|
||||
*/
|
||||
|
||||
TEST(RelayWebsocket, DeflateAllocFree)
|
||||
{
|
||||
struct t_relay_websocket_deflate *ws_deflate;
|
||||
|
||||
ws_deflate = relay_websocket_deflate_alloc ();
|
||||
LONGS_EQUAL(0, ws_deflate->enabled);
|
||||
LONGS_EQUAL(0, ws_deflate->server_context_takeover);
|
||||
LONGS_EQUAL(0, ws_deflate->server_context_takeover);
|
||||
LONGS_EQUAL(0, ws_deflate->window_bits_deflate);
|
||||
LONGS_EQUAL(0, ws_deflate->window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate->strm_deflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate->strm_inflate);
|
||||
|
||||
ws_deflate->window_bits_deflate = 15;
|
||||
ws_deflate->window_bits_inflate = 15;
|
||||
|
||||
ws_deflate->strm_deflate = (z_stream *)calloc (1, sizeof (*ws_deflate->strm_deflate));
|
||||
CHECK(ws_deflate->strm_deflate);
|
||||
relay_websocket_deflate_init_stream_deflate (ws_deflate);
|
||||
relay_websocket_deflate_free_stream_deflate (ws_deflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate->strm_deflate);
|
||||
|
||||
ws_deflate->strm_inflate = (z_stream *)calloc (1, sizeof (*ws_deflate->strm_inflate));
|
||||
CHECK(ws_deflate->strm_inflate);
|
||||
relay_websocket_deflate_init_stream_inflate (ws_deflate);
|
||||
relay_websocket_deflate_free_stream_inflate (ws_deflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate->strm_inflate);
|
||||
|
||||
relay_websocket_deflate_free (ws_deflate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_websocket_is_valid_http_get
|
||||
*/
|
||||
|
||||
TEST(RelayWebsocket, IsValidHttpGet)
|
||||
{
|
||||
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, NULL));
|
||||
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, ""));
|
||||
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "xxx"));
|
||||
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "GET /api\r\n"));
|
||||
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "GET /api test\r\n"));
|
||||
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "GET /api HTTP/1.1\r\n"));
|
||||
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_API, "GET /weechat\r\n"));
|
||||
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_API, "GET /weechat test\r\n"));
|
||||
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_API, "GET /weechat HTTP/1.1\r\n"));
|
||||
|
||||
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "GET /weechat test\r\n"));
|
||||
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_API, "GET /api test\r\n"));
|
||||
|
||||
LONGS_EQUAL(1, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "GET /weechat\r\n"));
|
||||
LONGS_EQUAL(1, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "GET /weechat HTTP/1.1\r\n"));
|
||||
LONGS_EQUAL(1, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_API, "GET /api\r\n"));
|
||||
LONGS_EQUAL(1, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_API, "GET /api HTTP/1.1\r\n"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_websocket_client_handshake_valid
|
||||
* relay_websocket_build_handshake
|
||||
*/
|
||||
|
||||
TEST(RelayWebsocket, ClientHandshakeValid)
|
||||
{
|
||||
struct t_relay_http_request *request;
|
||||
char *str;
|
||||
|
||||
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (NULL));
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
|
||||
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (NULL));
|
||||
|
||||
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (request));
|
||||
hashtable_set (request->headers, "upgrade", NULL);
|
||||
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (request));
|
||||
hashtable_set (request->headers, "upgrade", "test");
|
||||
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (request));
|
||||
hashtable_set (request->headers, "upgrade", "websocket");
|
||||
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (request));
|
||||
hashtable_set (request->headers, "sec-websocket-key", NULL);
|
||||
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (request));
|
||||
hashtable_set (request->headers, "sec-websocket-key", "CI1sXhf/u2o34BfWK7NeIg==");
|
||||
LONGS_EQUAL(0, relay_websocket_client_handshake_valid (request));
|
||||
|
||||
POINTERS_EQUAL(NULL, relay_websocket_build_handshake (NULL));
|
||||
|
||||
WEE_TEST_STR(
|
||||
"HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: fhLJYtv//ugX2vQXpifQgByRZ5Y=\r\n"
|
||||
"\r\n",
|
||||
relay_websocket_build_handshake (request));
|
||||
|
||||
config_file_option_set (relay_config_network_websocket_allowed_origins, "example.com", 1);
|
||||
LONGS_EQUAL(-2, relay_websocket_client_handshake_valid (request));
|
||||
hashtable_set (request->headers, "origin", NULL);
|
||||
LONGS_EQUAL(-2, relay_websocket_client_handshake_valid (request));
|
||||
hashtable_set (request->headers, "origin", "weechat.org");
|
||||
LONGS_EQUAL(-2, relay_websocket_client_handshake_valid (request));
|
||||
hashtable_set (request->headers, "origin", "example.com");
|
||||
LONGS_EQUAL(0, relay_websocket_client_handshake_valid (request));
|
||||
|
||||
relay_websocket_parse_extensions (
|
||||
"permessage-deflate; client_max_window_bits",
|
||||
request->ws_deflate);
|
||||
WEE_TEST_STR(
|
||||
"HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: fhLJYtv//ugX2vQXpifQgByRZ5Y=\r\n"
|
||||
"Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15; client_max_window_bits=15\r\n"
|
||||
"\r\n",
|
||||
relay_websocket_build_handshake (request));
|
||||
|
||||
relay_websocket_parse_extensions (
|
||||
"permessage-deflate; client_max_window_bits = 12; server_no_context_takeover",
|
||||
request->ws_deflate);
|
||||
WEE_TEST_STR(
|
||||
"HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: fhLJYtv//ugX2vQXpifQgByRZ5Y=\r\n"
|
||||
"Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; server_max_window_bits=15; client_max_window_bits=12\r\n"
|
||||
"\r\n",
|
||||
relay_websocket_build_handshake (request));
|
||||
|
||||
relay_websocket_parse_extensions (
|
||||
"permessage-deflate; client_max_window_bits = 12; server_max_window_bits=8; client_no_context_takeover; server_no_context_takeover",
|
||||
request->ws_deflate);
|
||||
WEE_TEST_STR(
|
||||
"HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: fhLJYtv//ugX2vQXpifQgByRZ5Y=\r\n"
|
||||
"Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover; server_max_window_bits=8; client_max_window_bits=12\r\n"
|
||||
"\r\n",
|
||||
relay_websocket_build_handshake (request));
|
||||
|
||||
relay_http_request_free (request);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_websocket_parse_extensions
|
||||
*/
|
||||
|
||||
TEST(RelayWebsocket, ParseExtensions)
|
||||
{
|
||||
struct t_relay_websocket_deflate ws_deflate;
|
||||
|
||||
relay_websocket_parse_extensions (NULL, NULL);
|
||||
relay_websocket_parse_extensions ("test", NULL);
|
||||
relay_websocket_parse_extensions (NULL, &ws_deflate);
|
||||
|
||||
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
||||
relay_websocket_parse_extensions ("test", &ws_deflate);
|
||||
LONGS_EQUAL(0, ws_deflate.enabled);
|
||||
|
||||
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
||||
relay_websocket_parse_extensions ("permessage-deflate", &ws_deflate);
|
||||
LONGS_EQUAL(1, ws_deflate.enabled);
|
||||
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
||||
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
||||
LONGS_EQUAL(15, ws_deflate.window_bits_deflate);
|
||||
LONGS_EQUAL(15, ws_deflate.window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
||||
|
||||
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
||||
relay_websocket_parse_extensions ("permessage-deflate; client_max_window_bits",
|
||||
&ws_deflate);
|
||||
LONGS_EQUAL(1, ws_deflate.enabled);
|
||||
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
||||
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
||||
LONGS_EQUAL(15, ws_deflate.window_bits_deflate);
|
||||
LONGS_EQUAL(15, ws_deflate.window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
||||
|
||||
/* client_max_window_bits < 8 (min value) */
|
||||
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
||||
relay_websocket_parse_extensions (
|
||||
"permessage-deflate; client_max_window_bits=4",
|
||||
&ws_deflate);
|
||||
LONGS_EQUAL(1, ws_deflate.enabled);
|
||||
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
||||
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
||||
LONGS_EQUAL(15, ws_deflate.window_bits_deflate);
|
||||
LONGS_EQUAL(8, ws_deflate.window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
||||
|
||||
/* client_max_window_bits > 15 (max value) */
|
||||
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
||||
relay_websocket_parse_extensions (
|
||||
"permessage-deflate; client_max_window_bits=30",
|
||||
&ws_deflate);
|
||||
LONGS_EQUAL(1, ws_deflate.enabled);
|
||||
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
||||
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
||||
LONGS_EQUAL(15, ws_deflate.window_bits_deflate);
|
||||
LONGS_EQUAL(15, ws_deflate.window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
||||
|
||||
/* invalid value for client_max_window_bits */
|
||||
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
||||
relay_websocket_parse_extensions (
|
||||
"permessage-deflate; client_max_window_bits=test",
|
||||
&ws_deflate);
|
||||
LONGS_EQUAL(1, ws_deflate.enabled);
|
||||
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
||||
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
||||
LONGS_EQUAL(15, ws_deflate.window_bits_deflate);
|
||||
LONGS_EQUAL(15, ws_deflate.window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
||||
|
||||
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
||||
relay_websocket_parse_extensions (
|
||||
"permessage-deflate; client_max_window_bits=9",
|
||||
&ws_deflate);
|
||||
LONGS_EQUAL(1, ws_deflate.enabled);
|
||||
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
||||
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
||||
LONGS_EQUAL(15, ws_deflate.window_bits_deflate);
|
||||
LONGS_EQUAL(9, ws_deflate.window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
||||
|
||||
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
||||
relay_websocket_parse_extensions (
|
||||
"permessage-deflate; client_max_window_bits=9; server_max_window_bits=10",
|
||||
&ws_deflate);
|
||||
LONGS_EQUAL(1, ws_deflate.enabled);
|
||||
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
||||
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
||||
LONGS_EQUAL(10, ws_deflate.window_bits_deflate);
|
||||
LONGS_EQUAL(9, ws_deflate.window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
||||
|
||||
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
||||
relay_websocket_parse_extensions (
|
||||
"permessage-deflate; client_max_window_bits=9; server_max_window_bits=10; "
|
||||
"server_no_context_takeover",
|
||||
&ws_deflate);
|
||||
LONGS_EQUAL(1, ws_deflate.enabled);
|
||||
LONGS_EQUAL(0, ws_deflate.server_context_takeover);
|
||||
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
||||
LONGS_EQUAL(10, ws_deflate.window_bits_deflate);
|
||||
LONGS_EQUAL(9, ws_deflate.window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
||||
|
||||
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
||||
relay_websocket_parse_extensions (
|
||||
"permessage-deflate; client_max_window_bits=9; server_max_window_bits=10; "
|
||||
"server_no_context_takeover; client_no_context_takeover",
|
||||
&ws_deflate);
|
||||
LONGS_EQUAL(1, ws_deflate.enabled);
|
||||
LONGS_EQUAL(0, ws_deflate.server_context_takeover);
|
||||
LONGS_EQUAL(0, ws_deflate.client_context_takeover);
|
||||
LONGS_EQUAL(10, ws_deflate.window_bits_deflate);
|
||||
LONGS_EQUAL(9, ws_deflate.window_bits_inflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
||||
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_websocket_deflate
|
||||
* relay_websocket_inflate
|
||||
*/
|
||||
|
||||
TEST(RelayWebsocket, Inflate)
|
||||
{
|
||||
struct t_relay_websocket_deflate *ws_deflate;
|
||||
char payload[256], *payload_comp, *payload_decomp;
|
||||
size_t size_comp, size_decomp;
|
||||
int i;
|
||||
|
||||
ws_deflate = relay_websocket_deflate_alloc ();
|
||||
CHECK(ws_deflate);
|
||||
|
||||
ws_deflate->window_bits_deflate = 15;
|
||||
ws_deflate->window_bits_inflate = 15;
|
||||
|
||||
ws_deflate->strm_deflate = (z_stream *)calloc (1, sizeof (*ws_deflate->strm_deflate));
|
||||
CHECK(ws_deflate->strm_deflate);
|
||||
LONGS_EQUAL(1, relay_websocket_deflate_init_stream_deflate (ws_deflate));
|
||||
|
||||
ws_deflate->strm_inflate = (z_stream *)calloc (1, sizeof (*ws_deflate->strm_inflate));
|
||||
CHECK(ws_deflate->strm_inflate);
|
||||
LONGS_EQUAL(1, relay_websocket_deflate_init_stream_inflate (ws_deflate));
|
||||
|
||||
for (i = 0; i < (int)sizeof (payload); i++)
|
||||
{
|
||||
payload[i] = i % 64;
|
||||
}
|
||||
|
||||
POINTERS_EQUAL(NULL, relay_websocket_deflate (NULL, 0, NULL, NULL));
|
||||
POINTERS_EQUAL(NULL, relay_websocket_deflate (payload, 0, NULL, NULL));
|
||||
POINTERS_EQUAL(NULL, relay_websocket_deflate (payload, sizeof (payload),
|
||||
NULL, NULL));
|
||||
POINTERS_EQUAL(NULL, relay_websocket_deflate (payload, sizeof (payload),
|
||||
ws_deflate->strm_deflate, NULL));
|
||||
|
||||
payload_comp = (char *)relay_websocket_deflate (payload, sizeof (payload),
|
||||
ws_deflate->strm_deflate, &size_comp);
|
||||
CHECK(payload_comp);
|
||||
CHECK((size_comp > 0) && (size_comp < (int)sizeof (payload)));
|
||||
|
||||
payload_decomp = (char *)relay_websocket_inflate (payload_comp, size_comp,
|
||||
ws_deflate->strm_inflate, &size_decomp);
|
||||
CHECK(payload_decomp);
|
||||
LONGS_EQUAL(sizeof (payload), size_decomp);
|
||||
MEMCMP_EQUAL(payload, payload_decomp, sizeof (payload));
|
||||
|
||||
free (payload_decomp);
|
||||
free (payload_comp);
|
||||
|
||||
relay_websocket_deflate_free (ws_deflate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_websocket_decode_frame
|
||||
*/
|
||||
|
||||
TEST(RelayWebsocket, DecodeFrame)
|
||||
{
|
||||
/* TODO: write tests */
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_websocket_encode_frame
|
||||
*/
|
||||
|
||||
TEST(RelayWebsocket, EncodeFrame)
|
||||
{
|
||||
/* TODO: write tests */
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_websocket_deflate_print_log
|
||||
*/
|
||||
|
||||
TEST(RelayWebsocket, DeflatePrintLog)
|
||||
{
|
||||
/* TODO: write tests */
|
||||
}
|
||||
Reference in New Issue
Block a user