1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; 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 */
37
38 /**
39 * SoupWebsocketExtension:
40 *
41 * Class for impelementing websocket extensions.
42 */
43
44 /**
45 * SoupWebsocketExtensionClass:
46 * @name: the name of the extension
47 * @parent_class: the parent class
48 * @configure: called to configure the extension with the given parameters
49 * @get_request_params: called by the client to build the request header.
50 * It should include the parameters string starting with ';'
51 * @get_response_params: called by the server to build the response header.
52 * It should include the parameters string starting with ';'
53 * @process_outgoing_message: called to process the payload data of a message
54 * before it's sent. Reserved bits of the header should be changed.
55 * @process_incoming_message: called to process the payload data of a message
56 * after it's received. Reserved bits of the header should be cleared.
57 *
58 * The class structure for the SoupWebsocketExtension.
59 *
60 */
61
G_DEFINE_ABSTRACT_TYPE(SoupWebsocketExtension,soup_websocket_extension,G_TYPE_OBJECT)62 G_DEFINE_ABSTRACT_TYPE (SoupWebsocketExtension, soup_websocket_extension, G_TYPE_OBJECT)
63
64 static void
65 soup_websocket_extension_init (SoupWebsocketExtension *extension)
66 {
67 }
68
69 static void
soup_websocket_extension_class_init(SoupWebsocketExtensionClass * auth_class)70 soup_websocket_extension_class_init (SoupWebsocketExtensionClass *auth_class)
71 {
72 }
73
74 /**
75 * soup_websocket_extension_configure:
76 * @extension: a #SoupWebsocketExtension
77 * @connection_type: either %SOUP_WEBSOCKET_CONNECTION_CLIENT or %SOUP_WEBSOCKET_CONNECTION_SERVER
78 * @params: (nullable): the parameters, or %NULL
79 * @error: return location for a #GError
80 *
81 * Configures @extension with the given @params
82 *
83 * Returns: %TRUE if extension could be configured with the given parameters, or %FALSE otherwise
84 */
85 gboolean
soup_websocket_extension_configure(SoupWebsocketExtension * extension,SoupWebsocketConnectionType connection_type,GHashTable * params,GError ** error)86 soup_websocket_extension_configure (SoupWebsocketExtension *extension,
87 SoupWebsocketConnectionType connection_type,
88 GHashTable *params,
89 GError **error)
90 {
91 SoupWebsocketExtensionClass *klass;
92
93 g_return_val_if_fail (SOUP_IS_WEBSOCKET_EXTENSION (extension), FALSE);
94 g_return_val_if_fail (connection_type != SOUP_WEBSOCKET_CONNECTION_UNKNOWN, FALSE);
95 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
96
97 klass = SOUP_WEBSOCKET_EXTENSION_GET_CLASS (extension);
98 if (!klass->configure)
99 return TRUE;
100
101 return klass->configure (extension, connection_type, params, error);
102 }
103
104 /**
105 * soup_websocket_extension_get_request_params:
106 * @extension: a #SoupWebsocketExtension
107 *
108 * Get the parameters strings to be included in the request header. If the extension
109 * doesn't include any parameter in the request, this function returns %NULL.
110 *
111 * Returns: (nullable) (transfer full): a new allocated string with the parameters
112 *
113 */
114 char *
soup_websocket_extension_get_request_params(SoupWebsocketExtension * extension)115 soup_websocket_extension_get_request_params (SoupWebsocketExtension *extension)
116 {
117 SoupWebsocketExtensionClass *klass;
118
119 g_return_val_if_fail (SOUP_IS_WEBSOCKET_EXTENSION (extension), NULL);
120
121 klass = SOUP_WEBSOCKET_EXTENSION_GET_CLASS (extension);
122 if (!klass->get_request_params)
123 return NULL;
124
125 return klass->get_request_params (extension);
126 }
127
128 /**
129 * soup_websocket_extension_get_response_params:
130 * @extension: a #SoupWebsocketExtension
131 *
132 * Get the parameters strings to be included in the response header. If the extension
133 * doesn't include any parameter in the response, this function returns %NULL.
134 *
135 * Returns: (nullable) (transfer full): a new allocated string with the parameters
136 *
137 */
138 char *
soup_websocket_extension_get_response_params(SoupWebsocketExtension * extension)139 soup_websocket_extension_get_response_params (SoupWebsocketExtension *extension)
140 {
141 SoupWebsocketExtensionClass *klass;
142
143 g_return_val_if_fail (SOUP_IS_WEBSOCKET_EXTENSION (extension), NULL);
144
145 klass = SOUP_WEBSOCKET_EXTENSION_GET_CLASS (extension);
146 if (!klass->get_response_params)
147 return NULL;
148
149 return klass->get_response_params (extension);
150 }
151
152 /**
153 * soup_websocket_extension_process_outgoing_message:
154 * @extension: a #SoupWebsocketExtension
155 * @header: (inout): the message header
156 * @payload: (transfer full): the payload data
157 * @error: return location for a #GError
158 *
159 * Process a message before it's sent. If the payload isn't changed the given
160 * @payload is just returned, otherwise g_bytes_unref() is called on the given
161 * @payload and a new #GBytes is returned with the new data.
162 *
163 * Extensions using reserved bits of the header will change them in @header.
164 *
165 * Returns: (transfer full): the message payload data, or %NULL in case of error
166 *
167 */
168 GBytes *
soup_websocket_extension_process_outgoing_message(SoupWebsocketExtension * extension,guint8 * header,GBytes * payload,GError ** error)169 soup_websocket_extension_process_outgoing_message (SoupWebsocketExtension *extension,
170 guint8 *header,
171 GBytes *payload,
172 GError **error)
173 {
174 SoupWebsocketExtensionClass *klass;
175
176 g_return_val_if_fail (SOUP_IS_WEBSOCKET_EXTENSION (extension), NULL);
177 g_return_val_if_fail (header != NULL, NULL);
178 g_return_val_if_fail (payload != NULL, NULL);
179 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
180
181 klass = SOUP_WEBSOCKET_EXTENSION_GET_CLASS (extension);
182 if (!klass->process_outgoing_message)
183 return payload;
184
185 return klass->process_outgoing_message (extension, header, payload, error);
186 }
187
188 /**
189 * soup_websocket_extension_process_incoming_message:
190 * @extension: a #SoupWebsocketExtension
191 * @header: (inout): the message header
192 * @payload: (transfer full): the payload data
193 * @error: return location for a #GError
194 *
195 * Process a message after it's received. If the payload isn't changed the given
196 * @payload is just returned, otherwise g_bytes_unref() is called on the given
197 * @payload and a new #GBytes is returned with the new data.
198 *
199 * Extensions using reserved bits of the header will reset them in @header.
200 *
201 * Returns: (transfer full): the message payload data, or %NULL in case of error
202 *
203 */
204 GBytes *
soup_websocket_extension_process_incoming_message(SoupWebsocketExtension * extension,guint8 * header,GBytes * payload,GError ** error)205 soup_websocket_extension_process_incoming_message (SoupWebsocketExtension *extension,
206 guint8 *header,
207 GBytes *payload,
208 GError **error)
209 {
210 SoupWebsocketExtensionClass *klass;
211
212 g_return_val_if_fail (SOUP_IS_WEBSOCKET_EXTENSION (extension), NULL);
213 g_return_val_if_fail (header != NULL, NULL);
214 g_return_val_if_fail (payload != NULL, NULL);
215 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
216
217 klass = SOUP_WEBSOCKET_EXTENSION_GET_CLASS (extension);
218 if (!klass->process_incoming_message)
219 return payload;
220
221 return klass->process_incoming_message (extension, header, payload, error);
222 }
223