You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
7.8KB

  1. /*
  2. * HTTP protocol for ffmpeg client
  3. * Copyright (c) 2000, 2001 Fabrice Bellard.
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. */
  19. #include "avformat.h"
  20. #include <unistd.h>
  21. #include <sys/types.h>
  22. #include <sys/socket.h>
  23. #include <netinet/in.h>
  24. #ifndef __BEOS__
  25. # include <arpa/inet.h>
  26. #else
  27. # include "barpainet.h"
  28. #endif
  29. #include <netdb.h>
  30. /* XXX: POST protocol is not completly implemented because ffmpeg use
  31. only a subset of it */
  32. //#define DEBUG
  33. /* used for protocol handling */
  34. #define BUFFER_SIZE 1024
  35. #define URL_SIZE 4096
  36. typedef struct {
  37. URLContext *hd;
  38. unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
  39. int line_count;
  40. int http_code;
  41. char location[URL_SIZE];
  42. } HTTPContext;
  43. static int http_connect(URLContext *h, const char *path, const char *hoststr,
  44. const char *auth);
  45. static int http_write(URLContext *h, uint8_t *buf, int size);
  46. static char *b64_encode(const unsigned char *src );
  47. /* return non zero if error */
  48. static int http_open(URLContext *h, const char *uri, int flags)
  49. {
  50. const char *path, *proxy_path;
  51. char hostname[1024], hoststr[1024];
  52. char auth[1024];
  53. char path1[1024];
  54. char buf[1024];
  55. int port, use_proxy, err;
  56. HTTPContext *s;
  57. URLContext *hd = NULL;
  58. h->is_streamed = 1;
  59. s = av_malloc(sizeof(HTTPContext));
  60. if (!s) {
  61. return -ENOMEM;
  62. }
  63. h->priv_data = s;
  64. proxy_path = getenv("http_proxy");
  65. use_proxy = (proxy_path != NULL) && !getenv("no_proxy") &&
  66. strstart(proxy_path, "http://", NULL);
  67. /* fill the dest addr */
  68. redo:
  69. /* needed in any case to build the host string */
  70. url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
  71. path1, sizeof(path1), uri);
  72. if (port > 0) {
  73. snprintf(hoststr, sizeof(hoststr), "%s:%d", hostname, port);
  74. } else {
  75. pstrcpy(hoststr, sizeof(hoststr), hostname);
  76. }
  77. if (use_proxy) {
  78. url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
  79. NULL, 0, proxy_path);
  80. path = uri;
  81. } else {
  82. if (path1[0] == '\0')
  83. path = "/";
  84. else
  85. path = path1;
  86. }
  87. if (port < 0)
  88. port = 80;
  89. snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
  90. err = url_open(&hd, buf, URL_RDWR);
  91. if (err < 0)
  92. goto fail;
  93. s->hd = hd;
  94. if (http_connect(h, path, hoststr, auth) < 0)
  95. goto fail;
  96. if (s->http_code == 303 && s->location[0] != '\0') {
  97. /* url moved, get next */
  98. uri = s->location;
  99. url_close(hd);
  100. goto redo;
  101. }
  102. return 0;
  103. fail:
  104. if (hd)
  105. url_close(hd);
  106. av_free(s);
  107. return AVERROR_IO;
  108. }
  109. static int http_getc(HTTPContext *s)
  110. {
  111. int len;
  112. if (s->buf_ptr >= s->buf_end) {
  113. len = url_read(s->hd, s->buffer, BUFFER_SIZE);
  114. if (len < 0) {
  115. return AVERROR_IO;
  116. } else if (len == 0) {
  117. return -1;
  118. } else {
  119. s->buf_ptr = s->buffer;
  120. s->buf_end = s->buffer + len;
  121. }
  122. }
  123. return *s->buf_ptr++;
  124. }
  125. static int process_line(HTTPContext *s, char *line, int line_count)
  126. {
  127. char *tag, *p;
  128. /* end of header */
  129. if (line[0] == '\0')
  130. return 0;
  131. p = line;
  132. if (line_count == 0) {
  133. while (!isspace(*p) && *p != '\0')
  134. p++;
  135. while (isspace(*p))
  136. p++;
  137. s->http_code = strtol(p, NULL, 10);
  138. #ifdef DEBUG
  139. printf("http_code=%d\n", s->http_code);
  140. #endif
  141. } else {
  142. while (*p != '\0' && *p != ':')
  143. p++;
  144. if (*p != ':')
  145. return 1;
  146. *p = '\0';
  147. tag = line;
  148. p++;
  149. while (isspace(*p))
  150. p++;
  151. if (!strcmp(tag, "Location")) {
  152. strcpy(s->location, p);
  153. }
  154. }
  155. return 1;
  156. }
  157. static int http_connect(URLContext *h, const char *path, const char *hoststr,
  158. const char *auth)
  159. {
  160. HTTPContext *s = h->priv_data;
  161. int post, err, ch;
  162. char line[1024], *q;
  163. /* send http header */
  164. post = h->flags & URL_WRONLY;
  165. snprintf(s->buffer, sizeof(s->buffer),
  166. "%s %s HTTP/1.0\r\n"
  167. "User-Agent: %s\r\n"
  168. "Accept: */*\r\n"
  169. "Host: %s\r\n"
  170. "Authorization: Basic %s\r\n"
  171. "\r\n",
  172. post ? "POST" : "GET",
  173. path,
  174. LIBAVFORMAT_IDENT,
  175. hoststr,
  176. b64_encode(auth));
  177. if (http_write(h, s->buffer, strlen(s->buffer)) < 0)
  178. return AVERROR_IO;
  179. /* init input buffer */
  180. s->buf_ptr = s->buffer;
  181. s->buf_end = s->buffer;
  182. s->line_count = 0;
  183. s->location[0] = '\0';
  184. if (post) {
  185. sleep(1);
  186. return 0;
  187. }
  188. /* wait for header */
  189. q = line;
  190. for(;;) {
  191. ch = http_getc(s);
  192. if (ch < 0)
  193. return AVERROR_IO;
  194. if (ch == '\n') {
  195. /* process line */
  196. if (q > line && q[-1] == '\r')
  197. q--;
  198. *q = '\0';
  199. #ifdef DEBUG
  200. printf("header='%s'\n", line);
  201. #endif
  202. err = process_line(s, line, s->line_count);
  203. if (err < 0)
  204. return err;
  205. if (err == 0)
  206. return 0;
  207. s->line_count++;
  208. q = line;
  209. } else {
  210. if ((q - line) < sizeof(line) - 1)
  211. *q++ = ch;
  212. }
  213. }
  214. }
  215. static int http_read(URLContext *h, uint8_t *buf, int size)
  216. {
  217. HTTPContext *s = h->priv_data;
  218. int len;
  219. /* read bytes from input buffer first */
  220. len = s->buf_end - s->buf_ptr;
  221. if (len > 0) {
  222. if (len > size)
  223. len = size;
  224. memcpy(buf, s->buf_ptr, len);
  225. s->buf_ptr += len;
  226. } else {
  227. len = url_read(s->hd, buf, size);
  228. }
  229. return len;
  230. }
  231. /* used only when posting data */
  232. static int http_write(URLContext *h, uint8_t *buf, int size)
  233. {
  234. HTTPContext *s = h->priv_data;
  235. return url_write(s->hd, buf, size);
  236. }
  237. static int http_close(URLContext *h)
  238. {
  239. HTTPContext *s = h->priv_data;
  240. url_close(s->hd);
  241. av_free(s);
  242. return 0;
  243. }
  244. URLProtocol http_protocol = {
  245. "http",
  246. http_open,
  247. http_read,
  248. http_write,
  249. NULL, /* seek */
  250. http_close,
  251. };
  252. /*****************************************************************************
  253. * b64_encode: stolen from VLC's http.c
  254. *****************************************************************************/
  255. static char *b64_encode( const unsigned char *src )
  256. {
  257. static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  258. unsigned int len= strlen(src);
  259. char *ret, *dst;
  260. unsigned i_bits = 0;
  261. unsigned i_shift = 0;
  262. if(len < UINT_MAX/4){
  263. ret=dst= av_malloc( len * 4 / 3 + 12 );
  264. }else
  265. return NULL;
  266. for( ;; )
  267. {
  268. if( *src )
  269. {
  270. i_bits = ( i_bits << 8 )|( *src++ );
  271. i_shift += 8;
  272. }
  273. else if( i_shift > 0 )
  274. {
  275. i_bits <<= 6 - i_shift;
  276. i_shift = 6;
  277. }
  278. else
  279. {
  280. *dst++ = '=';
  281. break;
  282. }
  283. while( i_shift >= 6 )
  284. {
  285. i_shift -= 6;
  286. *dst++ = b64[(i_bits >> i_shift)&0x3f];
  287. }
  288. }
  289. *dst++ = '\0';
  290. return ret;
  291. }