gchar *passwd;
GHashTable *auth_params;
+ guint content_length_limit;
+
/* TLS */
GTlsDatabase *tls_database;
GTlsInteraction *tls_interaction;
guint line;
guint8 *body_data;
- glong body_len;
+ guint body_len;
} GstRTSPBuilder;
/* function prototypes */
newconn->auth_params = NULL;
newconn->version = 0;
+ newconn->content_length_limit = G_MAXUINT;
+
*conn = newconn;
return GST_RTSP_OK;
/* we have a regular response */
if (builder->buffer[0] == '\0') {
gchar *hdrval;
+ gint64 content_length_parsed = 0;
/* empty line, end of message header */
/* see if there is a Content-Length header, but ignore it if this
gst_rtsp_message_get_header (message,
GST_RTSP_HDR_X_SESSIONCOOKIE, NULL, 0) != GST_RTSP_OK)) {
/* there is, prepare to read the body */
- builder->body_len = atol (hdrval);
+ errno = 0;
+ content_length_parsed = g_ascii_strtoll (hdrval, NULL, 10);
+ if (errno != 0 || content_length_parsed < 0) {
+ res = GST_RTSP_EPARSE;
+ goto invalid_body_len;
+ } else if (content_length_parsed > conn->content_length_limit) {
+ res = GST_RTSP_ENOMEM;
+ goto invalid_body_len;
+ }
+ builder->body_len = content_length_parsed;
builder->body_data = g_try_malloc (builder->body_len + 1);
/* we can't do much here, we need the length to know how many bytes
- * we need to read next and when allocation fails, something is
- * probably wrong with the length. */
- if (builder->body_data == NULL)
+ * we need to read next and when allocation fails, we can't read the payload. */
+ if (builder->body_data == NULL) {
+ res = GST_RTSP_ENOMEM;
goto invalid_body_len;
+ }
builder->body_data[builder->body_len] = '\0';
builder->offset = 0;
{
conn->may_cancel = TRUE;
GST_DEBUG ("could not allocate body");
- return GST_RTSP_ERROR;
+ return res;
}
invalid_format:
{
return res;
}
+/**
+ * gst_rtsp_connection_set_content_length_limit:
+ * @conn: a #GstRTSPConnection
+ * @limit: Content-Length limit
+ *
+ * Configure @conn to use the specified Content-Length limit.
+ * Both requests and responses are validated. If content-length is
+ * exceeded, ENOMEM error will be returned.
+ *
+ * Since: 1.18
+ */
+void
+gst_rtsp_connection_set_content_length_limit (GstRTSPConnection * conn,
+ guint limit)
+{
+ g_return_if_fail (conn != NULL);
+
+ conn->content_length_limit = limit;
+}
/**
* gst_rtsp_connection_get_url:
GST_END_TEST;
+GST_START_TEST (test_rtspconnection_send_receive_content_length)
+{
+ GSocketConnection *input_conn = NULL;
+ GSocketConnection *output_conn = NULL;
+ GSocket *input_sock;
+ GSocket *output_sock;
+ GstRTSPConnection *rtsp_output_conn;
+ GstRTSPConnection *rtsp_input_conn;
+ GstRTSPMessage *msg;
+
+ create_connection (&input_conn, &output_conn);
+ input_sock = g_socket_connection_get_socket (input_conn);
+ fail_unless (input_sock != NULL);
+ output_sock = g_socket_connection_get_socket (output_conn);
+ fail_unless (output_sock != NULL);
+
+ fail_unless (gst_rtsp_connection_create_from_socket (input_sock, "127.0.0.1",
+ 4444, NULL, &rtsp_input_conn) == GST_RTSP_OK);
+ fail_unless (rtsp_input_conn != NULL);
+
+ fail_unless (gst_rtsp_connection_create_from_socket (output_sock, "127.0.0.1",
+ 4444, NULL, &rtsp_output_conn) == GST_RTSP_OK);
+ fail_unless (rtsp_output_conn != NULL);
+
+ /* send request message with to big payload */
+ fail_unless (gst_rtsp_message_new_request (&msg, GST_RTSP_SETUP,
+ "rtsp://example.com/") == GST_RTSP_OK);
+ fail_unless (gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_LENGTH,
+ "2000") == GST_RTSP_OK);
+ fail_unless (gst_rtsp_connection_send (rtsp_output_conn, msg,
+ NULL) == GST_RTSP_OK);
+ fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK);
+ msg = NULL;
+
+ /* receive request message, expect ENOMEM */
+ gst_rtsp_connection_set_content_length_limit (rtsp_input_conn, 1000);
+ fail_unless (gst_rtsp_message_new (&msg) == GST_RTSP_OK);
+ fail_unless (gst_rtsp_connection_receive (rtsp_input_conn, msg, NULL) ==
+ GST_RTSP_ENOMEM);
+ fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK);
+ msg = NULL;
+
+ /* send request message with negative payload */
+ fail_unless (gst_rtsp_message_new_request (&msg, GST_RTSP_SETUP,
+ "rtsp://example.com/") == GST_RTSP_OK);
+ fail_unless (gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_LENGTH,
+ "-2000") == GST_RTSP_OK);
+ fail_unless (gst_rtsp_connection_send (rtsp_output_conn, msg,
+ NULL) == GST_RTSP_OK);
+ fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK);
+ msg = NULL;
+
+ /* receive request message, expect EPARSE */
+ fail_unless (gst_rtsp_message_new (&msg) == GST_RTSP_OK);
+ fail_unless (gst_rtsp_connection_receive (rtsp_input_conn, msg, NULL) ==
+ GST_RTSP_EPARSE);
+ fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK);
+ msg = NULL;
+
+ fail_unless (gst_rtsp_connection_close (rtsp_input_conn) == GST_RTSP_OK);
+ fail_unless (gst_rtsp_connection_free (rtsp_input_conn) == GST_RTSP_OK);
+ fail_unless (gst_rtsp_connection_close (rtsp_output_conn) == GST_RTSP_OK);
+ fail_unless (gst_rtsp_connection_free (rtsp_output_conn) == GST_RTSP_OK);
+
+ g_object_unref (input_conn);
+ g_object_unref (output_conn);
+}
+
+GST_END_TEST;
static Suite *
rtspconnection_suite (void)
tcase_add_test (tc_chain, test_rtspconnection_poll);
tcase_add_test (tc_chain, test_rtspconnection_backlog);
tcase_add_test (tc_chain, test_rtspconnection_ip);
+ tcase_add_test (tc_chain, test_rtspconnection_send_receive_content_length);
return s;
}