http.c
Go to the documentation of this file.
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 
22 #include "libavutil/avstring.h"
23 #include "avformat.h"
24 #include "internal.h"
25 #include "network.h"
26 #include "http.h"
27 #include "os_support.h"
28 #include "httpauth.h"
29 #include "url.h"
30 #include "libavutil/opt.h"
31 
32 /* XXX: POST protocol is not completely implemented because ffmpeg uses
33  only a subset of it. */
34 
35 /* The IO buffer size is unrelated to the max URL size in itself, but needs
36  * to be large enough to fit the full request headers (including long
37  * path names).
38  */
39 #define BUFFER_SIZE MAX_URL_SIZE
40 #define MAX_REDIRECTS 8
41 
42 typedef struct {
43  const AVClass *class;
45  unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
47  int http_code;
48  int64_t chunksize; /**< Used if "Transfer-Encoding: chunked" otherwise -1. */
49  char *content_type;
50  char *user_agent;
51  int64_t off, filesize;
55  char *headers;
56  int willclose; /**< Set if the server correctly handles Connection: close and will close the connection after feeding us the content. */
57  int seekable; /**< Control seekability, 0 = disable, 1 = enable, -1 = probe. */
59  int end_chunked_post; /**< A flag which indicates if the end of chunked encoding has been sent. */
60  int end_header; /**< A flag which indicates we have finished to read POST reply. */
61  int multiple_requests; /**< A flag which indicates if we use persistent connections. */
64  int is_akamai;
66  char *mime_type;
67  char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
68 } HTTPContext;
69 
70 #define OFFSET(x) offsetof(HTTPContext, x)
71 #define D AV_OPT_FLAG_DECODING_PARAM
72 #define E AV_OPT_FLAG_ENCODING_PARAM
73 #define DEFAULT_USER_AGENT "Mozilla/5.0 Lavf/" AV_STRINGIFY(LIBAVFORMAT_VERSION)
74 static const AVOption options[] = {
75 {"seekable", "control seekability of connection", OFFSET(seekable), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, D },
76 {"chunked_post", "use chunked transfer-encoding for posts", OFFSET(chunked_post), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
77 {"headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
78 {"content_type", "force a content type", OFFSET(content_type), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
79 {"user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = DEFAULT_USER_AGENT}, 0, 0, D },
80 {"multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E },
81 {"post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D|E },
82 {"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
83 {"mime_type", "set MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 },
84 {"cookies", "set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax", OFFSET(cookies), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 },
85 {NULL}
86 };
87 #define HTTP_CLASS(flavor)\
88 static const AVClass flavor ## _context_class = {\
89  .class_name = #flavor,\
90  .item_name = av_default_item_name,\
91  .option = options,\
92  .version = LIBAVUTIL_VERSION_INT,\
93 }
94 
96 HTTP_CLASS(https);
97 
98 static int http_connect(URLContext *h, const char *path, const char *local_path,
99  const char *hoststr, const char *auth,
100  const char *proxyauth, int *new_location);
101 
103 {
104  memcpy(&((HTTPContext*)dest->priv_data)->auth_state,
105  &((HTTPContext*)src->priv_data)->auth_state, sizeof(HTTPAuthState));
106  memcpy(&((HTTPContext*)dest->priv_data)->proxy_auth_state,
107  &((HTTPContext*)src->priv_data)->proxy_auth_state,
108  sizeof(HTTPAuthState));
109 }
110 
111 /* return non zero if error */
112 static int http_open_cnx(URLContext *h)
113 {
114  const char *path, *proxy_path, *lower_proto = "tcp", *local_path;
115  char hostname[1024], hoststr[1024], proto[10];
116  char auth[1024], proxyauth[1024] = "";
117  char path1[MAX_URL_SIZE];
118  char buf[1024], urlbuf[MAX_URL_SIZE];
119  int port, use_proxy, err, location_changed = 0, redirects = 0, attempts = 0;
120  HTTPAuthType cur_auth_type, cur_proxy_auth_type;
121  HTTPContext *s = h->priv_data;
122 
123  /* fill the dest addr */
124  redo:
125  /* needed in any case to build the host string */
126  av_url_split(proto, sizeof(proto), auth, sizeof(auth),
127  hostname, sizeof(hostname), &port,
128  path1, sizeof(path1), s->location);
129  ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
130 
131  proxy_path = getenv("http_proxy");
132  use_proxy = !ff_http_match_no_proxy(getenv("no_proxy"), hostname) &&
133  proxy_path != NULL && av_strstart(proxy_path, "http://", NULL);
134 
135  if (!strcmp(proto, "https")) {
136  lower_proto = "tls";
137  use_proxy = 0;
138  if (port < 0)
139  port = 443;
140  }
141  if (port < 0)
142  port = 80;
143 
144  if (path1[0] == '\0')
145  path = "/";
146  else
147  path = path1;
148  local_path = path;
149  if (use_proxy) {
150  /* Reassemble the request URL without auth string - we don't
151  * want to leak the auth to the proxy. */
152  ff_url_join(urlbuf, sizeof(urlbuf), proto, NULL, hostname, port, "%s",
153  path1);
154  path = urlbuf;
155  av_url_split(NULL, 0, proxyauth, sizeof(proxyauth),
156  hostname, sizeof(hostname), &port, NULL, 0, proxy_path);
157  }
158 
159  ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL);
160 
161  if (!s->hd) {
162  AVDictionary *opts = NULL;
163  char opts_format[20];
164  if (s->rw_timeout != -1) {
165  snprintf(opts_format, sizeof(opts_format), "%d", s->rw_timeout);
166  av_dict_set(&opts, "timeout", opts_format, 0);
167  } /* if option is not given, don't pass it and let tcp use its own default */
168  err = ffurl_open(&s->hd, buf, AVIO_FLAG_READ_WRITE,
169  &h->interrupt_callback, &opts);
170  av_dict_free(&opts);
171  if (err < 0)
172  goto fail;
173  }
174 
175  cur_auth_type = s->auth_state.auth_type;
176  cur_proxy_auth_type = s->auth_state.auth_type;
177  if (http_connect(h, path, local_path, hoststr, auth, proxyauth, &location_changed) < 0)
178  goto fail;
179  attempts++;
180  if (s->http_code == 401) {
181  if ((cur_auth_type == HTTP_AUTH_NONE || s->auth_state.stale) &&
182  s->auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) {
183  ffurl_closep(&s->hd);
184  goto redo;
185  } else
186  goto fail;
187  }
188  if (s->http_code == 407) {
189  if ((cur_proxy_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
190  s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) {
191  ffurl_closep(&s->hd);
192  goto redo;
193  } else
194  goto fail;
195  }
196  if ((s->http_code == 301 || s->http_code == 302 || s->http_code == 303 || s->http_code == 307)
197  && location_changed == 1) {
198  /* url moved, get next */
199  ffurl_closep(&s->hd);
200  if (redirects++ >= MAX_REDIRECTS)
201  return AVERROR(EIO);
202  /* Restart the authentication process with the new target, which
203  * might use a different auth mechanism. */
204  memset(&s->auth_state, 0, sizeof(s->auth_state));
205  attempts = 0;
206  location_changed = 0;
207  goto redo;
208  }
209  return 0;
210  fail:
211  if (s->hd)
212  ffurl_closep(&s->hd);
213  return AVERROR(EIO);
214 }
215 
216 int ff_http_do_new_request(URLContext *h, const char *uri)
217 {
218  HTTPContext *s = h->priv_data;
219 
220  s->off = 0;
221  av_strlcpy(s->location, uri, sizeof(s->location));
222 
223  return http_open_cnx(h);
224 }
225 
226 static int http_open(URLContext *h, const char *uri, int flags)
227 {
228  HTTPContext *s = h->priv_data;
229 
230  if( s->seekable == 1 )
231  h->is_streamed = 0;
232  else
233  h->is_streamed = 1;
234 
235  s->filesize = -1;
236  av_strlcpy(s->location, uri, sizeof(s->location));
237 
238  if (s->headers) {
239  int len = strlen(s->headers);
240  if (len < 2 || strcmp("\r\n", s->headers + len - 2))
241  av_log(h, AV_LOG_WARNING, "No trailing CRLF found in HTTP header.\n");
242  }
243 
244  return http_open_cnx(h);
245 }
246 static int http_getc(HTTPContext *s)
247 {
248  int len;
249  if (s->buf_ptr >= s->buf_end) {
250  len = ffurl_read(s->hd, s->buffer, BUFFER_SIZE);
251  if (len < 0) {
252  return len;
253  } else if (len == 0) {
254  return -1;
255  } else {
256  s->buf_ptr = s->buffer;
257  s->buf_end = s->buffer + len;
258  }
259  }
260  return *s->buf_ptr++;
261 }
262 
263 static int http_get_line(HTTPContext *s, char *line, int line_size)
264 {
265  int ch;
266  char *q;
267 
268  q = line;
269  for(;;) {
270  ch = http_getc(s);
271  if (ch < 0)
272  return ch;
273  if (ch == '\n') {
274  /* process line */
275  if (q > line && q[-1] == '\r')
276  q--;
277  *q = '\0';
278 
279  return 0;
280  } else {
281  if ((q - line) < line_size - 1)
282  *q++ = ch;
283  }
284  }
285 }
286 
287 static int process_line(URLContext *h, char *line, int line_count,
288  int *new_location)
289 {
290  HTTPContext *s = h->priv_data;
291  char *tag, *p, *end;
292 
293  /* end of header */
294  if (line[0] == '\0') {
295  s->end_header = 1;
296  return 0;
297  }
298 
299  p = line;
300  if (line_count == 0) {
301  while (!av_isspace(*p) && *p != '\0')
302  p++;
303  while (av_isspace(*p))
304  p++;
305  s->http_code = strtol(p, &end, 10);
306 
307  av_dlog(NULL, "http_code=%d\n", s->http_code);
308 
309  /* error codes are 4xx and 5xx, but regard 401 as a success, so we
310  * don't abort until all headers have been parsed. */
311  if (s->http_code >= 400 && s->http_code < 600 && (s->http_code != 401
312  || s->auth_state.auth_type != HTTP_AUTH_NONE) &&
313  (s->http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) {
314  end += strspn(end, SPACE_CHARS);
315  av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n",
316  s->http_code, end);
317  return -1;
318  }
319  } else {
320  while (*p != '\0' && *p != ':')
321  p++;
322  if (*p != ':')
323  return 1;
324 
325  *p = '\0';
326  tag = line;
327  p++;
328  while (av_isspace(*p))
329  p++;
330  if (!av_strcasecmp(tag, "Location")) {
331  av_strlcpy(s->location, p, sizeof(s->location));
332  *new_location = 1;
333  } else if (!av_strcasecmp (tag, "Content-Length") && s->filesize == -1) {
334  s->filesize = strtoll(p, NULL, 10);
335  } else if (!av_strcasecmp (tag, "Content-Range")) {
336  /* "bytes $from-$to/$document_size" */
337  const char *slash;
338  if (!strncmp (p, "bytes ", 6)) {
339  p += 6;
340  s->off = strtoll(p, NULL, 10);
341  if ((slash = strchr(p, '/')) && strlen(slash) > 0)
342  s->filesize = strtoll(slash+1, NULL, 10);
343  }
344  if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647))
345  h->is_streamed = 0; /* we _can_ in fact seek */
346  } else if (!av_strcasecmp(tag, "Accept-Ranges") && !strncmp(p, "bytes", 5) && s->seekable == -1) {
347  h->is_streamed = 0;
348  } else if (!av_strcasecmp (tag, "Transfer-Encoding") && !av_strncasecmp(p, "chunked", 7)) {
349  s->filesize = -1;
350  s->chunksize = 0;
351  } else if (!av_strcasecmp (tag, "WWW-Authenticate")) {
353  } else if (!av_strcasecmp (tag, "Authentication-Info")) {
355  } else if (!av_strcasecmp (tag, "Proxy-Authenticate")) {
357  } else if (!av_strcasecmp (tag, "Connection")) {
358  if (!strcmp(p, "close"))
359  s->willclose = 1;
360  } else if (!av_strcasecmp (tag, "Server") && !av_strcasecmp (p, "AkamaiGHost")) {
361  s->is_akamai = 1;
362  } else if (!av_strcasecmp (tag, "Content-Type")) {
363  av_free(s->mime_type); s->mime_type = av_strdup(p);
364  } else if (!av_strcasecmp (tag, "Set-Cookie")) {
365  if (!s->cookies) {
366  if (!(s->cookies = av_strdup(p)))
367  return AVERROR(ENOMEM);
368  } else {
369  char *tmp = s->cookies;
370  size_t str_size = strlen(tmp) + strlen(p) + 2;
371  if (!(s->cookies = av_malloc(str_size))) {
372  s->cookies = tmp;
373  return AVERROR(ENOMEM);
374  }
375  snprintf(s->cookies, str_size, "%s\n%s", tmp, p);
376  av_free(tmp);
377  }
378  }
379  }
380  return 1;
381 }
382 
383 /**
384  * Create a string containing cookie values for use as a HTTP cookie header
385  * field value for a particular path and domain from the cookie values stored in
386  * the HTTP protocol context. The cookie string is stored in *cookies.
387  *
388  * @return a negative value if an error condition occurred, 0 otherwise
389  */
390 static int get_cookies(HTTPContext *s, char **cookies, const char *path,
391  const char *domain)
392 {
393  // cookie strings will look like Set-Cookie header field values. Multiple
394  // Set-Cookie fields will result in multiple values delimited by a newline
395  int ret = 0;
396  char *next, *cookie, *set_cookies = av_strdup(s->cookies), *cset_cookies = set_cookies;
397 
398  if (!set_cookies) return AVERROR(EINVAL);
399 
400  *cookies = NULL;
401  while ((cookie = av_strtok(set_cookies, "\n", &next))) {
402  int domain_offset = 0;
403  char *param, *next_param, *cdomain = NULL, *cpath = NULL, *cvalue = NULL;
404  set_cookies = NULL;
405 
406  while ((param = av_strtok(cookie, "; ", &next_param))) {
407  cookie = NULL;
408  if (!av_strncasecmp("path=", param, 5)) {
409  av_free(cpath);
410  cpath = av_strdup(&param[5]);
411  } else if (!av_strncasecmp("domain=", param, 7)) {
412  av_free(cdomain);
413  cdomain = av_strdup(&param[7]);
414  } else if (!av_strncasecmp("secure", param, 6) ||
415  !av_strncasecmp("comment", param, 7) ||
416  !av_strncasecmp("max-age", param, 7) ||
417  !av_strncasecmp("version", param, 7)) {
418  // ignore Comment, Max-Age, Secure and Version
419  } else {
420  av_free(cvalue);
421  cvalue = av_strdup(param);
422  }
423  }
424 
425  // ensure all of the necessary values are valid
426  if (!cdomain || !cpath || !cvalue) {
428  "Invalid cookie found, no value, path or domain specified\n");
429  goto done_cookie;
430  }
431 
432  // check if the request path matches the cookie path
433  if (av_strncasecmp(path, cpath, strlen(cpath)))
434  goto done_cookie;
435 
436  // the domain should be at least the size of our cookie domain
437  domain_offset = strlen(domain) - strlen(cdomain);
438  if (domain_offset < 0)
439  goto done_cookie;
440 
441  // match the cookie domain
442  if (av_strcasecmp(&domain[domain_offset], cdomain))
443  goto done_cookie;
444 
445  // cookie parameters match, so copy the value
446  if (!*cookies) {
447  if (!(*cookies = av_strdup(cvalue))) {
448  ret = AVERROR(ENOMEM);
449  goto done_cookie;
450  }
451  } else {
452  char *tmp = *cookies;
453  size_t str_size = strlen(cvalue) + strlen(*cookies) + 3;
454  if (!(*cookies = av_malloc(str_size))) {
455  ret = AVERROR(ENOMEM);
456  goto done_cookie;
457  }
458  snprintf(*cookies, str_size, "%s; %s", tmp, cvalue);
459  av_free(tmp);
460  }
461 
462  done_cookie:
463  av_free(cdomain);
464  av_free(cpath);
465  av_free(cvalue);
466  if (ret < 0) {
467  if (*cookies) av_freep(cookies);
468  av_free(cset_cookies);
469  return ret;
470  }
471  }
472 
473  av_free(cset_cookies);
474 
475  return 0;
476 }
477 
478 static inline int has_header(const char *str, const char *header)
479 {
480  /* header + 2 to skip over CRLF prefix. (make sure you have one!) */
481  if (!str)
482  return 0;
483  return av_stristart(str, header + 2, NULL) || av_stristr(str, header);
484 }
485 
486 static int http_read_header(URLContext *h, int *new_location)
487 {
488  HTTPContext *s = h->priv_data;
489  char line[MAX_URL_SIZE];
490  int err = 0;
491 
492  s->chunksize = -1;
493 
494  for (;;) {
495  if ((err = http_get_line(s, line, sizeof(line))) < 0)
496  return err;
497 
498  av_dlog(NULL, "header='%s'\n", line);
499 
500  err = process_line(h, line, s->line_count, new_location);
501  if (err < 0)
502  return err;
503  if (err == 0)
504  break;
505  s->line_count++;
506  }
507 
508  return err;
509 }
510 
511 static int http_connect(URLContext *h, const char *path, const char *local_path,
512  const char *hoststr, const char *auth,
513  const char *proxyauth, int *new_location)
514 {
515  HTTPContext *s = h->priv_data;
516  int post, err;
517  char headers[4096] = "";
518  char *authstr = NULL, *proxyauthstr = NULL;
519  int64_t off = s->off;
520  int len = 0;
521  const char *method;
522 
523 
524  /* send http header */
525  post = h->flags & AVIO_FLAG_WRITE;
526 
527  if (s->post_data) {
528  /* force POST method and disable chunked encoding when
529  * custom HTTP post data is set */
530  post = 1;
531  s->chunked_post = 0;
532  }
533 
534  method = post ? "POST" : "GET";
535  authstr = ff_http_auth_create_response(&s->auth_state, auth, local_path,
536  method);
537  proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth,
538  local_path, method);
539 
540  /* set default headers if needed */
541  if (!has_header(s->headers, "\r\nUser-Agent: "))
542  len += av_strlcatf(headers + len, sizeof(headers) - len,
543  "User-Agent: %s\r\n", s->user_agent);
544  if (!has_header(s->headers, "\r\nAccept: "))
545  len += av_strlcpy(headers + len, "Accept: */*\r\n",
546  sizeof(headers) - len);
547  // Note: we send this on purpose even when s->off is 0 when we're probing,
548  // since it allows us to detect more reliably if a (non-conforming)
549  // server supports seeking by analysing the reply headers.
550  if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->seekable == -1))
551  len += av_strlcatf(headers + len, sizeof(headers) - len,
552  "Range: bytes=%"PRId64"-\r\n", s->off);
553 
554  if (!has_header(s->headers, "\r\nConnection: ")) {
555  if (s->multiple_requests) {
556  len += av_strlcpy(headers + len, "Connection: keep-alive\r\n",
557  sizeof(headers) - len);
558  } else {
559  len += av_strlcpy(headers + len, "Connection: close\r\n",
560  sizeof(headers) - len);
561  }
562  }
563 
564  if (!has_header(s->headers, "\r\nHost: "))
565  len += av_strlcatf(headers + len, sizeof(headers) - len,
566  "Host: %s\r\n", hoststr);
567  if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data)
568  len += av_strlcatf(headers + len, sizeof(headers) - len,
569  "Content-Length: %d\r\n", s->post_datalen);
570  if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
571  len += av_strlcatf(headers + len, sizeof(headers) - len,
572  "Content-Type: %s\r\n", s->content_type);
573  if (!has_header(s->headers, "\r\nCookie: ") && s->cookies) {
574  char *cookies = NULL;
575  if (!get_cookies(s, &cookies, path, hoststr)) {
576  len += av_strlcatf(headers + len, sizeof(headers) - len,
577  "Cookie: %s\r\n", cookies);
578  av_free(cookies);
579  }
580  }
581 
582  /* now add in custom headers */
583  if (s->headers)
584  av_strlcpy(headers + len, s->headers, sizeof(headers) - len);
585 
586  snprintf(s->buffer, sizeof(s->buffer),
587  "%s %s HTTP/1.1\r\n"
588  "%s"
589  "%s"
590  "%s"
591  "%s%s"
592  "\r\n",
593  method,
594  path,
595  post && s->chunked_post ? "Transfer-Encoding: chunked\r\n" : "",
596  headers,
597  authstr ? authstr : "",
598  proxyauthstr ? "Proxy-" : "", proxyauthstr ? proxyauthstr : "");
599 
600  av_freep(&authstr);
601  av_freep(&proxyauthstr);
602  if ((err = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
603  return err;
604 
605  if (s->post_data)
606  if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0)
607  return err;
608 
609  /* init input buffer */
610  s->buf_ptr = s->buffer;
611  s->buf_end = s->buffer;
612  s->line_count = 0;
613  s->off = 0;
614  s->filesize = -1;
615  s->willclose = 0;
616  s->end_chunked_post = 0;
617  s->end_header = 0;
618  if (post && !s->post_data) {
619  /* Pretend that it did work. We didn't read any header yet, since
620  * we've still to send the POST data, but the code calling this
621  * function will check http_code after we return. */
622  s->http_code = 200;
623  return 0;
624  }
625 
626  /* wait for header */
627  err = http_read_header(h, new_location);
628  if (err < 0)
629  return err;
630 
631  return (off == s->off) ? 0 : -1;
632 }
633 
634 
635 static int http_buf_read(URLContext *h, uint8_t *buf, int size)
636 {
637  HTTPContext *s = h->priv_data;
638  int len;
639  /* read bytes from input buffer first */
640  len = s->buf_end - s->buf_ptr;
641  if (len > 0) {
642  if (len > size)
643  len = size;
644  memcpy(buf, s->buf_ptr, len);
645  s->buf_ptr += len;
646  } else {
647  if (!s->willclose && s->filesize >= 0 && s->off >= s->filesize)
648  return AVERROR_EOF;
649  len = ffurl_read(s->hd, buf, size);
650  }
651  if (len > 0) {
652  s->off += len;
653  if (s->chunksize > 0)
654  s->chunksize -= len;
655  }
656  return len;
657 }
658 
659 static int http_read(URLContext *h, uint8_t *buf, int size)
660 {
661  HTTPContext *s = h->priv_data;
662  int err, new_location;
663 
664  if (!s->hd)
665  return AVERROR_EOF;
666 
667  if (s->end_chunked_post && !s->end_header) {
668  err = http_read_header(h, &new_location);
669  if (err < 0)
670  return err;
671  }
672 
673  if (s->chunksize >= 0) {
674  if (!s->chunksize) {
675  char line[32];
676 
677  for(;;) {
678  do {
679  if ((err = http_get_line(s, line, sizeof(line))) < 0)
680  return err;
681  } while (!*line); /* skip CR LF from last chunk */
682 
683  s->chunksize = strtoll(line, NULL, 16);
684 
685  av_dlog(NULL, "Chunked encoding data size: %"PRId64"'\n", s->chunksize);
686 
687  if (!s->chunksize)
688  return 0;
689  break;
690  }
691  }
692  size = FFMIN(size, s->chunksize);
693  }
694  return http_buf_read(h, buf, size);
695 }
696 
697 /* used only when posting data */
698 static int http_write(URLContext *h, const uint8_t *buf, int size)
699 {
700  char temp[11] = ""; /* 32-bit hex + CRLF + nul */
701  int ret;
702  char crlf[] = "\r\n";
703  HTTPContext *s = h->priv_data;
704 
705  if (!s->chunked_post) {
706  /* non-chunked data is sent without any special encoding */
707  return ffurl_write(s->hd, buf, size);
708  }
709 
710  /* silently ignore zero-size data since chunk encoding that would
711  * signal EOF */
712  if (size > 0) {
713  /* upload data using chunked encoding */
714  snprintf(temp, sizeof(temp), "%x\r\n", size);
715 
716  if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 ||
717  (ret = ffurl_write(s->hd, buf, size)) < 0 ||
718  (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0)
719  return ret;
720  }
721  return size;
722 }
723 
724 static int http_shutdown(URLContext *h, int flags)
725 {
726  int ret = 0;
727  char footer[] = "0\r\n\r\n";
728  HTTPContext *s = h->priv_data;
729 
730  /* signal end of chunked encoding if used */
731  if ((flags & AVIO_FLAG_WRITE) && s->chunked_post) {
732  ret = ffurl_write(s->hd, footer, sizeof(footer) - 1);
733  ret = ret > 0 ? 0 : ret;
734  s->end_chunked_post = 1;
735  }
736 
737  return ret;
738 }
739 
740 static int http_close(URLContext *h)
741 {
742  int ret = 0;
743  HTTPContext *s = h->priv_data;
744 
745  if (!s->end_chunked_post) {
746  /* Close the write direction by sending the end of chunked encoding. */
747  ret = http_shutdown(h, h->flags);
748  }
749 
750  if (s->hd)
751  ffurl_closep(&s->hd);
752  return ret;
753 }
754 
755 static int64_t http_seek(URLContext *h, int64_t off, int whence)
756 {
757  HTTPContext *s = h->priv_data;
758  URLContext *old_hd = s->hd;
759  int64_t old_off = s->off;
760  uint8_t old_buf[BUFFER_SIZE];
761  int old_buf_size;
762 
763  if (whence == AVSEEK_SIZE)
764  return s->filesize;
765  else if ((s->filesize == -1 && whence == SEEK_END) || h->is_streamed)
766  return -1;
767 
768  /* we save the old context in case the seek fails */
769  old_buf_size = s->buf_end - s->buf_ptr;
770  memcpy(old_buf, s->buf_ptr, old_buf_size);
771  s->hd = NULL;
772  if (whence == SEEK_CUR)
773  off += s->off;
774  else if (whence == SEEK_END)
775  off += s->filesize;
776  s->off = off;
777 
778  /* if it fails, continue on old connection */
779  if (http_open_cnx(h) < 0) {
780  memcpy(s->buffer, old_buf, old_buf_size);
781  s->buf_ptr = s->buffer;
782  s->buf_end = s->buffer + old_buf_size;
783  s->hd = old_hd;
784  s->off = old_off;
785  return -1;
786  }
787  ffurl_close(old_hd);
788  return off;
789 }
790 
791 static int
793 {
794  HTTPContext *s = h->priv_data;
795  return ffurl_get_file_handle(s->hd);
796 }
797 
798 #if CONFIG_HTTP_PROTOCOL
799 URLProtocol ff_http_protocol = {
800  .name = "http",
801  .url_open = http_open,
802  .url_read = http_read,
803  .url_write = http_write,
804  .url_seek = http_seek,
805  .url_close = http_close,
806  .url_get_file_handle = http_get_file_handle,
807  .url_shutdown = http_shutdown,
808  .priv_data_size = sizeof(HTTPContext),
809  .priv_data_class = &http_context_class,
811 };
812 #endif
813 #if CONFIG_HTTPS_PROTOCOL
814 URLProtocol ff_https_protocol = {
815  .name = "https",
816  .url_open = http_open,
817  .url_read = http_read,
818  .url_write = http_write,
819  .url_seek = http_seek,
820  .url_close = http_close,
821  .url_get_file_handle = http_get_file_handle,
822  .url_shutdown = http_shutdown,
823  .priv_data_size = sizeof(HTTPContext),
824  .priv_data_class = &https_context_class,
826 };
827 #endif
828 
829 #if CONFIG_HTTPPROXY_PROTOCOL
830 static int http_proxy_close(URLContext *h)
831 {
832  HTTPContext *s = h->priv_data;
833  if (s->hd)
834  ffurl_closep(&s->hd);
835  return 0;
836 }
837 
838 static int http_proxy_open(URLContext *h, const char *uri, int flags)
839 {
840  HTTPContext *s = h->priv_data;
841  char hostname[1024], hoststr[1024];
842  char auth[1024], pathbuf[1024], *path;
843  char lower_url[100];
844  int port, ret = 0, attempts = 0;
845  HTTPAuthType cur_auth_type;
846  char *authstr;
847  int new_loc;
848  AVDictionary *opts = NULL;
849  char opts_format[20];
850 
851  if( s->seekable == 1 )
852  h->is_streamed = 0;
853  else
854  h->is_streamed = 1;
855 
856  av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
857  pathbuf, sizeof(pathbuf), uri);
858  ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
859  path = pathbuf;
860  if (*path == '/')
861  path++;
862 
863  ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port,
864  NULL);
865 redo:
866  if (s->rw_timeout != -1) {
867  snprintf(opts_format, sizeof(opts_format), "%d", s->rw_timeout);
868  av_dict_set(&opts, "timeout", opts_format, 0);
869  } /* if option is not given, don't pass it and let tcp use its own default */
870  ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
871  &h->interrupt_callback, &opts);
872  av_dict_free(&opts);
873  if (ret < 0)
874  return ret;
875 
877  path, "CONNECT");
878  snprintf(s->buffer, sizeof(s->buffer),
879  "CONNECT %s HTTP/1.1\r\n"
880  "Host: %s\r\n"
881  "Connection: close\r\n"
882  "%s%s"
883  "\r\n",
884  path,
885  hoststr,
886  authstr ? "Proxy-" : "", authstr ? authstr : "");
887  av_freep(&authstr);
888 
889  if ((ret = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
890  goto fail;
891 
892  s->buf_ptr = s->buffer;
893  s->buf_end = s->buffer;
894  s->line_count = 0;
895  s->filesize = -1;
896  cur_auth_type = s->proxy_auth_state.auth_type;
897 
898  /* Note: This uses buffering, potentially reading more than the
899  * HTTP header. If tunneling a protocol where the server starts
900  * the conversation, we might buffer part of that here, too.
901  * Reading that requires using the proper ffurl_read() function
902  * on this URLContext, not using the fd directly (as the tls
903  * protocol does). This shouldn't be an issue for tls though,
904  * since the client starts the conversation there, so there
905  * is no extra data that we might buffer up here.
906  */
907  ret = http_read_header(h, &new_loc);
908  if (ret < 0)
909  goto fail;
910 
911  attempts++;
912  if (s->http_code == 407 &&
913  (cur_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
914  s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 2) {
915  ffurl_closep(&s->hd);
916  goto redo;
917  }
918 
919  if (s->http_code < 400)
920  return 0;
921  ret = AVERROR(EIO);
922 
923 fail:
924  http_proxy_close(h);
925  return ret;
926 }
927 
928 static int http_proxy_write(URLContext *h, const uint8_t *buf, int size)
929 {
930  HTTPContext *s = h->priv_data;
931  return ffurl_write(s->hd, buf, size);
932 }
933 
934 URLProtocol ff_httpproxy_protocol = {
935  .name = "httpproxy",
936  .url_open = http_proxy_open,
937  .url_read = http_buf_read,
938  .url_write = http_proxy_write,
939  .url_close = http_proxy_close,
940  .url_get_file_handle = http_get_file_handle,
941  .priv_data_size = sizeof(HTTPContext),
943 };
944 #endif
static int http_get_line(HTTPContext *s, char *line, int line_size)
Definition: http.c:263
void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url)
Split a URL string into components.
static int http_open(URLContext *h, const char *uri, int flags)
Definition: http.c:226
static int http_connect(URLContext *h, const char *path, const char *local_path, const char *hoststr, const char *auth, const char *proxyauth, int *new_location)
Definition: http.c:511
struct HTTPContext HTTPContext
const char * s
Definition: avisynth_c.h:668
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:35
int rw_timeout
Definition: http.c:65
uint8_t * post_data
Definition: http.c:62
AVOption.
Definition: opt.h:251
char location[MAX_URL_SIZE]
Definition: http.c:52
HTTPAuthType
Authentication types, ordered from weakest to strongest.
Definition: httpauth.h:28
#define BUFFER_SIZE
Definition: http.c:39
static int http_close(URLContext *h)
Definition: http.c:740
else temp
Definition: vf_mcdeint.c:148
int ffurl_write(URLContext *h, const unsigned char *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition: avio.c:317
char * av_stristr(const char *s1, const char *s2)
Locate the first case-independent occurrence in the string haystack of the string needle...
Definition: avstring.c:55
int is_streamed
true if streamed (no seek possible), default = false
Definition: url.h:48
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
AVIOInterruptCB interrupt_callback
Definition: url.h:50
HTTPAuthState proxy_auth_state
Definition: http.c:54
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:333
int av_strncasecmp(const char *a, const char *b, size_t n)
Locale-independent case-insensitive compare.
Definition: avstring.c:222
int flags
Definition: url.h:46
char * content_type
Definition: http.c:49
av_dlog(ac->avr,"%d samples - audio_convert: %s to %s (%s)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt), use_generic?ac->func_descr_generic:ac->func_descr)
static int http_getc(HTTPContext *s)
Definition: http.c:246
HTTP Authentication state structure.
Definition: httpauth.h:55
FFmpeg currently uses a custom build this text attempts to document some of its obscure features and options Makefile the full command issued by make and its output will be shown on the screen DESTDIR Destination directory for the install useful to prepare packages or install FFmpeg in cross environments Makefile builds all the libraries and the executables fate Run the fate test note you must have installed it fate list Will list all fate regression test targets install Install headers
Definition: build_system.txt:1
int ff_url_join(char *str, int size, const char *proto, const char *authorization, const char *hostname, int port, const char *fmt,...) av_printf_format(7
Assemble a URL string from components.
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
#define MAX_URL_SIZE
int end_chunked_post
A flag which indicates if the end of chunked encoding has been sent.
Definition: http.c:59
int av_stristart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str independent of case.
Definition: avstring.c:44
static int http_get_file_handle(URLContext *h)
Definition: http.c:792
static int http_buf_read(URLContext *h, uint8_t *buf, int size)
Definition: http.c:635
uint8_t
int post_datalen
Definition: http.c:63
AVOptions.
miscellaneous OS support macros and functions.
static int http_read_header(URLContext *h, int *new_location)
Definition: http.c:486
end end
int is_akamai
Definition: http.c:64
uint32_t tag
Definition: movenc.c:894
#define DEFAULT_USER_AGENT
Definition: http.c:73
#define AVERROR_EOF
End of file.
Definition: error.h:55
void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
Initialize the authentication state based on another HTTP URLContext.
Definition: http.c:102
int line_count
Definition: http.c:46
static int http_open_cnx(URLContext *h)
Definition: http.c:112
unsigned char * buf_end
Definition: http.c:45
int chunked_post
Definition: http.c:58
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
#define E
Definition: http.c:72
static int http_write(URLContext *h, const uint8_t *buf, int size)
Definition: http.c:698
static const AVOption options[]
Definition: http.c:74
About Git write you should know how to use GIT properly Luckily Git comes with excellent documentation git help man git shows you the available git< command > help man git< command > shows information about the subcommand< command > The most comprehensive manual is the website Git Reference http
Definition: git-howto.txt:5
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:162
Definition: graph2dot.c:48
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
#define OFFSET(x)
Definition: http.c:70
int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.c:298
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:82
int size
char * headers
Definition: http.c:55
char * user_agent
Definition: http.c:50
#define FFMIN(a, b)
Definition: common.h:58
int64_t off
Definition: http.c:51
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:212
ret
Definition: avfilter.c:821
int willclose
Set if the server correctly handles Connection: close and will close the connection after feeding us ...
Definition: http.c:56
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition: avio.c:399
int stale
Auth ok, but needs to be resent with a new nonce.
Definition: httpauth.h:71
offset must point to a pointer immediately followed by an int for the length
Definition: opt.h:228
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition: avio.c:338
NULL
Definition: eval.c:55
static int http_read(URLContext *h, uint8_t *buf, int size)
Definition: http.c:659
dest
Definition: start.py:60
AVS_Value src
Definition: avisynth_c.h:523
char * av_strdup(const char *s)
Duplicate the string s.
Definition: mem.c:220
int seekable
Control seekability, 0 = disable, 1 = enable, -1 = probe.
Definition: http.c:57
void * buf
Definition: avisynth_c.h:594
Definition: url.h:41
#define AVIO_FLAG_READ_WRITE
read-write pseudo flag
Definition: avio.h:334
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:62
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:73
Describe the class of an AVClass context structure.
Definition: log.h:50
#define SPACE_CHARS
int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
void * priv_data
Definition: url.h:44
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:100
#define snprintf
Definition: snprintf.h:34
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
char * ff_http_auth_create_response(HTTPAuthState *state, const char *auth, const char *path, const char *method)
Definition: httpauth.c:242
const char * name
Definition: url.h:55
URLContext * hd
Definition: http.c:44
static int has_header(const char *str, const char *header)
Definition: http.c:478
char * mime_type
Definition: http.c:66
static int flags
Definition: cpu.c:23
int ffurl_close(URLContext *h)
Definition: avio.c:359
static int process_line(URLContext *h, char *line, int line_count, int *new_location)
Definition: http.c:287
int ff_http_do_new_request(URLContext *h, const char *uri)
Send a new HTTP request, reusing the old connection.
Definition: http.c:216
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok()...
Definition: avstring.c:183
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:33
Main libavformat public API header.
char * cookies
holds newline ( ) delimited Set-Cookie header field values (without the "Set-Cookie: " field name) ...
Definition: http.c:67
#define MAX_REDIRECTS
Definition: http.c:40
int ffurl_open(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create an URLContext for accessing to the resource indicated by url, and open it. ...
Definition: avio.c:247
static int get_cookies(HTTPContext *s, char **cookies, const char *path, const char *domain)
Create a string containing cookie values for use as a HTTP cookie header field value for a particular...
Definition: http.c:390
int http_code
Definition: http.c:47
the buffer and buffer reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFilterBuffer structures They must not be accessed but through references stored in AVFilterBufferRef structures Several references can point to the same buffer
#define AVSEEK_SIZE
Passing this as the "whence" parameter to a seek function causes it to return the filesize without se...
Definition: avio.h:222
void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, const char *value)
Definition: httpauth.c:90
int multiple_requests
A flag which indicates if we use persistent connections.
Definition: http.c:61
HTTPAuthState auth_state
Definition: http.c:53
int len
uint8_t * buffer
Definition: ffserver.c:171
int64_t filesize
Definition: http.c:51
static int http_shutdown(URLContext *h, int flags)
Definition: http.c:724
About Git write you should know how to use GIT properly Luckily Git comes with excellent documentation git help man git shows you the available git< command > help man git< command > shows information about the subcommand< command > The most comprehensive manual is the website Git Reference visit they are quite exhaustive You do not need a special username or password All you need is to provide a ssh public key to the Git server admin What follows now is a basic introduction to Git and some FFmpeg specific guidelines Read it at least if you are granted commit privileges to the FFmpeg project you are expected to be familiar with these rules I if not You can get git from etc no matter how small Every one of them has been saved from looking like a fool by this many times It s very easy for stray debug output or cosmetic modifications to slip please avoid problems through this extra level of scrutiny For cosmetics only commits you should e g by running git config global user name My Name git config global user email my email which is either set in your personal configuration file through git config core editor or set by one of the following environment VISUAL or EDITOR Log messages should be concise but descriptive Explain why you made a what you did will be obvious from the changes themselves most of the time Saying just bug fix or is bad Remember that people of varying skill levels look at and educate themselves while reading through your code Don t include filenames in log Git provides that information Possibly make the commit message have a descriptive first line
Definition: git-howto.txt:153
int end_header
A flag which indicates we have finished to read POST reply.
Definition: http.c:60
unsigned char * buf_ptr
Definition: http.c:45
#define D
Definition: http.c:71
HTTPAuthType auth_type
The currently chosen auth type.
Definition: httpauth.h:59
unbuffered private I/O API
static int64_t http_seek(URLContext *h, int64_t off, int whence)
Definition: http.c:755
int ffurl_read(URLContext *h, unsigned char *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf...
Definition: avio.c:303
int64_t chunksize
Used if "Transfer-Encoding: chunked" otherwise -1.
Definition: http.c:48
#define HTTP_CLASS(flavor)
Definition: http.c:87
No authentication specified.
Definition: httpauth.h:29