diff --git a/ChangeLog b/ChangeLog index 17072657a3..29f16e554b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2007-05-24 Wim Taymans + + Patch by: Peter Kjellerstedt + + * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_setup_auth), + (gst_rtspsrc_try_send), (gst_rtspsrc_parse_methods), + (gst_rtspsrc_setup_streams), (gst_rtspsrc_open), + (gst_rtspsrc_play): + (rtsp_connection_send), (rtsp_connection_receive): + * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_after_send): + Fix for new API. + + * gst/rtsp/rtspconnection.c: (add_auth_header), + Only add authorisation and session headers when sending messages. + + * gst/rtsp/rtspmessage.c: (key_value_foreach), (rtsp_message_init), + (rtsp_message_init_request), (rtsp_message_init_response), + (rtsp_message_unset), (rtsp_message_add_header), + (rtsp_message_remove_header), (rtsp_message_get_header), + (rtsp_message_append_headers), (dump_key_value), + (rtsp_message_dump): + * gst/rtsp/rtspmessage.h: + Add support for multiple headers of the same type by storing the parsed + headers in a GArray instaed of a hashtable. + 2007-05-21 Wim Taymans * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init), diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index 18c0421333..5b6a35ad99 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -2640,7 +2640,7 @@ gst_rtspsrc_setup_auth (GstRTSPSrc * src, RTSPMessage * response) gchar *hdr; /* Identify the available auth methods and see if any are supported */ - if (rtsp_message_get_header (response, RTSP_HDR_WWW_AUTHENTICATE, &hdr) == + if (rtsp_message_get_header (response, RTSP_HDR_WWW_AUTHENTICATE, &hdr, 0) == RTSP_OK) { gst_rtspsrc_parse_auth_hdr (hdr, &avail_methods); } @@ -2772,7 +2772,7 @@ next: return RTSP_OK; /* store new content base if any */ - rtsp_message_get_header (response, RTSP_HDR_CONTENT_BASE, &content_base); + rtsp_message_get_header (response, RTSP_HDR_CONTENT_BASE, &content_base, 0); g_free (src->content_base); src->content_base = g_strdup (content_base); @@ -2905,53 +2905,63 @@ error_response: static gboolean gst_rtspsrc_parse_methods (GstRTSPSrc * src, RTSPMessage * response) { + RTSPHeaderField field; gchar *respoptions = NULL; gchar **options; + gint indx = 0; gint i; /* clear supported methods */ src->methods = 0; - /* Try Allow Header first */ - rtsp_message_get_header (response, RTSP_HDR_ALLOW, &respoptions); - if (!respoptions) - /* Then maybe Public Header... */ - rtsp_message_get_header (response, RTSP_HDR_PUBLIC, &respoptions); - if (!respoptions) { - /* this field is not required, assume the server supports - * DESCRIBE, SETUP and PLAY */ + /* try the Allow header first */ + field = RTSP_HDR_ALLOW; + while (TRUE) { + rtsp_message_get_header (response, field, &respoptions, indx); + if (indx == 0 && !respoptions) { + /* if no Allow header was found then try the Public header... */ + field = RTSP_HDR_PUBLIC; + rtsp_message_get_header (response, field, &respoptions, indx); + } + if (!respoptions) + break; + + /* If we get here, the server gave a list of supported methods, parse + * them here. The string is like: + * + * OPTIONS, DESCRIBE, ANNOUNCE, PLAY, SETUP, ... + */ + options = g_strsplit (respoptions, ",", 0); + + for (i = 0; options[i]; i++) { + gchar *stripped; + gint method; + + stripped = g_strstrip (options[i]); + method = rtsp_find_method (stripped); + + /* keep bitfield of supported methods */ + if (method != RTSP_INVALID) + src->methods |= method; + } + g_strfreev (options); + + indx++; + } + + if (src->methods == 0) { + /* neither Allow nor Public are required, assume the server supports + * DESCRIBE, SETUP, PLAY and PAUSE */ GST_DEBUG_OBJECT (src, "could not get OPTIONS"); src->methods = RTSP_DESCRIBE | RTSP_SETUP | RTSP_PLAY | RTSP_PAUSE; - goto done; } - /* If we get here, the server gave a list of supported methods, parse - * them here. The string is like: - * - * OPTIONS, DESCRIBE, ANNOUNCE, PLAY, SETUP, ... - */ - options = g_strsplit (respoptions, ",", 0); - - for (i = 0; options[i]; i++) { - gchar *stripped; - gint method; - - stripped = g_strstrip (options[i]); - method = rtsp_find_method (stripped); - - /* keep bitfield of supported methods */ - if (method != RTSP_INVALID) - src->methods |= method; - } - g_strfreev (options); - /* we need describe and setup */ if (!(src->methods & RTSP_DESCRIBE)) goto no_describe; if (!(src->methods & RTSP_SETUP)) goto no_setup; -done: return TRUE; /* ERRORS */ @@ -3219,7 +3229,7 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src) gchar *resptrans = NULL; RTSPTransport transport = { 0 }; - rtsp_message_get_header (&response, RTSP_HDR_TRANSPORT, &resptrans); + rtsp_message_get_header (&response, RTSP_HDR_TRANSPORT, &resptrans, 0); if (!resptrans) goto no_transport; @@ -3425,7 +3435,7 @@ gst_rtspsrc_open (GstRTSPSrc * src) goto send_error; /* check if reply is SDP */ - rtsp_message_get_header (&response, RTSP_HDR_CONTENT_TYPE, &respcont); + rtsp_message_get_header (&response, RTSP_HDR_CONTENT_TYPE, &respcont, 0); /* could not be set but since the request returned OK, we assume it * was SDP, else check it. */ if (respcont) { @@ -3756,14 +3766,14 @@ gst_rtspsrc_play (GstRTSPSrc * src) /* parse RTP npt field. This is the current position in the stream (Normal * Play Time) and should be put in the NEWSEGMENT position field. */ - if (rtsp_message_get_header (&response, RTSP_HDR_RANGE, &range) == RTSP_OK) + if (rtsp_message_get_header (&response, RTSP_HDR_RANGE, &range, 0) == RTSP_OK) gst_rtspsrc_parse_range (src, range); /* parse the RTP-Info header field (if ANY) to get the base seqnum and timestamp * for the RTP packets. If this is not present, we assume all starts from 0... * This is info for the RTP session manager that we pass to it in caps. */ if (rtsp_message_get_header (&response, RTSP_HDR_RTP_INFO, - &rtpinfo) == RTSP_OK) + &rtpinfo, 0) == RTSP_OK) gst_rtspsrc_parse_rtpinfo (src, rtpinfo); rtsp_message_unset (&response); diff --git a/gst/rtsp/rtspconnection.c b/gst/rtsp/rtspconnection.c index 086dddcb79..e20de2314c 100644 --- a/gst/rtsp/rtspconnection.c +++ b/gst/rtsp/rtspconnection.c @@ -273,15 +273,7 @@ timeout: } static void -append_header (gint key, gchar * value, GString * str) -{ - const gchar *keystr = rtsp_header_as_text (key); - - g_string_append_printf (str, "%s: %s\r\n", keystr, value); -} - -static void -append_auth_header (RTSPConnection * conn, RTSPMessage * message, GString * str) +add_auth_header (RTSPConnection * conn, RTSPMessage * message) { switch (conn->auth_method) { case RTSP_AUTH_BASIC:{ @@ -290,7 +282,7 @@ append_auth_header (RTSPConnection * conn, RTSPMessage * message, GString * str) gchar *user_pass64 = util_base64_encode (user_pass, strlen (user_pass)); gchar *auth_string = g_strdup_printf ("Basic %s", user_pass64); - append_header (RTSP_HDR_AUTHORIZATION, auth_string, str); + rtsp_message_add_header (message, RTSP_HDR_AUTHORIZATION, auth_string); g_free (user_pass); g_free (user_pass64); @@ -427,6 +419,12 @@ rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message, "CSeq: %d\r\n", rtsp_method_as_text (message->type_data.request.method), message->type_data.request.uri, conn->cseq++); + /* add session id if we have one */ + if (conn->session_id[0] != '\0') { + rtsp_message_add_header (message, RTSP_HDR_SESSION, conn->session_id); + } + /* add any authentication headers */ + add_auth_header (conn, message); break; case RTSP_MESSAGE_RESPONSE: /* create response string */ @@ -455,39 +453,28 @@ rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message, break; } - /* append specific headers and body */ - switch (message->type) { - case RTSP_MESSAGE_REQUEST: - case RTSP_MESSAGE_RESPONSE: - /* append session id if we have one */ - if (conn->session_id[0] != '\0') { - append_header (RTSP_HDR_SESSION, conn->session_id, str); - } - /* append headers */ - g_hash_table_foreach (message->hdr_fields, (GHFunc) append_header, str); + /* append headers and body */ + if (message->type != RTSP_MESSAGE_DATA) { + /* append headers */ + rtsp_message_append_headers (message, str); - /* Append any authentication headers */ - append_auth_header (conn, message, str); + /* append Content-Length and body if needed */ + if (message->body != NULL && message->body_size > 0) { + gchar *len; - /* append Content-Length and body if needed */ - if (message->body != NULL && message->body_size > 0) { - gchar *len; - - len = g_strdup_printf ("%d", message->body_size); - append_header (RTSP_HDR_CONTENT_LENGTH, len, str); - g_free (len); - /* header ends here */ - g_string_append (str, "\r\n"); - str = - g_string_append_len (str, (gchar *) message->body, - message->body_size); - } else { - /* just end headers */ - g_string_append (str, "\r\n"); - } - break; - default: - break; + len = g_strdup_printf ("%d", message->body_size); + g_string_append_printf (str, "%s: %s\r\n", + rtsp_header_as_text (RTSP_HDR_CONTENT_LENGTH), len); + g_free (len); + /* header ends here */ + g_string_append (str, "\r\n"); + str = + g_string_append_len (str, (gchar *) message->body, + message->body_size); + } else { + /* just end headers */ + g_string_append (str, "\r\n"); + } } /* write request */ @@ -914,7 +901,7 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg, if (need_body) { /* see if there is a Content-Length header */ if (rtsp_message_get_header (msg, RTSP_HDR_CONTENT_LENGTH, - &hdrval) == RTSP_OK) { + &hdrval, 0) == RTSP_OK) { /* there is, read the body */ content_length = atol (hdrval); RTSP_CHECK (read_body (conn, content_length, msg, timeout), read_error); @@ -925,7 +912,7 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg, gchar *session_id; if (rtsp_message_get_header (msg, RTSP_HDR_SESSION, - &session_id) == RTSP_OK) { + &session_id, 0) == RTSP_OK) { gint sesslen, maxlen, i; /* default session timeout */ diff --git a/gst/rtsp/rtspextwms.c b/gst/rtsp/rtspextwms.c index b79a458608..e336176a2a 100644 --- a/gst/rtsp/rtspextwms.c +++ b/gst/rtsp/rtspextwms.c @@ -86,7 +86,7 @@ rtsp_ext_wms_after_send (RTSPExtensionCtx * ctx, RTSPMessage * req, { gchar *server = NULL; - rtsp_message_get_header (resp, RTSP_HDR_SERVER, &server); + rtsp_message_get_header (resp, RTSP_HDR_SERVER, &server, 0); if (server && g_str_has_prefix (server, SERVER_PREFIX)) rext->active = TRUE; else diff --git a/gst/rtsp/rtspmessage.c b/gst/rtsp/rtspmessage.c index ed622c3375..2cb12bf3e1 100644 --- a/gst/rtsp/rtspmessage.c +++ b/gst/rtsp/rtspmessage.c @@ -45,6 +45,24 @@ #include "rtspmessage.h" +typedef struct _RTSPKeyValue +{ + RTSPHeaderField field; + gchar *value; +} RTSPKeyValue; + +static void +key_value_foreach (GArray * array, GFunc func, gpointer user_data) +{ + guint i; + + g_return_if_fail (array != NULL); + + for (i = 0; i < array->len; i++) { + (*func) (&g_array_index (array, RTSPKeyValue, i), user_data); + } +} + RTSPResult rtsp_message_new (RTSPMessage ** msg) { @@ -67,8 +85,7 @@ rtsp_message_init (RTSPMessage * msg) rtsp_message_unset (msg); msg->type = RTSP_MESSAGE_INVALID; - msg->hdr_fields = - g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue)); return RTSP_OK; } @@ -101,8 +118,7 @@ rtsp_message_init_request (RTSPMessage * msg, RTSPMethod method, msg->type = RTSP_MESSAGE_REQUEST; msg->type_data.request.method = method; msg->type_data.request.uri = g_strdup (uri); - msg->hdr_fields = - g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue)); return RTSP_OK; } @@ -136,19 +152,19 @@ rtsp_message_init_response (RTSPMessage * msg, RTSPStatusCode code, msg->type = RTSP_MESSAGE_RESPONSE; msg->type_data.response.code = code; msg->type_data.response.reason = g_strdup (reason); - msg->hdr_fields = - g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue)); if (request) { gchar *header; /* copy CSEQ */ - if (rtsp_message_get_header (request, RTSP_HDR_CSEQ, &header) == RTSP_OK) { + if (rtsp_message_get_header (request, RTSP_HDR_CSEQ, &header, 0) == RTSP_OK) { rtsp_message_add_header (msg, RTSP_HDR_CSEQ, header); } /* copy session id */ - if (rtsp_message_get_header (request, RTSP_HDR_SESSION, &header) == RTSP_OK) { + if (rtsp_message_get_header (request, RTSP_HDR_SESSION, &header, + 0) == RTSP_OK) { char *pos; header = g_strdup (header); @@ -201,7 +217,7 @@ rtsp_message_unset (RTSPMessage * msg) } if (msg->hdr_fields != NULL) - g_hash_table_destroy (msg->hdr_fields); + g_array_free (msg->hdr_fields, TRUE); g_free (msg->body); @@ -228,44 +244,80 @@ RTSPResult rtsp_message_add_header (RTSPMessage * msg, RTSPHeaderField field, const gchar * value) { + RTSPKeyValue key_value; + g_return_val_if_fail (msg != NULL, RTSP_EINVAL); g_return_val_if_fail (value != NULL, RTSP_EINVAL); - g_hash_table_insert (msg->hdr_fields, GINT_TO_POINTER (field), - g_strdup (value)); + key_value.field = field; + key_value.value = g_strdup (value); + + g_array_append_val (msg->hdr_fields, key_value); return RTSP_OK; } RTSPResult -rtsp_message_remove_header (RTSPMessage * msg, RTSPHeaderField field) +rtsp_message_remove_header (RTSPMessage * msg, RTSPHeaderField field, gint indx) { + RTSPResult res = RTSP_ENOTIMPL; + guint i = 0; + gint cnt = 0; + g_return_val_if_fail (msg != NULL, RTSP_EINVAL); - g_hash_table_remove (msg->hdr_fields, GINT_TO_POINTER (field)); + while (i < msg->hdr_fields->len) { + RTSPKeyValue key_value = g_array_index (msg->hdr_fields, RTSPKeyValue, i); - return RTSP_ENOTIMPL; + if (key_value.field == field && (indx == -1 || cnt++ == indx)) { + g_array_remove_index (msg->hdr_fields, i); + res = RTSP_OK; + if (indx != -1) + break; + } else { + i++; + } + } + + return res; } RTSPResult rtsp_message_get_header (const RTSPMessage * msg, RTSPHeaderField field, - gchar ** value) + gchar ** value, gint indx) { - gchar *val; + guint i; + gint cnt = 0; g_return_val_if_fail (msg != NULL, RTSP_EINVAL); - if (msg->type == RTSP_MESSAGE_INVALID || msg->type == RTSP_MESSAGE_DATA) - return RTSP_ENOTIMPL; + for (i = 0; i < msg->hdr_fields->len; i++) { + RTSPKeyValue key_value = g_array_index (msg->hdr_fields, RTSPKeyValue, i); - val = g_hash_table_lookup (msg->hdr_fields, GINT_TO_POINTER (field)); - if (val == NULL) - return RTSP_ENOTIMPL; + if (key_value.field == field && cnt++ == indx) { + if (value) + *value = key_value.value; + return RTSP_OK; + } + } - if (value) - *value = val; + return RTSP_ENOTIMPL; +} - return RTSP_OK; +void +rtsp_message_append_headers (const RTSPMessage * msg, GString * str) +{ + guint i; + + g_return_if_fail (msg != NULL); + g_return_if_fail (str != NULL); + + for (i = 0; i < msg->hdr_fields->len; i++) { + RTSPKeyValue key_value = g_array_index (msg->hdr_fields, RTSPKeyValue, i); + const gchar *keystr = rtsp_header_as_text (key_value.field); + + g_string_append_printf (str, "%s: %s\r\n", keystr, key_value.value); + } } RTSPResult @@ -352,12 +404,12 @@ dump_mem (guint8 * mem, guint size) } static void -dump_key_value (gpointer key, gpointer value, gpointer data) +dump_key_value (gpointer data, gpointer user_data) { - RTSPHeaderField field = GPOINTER_TO_INT (key); + RTSPKeyValue *key_value = (RTSPKeyValue *) data; - g_print (" key: '%s', value: '%s'\n", rtsp_header_as_text (field), - (gchar *) value); + g_print (" key: '%s', value: '%s'\n", + rtsp_header_as_text (key_value->field), key_value->value); } RTSPResult @@ -376,7 +428,7 @@ rtsp_message_dump (RTSPMessage * msg) rtsp_method_as_text (msg->type_data.request.method)); g_print (" uri: '%s'\n", msg->type_data.request.uri); g_print (" headers:\n"); - g_hash_table_foreach (msg->hdr_fields, dump_key_value, NULL); + key_value_foreach (msg->hdr_fields, dump_key_value, NULL); g_print (" body:\n"); rtsp_message_get_body (msg, &data, &size); dump_mem (data, size); @@ -387,7 +439,7 @@ rtsp_message_dump (RTSPMessage * msg) g_print (" code: '%d'\n", msg->type_data.response.code); g_print (" reason: '%s'\n", msg->type_data.response.reason); g_print (" headers:\n"); - g_hash_table_foreach (msg->hdr_fields, dump_key_value, NULL); + key_value_foreach (msg->hdr_fields, dump_key_value, NULL); rtsp_message_get_body (msg, &data, &size); g_print (" body: length %d\n", size); dump_mem (data, size); diff --git a/gst/rtsp/rtspmessage.h b/gst/rtsp/rtspmessage.h index 089676c13e..2c099f17ff 100644 --- a/gst/rtsp/rtspmessage.h +++ b/gst/rtsp/rtspmessage.h @@ -75,7 +75,7 @@ typedef struct _RTSPMessage } data; } type_data; - GHashTable *hdr_fields; + GArray *hdr_fields; guint8 *body; guint body_size; @@ -112,10 +112,15 @@ RTSPResult rtsp_message_add_header (RTSPMessage *msg, RTSPHeaderField field, const gchar *value); RTSPResult rtsp_message_remove_header (RTSPMessage *msg, - RTSPHeaderField field); + RTSPHeaderField field, + gint indx); RTSPResult rtsp_message_get_header (const RTSPMessage *msg, RTSPHeaderField field, - gchar **value); + gchar **value, + gint indx); + +void rtsp_message_append_headers (const RTSPMessage *msg, + GString *str); RTSPResult rtsp_message_set_body (RTSPMessage *msg, const guint8 *data,