parseurl.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /*
  2. * Copyright (C) 2009 Andrej Stepanchuk
  3. * Copyright (C) 2009-2010 Howard Chu
  4. *
  5. * This file is part of librtmp.
  6. *
  7. * librtmp is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1,
  10. * or (at your option) any later version.
  11. *
  12. * librtmp 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
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with librtmp see the file COPYING. If not, write to
  19. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  20. * Boston, MA 02110-1301, USA.
  21. * http://www.gnu.org/copyleft/lgpl.html
  22. */
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <assert.h>
  26. #include <ctype.h>
  27. #include "rtmp_sys.h"
  28. #include "log.h"
  29. int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port,
  30. AVal *playpath, AVal *app)
  31. {
  32. char *p, *end, *col, *ques, *slash;
  33. RTMP_Log(RTMP_LOGDEBUG, "Parsing...");
  34. *protocol = RTMP_PROTOCOL_RTMP;
  35. *port = 0;
  36. playpath->av_len = 0;
  37. playpath->av_val = NULL;
  38. app->av_len = 0;
  39. app->av_val = NULL;
  40. /* Old School Parsing */
  41. /* look for usual :// pattern */
  42. p = strstr(url, "://");
  43. if(!p) {
  44. RTMP_Log(RTMP_LOGERROR, "RTMP URL: No :// in url!");
  45. return FALSE;
  46. }
  47. {
  48. int len = (int)(p-url);
  49. if(len == 4 && strncasecmp(url, "rtmp", 4)==0)
  50. *protocol = RTMP_PROTOCOL_RTMP;
  51. else if(len == 5 && strncasecmp(url, "rtmpt", 5)==0)
  52. *protocol = RTMP_PROTOCOL_RTMPT;
  53. else if(len == 5 && strncasecmp(url, "rtmps", 5)==0)
  54. *protocol = RTMP_PROTOCOL_RTMPS;
  55. else if(len == 5 && strncasecmp(url, "rtmpe", 5)==0)
  56. *protocol = RTMP_PROTOCOL_RTMPE;
  57. else if(len == 5 && strncasecmp(url, "rtmfp", 5)==0)
  58. *protocol = RTMP_PROTOCOL_RTMFP;
  59. else if(len == 6 && strncasecmp(url, "rtmpte", 6)==0)
  60. *protocol = RTMP_PROTOCOL_RTMPTE;
  61. else if(len == 6 && strncasecmp(url, "rtmpts", 6)==0)
  62. *protocol = RTMP_PROTOCOL_RTMPTS;
  63. else {
  64. RTMP_Log(RTMP_LOGWARNING, "Unknown protocol!\n");
  65. goto parsehost;
  66. }
  67. }
  68. RTMP_Log(RTMP_LOGDEBUG, "Parsed protocol: %d", *protocol);
  69. parsehost:
  70. /* let's get the hostname */
  71. p+=3;
  72. /* check for sudden death */
  73. if(*p==0) {
  74. RTMP_Log(RTMP_LOGWARNING, "No hostname in URL!");
  75. return FALSE;
  76. }
  77. end = p + strlen(p);
  78. col = strchr(p, ':');
  79. ques = strchr(p, '?');
  80. slash = strchr(p, '/');
  81. {
  82. int hostlen;
  83. if(slash)
  84. hostlen = slash - p;
  85. else
  86. hostlen = end - p;
  87. if(col && col -p < hostlen)
  88. hostlen = col - p;
  89. if(hostlen < 256) {
  90. host->av_val = p;
  91. host->av_len = hostlen;
  92. RTMP_Log(RTMP_LOGDEBUG, "Parsed host : %.*s", hostlen, host->av_val);
  93. } else {
  94. RTMP_Log(RTMP_LOGWARNING, "Hostname exceeds 255 characters!");
  95. }
  96. p+=hostlen;
  97. }
  98. /* get the port number if available */
  99. if(*p == ':') {
  100. unsigned int p2;
  101. p++;
  102. p2 = atoi(p);
  103. if(p2 > 65535) {
  104. RTMP_Log(RTMP_LOGWARNING, "Invalid port number!");
  105. } else {
  106. *port = p2;
  107. }
  108. }
  109. if(!slash) {
  110. RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!");
  111. return TRUE;
  112. }
  113. p = slash+1;
  114. {
  115. /* parse application
  116. *
  117. * rtmp://host[:port]/app[/appinstance][/...]
  118. * application = app[/appinstance]
  119. */
  120. char *slash2, *slash3 = NULL, *slash4 = NULL;
  121. int applen, appnamelen;
  122. slash2 = strchr(p, '/');
  123. if(slash2)
  124. slash3 = strchr(slash2+1, '/');
  125. if(slash3)
  126. slash4 = strchr(slash3+1, '/');
  127. applen = end-p; /* ondemand, pass all parameters as app */
  128. appnamelen = applen; /* ondemand length */
  129. if(ques && strstr(p, "slist=")) { /* whatever it is, the '?' and slist= means we need to use everything as app and parse plapath from slist= */
  130. appnamelen = ques-p;
  131. }
  132. else if(strncmp(p, "ondemand/", 9)==0) {
  133. /* app = ondemand/foobar, only pass app=ondemand */
  134. applen = 8;
  135. appnamelen = 8;
  136. }
  137. else { /* app!=ondemand, so app is app[/appinstance] */
  138. if(slash4)
  139. appnamelen = slash4-p;
  140. else if(slash3)
  141. appnamelen = slash3-p;
  142. else if(slash2)
  143. appnamelen = slash2-p;
  144. applen = appnamelen;
  145. }
  146. app->av_val = p;
  147. app->av_len = applen;
  148. RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p);
  149. p += appnamelen;
  150. }
  151. if (*p == '/')
  152. p++;
  153. if (end-p) {
  154. AVal av = {p, end-p};
  155. RTMP_ParsePlaypath(&av, playpath);
  156. }
  157. return TRUE;
  158. }
  159. /*
  160. * Extracts playpath from RTMP URL. playpath is the file part of the
  161. * URL, i.e. the part that comes after rtmp://host:port/app/
  162. *
  163. * Returns the stream name in a format understood by FMS. The name is
  164. * the playpath part of the URL with formatting depending on the stream
  165. * type:
  166. *
  167. * mp4 streams: prepend "mp4:", remove extension
  168. * mp3 streams: prepend "mp3:", remove extension
  169. * flv streams: remove extension
  170. */
  171. void RTMP_ParsePlaypath(AVal *in, AVal *out) {
  172. int addMP4 = 0;
  173. int addMP3 = 0;
  174. int subExt = 0;
  175. const char *playpath = in->av_val;
  176. const char *temp, *q, *ext = NULL;
  177. const char *ppstart = playpath;
  178. char *streamname, *destptr, *p;
  179. int pplen = in->av_len;
  180. out->av_val = NULL;
  181. out->av_len = 0;
  182. if ((*ppstart == '?') &&
  183. (temp=strstr(ppstart, "slist=")) != 0) {
  184. ppstart = temp+6;
  185. pplen = strlen(ppstart);
  186. temp = strchr(ppstart, '&');
  187. if (temp) {
  188. pplen = temp-ppstart;
  189. }
  190. }
  191. q = strchr(ppstart, '?');
  192. if (pplen >= 4) {
  193. if (q)
  194. ext = q-4;
  195. else
  196. ext = &ppstart[pplen-4];
  197. if ((strncmp(ext, ".f4v", 4) == 0) ||
  198. (strncmp(ext, ".mp4", 4) == 0)) {
  199. addMP4 = 1;
  200. subExt = 1;
  201. /* Only remove .flv from rtmp URL, not slist params */
  202. } else if ((ppstart == playpath) &&
  203. (strncmp(ext, ".flv", 4) == 0)) {
  204. subExt = 1;
  205. } else if (strncmp(ext, ".mp3", 4) == 0) {
  206. addMP3 = 1;
  207. subExt = 1;
  208. }
  209. }
  210. streamname = (char *)malloc((pplen+4+1)*sizeof(char));
  211. if (!streamname)
  212. return;
  213. destptr = streamname;
  214. if (addMP4) {
  215. if (strncmp(ppstart, "mp4:", 4)) {
  216. strcpy(destptr, "mp4:");
  217. destptr += 4;
  218. } else {
  219. subExt = 0;
  220. }
  221. } else if (addMP3) {
  222. if (strncmp(ppstart, "mp3:", 4)) {
  223. strcpy(destptr, "mp3:");
  224. destptr += 4;
  225. } else {
  226. subExt = 0;
  227. }
  228. }
  229. for (p=(char *)ppstart; pplen >0;) {
  230. /* skip extension */
  231. if (subExt && p == ext) {
  232. p += 4;
  233. pplen -= 4;
  234. continue;
  235. }
  236. if (*p == '%') {
  237. unsigned int c;
  238. sscanf(p+1, "%02x", &c);
  239. *destptr++ = c;
  240. pplen -= 3;
  241. p += 3;
  242. } else {
  243. *destptr++ = *p++;
  244. pplen--;
  245. }
  246. }
  247. *destptr = '\0';
  248. out->av_val = streamname;
  249. out->av_len = destptr - streamname;
  250. }