Commit d4c6819e authored by Ignacio Casal Quinteiro's avatar Ignacio Casal Quinteiro
Browse files

Add max-incoming-payload-size property to the websocket connection.

This allows to change the limit for the payload of websocket packets.
Also add the corresponding unit test.

https://bugzilla.gnome.org/show_bug.cgi?id=770022
parent cec6e734
......@@ -80,6 +80,7 @@ enum {
PROP_ORIGIN,
PROP_PROTOCOL,
PROP_STATE,
PROP_MAX_INCOMING_PAYLOAD_SIZE,
};
enum {
......@@ -105,6 +106,7 @@ struct _SoupWebsocketConnectionPrivate {
SoupURI *uri;
char *origin;
char *protocol;
guint64 max_incoming_payload_size;
gushort peer_close_code;
char *peer_close_data;
......@@ -131,7 +133,7 @@ struct _SoupWebsocketConnectionPrivate {
GByteArray *message_data;
};
#define MAX_PAYLOAD 128 * 1024
#define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024
G_DEFINE_TYPE (SoupWebsocketConnection, soup_websocket_connection, G_TYPE_OBJECT)
......@@ -500,9 +502,9 @@ too_big_error_and_close (SoupWebsocketConnection *self,
self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ?
"Received extremely large WebSocket data from the client" :
"Received extremely large WebSocket data from the server");
g_debug ("%s is trying to frame of size %" G_GUINT64_FORMAT " or greater, but max supported size is 128KiB",
g_debug ("%s is trying to frame of size %" G_GUINT64_FORMAT " or greater, but max supported size is %" G_GUINT64_FORMAT,
self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? "server" : "client",
payload_len);
payload_len, self->pv->max_incoming_payload_size);
emit_error_and_close (self, error, TRUE);
/* The input is in an invalid state now */
......@@ -728,7 +730,8 @@ process_frame (SoupWebsocketConnection *self)
}
/* Safety valve */
if (payload_len >= MAX_PAYLOAD) {
if (self->pv->max_incoming_payload_size > 0 &&
payload_len >= self->pv->max_incoming_payload_size) {
too_big_error_and_close (self, payload_len);
return FALSE;
}
......@@ -963,6 +966,7 @@ soup_websocket_connection_get_property (GObject *object,
GParamSpec *pspec)
{
SoupWebsocketConnection *self = SOUP_WEBSOCKET_CONNECTION (object);
SoupWebsocketConnectionPrivate *pv = self->pv;
switch (prop_id) {
case PROP_IO_STREAM:
......@@ -989,6 +993,10 @@ soup_websocket_connection_get_property (GObject *object,
g_value_set_enum (value, soup_websocket_connection_get_state (self));
break;
case PROP_MAX_INCOMING_PAYLOAD_SIZE:
g_value_set_uint64 (value, pv->max_incoming_payload_size);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -1029,6 +1037,10 @@ soup_websocket_connection_set_property (GObject *object,
pv->protocol = g_value_dup_string (value);
break;
case PROP_MAX_INCOMING_PAYLOAD_SIZE:
pv->max_incoming_payload_size = g_value_get_uint64 (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -1196,6 +1208,25 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* SoupWebsocketConnection:max-incoming-payload-size:
*
* The maximum payload size for incoming packets the protocol expects
* or 0 to not limit it.
*
* Since: 2.56
*/
g_object_class_install_property (gobject_class, PROP_MAX_INCOMING_PAYLOAD_SIZE,
g_param_spec_uint64 ("max-incoming-payload-size",
"Max incoming payload size",
"Max incoming payload size ",
0,
G_MAXUINT64,
MAX_INCOMING_PAYLOAD_SIZE_DEFAULT,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
/**
* SoupWebsocketConnection::message:
* @self: the WebSocket
......@@ -1569,3 +1600,49 @@ soup_websocket_connection_close (SoupWebsocketConnection *self,
send_close (self, flags, code, data);
close_io_after_timeout (self);
}
/**
* soup_websocket_connection_get_max_incoming_payload_size:
* @self: the WebSocket
*
* Gets the maximum payload size allowed for incoming packets.
*
* Returns: the maximum payload size.
*
* Since: 2.56
*/
guint64
soup_websocket_connection_get_max_incoming_payload_size (SoupWebsocketConnection *self)
{
SoupWebsocketConnectionPrivate *pv;
g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_INCOMING_PAYLOAD_SIZE_DEFAULT);
pv = self->pv;
return pv->max_incoming_payload_size;
}
/**
* soup_websocket_connection_set_max_incoming_payload_size:
* @self: the WebSocket
* @max_incoming_payload_size: the maximum payload size
*
* Sets the maximum payload size allowed for incoming packets. It
* does not limit the outgoing packet size.
*
* Since: 2.56
*/
void
soup_websocket_connection_set_max_incoming_payload_size (SoupWebsocketConnection *self,
guint64 max_incoming_payload_size)
{
SoupWebsocketConnectionPrivate *pv;
g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self));
pv = self->pv;
if (pv->max_incoming_payload_size != max_incoming_payload_size) {
pv->max_incoming_payload_size = max_incoming_payload_size;
g_object_notify (G_OBJECT (self), "max-incoming-payload-size");
}
}
......@@ -105,6 +105,13 @@ void soup_websocket_connection_close (SoupWebsocketConne
gushort code,
const char *data);
SOUP_AVAILABLE_IN_2_56
guint64 soup_websocket_connection_get_max_incoming_payload_size (SoupWebsocketConnection *self);
SOUP_AVAILABLE_IN_2_56
void soup_websocket_connection_set_max_incoming_payload_size (SoupWebsocketConnection *self,
guint64 max_incoming_payload_size);
G_END_DECLS
#endif /* __SOUP_WEBSOCKET_CONNECTION_H__ */
......@@ -380,6 +380,19 @@ test_send_big_packets (Test *test,
g_assert (g_bytes_equal (sent, received));
g_bytes_unref (sent);
g_bytes_unref (received);
received = NULL;
soup_websocket_connection_set_max_incoming_payload_size (test->client, 1000 * 1000 + 1);
g_assert (soup_websocket_connection_get_max_incoming_payload_size (test->client) == (1000 * 1000 + 1));
soup_websocket_connection_set_max_incoming_payload_size (test->server, 1000 * 1000 + 1);
g_assert (soup_websocket_connection_get_max_incoming_payload_size (test->server) == (1000 * 1000 + 1));
sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000);
soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL));
WAIT_UNTIL (received != NULL);
g_assert (g_bytes_equal (sent, received));
g_bytes_unref (sent);
g_bytes_unref (received);
}
static void
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment