rtspdefs: add RFC 4567 headers and status code
[platform/upstream/gstreamer.git] / gst-libs / gst / rtsp / gstrtspdefs.c
1 /* GStreamer
2  * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 /*
20  * Unless otherwise indicated, Source Code is licensed under MIT license.
21  * See further explanation attached in License Statement (distributed in the file
22  * LICENSE).
23  *
24  * Permission is hereby granted, free of charge, to any person obtaining a copy of
25  * this software and associated documentation files (the "Software"), to deal in
26  * the Software without restriction, including without limitation the rights to
27  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
28  * of the Software, and to permit persons to whom the Software is furnished to do
29  * so, subject to the following conditions:
30  *
31  * The above copyright notice and this permission notice shall be included in all
32  * copies or substantial portions of the Software.
33  *
34  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40  * SOFTWARE.
41  */
42
43 /**
44  * SECTION:gstrtspdefs
45  * @short_description: common RTSP defines
46  * @see_also: gstrtspurl, gstrtspconnection
47  *  
48  * Provides common defines for the RTSP library. 
49  *  
50  * Last reviewed on 2007-07-24 (0.10.14)
51  */
52
53 #include <errno.h>
54
55 #include "gstrtspdefs.h"
56
57 struct rtsp_header
58 {
59   const gchar *name;
60   gboolean multiple;
61 };
62
63 static const gchar *rtsp_methods[] = {
64   "DESCRIBE",
65   "ANNOUNCE",
66   "GET_PARAMETER",
67   "OPTIONS",
68   "PAUSE",
69   "PLAY",
70   "RECORD",
71   "REDIRECT",
72   "SETUP",
73   "SET_PARAMETER",
74   "TEARDOWN",
75   "GET",
76   "POST",
77   NULL
78 };
79
80 static struct rtsp_header rtsp_headers[] = {
81   {"Accept", TRUE},
82   {"Accept-Encoding", TRUE},
83   {"Accept-Language", TRUE},
84   {"Allow", TRUE},
85   {"Authorization", FALSE},
86   {"Bandwidth", FALSE},
87   {"Blocksize", FALSE},
88   {"Cache-Control", TRUE},
89   {"Conference", FALSE},
90   {"Connection", TRUE},
91   {"Content-Base", FALSE},
92   {"Content-Encoding", TRUE},
93   {"Content-Language", TRUE},
94   {"Content-Length", FALSE},
95   {"Content-Location", FALSE},
96   {"Content-Type", FALSE},
97   {"CSeq", FALSE},
98   {"Date", FALSE},
99   {"Expires", FALSE},
100   {"From", FALSE},
101   {"If-Modified-Since", FALSE},
102   {"Last-Modified", FALSE},
103   {"Proxy-Authenticate", TRUE},
104   {"Proxy-Require", TRUE},
105   {"Public", TRUE},
106   {"Range", FALSE},
107   {"Referer", FALSE},
108   {"Require", TRUE},
109   {"Retry-After", FALSE},
110   {"RTP-Info", TRUE},
111   {"Scale", FALSE},
112   {"Session", FALSE},
113   {"Server", FALSE},
114   {"Speed", FALSE},
115   {"Transport", TRUE},
116   {"Unsupported", FALSE},
117   {"User-Agent", FALSE},
118   {"Via", TRUE},
119   {"WWW-Authenticate", TRUE},
120
121   /* Real extensions */
122   {"ClientChallenge", FALSE},
123   {"RealChallenge1", FALSE},
124   {"RealChallenge2", FALSE},
125   {"RealChallenge3", FALSE},
126   {"Subscribe", FALSE},
127   {"Alert", FALSE},
128   {"ClientID", FALSE},
129   {"CompanyID", FALSE},
130   {"GUID", FALSE},
131   {"RegionData", FALSE},
132   {"SupportsMaximumASMBandwidth", FALSE},
133   {"Language", FALSE},
134   {"PlayerStarttime", FALSE},
135
136   /* Since 0.10.16 */
137   {"Location", FALSE},
138
139   /* Since 0.10.23 */
140   {"ETag", FALSE},
141   {"If-Match", TRUE},
142
143   /* WM extensions [MS-RTSP] Since 0.10.23 */
144   {"Accept-Charset", TRUE},
145   {"Supported", TRUE},
146   {"Vary", TRUE},
147   {"X-Accelerate-Streaming", FALSE},
148   {"X-Accept-Authentication", FALSE},
149   {"X-Accept-Proxy-Authentication", FALSE},
150   {"X-Broadcast-Id", FALSE},
151   {"X-Burst-Streaming", FALSE},
152   {"X-Notice", FALSE},
153   {"X-Player-Lag-Time", FALSE},
154   {"X-Playlist", FALSE},
155   {"X-Playlist-Change-Notice", FALSE},
156   {"X-Playlist-Gen-Id", FALSE},
157   {"X-Playlist-Seek-Id", FALSE},
158   {"X-Proxy-Client-Agent", FALSE},
159   {"X-Proxy-Client-Verb", FALSE},
160   {"X-Receding-PlaylistChange", FALSE},
161   {"X-RTP-Info", FALSE},
162   {"X-StartupProfile", FALSE},
163
164   /* Since 0.10.24 */
165   {"Timestamp", FALSE},
166
167   /* Since 0.10.25 */
168   {"Authentication-Info", FALSE},
169   {"Host", FALSE},
170   {"Pragma", TRUE},
171   {"X-Server-IP-Address", FALSE},
172   {"X-Sessioncookie", FALSE},
173
174   /* Since 0.10.36 */
175   {"RTCP-Interval", FALSE},
176
177   /* Since 1.4 */
178   {"KeyMgmt", FALSE},
179
180   {NULL, FALSE}
181 };
182
183 #define DEF_STATUS(c, t) \
184   g_hash_table_insert (statuses, GUINT_TO_POINTER(c), (gpointer) t)
185
186 static GHashTable *
187 rtsp_init_status (void)
188 {
189   GHashTable *statuses = g_hash_table_new (NULL, NULL);
190
191   DEF_STATUS (GST_RTSP_STS_CONTINUE, "Continue");
192   DEF_STATUS (GST_RTSP_STS_OK, "OK");
193   DEF_STATUS (GST_RTSP_STS_CREATED, "Created");
194   DEF_STATUS (GST_RTSP_STS_LOW_ON_STORAGE, "Low on Storage Space");
195   DEF_STATUS (GST_RTSP_STS_MULTIPLE_CHOICES, "Multiple Choices");
196   DEF_STATUS (GST_RTSP_STS_MOVED_PERMANENTLY, "Moved Permanently");
197   DEF_STATUS (GST_RTSP_STS_MOVE_TEMPORARILY, "Move Temporarily");
198   DEF_STATUS (GST_RTSP_STS_SEE_OTHER, "See Other");
199   DEF_STATUS (GST_RTSP_STS_NOT_MODIFIED, "Not Modified");
200   DEF_STATUS (GST_RTSP_STS_USE_PROXY, "Use Proxy");
201   DEF_STATUS (GST_RTSP_STS_BAD_REQUEST, "Bad Request");
202   DEF_STATUS (GST_RTSP_STS_UNAUTHORIZED, "Unauthorized");
203   DEF_STATUS (GST_RTSP_STS_PAYMENT_REQUIRED, "Payment Required");
204   DEF_STATUS (GST_RTSP_STS_FORBIDDEN, "Forbidden");
205   DEF_STATUS (GST_RTSP_STS_NOT_FOUND, "Not Found");
206   DEF_STATUS (GST_RTSP_STS_METHOD_NOT_ALLOWED, "Method Not Allowed");
207   DEF_STATUS (GST_RTSP_STS_NOT_ACCEPTABLE, "Not Acceptable");
208   DEF_STATUS (GST_RTSP_STS_PROXY_AUTH_REQUIRED,
209       "Proxy Authentication Required");
210   DEF_STATUS (GST_RTSP_STS_REQUEST_TIMEOUT, "Request Time-out");
211   DEF_STATUS (GST_RTSP_STS_GONE, "Gone");
212   DEF_STATUS (GST_RTSP_STS_LENGTH_REQUIRED, "Length Required");
213   DEF_STATUS (GST_RTSP_STS_PRECONDITION_FAILED, "Precondition Failed");
214   DEF_STATUS (GST_RTSP_STS_REQUEST_ENTITY_TOO_LARGE,
215       "Request Entity Too Large");
216   DEF_STATUS (GST_RTSP_STS_REQUEST_URI_TOO_LARGE, "Request-URI Too Large");
217   DEF_STATUS (GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
218   DEF_STATUS (GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD,
219       "Parameter Not Understood");
220   DEF_STATUS (GST_RTSP_STS_CONFERENCE_NOT_FOUND, "Conference Not Found");
221   DEF_STATUS (GST_RTSP_STS_NOT_ENOUGH_BANDWIDTH, "Not Enough Bandwidth");
222   DEF_STATUS (GST_RTSP_STS_SESSION_NOT_FOUND, "Session Not Found");
223   DEF_STATUS (GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
224       "Method Not Valid in This State");
225   DEF_STATUS (GST_RTSP_STS_HEADER_FIELD_NOT_VALID_FOR_RESOURCE,
226       "Header Field Not Valid for Resource");
227   DEF_STATUS (GST_RTSP_STS_INVALID_RANGE, "Invalid Range");
228   DEF_STATUS (GST_RTSP_STS_PARAMETER_IS_READONLY, "Parameter Is Read-Only");
229   DEF_STATUS (GST_RTSP_STS_AGGREGATE_OPERATION_NOT_ALLOWED,
230       "Aggregate operation not allowed");
231   DEF_STATUS (GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED,
232       "Only aggregate operation allowed");
233   DEF_STATUS (GST_RTSP_STS_UNSUPPORTED_TRANSPORT, "Unsupported transport");
234   DEF_STATUS (GST_RTSP_STS_DESTINATION_UNREACHABLE, "Destination unreachable");
235   DEF_STATUS (GST_RTSP_STS_KEY_MANAGEMENT_FAILURE, "Key management failure");
236   DEF_STATUS (GST_RTSP_STS_INTERNAL_SERVER_ERROR, "Internal Server Error");
237   DEF_STATUS (GST_RTSP_STS_NOT_IMPLEMENTED, "Not Implemented");
238   DEF_STATUS (GST_RTSP_STS_BAD_GATEWAY, "Bad Gateway");
239   DEF_STATUS (GST_RTSP_STS_SERVICE_UNAVAILABLE, "Service Unavailable");
240   DEF_STATUS (GST_RTSP_STS_GATEWAY_TIMEOUT, "Gateway Time-out");
241   DEF_STATUS (GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
242       "RTSP Version not supported");
243   DEF_STATUS (GST_RTSP_STS_OPTION_NOT_SUPPORTED, "Option not supported");
244
245   return statuses;
246 }
247
248 /**
249  * gst_rtsp_strresult:
250  * @result: a #GstRTSPResult
251  *
252  * Convert @result in a human readable string.
253  *
254  * Returns: a newly allocated string. g_free() after usage.
255  */
256 gchar *
257 gst_rtsp_strresult (GstRTSPResult result)
258 {
259   switch (result) {
260     case GST_RTSP_OK:
261       return g_strdup ("OK");
262     case GST_RTSP_ESYS:
263       return g_strdup ("System error");
264     case GST_RTSP_ENET:
265       return g_strdup ("Network error");
266     case GST_RTSP_ERROR:
267       return g_strdup ("Generic error");
268     case GST_RTSP_EINVAL:
269       return g_strdup ("Invalid parameter specified");
270     case GST_RTSP_EINTR:
271       return g_strdup ("Operation interrupted");
272     case GST_RTSP_ENOMEM:
273       return g_strdup ("Out of memory");
274     case GST_RTSP_ERESOLV:
275       return g_strdup ("Cannot resolve host");
276     case GST_RTSP_ENOTIMPL:
277       return g_strdup ("Function not implemented");
278     case GST_RTSP_EPARSE:
279       return g_strdup ("Parse error");
280     case GST_RTSP_EWSASTART:
281       return g_strdup ("Error on WSAStartup");
282     case GST_RTSP_EWSAVERSION:
283       return g_strdup ("Windows sockets are not version 0x202");
284     case GST_RTSP_EEOF:
285       return g_strdup ("Received end-of-file");
286     case GST_RTSP_ENOTIP:
287       return g_strdup ("Host is not a valid IP address");
288     case GST_RTSP_ETIMEOUT:
289       return g_strdup ("Timeout while waiting for server response");
290     case GST_RTSP_ETGET:
291       return g_strdup ("Tunnel GET request received");
292     case GST_RTSP_ETPOST:
293       return g_strdup ("Tunnel POST request received");
294     case GST_RTSP_ELAST:
295     default:
296       return g_strdup_printf ("Unknown error (%d)", result);
297   }
298 }
299
300 /**
301  * gst_rtsp_method_as_text:
302  * @method: a #GstRTSPMethod
303  *
304  * Convert @method to a string.
305  *
306  * Returns: a string representation of @method.
307  */
308 const gchar *
309 gst_rtsp_method_as_text (GstRTSPMethod method)
310 {
311   gint i;
312
313   if (method == GST_RTSP_INVALID)
314     return NULL;
315
316   i = 0;
317   while ((method & 1) == 0) {
318     i++;
319     method >>= 1;
320   }
321   return rtsp_methods[i];
322 }
323
324 /**
325  * gst_rtsp_version_as_text:
326  * @version: a #GstRTSPVersion
327  *
328  * Convert @version to a string.
329  *
330  * Returns: a string representation of @version.
331  */
332 const gchar *
333 gst_rtsp_version_as_text (GstRTSPVersion version)
334 {
335   switch (version) {
336     case GST_RTSP_VERSION_1_0:
337       return "1.0";
338
339     case GST_RTSP_VERSION_1_1:
340       return "1.1";
341
342     default:
343       return "0.0";
344   }
345 }
346
347 /**
348  * gst_rtsp_header_as_text:
349  * @field: a #GstRTSPHeaderField
350  *
351  * Convert @field to a string.
352  *
353  * Returns: a string representation of @field.
354  */
355 const gchar *
356 gst_rtsp_header_as_text (GstRTSPHeaderField field)
357 {
358   if (field == GST_RTSP_HDR_INVALID)
359     return NULL;
360   else
361     return rtsp_headers[field - 1].name;
362 }
363
364 /**
365  * gst_rtsp_status_as_text:
366  * @code: a #GstRTSPStatusCode
367  *
368  * Convert @code to a string.
369  *
370  * Returns: a string representation of @code.
371  */
372 const gchar *
373 gst_rtsp_status_as_text (GstRTSPStatusCode code)
374 {
375   static GHashTable *statuses;
376
377   if (G_UNLIKELY (statuses == NULL))
378     statuses = rtsp_init_status ();
379
380   return g_hash_table_lookup (statuses, GUINT_TO_POINTER (code));
381 }
382
383 /**
384  * gst_rtsp_find_header_field:
385  * @header: a header string
386  *
387  * Convert @header to a #GstRTSPHeaderField.
388  *
389  * Returns: a #GstRTSPHeaderField for @header or #GST_RTSP_HDR_INVALID if the
390  * header field is unknown.
391  */
392 GstRTSPHeaderField
393 gst_rtsp_find_header_field (const gchar * header)
394 {
395   gint idx;
396
397   for (idx = 0; rtsp_headers[idx].name; idx++) {
398     if (g_ascii_strcasecmp (rtsp_headers[idx].name, header) == 0) {
399       return idx + 1;
400     }
401   }
402   return GST_RTSP_HDR_INVALID;
403 }
404
405 /**
406  * gst_rtsp_find_method:
407  * @method: a method
408  *
409  * Convert @method to a #GstRTSPMethod.
410  *
411  * Returns: a #GstRTSPMethod for @method or #GST_RTSP_INVALID if the
412  * method is unknown.
413  */
414 GstRTSPMethod
415 gst_rtsp_find_method (const gchar * method)
416 {
417   gint idx;
418
419   for (idx = 0; rtsp_methods[idx]; idx++) {
420     if (g_ascii_strcasecmp (rtsp_methods[idx], method) == 0) {
421       return (1 << idx);
422     }
423   }
424   return GST_RTSP_INVALID;
425 }
426
427 /**
428  * gst_rtsp_options_as_text:
429  * @options: one or more #GstRTSPMethod
430  *
431  * Convert @options to a string.
432  *
433  * Returns: a new string of @options. g_free() after usage.
434  */
435 gchar *
436 gst_rtsp_options_as_text (GstRTSPMethod options)
437 {
438   GString *str;
439
440   str = g_string_new ("");
441
442   if (options & GST_RTSP_OPTIONS)
443     g_string_append (str, "OPTIONS, ");
444   if (options & GST_RTSP_DESCRIBE)
445     g_string_append (str, "DESCRIBE, ");
446   if (options & GST_RTSP_ANNOUNCE)
447     g_string_append (str, "ANNOUNCE, ");
448   if (options & GST_RTSP_GET_PARAMETER)
449     g_string_append (str, "GET_PARAMETER, ");
450   if (options & GST_RTSP_PAUSE)
451     g_string_append (str, "PAUSE, ");
452   if (options & GST_RTSP_PLAY)
453     g_string_append (str, "PLAY, ");
454   if (options & GST_RTSP_RECORD)
455     g_string_append (str, "RECORD, ");
456   if (options & GST_RTSP_REDIRECT)
457     g_string_append (str, "REDIRECT, ");
458   if (options & GST_RTSP_SETUP)
459     g_string_append (str, "SETUP, ");
460   if (options & GST_RTSP_SET_PARAMETER)
461     g_string_append (str, "SET_PARAMETER, ");
462   if (options & GST_RTSP_TEARDOWN)
463     g_string_append (str, "TEARDOWN, ");
464
465   /* remove trailing ", " if there is one */
466   if (str->len > 2)
467     str = g_string_truncate (str, str->len - 2);
468
469   return g_string_free (str, FALSE);
470 }
471
472 /**
473  * gst_rtsp_options_from_text:
474  * @options: a comma separated list of options
475  *
476  * Convert the comma separated list @options to a #GstRTSPMethod bitwise or
477  * of methods. This functions is the reverse of gst_rtsp_options_as_text().
478  *
479  * Returns: a #GstRTSPMethod
480  *
481  * Since: 1.2
482  */
483 GstRTSPMethod
484 gst_rtsp_options_from_text (const gchar * options)
485 {
486   GstRTSPMethod methods;
487   gchar **ostr;
488   gint i;
489
490   /* The string is like:
491    * OPTIONS, DESCRIBE, ANNOUNCE, PLAY, SETUP, ...
492    */
493   ostr = g_strsplit (options, ",", 0);
494
495   methods = 0;
496   for (i = 0; ostr[i]; i++) {
497     gchar *stripped;
498     GstRTSPMethod method;
499
500     stripped = g_strstrip (ostr[i]);
501     method = gst_rtsp_find_method (stripped);
502
503     /* keep bitfield of supported methods */
504     if (method != GST_RTSP_INVALID)
505       methods |= method;
506   }
507   g_strfreev (ostr);
508
509   return methods;
510 }
511
512 /**
513  * gst_rtsp_header_allow_multiple:
514  * @field: a #GstRTSPHeaderField
515  *
516  * Check whether @field may appear multiple times in a message.
517  *
518  * Returns: %TRUE if multiple headers are allowed.
519  */
520 gboolean
521 gst_rtsp_header_allow_multiple (GstRTSPHeaderField field)
522 {
523   if (field == GST_RTSP_HDR_INVALID)
524     return FALSE;
525   else
526     return rtsp_headers[field - 1].multiple;
527 }