1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * soup-websocket-extension.c
4 *
5 * Copyright (C) 2019 Igalia S.L.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "soup-websocket-extension.h"
28
29 /**
30 * SECTION:soup-websocket-extension
31 * @short_description: a WebSocket extension
32 * @see_also: #SoupSession, #SoupWebsocketExtensionManager
33 *
34 * SoupWebsocketExtension is the base class for WebSocket extension objects.
35 *
36 * Since: 2.68
37 */
38
39 /**
40 * SoupWebsocketExtensionClass:
41 * @parent_class: the parent class
42 * @configure: called to configure the extension with the given parameters
43 * @get_request_params: called by the client to build the request header.
44 * It should include the parameters string starting with ';'
45 * @get_response_params: called by the server to build the response header.
46 * It should include the parameters string starting with ';'
47 * @process_outgoing_message: called to process the payload data of a message
48 * before it's sent. Reserved bits of the header should be changed.
49 * @process_incoming_message: called to process the payload data of a message
50 * after it's received. Reserved bits of the header should be cleared.
51 *
52 * The class structure for the SoupWebsocketExtension.
53 *
54 * Since: 2.68
55 */
56
G_DEFINE_ABSTRACT_TYPE(SoupWebsocketExtension,soup_websocket_extension,G_TYPE_OBJECT)57 G_DEFINE_ABSTRACT_TYPE (SoupWebsocketExtension, soup_websocket_extension, G_TYPE_OBJECT)
58
59 static void
60 soup_websocket_extension_init (SoupWebsocketExtension *extension)
61 {
62 }
63
64 static void
soup_websocket_extension_class_init(SoupWebsocketExtensionClass * auth_class)65 soup_websocket_extension_class_init (SoupWebsocketExtensionClass *auth_class)
66 {
67 }
68
69 /**
70 * soup_websocket_extension_configure:
71 * @extension: a #SoupWebsocketExtension
72 * @connection_type: either %SOUP_WEBSOCKET_CONNECTION_CLIENT or %SOUP_WEBSOCKET_CONNECTION_SERVER
73 * @params: (nullable): the parameters, or %NULL
74 * @error: return location for a #GError
75 *
76 * Configures @extension with the given @params
77 *
78 * Return value: %TRUE if extension could be configured with the given parameters, or %FALSE otherwise
79 */
80 gboolean
soup_websocket_extension_configure(SoupWebsocketExtension * extension,SoupWebsocketConnectionType connection_type,GHashTable * params,GError ** error)81 soup_websocket_extension_configure (SoupWebsocketExtension *extension,
82 SoupWebsocketConnectionType connection_type,
83 GHashTable *params,
84 GError **error)
85 {
86 SoupWebsocketExtensionClass *klass;
87
88 g_return_val_if_fail (SOUP_IS_WEBSOCKET_EXTENSION (extension), FALSE);
89 g_return_val_if_fail (connection_type != SOUP_WEBSOCKET_CONNECTION_UNKNOWN, FALSE);
90 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
91
92 klass = SOUP_WEBSOCKET_EXTENSION_GET_CLASS (extension);
93 if (!klass->configure)
94 return TRUE;
95
96 return klass->configure (extension, connection_type, params, error);
97 }
98
99 /**
100 * soup_websocket_extension_get_request_params:
101 * @extension: a #SoupWebsocketExtension
102 *
103 * Get the parameters strings to be included in the request header. If the extension
104 * doesn't include any parameter in the request, this function returns %NULL.
105 *
106 * Returns: (nullable) (transfer full): a new allocated string with the parameters
107 *
108 * Since: 2.68
109 */
110 char *
soup_websocket_extension_get_request_params(SoupWebsocketExtension * extension)111 soup_websocket_extension_get_request_params (SoupWebsocketExtension *extension)
112 {
113 SoupWebsocketExtensionClass *klass;
114
115 g_return_val_if_fail (SOUP_IS_WEBSOCKET_EXTENSION (extension), NULL);
116
117 klass = SOUP_WEBSOCKET_EXTENSION_GET_CLASS (extension);
118 if (!klass->get_request_params)
119 return NULL;
120
121 return klass->get_request_params (extension);
122 }
123
124 /**
125 * soup_websocket_extension_get_response_params:
126 * @extension: a #SoupWebsocketExtension
127 *
128 * Get the parameters strings to be included in the response header. If the extension
129 * doesn't include any parameter in the response, this function returns %NULL.
130 *
131 * Returns: (nullable) (transfer full): a new allocated string with the parameters
132 *
133 * Since: 2.68
134 */
135 char *
soup_websocket_extension_get_response_params(SoupWebsocketExtension * extension)136 soup_websocket_extension_get_response_params (SoupWebsocketExtension *extension)
137 {
138 SoupWebsocketExtensionClass *klass;
139
140 g_return_val_if_fail (SOUP_IS_WEBSOCKET_EXTENSION (extension), NULL);
141
142 klass = SOUP_WEBSOCKET_EXTENSION_GET_CLASS (extension);
143 if (!klass->get_response_params)
144 return NULL;
145
146 return klass->get_response_params (extension);
147 }
148
149 /**
150 * soup_websocket_extension_process_outgoing_message:
151 * @extension: a #SoupWebsocketExtension
152 * @header: (inout): the message header
153 * @payload: (transfer full): the payload data
154 * @error: return location for a #GError
155 *
156 * Process a message before it's sent. If the payload isn't changed the given
157 * @payload is just returned, otherwise g_bytes_unref() is called on the given
158 * @payload and a new #GBytes is returned with the new data.
159 *
160 * Extensions using reserved bits of the header will change them in @header.
161 *
162 * Returns: (transfer full): the message payload data, or %NULL in case of error
163 *
164 * Since: 2.68
165 */
166 GBytes *
soup_websocket_extension_process_outgoing_message(SoupWebsocketExtension * extension,guint8 * header,GBytes * payload,GError ** error)167 soup_websocket_extension_process_outgoing_message (SoupWebsocketExtension *extension,
168 guint8 *header,
169 GBytes *payload,
170 GError **error)
171 {
172 SoupWebsocketExtensionClass *klass;
173
174 g_return_val_if_fail (SOUP_IS_WEBSOCKET_EXTENSION (extension), NULL);
175 g_return_val_if_fail (header != NULL, NULL);
176 g_return_val_if_fail (payload != NULL, NULL);
177 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
178
179 klass = SOUP_WEBSOCKET_EXTENSION_GET_CLASS (extension);
180 if (!klass->process_outgoing_message)
181 return payload;
182
183 return klass->process_outgoing_message (extension, header, payload, error);
184 }
185
186 /**
187 * soup_websocket_extension_process_incoming_message:
188 * @extension: a #SoupWebsocketExtension
189 * @header: (inout): the message header
190 * @payload: (transfer full): the payload data
191 * @error: return location for a #GError
192 *
193 * Process a message after it's received. If the payload isn't changed the given
194 * @payload is just returned, otherwise g_bytes_unref() is called on the given
195 * @payload and a new #GBytes is returned with the new data.
196 *
197 * Extensions using reserved bits of the header will reset them in @header.
198 *
199 * Returns: (transfer full): the message payload data, or %NULL in case of error
200 *
201 * Since: 2.68
202 */
203 GBytes *
soup_websocket_extension_process_incoming_message(SoupWebsocketExtension * extension,guint8 * header,GBytes * payload,GError ** error)204 soup_websocket_extension_process_incoming_message (SoupWebsocketExtension *extension,
205 guint8 *header,
206 GBytes *payload,
207 GError **error)
208 {
209 SoupWebsocketExtensionClass *klass;
210
211 g_return_val_if_fail (SOUP_IS_WEBSOCKET_EXTENSION (extension), NULL);
212 g_return_val_if_fail (header != NULL, NULL);
213 g_return_val_if_fail (payload != NULL, NULL);
214 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
215
216 klass = SOUP_WEBSOCKET_EXTENSION_GET_CLASS (extension);
217 if (!klass->process_incoming_message)
218 return payload;
219
220 return klass->process_incoming_message (extension, header, payload, error);
221 }
222