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.

324 lines
7.8KB

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