FFmpeg
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 <stdbool.h>
23 
24 #include "config.h"
25 #include "config_components.h"
26 
27 #include <string.h>
28 #include <time.h>
29 #if CONFIG_ZLIB
30 #include <zlib.h>
31 #endif /* CONFIG_ZLIB */
32 
33 #include "libavutil/avassert.h"
34 #include "libavutil/avstring.h"
35 #include "libavutil/bprint.h"
36 #include "libavutil/getenv_utf8.h"
37 #include "libavutil/macros.h"
38 #include "libavutil/mem.h"
39 #include "libavutil/opt.h"
40 #include "libavutil/time.h"
41 #include "libavutil/parseutils.h"
42 
43 #include "avformat.h"
44 #include "http.h"
45 #include "httpauth.h"
46 #include "internal.h"
47 #include "network.h"
48 #include "os_support.h"
49 #include "url.h"
50 #include "version.h"
51 
52 /* XXX: POST protocol is not completely implemented because ffmpeg uses
53  * only a subset of it. */
54 
55 /* The IO buffer size is unrelated to the max URL size in itself, but needs
56  * to be large enough to fit the full request headers (including long
57  * path names). */
58 #define BUFFER_SIZE (MAX_URL_SIZE + HTTP_HEADERS_SIZE)
59 #define MAX_REDIRECTS 8
60 #define MAX_CACHED_REDIRECTS 32
61 #define HTTP_SINGLE 1
62 #define HTTP_MUTLI 2
63 #define MAX_DATE_LEN 19
64 #define WHITESPACES " \n\t\r"
65 typedef enum {
71 
72 typedef struct HTTPContext {
73  const AVClass *class;
75  unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
77  int http_code;
78  /* Used if "Transfer-Encoding: chunked" otherwise -1. */
79  uint64_t chunksize;
80  int chunkend;
82  char *uri;
83  char *location;
86  char *http_proxy;
87  char *headers;
88  char *mime_type;
89  char *http_version;
90  char *user_agent;
91  char *referer;
92  char *content_type;
93  /* Set if the server correctly handles Connection: close and will close
94  * the connection after feeding us the content. */
95  int willclose;
96  int seekable; /**< Control seekability, 0 = disable, 1 = enable, -1 = probe. */
98  /* A flag which indicates if the end of chunked encoding has been sent. */
100  /* A flag which indicates we have finished to read POST reply. */
102  /* A flag which indicates if we use persistent connections. */
104  uint8_t *post_data;
108  char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
109  /* A dictionary containing cookies keyed by cookie name */
111  int icy;
112  /* how much data was read since the last ICY metadata packet */
113  uint64_t icy_data_read;
114  /* after how many bytes of read data a new metadata packet will be found */
115  uint64_t icy_metaint;
119 #if CONFIG_ZLIB
120  int compressed;
121  z_stream inflate_stream;
122  uint8_t *inflate_buffer;
123 #endif /* CONFIG_ZLIB */
125  /* -1 = try to send if applicable, 0 = always disabled, 1 = always enabled */
127  char *method;
134  int listen;
135  char *resource;
146  unsigned int retry_after;
150  int partial_requests; /* whether or not to limit requests to initial_request_size */
151  /* Connection statistics */
157  int sum_latency; /* divide by nb_requests */
160 } HTTPContext;
161 
162 #define OFFSET(x) offsetof(HTTPContext, x)
163 #define D AV_OPT_FLAG_DECODING_PARAM
164 #define E AV_OPT_FLAG_ENCODING_PARAM
165 #define DEFAULT_USER_AGENT "Lavf/" AV_STRINGIFY(LIBAVFORMAT_VERSION)
166 
167 static const AVOption options[] = {
168  { "seekable", "control seekability of connection", OFFSET(seekable), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, D },
169  { "chunked_post", "use chunked transfer-encoding for posts", OFFSET(chunked_post), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E },
170  { "http_proxy", "set HTTP proxy to tunnel through", OFFSET(http_proxy), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
171  { "headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
172  { "content_type", "set a specific content type for the POST messages", OFFSET(content_type), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
173  { "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D },
174  { "referer", "override referer header", OFFSET(referer), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D },
175  { "multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D | E },
176  { "initial_request_size", "size (in bytes) of initial requests made during probing / header parsing", OFFSET(initial_request_size), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
177  { "post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D | E },
178  { "mime_type", "export the MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY },
179  { "http_version", "export the http response version", OFFSET(http_version), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY },
180  { "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, { .str = NULL }, 0, 0, D },
181  { "icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D },
182  { "icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT },
183  { "icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT },
184  { "metadata", "metadata read from the bitstream", OFFSET(metadata), AV_OPT_TYPE_DICT, {0}, 0, 0, AV_OPT_FLAG_EXPORT },
185  { "auth_type", "HTTP authentication type", OFFSET(auth_state.auth_type), AV_OPT_TYPE_INT, { .i64 = HTTP_AUTH_NONE }, HTTP_AUTH_NONE, HTTP_AUTH_BASIC, D | E, .unit = "auth_type"},
186  { "none", "No auth method set, autodetect", 0, AV_OPT_TYPE_CONST, { .i64 = HTTP_AUTH_NONE }, 0, 0, D | E, .unit = "auth_type"},
187  { "basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, { .i64 = HTTP_AUTH_BASIC }, 0, 0, D | E, .unit = "auth_type"},
188  { "send_expect_100", "Force sending an Expect: 100-continue header for POST", OFFSET(send_expect_100), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, E },
189  { "location", "The actual location of the data received", OFFSET(location), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
190  { "offset", "initial byte offset", OFFSET(off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
191  { "end_offset", "try to limit the request to bytes preceding this offset", OFFSET(end_off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
192  { "method", "Override the HTTP method or set the expected HTTP method from a client", OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
193  { "reconnect", "auto reconnect after disconnect before EOF", OFFSET(reconnect), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
194  { "reconnect_at_eof", "auto reconnect at EOF", OFFSET(reconnect_at_eof), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
195  { "reconnect_on_network_error", "auto reconnect in case of tcp/tls error during connect", OFFSET(reconnect_on_network_error), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
196  { "reconnect_on_http_error", "list of http status codes to reconnect on", OFFSET(reconnect_on_http_error), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D },
197  { "reconnect_streamed", "auto reconnect streamed / non seekable streams", OFFSET(reconnect_streamed), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
198  { "reconnect_delay_max", "max reconnect delay in seconds after which to give up", OFFSET(reconnect_delay_max), AV_OPT_TYPE_INT, { .i64 = 120 }, 0, UINT_MAX/1000/1000, D },
199  { "reconnect_max_retries", "the max number of times to retry a connection", OFFSET(reconnect_max_retries), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, D },
200  { "reconnect_delay_total_max", "max total reconnect delay in seconds after which to give up", OFFSET(reconnect_delay_total_max), AV_OPT_TYPE_INT, { .i64 = 256 }, 0, UINT_MAX/1000/1000, D },
201  { "respect_retry_after", "respect the Retry-After header when retrying connections", OFFSET(respect_retry_after), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D },
202  { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, D | E },
203  { "resource", "The resource requested by a client", OFFSET(resource), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
204  { "reply_code", "The http status code to return to a client", OFFSET(reply_code), AV_OPT_TYPE_INT, { .i64 = 200}, INT_MIN, 599, E},
205  { "short_seek_size", "Threshold to favor readahead over seek.", OFFSET(short_seek_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D },
206  { "max_redirects", "Maximum number of redirects", OFFSET(max_redirects), AV_OPT_TYPE_INT, { .i64 = MAX_REDIRECTS }, 0, INT_MAX, D },
207  { NULL }
208 };
209 
210 static int http_connect(URLContext *h, const char *path, const char *local_path,
211  const char *hoststr, const char *auth,
212  const char *proxyauth);
213 static int http_read_header(URLContext *h);
214 static int http_shutdown(URLContext *h, int flags);
215 
217 {
218  memcpy(&((HTTPContext *)dest->priv_data)->auth_state,
219  &((HTTPContext *)src->priv_data)->auth_state,
220  sizeof(HTTPAuthState));
221  memcpy(&((HTTPContext *)dest->priv_data)->proxy_auth_state,
222  &((HTTPContext *)src->priv_data)->proxy_auth_state,
223  sizeof(HTTPAuthState));
224 }
225 
227 {
228  const char *path, *proxy_path, *lower_proto = "tcp", *local_path;
229  char *env_http_proxy, *env_no_proxy;
230  char *hashmark;
231  char hostname[1024], hoststr[1024], proto[10], tmp_host[1024];
232  char auth[1024], proxyauth[1024] = "";
233  char path1[MAX_URL_SIZE], sanitized_path[MAX_URL_SIZE + 1];
234  char buf[1024], urlbuf[MAX_URL_SIZE];
235  int port, use_proxy, err = 0;
236  HTTPContext *s = h->priv_data;
237 
238  av_url_split(proto, sizeof(proto), auth, sizeof(auth),
239  hostname, sizeof(hostname), &port,
240  path1, sizeof(path1), s->location);
241 
242  av_strlcpy(tmp_host, hostname, sizeof(tmp_host));
243  // In case of an IPv6 address, we need to strip the Zone ID,
244  // if any. We do it at the first % sign, as percent encoding
245  // can be used in the Zone ID itself.
246  if (strchr(tmp_host, ':'))
247  tmp_host[strcspn(tmp_host, "%")] = '\0';
248  ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, tmp_host, port, NULL);
249 
250  env_http_proxy = getenv_utf8("http_proxy");
251  proxy_path = s->http_proxy ? s->http_proxy : env_http_proxy;
252 
253  env_no_proxy = getenv_utf8("no_proxy");
254  use_proxy = !ff_http_match_no_proxy(env_no_proxy, hostname) &&
255  proxy_path && av_strstart(proxy_path, "http://", NULL);
256  freeenv_utf8(env_no_proxy);
257 
258  if (h->protocol_whitelist && av_match_list(proto, h->protocol_whitelist, ',') <= 0) {
259  av_log(h, AV_LOG_ERROR, "Protocol '%s' not on whitelist '%s'!\n", proto, h->protocol_whitelist);
260  return AVERROR(EINVAL);
261  }
262 
263  if (h->protocol_blacklist && av_match_list(proto, h->protocol_blacklist, ',') > 0) {
264  av_log(h, AV_LOG_ERROR, "Protocol '%s' on blacklist '%s'!\n", proto, h->protocol_blacklist);
265  return AVERROR(EINVAL);
266  }
267 
268  if (!strcmp(proto, "https")) {
269  lower_proto = "tls";
270  use_proxy = 0;
271  if (port < 0)
272  port = 443;
273  /* pass http_proxy to underlying protocol */
274  if (s->http_proxy) {
275  err = av_dict_set(options, "http_proxy", s->http_proxy, 0);
276  if (err < 0)
277  goto end;
278  }
279  } else if (strcmp(proto, "http")) {
280  err = AVERROR(EINVAL);
281  goto end;
282  }
283 
284  if (port < 0)
285  port = 80;
286 
287  hashmark = strchr(path1, '#');
288  if (hashmark)
289  *hashmark = '\0';
290 
291  if (path1[0] == '\0') {
292  path = "/";
293  } else if (path1[0] == '?') {
294  snprintf(sanitized_path, sizeof(sanitized_path), "/%s", path1);
295  path = sanitized_path;
296  } else {
297  path = path1;
298  }
299  local_path = path;
300  if (use_proxy) {
301  /* Reassemble the request URL without auth string - we don't
302  * want to leak the auth to the proxy. */
303  ff_url_join(urlbuf, sizeof(urlbuf), proto, NULL, hostname, port, "%s",
304  path1);
305  path = urlbuf;
306  av_url_split(NULL, 0, proxyauth, sizeof(proxyauth),
307  hostname, sizeof(hostname), &port, NULL, 0, proxy_path);
308  }
309 
310  ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL);
311 
312  if (!s->hd) {
313  s->nb_connections++;
315  &h->interrupt_callback, options,
316  h->protocol_whitelist, h->protocol_blacklist, h);
317  }
318 
319 end:
320  freeenv_utf8(env_http_proxy);
321  return err < 0 ? err : http_connect(
322  h, path, local_path, hoststr, auth, proxyauth);
323 }
324 
325 static int http_should_reconnect(HTTPContext *s, int err)
326 {
327  const char *status_group;
328  char http_code[4];
329 
330  switch (err) {
337  status_group = "4xx";
338  break;
339 
341  status_group = "5xx";
342  break;
343 
344  default:
345  return s->reconnect_on_network_error;
346  }
347 
348  if (!s->reconnect_on_http_error)
349  return 0;
350 
351  if (av_match_list(status_group, s->reconnect_on_http_error, ',') > 0)
352  return 1;
353 
354  snprintf(http_code, sizeof(http_code), "%d", s->http_code);
355 
356  return av_match_list(http_code, s->reconnect_on_http_error, ',') > 0;
357 }
358 
360 {
361  AVDictionaryEntry *re;
362  int64_t expiry;
363  char *delim;
364 
365  re = av_dict_get(s->redirect_cache, s->location, NULL, AV_DICT_MATCH_CASE);
366  if (!re) {
367  return NULL;
368  }
369 
370  delim = strchr(re->value, ';');
371  if (!delim) {
372  return NULL;
373  }
374 
375  expiry = strtoll(re->value, NULL, 10);
376  if (time(NULL) > expiry) {
377  return NULL;
378  }
379 
380  return delim + 1;
381 }
382 
383 static int redirect_cache_set(HTTPContext *s, const char *source, const char *dest, int64_t expiry)
384 {
385  char *value;
386  int ret;
387 
388  value = av_asprintf("%"PRIi64";%s", expiry, dest);
389  if (!value) {
390  return AVERROR(ENOMEM);
391  }
392 
394  if (ret < 0)
395  return ret;
396 
397  return 0;
398 }
399 
400 /* return non zero if error */
402 {
403  HTTPAuthType cur_auth_type, cur_proxy_auth_type;
404  HTTPContext *s = h->priv_data;
405  int ret, conn_attempts = 1, auth_attempts = 0, redirects = 0;
406  int reconnect_delay = 0;
407  int reconnect_delay_total = 0;
408  uint64_t off;
409  char *cached;
410 
411 redo:
412 
413  cached = redirect_cache_get(s);
414  if (cached) {
415  if (redirects++ >= s->max_redirects)
416  return AVERROR(EIO);
417 
418  av_free(s->location);
419  s->location = av_strdup(cached);
420  if (!s->location) {
421  ret = AVERROR(ENOMEM);
422  goto fail;
423  }
424  goto redo;
425  }
426 
427  av_dict_copy(options, s->chained_options, 0);
428 
429  cur_auth_type = s->auth_state.auth_type;
430  cur_proxy_auth_type = s->auth_state.auth_type;
431 
432  off = s->off;
434  if (ret < 0) {
435  if (!http_should_reconnect(s, ret) ||
436  reconnect_delay > s->reconnect_delay_max ||
437  (s->reconnect_max_retries >= 0 && conn_attempts > s->reconnect_max_retries) ||
438  reconnect_delay_total > s->reconnect_delay_total_max)
439  goto fail;
440 
441  /* Both fields here are in seconds. */
442  if (s->respect_retry_after && s->retry_after > 0) {
443  reconnect_delay = s->retry_after;
444  if (reconnect_delay > s->reconnect_delay_max)
445  goto fail;
446  s->retry_after = 0;
447  s->nb_retries++;
448  }
449 
450  av_log(h, AV_LOG_WARNING, "Will reconnect at %"PRIu64" in %d second(s).\n", off, reconnect_delay);
451  ret = ff_network_sleep_interruptible(1000U * 1000 * reconnect_delay, &h->interrupt_callback);
452  if (ret != AVERROR(ETIMEDOUT))
453  goto fail;
454  reconnect_delay_total += reconnect_delay;
455  reconnect_delay = 1 + 2 * reconnect_delay;
456  s->nb_reconnects++;
457  conn_attempts++;
458 
459  /* restore the offset (http_connect resets it) */
460  s->off = off;
461 
462  ffurl_closep(&s->hd);
463  goto redo;
464  }
465 
466  auth_attempts++;
467  if (s->http_code == 401) {
468  if ((cur_auth_type == HTTP_AUTH_NONE || s->auth_state.stale) &&
469  s->auth_state.auth_type != HTTP_AUTH_NONE && auth_attempts < 4) {
470  ffurl_closep(&s->hd);
471  goto redo;
472  } else
473  goto fail;
474  }
475  if (s->http_code == 407) {
476  if ((cur_proxy_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
477  s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && auth_attempts < 4) {
478  ffurl_closep(&s->hd);
479  goto redo;
480  } else
481  goto fail;
482  }
483  if ((s->http_code == 301 || s->http_code == 302 ||
484  s->http_code == 303 || s->http_code == 307 || s->http_code == 308) &&
485  s->new_location) {
486  /* url moved, get next */
487  ffurl_closep(&s->hd);
488  if (redirects++ >= s->max_redirects)
489  return AVERROR(EIO);
490 
491  if (!s->expires) {
492  s->expires = (s->http_code == 301 || s->http_code == 308) ? INT64_MAX : -1;
493  }
494 
495  if (s->expires > time(NULL) && av_dict_count(s->redirect_cache) < MAX_CACHED_REDIRECTS) {
496  redirect_cache_set(s, s->location, s->new_location, s->expires);
497  }
498 
499  av_free(s->location);
500  s->location = s->new_location;
501  s->new_location = NULL;
502  s->nb_redirects++;
503 
504  /* Restart the authentication process with the new target, which
505  * might use a different auth mechanism. */
506  memset(&s->auth_state, 0, sizeof(s->auth_state));
507  auth_attempts = 0;
508  goto redo;
509  }
510  return 0;
511 
512 fail:
513  if (s->hd)
514  ffurl_closep(&s->hd);
515  if (ret < 0)
516  return ret;
517  return ff_http_averror(s->http_code, AVERROR(EIO));
518 }
519 
520 int ff_http_do_new_request(URLContext *h, const char *uri) {
521  return ff_http_do_new_request2(h, uri, NULL);
522 }
523 
525 {
526  HTTPContext *s = h->priv_data;
528  int ret;
529  char hostname1[1024], hostname2[1024], proto1[10], proto2[10];
530  int port1, port2;
531 
532  if (!h->prot ||
533  !(!strcmp(h->prot->name, "http") ||
534  !strcmp(h->prot->name, "https")))
535  return AVERROR(EINVAL);
536 
537  av_url_split(proto1, sizeof(proto1), NULL, 0,
538  hostname1, sizeof(hostname1), &port1,
539  NULL, 0, s->location);
540  av_url_split(proto2, sizeof(proto2), NULL, 0,
541  hostname2, sizeof(hostname2), &port2,
542  NULL, 0, uri);
543  if (strcmp(proto1, proto2) != 0) {
544  av_log(h, AV_LOG_INFO, "Cannot reuse HTTP connection for different protocol %s vs %s\n",
545  proto1, proto2);
546  return AVERROR(EINVAL);
547  }
548  if (port1 != port2 || strncmp(hostname1, hostname2, sizeof(hostname2)) != 0) {
549  av_log(h, AV_LOG_INFO, "Cannot reuse HTTP connection for different host: %s:%d != %s:%d\n",
550  hostname1, port1,
551  hostname2, port2
552  );
553  return AVERROR(EINVAL);
554  }
555 
556  if (!s->end_chunked_post) {
557  ret = http_shutdown(h, h->flags);
558  if (ret < 0)
559  return ret;
560  }
561 
562  if (s->willclose)
563  return AVERROR_EOF;
564 
565  s->end_chunked_post = 0;
566  s->chunkend = 0;
567  s->off = 0;
568  s->icy_data_read = 0;
569 
570  av_free(s->location);
571  s->location = av_strdup(uri);
572  if (!s->location)
573  return AVERROR(ENOMEM);
574 
575  av_free(s->uri);
576  s->uri = av_strdup(uri);
577  if (!s->uri)
578  return AVERROR(ENOMEM);
579 
580  if ((ret = av_opt_set_dict(s, opts)) < 0)
581  return ret;
582 
583  av_log(s, AV_LOG_INFO, "Opening \'%s\' for %s\n", uri, h->flags & AVIO_FLAG_WRITE ? "writing" : "reading");
584  ret = http_open_cnx(h, &options);
586  return ret;
587 }
588 
589 int ff_http_averror(int status_code, int default_averror)
590 {
591  switch (status_code) {
592  case 400: return AVERROR_HTTP_BAD_REQUEST;
593  case 401: return AVERROR_HTTP_UNAUTHORIZED;
594  case 403: return AVERROR_HTTP_FORBIDDEN;
595  case 404: return AVERROR_HTTP_NOT_FOUND;
596  case 429: return AVERROR_HTTP_TOO_MANY_REQUESTS;
597  default: break;
598  }
599  if (status_code >= 400 && status_code <= 499)
600  return AVERROR_HTTP_OTHER_4XX;
601  else if (status_code >= 500)
603  else
604  return default_averror;
605 }
606 
608 {
609  HTTPContext *s = h->priv_data;
610  return s->new_location;
611 }
612 
613 static int http_write_reply(URLContext* h, int status_code)
614 {
615  int ret, body = 0, reply_code, message_len;
616  const char *reply_text, *content_type;
617  HTTPContext *s = h->priv_data;
618  char message[BUFFER_SIZE];
619  content_type = "text/plain";
620 
621  if (status_code < 0)
622  body = 1;
623  switch (status_code) {
625  case 400:
626  reply_code = 400;
627  reply_text = "Bad Request";
628  break;
630  case 403:
631  reply_code = 403;
632  reply_text = "Forbidden";
633  break;
635  case 404:
636  reply_code = 404;
637  reply_text = "Not Found";
638  break;
640  case 429:
641  reply_code = 429;
642  reply_text = "Too Many Requests";
643  break;
644  case 200:
645  reply_code = 200;
646  reply_text = "OK";
647  content_type = s->content_type ? s->content_type : "application/octet-stream";
648  break;
650  case 500:
651  reply_code = 500;
652  reply_text = "Internal server error";
653  break;
654  default:
655  return AVERROR(EINVAL);
656  }
657  if (body) {
658  s->chunked_post = 0;
659  message_len = snprintf(message, sizeof(message),
660  "HTTP/1.1 %03d %s\r\n"
661  "Content-Type: %s\r\n"
662  "Content-Length: %zu\r\n"
663  "%s"
664  "\r\n"
665  "%03d %s\r\n",
666  reply_code,
667  reply_text,
668  content_type,
669  strlen(reply_text) + 6, // 3 digit status code + space + \r\n
670  s->headers ? s->headers : "",
671  reply_code,
672  reply_text);
673  } else {
674  s->chunked_post = 1;
675  message_len = snprintf(message, sizeof(message),
676  "HTTP/1.1 %03d %s\r\n"
677  "Content-Type: %s\r\n"
678  "Transfer-Encoding: chunked\r\n"
679  "%s"
680  "\r\n",
681  reply_code,
682  reply_text,
683  content_type,
684  s->headers ? s->headers : "");
685  }
686  av_log(h, AV_LOG_TRACE, "HTTP reply header: \n%s----\n", message);
687  if ((ret = ffurl_write(s->hd, message, message_len)) < 0)
688  return ret;
689  return 0;
690 }
691 
693 {
694  av_assert0(error < 0);
696 }
697 
699 {
700  int ret, err;
701  HTTPContext *ch = c->priv_data;
702  URLContext *cl = ch->hd;
703  switch (ch->handshake_step) {
704  case LOWER_PROTO:
705  av_log(c, AV_LOG_TRACE, "Lower protocol\n");
706  if ((ret = ffurl_handshake(cl)) > 0)
707  return 2 + ret;
708  if (ret < 0)
709  return ret;
711  ch->is_connected_server = 1;
712  return 2;
713  case READ_HEADERS:
714  av_log(c, AV_LOG_TRACE, "Read headers\n");
715  if ((err = http_read_header(c)) < 0) {
716  handle_http_errors(c, err);
717  return err;
718  }
720  return 1;
721  case WRITE_REPLY_HEADERS:
722  av_log(c, AV_LOG_TRACE, "Reply code: %d\n", ch->reply_code);
723  if ((err = http_write_reply(c, ch->reply_code)) < 0)
724  return err;
725  ch->handshake_step = FINISH;
726  return 1;
727  case FINISH:
728  return 0;
729  }
730  // this should never be reached.
731  return AVERROR(EINVAL);
732 }
733 
734 static int http_listen(URLContext *h, const char *uri, int flags,
735  AVDictionary **options) {
736  HTTPContext *s = h->priv_data;
737  int ret;
738  char hostname[1024], proto[10];
739  char lower_url[100];
740  const char *lower_proto = "tcp";
741  int port;
742  av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
743  NULL, 0, uri);
744  if (!strcmp(proto, "https"))
745  lower_proto = "tls";
746  ff_url_join(lower_url, sizeof(lower_url), lower_proto, NULL, hostname, port,
747  NULL);
748  if ((ret = av_dict_set_int(options, "listen", s->listen, 0)) < 0)
749  goto fail;
750  if ((ret = ffurl_open_whitelist(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
751  &h->interrupt_callback, options,
752  h->protocol_whitelist, h->protocol_blacklist, h
753  )) < 0)
754  goto fail;
755  s->handshake_step = LOWER_PROTO;
756  if (s->listen == HTTP_SINGLE) { /* single client */
757  s->reply_code = 200;
758  while ((ret = http_handshake(h)) > 0);
759  }
760 fail:
761  av_dict_free(&s->chained_options);
762  av_dict_free(&s->cookie_dict);
763  return ret;
764 }
765 
766 static int http_open(URLContext *h, const char *uri, int flags,
768 {
769  HTTPContext *s = h->priv_data;
770  int ret;
771 
772  if( s->seekable == 1 )
773  h->is_streamed = 0;
774  else
775  h->is_streamed = 1;
776 
777  s->partial_requests = s->seekable != 0 && s->initial_request_size > 0;
778  s->filesize = UINT64_MAX;
779 
780  s->location = av_strdup(uri);
781  if (!s->location)
782  return AVERROR(ENOMEM);
783 
784  s->uri = av_strdup(uri);
785  if (!s->uri)
786  return AVERROR(ENOMEM);
787 
788  if (options)
789  av_dict_copy(&s->chained_options, *options, 0);
790 
791  if (s->headers) {
792  int len = strlen(s->headers);
793  if (len < 2 || strcmp("\r\n", s->headers + len - 2)) {
795  "No trailing CRLF found in HTTP header. Adding it.\n");
796  ret = av_reallocp(&s->headers, len + 3);
797  if (ret < 0)
798  goto bail_out;
799  s->headers[len] = '\r';
800  s->headers[len + 1] = '\n';
801  s->headers[len + 2] = '\0';
802  }
803  }
804 
805  if (s->listen) {
806  return http_listen(h, uri, flags, options);
807  }
809 bail_out:
810  if (ret < 0) {
811  av_dict_free(&s->chained_options);
812  av_dict_free(&s->cookie_dict);
813  av_dict_free(&s->redirect_cache);
814  av_freep(&s->new_location);
815  av_freep(&s->uri);
816  }
817  return ret;
818 }
819 
821 {
822  int ret;
823  HTTPContext *sc = s->priv_data;
824  HTTPContext *cc;
825  URLContext *sl = sc->hd;
826  URLContext *cl = NULL;
827 
828  av_assert0(sc->listen);
829  if ((ret = ffurl_alloc(c, s->filename, s->flags, &sl->interrupt_callback)) < 0)
830  goto fail;
831  cc = (*c)->priv_data;
832  if ((ret = ffurl_accept(sl, &cl)) < 0)
833  goto fail;
834  cc->hd = cl;
835  cc->is_multi_client = 1;
836  return 0;
837 fail:
838  if (c) {
839  ffurl_closep(c);
840  }
841  return ret;
842 }
843 
844 static int http_getc(HTTPContext *s)
845 {
846  int len;
847  if (s->buf_ptr >= s->buf_end) {
848  len = ffurl_read(s->hd, s->buffer, BUFFER_SIZE);
849  if (len < 0) {
850  return len;
851  } else if (len == 0) {
852  return AVERROR_EOF;
853  } else {
854  s->buf_ptr = s->buffer;
855  s->buf_end = s->buffer + len;
856  }
857  }
858  return *s->buf_ptr++;
859 }
860 
861 static int http_get_line(HTTPContext *s, char *line, int line_size)
862 {
863  int ch;
864  char *q;
865 
866  q = line;
867  for (;;) {
868  ch = http_getc(s);
869  if (ch < 0)
870  return ch;
871  if (ch == '\n') {
872  /* process line */
873  if (q > line && q[-1] == '\r')
874  q--;
875  *q = '\0';
876 
877  return 0;
878  } else {
879  if ((q - line) < line_size - 1)
880  *q++ = ch;
881  }
882  }
883 }
884 
885 static int check_http_code(URLContext *h, int http_code, const char *end)
886 {
887  HTTPContext *s = h->priv_data;
888  /* error codes are 4xx and 5xx, but regard 401 as a success, so we
889  * don't abort until all headers have been parsed. */
890  if (http_code >= 400 && http_code < 600 &&
891  (http_code != 401 || s->auth_state.auth_type != HTTP_AUTH_NONE) &&
892  (http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) {
893  end += strspn(end, SPACE_CHARS);
894  av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n", http_code, end);
895  return ff_http_averror(http_code, AVERROR(EIO));
896  }
897  return 0;
898 }
899 
900 static int parse_location(HTTPContext *s, const char *p)
901 {
902  char redirected_location[MAX_URL_SIZE];
903  ff_make_absolute_url(redirected_location, sizeof(redirected_location),
904  s->location, p);
905  av_freep(&s->new_location);
906  s->new_location = av_strdup(redirected_location);
907  if (!s->new_location)
908  return AVERROR(ENOMEM);
909  return 0;
910 }
911 
912 /* "bytes $from-$to/$document_size" */
913 static void parse_content_range(URLContext *h, const char *p)
914 {
915  HTTPContext *s = h->priv_data;
916  const char *slash, *end;
917 
918  if (!strncmp(p, "bytes ", 6)) {
919  p += 6;
920  s->off = strtoull(p, NULL, 10);
921  if ((end = strchr(p, '-')) && strlen(end) > 0)
922  s->range_end = strtoull(end + 1, NULL, 10) + 1;
923  if ((slash = strchr(p, '/')) && strlen(slash) > 0)
924  s->filesize_from_content_range = strtoull(slash + 1, NULL, 10);
925  }
926  if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647))
927  h->is_streamed = 0; /* we _can_ in fact seek */
928 }
929 
930 static int parse_content_encoding(URLContext *h, const char *p)
931 {
932  if (!av_strncasecmp(p, "gzip", 4) ||
933  !av_strncasecmp(p, "deflate", 7)) {
934 #if CONFIG_ZLIB
935  HTTPContext *s = h->priv_data;
936 
937  s->compressed = 1;
938  inflateEnd(&s->inflate_stream);
939  if (inflateInit2(&s->inflate_stream, 32 + 15) != Z_OK) {
940  av_log(h, AV_LOG_WARNING, "Error during zlib initialisation: %s\n",
941  s->inflate_stream.msg);
942  return AVERROR(ENOSYS);
943  }
944  if (zlibCompileFlags() & (1 << 17)) {
946  "Your zlib was compiled without gzip support.\n");
947  return AVERROR(ENOSYS);
948  }
949 #else
951  "Compressed (%s) content, need zlib with gzip support\n", p);
952  return AVERROR(ENOSYS);
953 #endif /* CONFIG_ZLIB */
954  } else if (!av_strncasecmp(p, "identity", 8)) {
955  // The normal, no-encoding case (although servers shouldn't include
956  // the header at all if this is the case).
957  } else {
958  av_log(h, AV_LOG_WARNING, "Unknown content coding: %s\n", p);
959  }
960  return 0;
961 }
962 
963 // Concat all Icy- header lines
964 static int parse_icy(HTTPContext *s, const char *tag, const char *p)
965 {
966  int len = 4 + strlen(p) + strlen(tag);
967  int is_first = !s->icy_metadata_headers;
968  int ret;
969 
970  av_dict_set(&s->metadata, tag, p, 0);
971 
972  if (s->icy_metadata_headers)
973  len += strlen(s->icy_metadata_headers);
974 
975  if ((ret = av_reallocp(&s->icy_metadata_headers, len)) < 0)
976  return ret;
977 
978  if (is_first)
979  *s->icy_metadata_headers = '\0';
980 
981  av_strlcatf(s->icy_metadata_headers, len, "%s: %s\n", tag, p);
982 
983  return 0;
984 }
985 
986 static int parse_http_date(const char *date_str, struct tm *buf)
987 {
988  char date_buf[MAX_DATE_LEN];
989  int i, j, date_buf_len = MAX_DATE_LEN-1;
990  char *date;
991 
992  // strip off any punctuation or whitespace
993  for (i = 0, j = 0; date_str[i] != '\0' && j < date_buf_len; i++) {
994  if ((date_str[i] >= '0' && date_str[i] <= '9') ||
995  (date_str[i] >= 'A' && date_str[i] <= 'Z') ||
996  (date_str[i] >= 'a' && date_str[i] <= 'z')) {
997  date_buf[j] = date_str[i];
998  j++;
999  }
1000  }
1001  date_buf[j] = '\0';
1002  date = date_buf;
1003 
1004  // move the string beyond the day of week
1005  while ((*date < '0' || *date > '9') && *date != '\0')
1006  date++;
1007 
1008  return av_small_strptime(date, "%d%b%Y%H%M%S", buf) ? 0 : AVERROR(EINVAL);
1009 }
1010 
1011 static int parse_set_cookie(const char *set_cookie, AVDictionary **dict)
1012 {
1013  char *param, *next_param, *cstr, *back;
1014  char *saveptr = NULL;
1015 
1016  if (!set_cookie[0])
1017  return 0;
1018 
1019  if (!(cstr = av_strdup(set_cookie)))
1020  return AVERROR(EINVAL);
1021 
1022  // strip any trailing whitespace
1023  back = &cstr[strlen(cstr)-1];
1024  while (strchr(WHITESPACES, *back)) {
1025  *back='\0';
1026  if (back == cstr)
1027  break;
1028  back--;
1029  }
1030 
1031  next_param = cstr;
1032  while ((param = av_strtok(next_param, ";", &saveptr))) {
1033  char *name, *value;
1034  next_param = NULL;
1035  param += strspn(param, WHITESPACES);
1036  if ((name = av_strtok(param, "=", &value))) {
1037  if (av_dict_set(dict, name, value, 0) < 0) {
1038  av_free(cstr);
1039  return -1;
1040  }
1041  }
1042  }
1043 
1044  av_free(cstr);
1045  return 0;
1046 }
1047 
1048 static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
1049 {
1050  AVDictionary *new_params = NULL;
1051  const AVDictionaryEntry *e, *cookie_entry;
1052  char *eql, *name;
1053 
1054  // ensure the cookie is parsable
1055  if (parse_set_cookie(p, &new_params))
1056  return -1;
1057 
1058  // if there is no cookie value there is nothing to parse
1059  cookie_entry = av_dict_iterate(new_params, NULL);
1060  if (!cookie_entry || !cookie_entry->value) {
1061  av_dict_free(&new_params);
1062  return -1;
1063  }
1064 
1065  // ensure the cookie is not expired or older than an existing value
1066  if ((e = av_dict_get(new_params, "expires", NULL, 0)) && e->value) {
1067  struct tm new_tm = {0};
1068  if (!parse_http_date(e->value, &new_tm)) {
1069  AVDictionaryEntry *e2;
1070 
1071  // if the cookie has already expired ignore it
1072  if (av_timegm(&new_tm) < av_gettime() / 1000000) {
1073  av_dict_free(&new_params);
1074  return 0;
1075  }
1076 
1077  // only replace an older cookie with the same name
1078  e2 = av_dict_get(*cookies, cookie_entry->key, NULL, 0);
1079  if (e2 && e2->value) {
1080  AVDictionary *old_params = NULL;
1081  if (!parse_set_cookie(p, &old_params)) {
1082  e2 = av_dict_get(old_params, "expires", NULL, 0);
1083  if (e2 && e2->value) {
1084  struct tm old_tm = {0};
1085  if (!parse_http_date(e->value, &old_tm)) {
1086  if (av_timegm(&new_tm) < av_timegm(&old_tm)) {
1087  av_dict_free(&new_params);
1088  av_dict_free(&old_params);
1089  return -1;
1090  }
1091  }
1092  }
1093  }
1094  av_dict_free(&old_params);
1095  }
1096  }
1097  }
1098  av_dict_free(&new_params);
1099 
1100  // duplicate the cookie name (dict will dupe the value)
1101  if (!(eql = strchr(p, '='))) return AVERROR(EINVAL);
1102  if (!(name = av_strndup(p, eql - p))) return AVERROR(ENOMEM);
1103 
1104  // add the cookie to the dictionary
1105  av_dict_set(cookies, name, eql, AV_DICT_DONT_STRDUP_KEY);
1106 
1107  return 0;
1108 }
1109 
1110 static int cookie_string(AVDictionary *dict, char **cookies)
1111 {
1112  const AVDictionaryEntry *e = NULL;
1113  int len = 1;
1114 
1115  // determine how much memory is needed for the cookies string
1116  while ((e = av_dict_iterate(dict, e)))
1117  len += strlen(e->key) + strlen(e->value) + 1;
1118 
1119  // reallocate the cookies
1120  e = NULL;
1121  if (*cookies) av_free(*cookies);
1122  *cookies = av_malloc(len);
1123  if (!*cookies) return AVERROR(ENOMEM);
1124  *cookies[0] = '\0';
1125 
1126  // write out the cookies
1127  while ((e = av_dict_iterate(dict, e)))
1128  av_strlcatf(*cookies, len, "%s%s\n", e->key, e->value);
1129 
1130  return 0;
1131 }
1132 
1133 static void parse_expires(HTTPContext *s, const char *p)
1134 {
1135  struct tm tm;
1136 
1137  if (!parse_http_date(p, &tm)) {
1138  s->expires = av_timegm(&tm);
1139  }
1140 }
1141 
1142 static void parse_cache_control(HTTPContext *s, const char *p)
1143 {
1144  char *age;
1145  int offset;
1146 
1147  /* give 'Expires' higher priority over 'Cache-Control' */
1148  if (s->expires) {
1149  return;
1150  }
1151 
1152  if (av_stristr(p, "no-cache") || av_stristr(p, "no-store")) {
1153  s->expires = -1;
1154  return;
1155  }
1156 
1157  age = av_stristr(p, "s-maxage=");
1158  offset = 9;
1159  if (!age) {
1160  age = av_stristr(p, "max-age=");
1161  offset = 8;
1162  }
1163 
1164  if (age) {
1165  s->expires = time(NULL) + atoi(p + offset);
1166  }
1167 }
1168 
1169 static int process_line(URLContext *h, char *line, int line_count, int *parsed_http_code)
1170 {
1171  HTTPContext *s = h->priv_data;
1172  const char *auto_method = h->flags & AVIO_FLAG_READ ? "POST" : "GET";
1173  char *tag, *p, *end, *method, *resource, *version;
1174  int ret;
1175 
1176  /* end of header */
1177  if (line[0] == '\0') {
1178  s->end_header = 1;
1179  return 0;
1180  }
1181 
1182  p = line;
1183  if (line_count == 0) {
1184  if (s->is_connected_server) {
1185  // HTTP method
1186  method = p;
1187  while (*p && !av_isspace(*p))
1188  p++;
1189  *(p++) = '\0';
1190  av_log(h, AV_LOG_TRACE, "Received method: %s\n", method);
1191  if (s->method) {
1192  if (av_strcasecmp(s->method, method)) {
1193  av_log(h, AV_LOG_ERROR, "Received and expected HTTP method do not match. (%s expected, %s received)\n",
1194  s->method, method);
1195  return ff_http_averror(400, AVERROR(EIO));
1196  }
1197  } else {
1198  // use autodetected HTTP method to expect
1199  av_log(h, AV_LOG_TRACE, "Autodetected %s HTTP method\n", auto_method);
1200  if (av_strcasecmp(auto_method, method)) {
1201  av_log(h, AV_LOG_ERROR, "Received and autodetected HTTP method did not match "
1202  "(%s autodetected %s received)\n", auto_method, method);
1203  return ff_http_averror(400, AVERROR(EIO));
1204  }
1205  if (!(s->method = av_strdup(method)))
1206  return AVERROR(ENOMEM);
1207  }
1208 
1209  // HTTP resource
1210  while (av_isspace(*p))
1211  p++;
1212  resource = p;
1213  while (*p && !av_isspace(*p))
1214  p++;
1215  *(p++) = '\0';
1216  av_log(h, AV_LOG_TRACE, "Requested resource: %s\n", resource);
1217  if (!(s->resource = av_strdup(resource)))
1218  return AVERROR(ENOMEM);
1219 
1220  // HTTP version
1221  while (av_isspace(*p))
1222  p++;
1223  version = p;
1224  while (*p && !av_isspace(*p))
1225  p++;
1226  *p = '\0';
1227  if (av_strncasecmp(version, "HTTP/", 5)) {
1228  av_log(h, AV_LOG_ERROR, "Malformed HTTP version string.\n");
1229  return ff_http_averror(400, AVERROR(EIO));
1230  }
1231  av_log(h, AV_LOG_TRACE, "HTTP version string: %s\n", version);
1232  } else {
1233  if (av_strncasecmp(p, "HTTP/1.0", 8) == 0)
1234  s->willclose = 1;
1235  while (*p != '/' && *p != '\0')
1236  p++;
1237  while (*p == '/')
1238  p++;
1239  av_freep(&s->http_version);
1240  s->http_version = av_strndup(p, 3);
1241  while (!av_isspace(*p) && *p != '\0')
1242  p++;
1243  while (av_isspace(*p))
1244  p++;
1245  s->http_code = strtol(p, &end, 10);
1246 
1247  av_log(h, AV_LOG_TRACE, "http_code=%d\n", s->http_code);
1248 
1249  *parsed_http_code = 1;
1250 
1251  if ((ret = check_http_code(h, s->http_code, end)) < 0)
1252  return ret;
1253  }
1254  } else {
1255  while (*p != '\0' && *p != ':')
1256  p++;
1257  if (*p != ':')
1258  return 1;
1259 
1260  *p = '\0';
1261  tag = line;
1262  p++;
1263  while (av_isspace(*p))
1264  p++;
1265  if (!av_strcasecmp(tag, "Location")) {
1266  if ((ret = parse_location(s, p)) < 0)
1267  return ret;
1268  } else if (!av_strcasecmp(tag, "Content-Length") &&
1269  s->filesize == UINT64_MAX) {
1270  s->filesize = strtoull(p, NULL, 10);
1271  } else if (!av_strcasecmp(tag, "Content-Range")) {
1273  } else if (!av_strcasecmp(tag, "Accept-Ranges") &&
1274  !strncmp(p, "bytes", 5) &&
1275  s->seekable == -1) {
1276  h->is_streamed = 0;
1277  } else if (!av_strcasecmp(tag, "Transfer-Encoding") &&
1278  !av_strncasecmp(p, "chunked", 7)) {
1279  s->filesize = UINT64_MAX;
1280  s->chunksize = 0;
1281  } else if (!av_strcasecmp(tag, "WWW-Authenticate")) {
1282  ff_http_auth_handle_header(&s->auth_state, tag, p);
1283  } else if (!av_strcasecmp(tag, "Authentication-Info")) {
1284  ff_http_auth_handle_header(&s->auth_state, tag, p);
1285  } else if (!av_strcasecmp(tag, "Proxy-Authenticate")) {
1286  ff_http_auth_handle_header(&s->proxy_auth_state, tag, p);
1287  } else if (!av_strcasecmp(tag, "Connection")) {
1288  if (!strcmp(p, "close"))
1289  s->willclose = 1;
1290  } else if (!av_strcasecmp(tag, "Server")) {
1291  if (!av_strcasecmp(p, "AkamaiGHost")) {
1292  s->is_akamai = 1;
1293  } else if (!av_strncasecmp(p, "MediaGateway", 12)) {
1294  s->is_mediagateway = 1;
1295  }
1296  } else if (!av_strcasecmp(tag, "Content-Type")) {
1297  av_free(s->mime_type);
1298  s->mime_type = av_get_token((const char **)&p, ";");
1299  } else if (!av_strcasecmp(tag, "Set-Cookie")) {
1300  if (parse_cookie(s, p, &s->cookie_dict))
1301  av_log(h, AV_LOG_WARNING, "Unable to parse '%s'\n", p);
1302  } else if (!av_strcasecmp(tag, "Icy-MetaInt")) {
1303  s->icy_metaint = strtoull(p, NULL, 10);
1304  } else if (!av_strncasecmp(tag, "Icy-", 4)) {
1305  if ((ret = parse_icy(s, tag, p)) < 0)
1306  return ret;
1307  } else if (!av_strcasecmp(tag, "Content-Encoding")) {
1308  if ((ret = parse_content_encoding(h, p)) < 0)
1309  return ret;
1310  } else if (!av_strcasecmp(tag, "Expires")) {
1311  parse_expires(s, p);
1312  } else if (!av_strcasecmp(tag, "Cache-Control")) {
1314  } else if (!av_strcasecmp(tag, "Retry-After")) {
1315  /* The header can be either an integer that represents seconds, or a date. */
1316  struct tm tm;
1317  int date_ret = parse_http_date(p, &tm);
1318  if (!date_ret) {
1319  time_t retry = av_timegm(&tm);
1320  int64_t now = av_gettime() / 1000000;
1321  int64_t diff = ((int64_t) retry) - now;
1322  s->retry_after = (unsigned int) FFMAX(0, diff);
1323  } else {
1324  s->retry_after = strtoul(p, NULL, 10);
1325  }
1326  }
1327  }
1328  return 1;
1329 }
1330 
1331 /**
1332  * Create a string containing cookie values for use as a HTTP cookie header
1333  * field value for a particular path and domain from the cookie values stored in
1334  * the HTTP protocol context. The cookie string is stored in *cookies, and may
1335  * be NULL if there are no valid cookies.
1336  *
1337  * @return a negative value if an error condition occurred, 0 otherwise
1338  */
1339 static int get_cookies(HTTPContext *s, char **cookies, const char *path,
1340  const char *domain)
1341 {
1342  // cookie strings will look like Set-Cookie header field values. Multiple
1343  // Set-Cookie fields will result in multiple values delimited by a newline
1344  int ret = 0;
1345  char *cookie, *set_cookies, *next;
1346  char *saveptr = NULL;
1347 
1348  // destroy any cookies in the dictionary.
1349  av_dict_free(&s->cookie_dict);
1350 
1351  if (!s->cookies)
1352  return 0;
1353 
1354  next = set_cookies = av_strdup(s->cookies);
1355  if (!next)
1356  return AVERROR(ENOMEM);
1357 
1358  *cookies = NULL;
1359  while ((cookie = av_strtok(next, "\n", &saveptr)) && !ret) {
1360  AVDictionary *cookie_params = NULL;
1361  const AVDictionaryEntry *cookie_entry, *e;
1362 
1363  next = NULL;
1364  // store the cookie in a dict in case it is updated in the response
1365  if (parse_cookie(s, cookie, &s->cookie_dict))
1366  av_log(s, AV_LOG_WARNING, "Unable to parse '%s'\n", cookie);
1367 
1368  // continue on to the next cookie if this one cannot be parsed
1369  if (parse_set_cookie(cookie, &cookie_params))
1370  goto skip_cookie;
1371 
1372  // if the cookie has no value, skip it
1373  cookie_entry = av_dict_iterate(cookie_params, NULL);
1374  if (!cookie_entry || !cookie_entry->value)
1375  goto skip_cookie;
1376 
1377  // if the cookie has expired, don't add it
1378  if ((e = av_dict_get(cookie_params, "expires", NULL, 0)) && e->value) {
1379  struct tm tm_buf = {0};
1380  if (!parse_http_date(e->value, &tm_buf)) {
1381  if (av_timegm(&tm_buf) < av_gettime() / 1000000)
1382  goto skip_cookie;
1383  }
1384  }
1385 
1386  // if no domain in the cookie assume it applied to this request
1387  if ((e = av_dict_get(cookie_params, "domain", NULL, 0)) && e->value) {
1388  // find the offset comparison is on the min domain (b.com, not a.b.com)
1389  int domain_offset = strlen(domain) - strlen(e->value);
1390  if (domain_offset < 0)
1391  goto skip_cookie;
1392 
1393  // match the cookie domain
1394  if (av_strcasecmp(&domain[domain_offset], e->value))
1395  goto skip_cookie;
1396  }
1397 
1398  // if a cookie path is provided, ensure the request path is within that path
1399  e = av_dict_get(cookie_params, "path", NULL, 0);
1400  if (e && av_strncasecmp(path, e->value, strlen(e->value)))
1401  goto skip_cookie;
1402 
1403  // cookie parameters match, so copy the value
1404  if (!*cookies) {
1405  *cookies = av_asprintf("%s=%s", cookie_entry->key, cookie_entry->value);
1406  } else {
1407  char *tmp = *cookies;
1408  *cookies = av_asprintf("%s; %s=%s", tmp, cookie_entry->key, cookie_entry->value);
1409  av_free(tmp);
1410  }
1411  if (!*cookies)
1412  ret = AVERROR(ENOMEM);
1413 
1414  skip_cookie:
1415  av_dict_free(&cookie_params);
1416  }
1417 
1418  av_free(set_cookies);
1419 
1420  return ret;
1421 }
1422 
1423 static inline int has_header(const char *str, const char *header)
1424 {
1425  /* header + 2 to skip over CRLF prefix. (make sure you have one!) */
1426  if (!str)
1427  return 0;
1428  return av_stristart(str, header + 2, NULL) || av_stristr(str, header);
1429 }
1430 
1432 {
1433  HTTPContext *s = h->priv_data;
1434  char line[MAX_URL_SIZE];
1435  int err = 0, http_err = 0;
1436 
1437  av_freep(&s->new_location);
1438  s->expires = 0;
1439  s->chunksize = UINT64_MAX;
1440  s->filesize_from_content_range = UINT64_MAX;
1441 
1442  for (;;) {
1443  int parsed_http_code = 0;
1444 
1445  if ((err = http_get_line(s, line, sizeof(line))) < 0) {
1446  av_log(h, AV_LOG_ERROR, "Error reading HTTP response: %s\n",
1447  av_err2str(err));
1448  return err;
1449  }
1450 
1451  av_log(h, AV_LOG_TRACE, "header='%s'\n", line);
1452 
1453  err = process_line(h, line, s->line_count, &parsed_http_code);
1454  if (err < 0) {
1455  if (parsed_http_code) {
1456  http_err = err;
1457  } else {
1458  /* Prefer to return HTTP code error if we've already seen one. */
1459  if (http_err)
1460  return http_err;
1461  else
1462  return err;
1463  }
1464  }
1465  if (err == 0)
1466  break;
1467  s->line_count++;
1468  }
1469  if (http_err)
1470  return http_err;
1471 
1472  // filesize from Content-Range can always be used, even if using chunked Transfer-Encoding
1473  if (s->filesize_from_content_range != UINT64_MAX)
1474  s->filesize = s->filesize_from_content_range;
1475 
1476  if (s->seekable == -1 && s->is_mediagateway && s->filesize == 2000000000)
1477  h->is_streamed = 1; /* we can in fact _not_ seek */
1478 
1479  if (h->is_streamed)
1480  s->partial_requests = 0; /* unable to use partial requests */
1481 
1482  // add any new cookies into the existing cookie string
1483  cookie_string(s->cookie_dict, &s->cookies);
1484  av_dict_free(&s->cookie_dict);
1485 
1486  return err;
1487 }
1488 
1489 /**
1490  * Escape unsafe characters in path in order to pass them safely to the HTTP
1491  * request. Insipred by the algorithm in GNU wget:
1492  * - escape "%" characters not followed by two hex digits
1493  * - escape all "unsafe" characters except which are also "reserved"
1494  * - pass through everything else
1495  */
1496 static void bprint_escaped_path(AVBPrint *bp, const char *path)
1497 {
1498 #define NEEDS_ESCAPE(ch) \
1499  ((ch) <= ' ' || (ch) >= '\x7f' || \
1500  (ch) == '"' || (ch) == '%' || (ch) == '<' || (ch) == '>' || (ch) == '\\' || \
1501  (ch) == '^' || (ch) == '`' || (ch) == '{' || (ch) == '}' || (ch) == '|')
1502  while (*path) {
1503  char buf[1024];
1504  char *q = buf;
1505  while (*path && q - buf < sizeof(buf) - 4) {
1506  if (path[0] == '%' && av_isxdigit(path[1]) && av_isxdigit(path[2])) {
1507  *q++ = *path++;
1508  *q++ = *path++;
1509  *q++ = *path++;
1510  } else if (NEEDS_ESCAPE(*path)) {
1511  q += snprintf(q, 4, "%%%02X", (uint8_t)*path++);
1512  } else {
1513  *q++ = *path++;
1514  }
1515  }
1516  av_bprint_append_data(bp, buf, q - buf);
1517  }
1518 }
1519 
1520 static int http_connect(URLContext *h, const char *path, const char *local_path,
1521  const char *hoststr, const char *auth,
1522  const char *proxyauth)
1523 {
1524  HTTPContext *s = h->priv_data;
1525  int post, err;
1526  AVBPrint request;
1527  char *authstr = NULL, *proxyauthstr = NULL;
1528  uint64_t off = s->off;
1529  const char *method;
1530  int send_expect_100 = 0;
1531 
1532  av_bprint_init_for_buffer(&request, s->buffer, sizeof(s->buffer));
1533 
1534  /* send http header */
1535  post = h->flags & AVIO_FLAG_WRITE;
1536 
1537  if (s->post_data) {
1538  /* force POST method and disable chunked encoding when
1539  * custom HTTP post data is set */
1540  post = 1;
1541  s->chunked_post = 0;
1542  }
1543 
1544  if (s->method)
1545  method = s->method;
1546  else
1547  method = post ? "POST" : "GET";
1548 
1549  authstr = ff_http_auth_create_response(&s->auth_state, auth,
1550  local_path, method);
1551  proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth,
1552  local_path, method);
1553 
1554  if (post && !s->post_data) {
1555  if (s->send_expect_100 != -1) {
1556  send_expect_100 = s->send_expect_100;
1557  } else {
1558  send_expect_100 = 0;
1559  /* The user has supplied authentication but we don't know the auth type,
1560  * send Expect: 100-continue to get the 401 response including the
1561  * WWW-Authenticate header, or an 100 continue if no auth actually
1562  * is needed. */
1563  if (auth && *auth &&
1564  s->auth_state.auth_type == HTTP_AUTH_NONE &&
1565  s->http_code != 401)
1566  send_expect_100 = 1;
1567  }
1568  }
1569 
1570  av_bprintf(&request, "%s ", method);
1571  bprint_escaped_path(&request, path);
1572  av_bprintf(&request, " HTTP/1.1\r\n");
1573 
1574  if (post && s->chunked_post)
1575  av_bprintf(&request, "Transfer-Encoding: chunked\r\n");
1576  /* set default headers if needed */
1577  if (!has_header(s->headers, "\r\nUser-Agent: "))
1578  av_bprintf(&request, "User-Agent: %s\r\n", s->user_agent);
1579  if (s->referer) {
1580  /* set default headers if needed */
1581  if (!has_header(s->headers, "\r\nReferer: "))
1582  av_bprintf(&request, "Referer: %s\r\n", s->referer);
1583  }
1584  if (!has_header(s->headers, "\r\nAccept: "))
1585  av_bprintf(&request, "Accept: */*\r\n");
1586  // Note: we send the Range header on purpose, even when we're probing,
1587  // since it allows us to detect more reliably if a (non-conforming)
1588  // server supports seeking by analysing the reply headers.
1589  if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->end_off || s->seekable != 0)) {
1590  av_bprintf(&request, "Range: bytes=%"PRIu64"-", s->off);
1591  if (s->partial_requests && s->seekable != 0) {
1592  uint64_t target_off = s->off + s->initial_request_size;
1593  if (target_off < s->off) /* overflow */
1594  target_off = UINT64_MAX;
1595  if (s->end_off)
1596  target_off = FFMIN(target_off, s->end_off);
1597  if (target_off != UINT64_MAX)
1598  av_bprintf(&request, "%"PRId64, target_off - 1);
1599  } else if (s->end_off)
1600  av_bprintf(&request, "%"PRId64, s->end_off - 1);
1601  av_bprintf(&request, "\r\n");
1602  }
1603  if (send_expect_100 && !has_header(s->headers, "\r\nExpect: "))
1604  av_bprintf(&request, "Expect: 100-continue\r\n");
1605 
1606  if (!has_header(s->headers, "\r\nConnection: "))
1607  av_bprintf(&request, "Connection: %s\r\n", s->multiple_requests ? "keep-alive" : "close");
1608 
1609  if (!has_header(s->headers, "\r\nHost: "))
1610  av_bprintf(&request, "Host: %s\r\n", hoststr);
1611  if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data)
1612  av_bprintf(&request, "Content-Length: %d\r\n", s->post_datalen);
1613 
1614  if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
1615  av_bprintf(&request, "Content-Type: %s\r\n", s->content_type);
1616  if (!has_header(s->headers, "\r\nCookie: ") && s->cookies) {
1617  char *cookies = NULL;
1618  if (!get_cookies(s, &cookies, path, hoststr) && cookies) {
1619  av_bprintf(&request, "Cookie: %s\r\n", cookies);
1620  av_free(cookies);
1621  }
1622  }
1623  if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy)
1624  av_bprintf(&request, "Icy-MetaData: 1\r\n");
1625 
1626  /* now add in custom headers */
1627  if (s->headers)
1628  av_bprintf(&request, "%s", s->headers);
1629 
1630  if (authstr)
1631  av_bprintf(&request, "%s", authstr);
1632  if (proxyauthstr)
1633  av_bprintf(&request, "Proxy-%s", proxyauthstr);
1634  av_bprintf(&request, "\r\n");
1635 
1636  av_log(h, AV_LOG_DEBUG, "request: %s\n", request.str);
1637 
1638  if (!av_bprint_is_complete(&request)) {
1639  av_log(h, AV_LOG_ERROR, "overlong headers\n");
1640  err = AVERROR(EINVAL);
1641  goto done;
1642  }
1643 
1644  if ((err = ffurl_write(s->hd, request.str, request.len)) < 0)
1645  goto done;
1646 
1647  if (s->post_data)
1648  if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0)
1649  goto done;
1650 
1651  /* init input buffer */
1652  s->buf_ptr = s->buffer;
1653  s->buf_end = s->buffer;
1654  s->line_count = 0;
1655  s->off = 0;
1656  s->icy_data_read = 0;
1657  s->filesize = UINT64_MAX;
1658  s->willclose = 0;
1659  s->end_chunked_post = 0;
1660  s->end_header = 0;
1661 #if CONFIG_ZLIB
1662  s->compressed = 0;
1663 #endif
1664  if (post && !s->post_data && !send_expect_100) {
1665  /* Pretend that it did work. We didn't read any header yet, since
1666  * we've still to send the POST data, but the code calling this
1667  * function will check http_code after we return. */
1668  s->http_code = 200;
1669  err = 0;
1670  goto done;
1671  }
1672 
1673  /* wait for header */
1674  int64_t latency = av_gettime();
1675  err = http_read_header(h);
1676  latency = av_gettime() - latency;
1677  if (err < 0)
1678  goto done;
1679 
1680  s->nb_requests++;
1681  s->sum_latency += latency;
1682  s->max_latency = FFMAX(s->max_latency, latency);
1683 
1684  if (s->new_location)
1685  s->off = off;
1686 
1687  err = (off == s->off) ? 0 : -1;
1688 done:
1689  av_freep(&authstr);
1690  av_freep(&proxyauthstr);
1691  return err;
1692 }
1693 
1694 static int http_buf_read(URLContext *h, uint8_t *buf, int size)
1695 {
1696  HTTPContext *s = h->priv_data;
1697  int len;
1698 
1699  if (!s->hd)
1700  return AVERROR(EIO);
1701 
1702  if (s->chunksize != UINT64_MAX) {
1703  if (s->chunkend) {
1704  return AVERROR_EOF;
1705  }
1706  if (!s->chunksize) {
1707  char line[32];
1708  int err;
1709 
1710  do {
1711  if ((err = http_get_line(s, line, sizeof(line))) < 0)
1712  return err;
1713  } while (!*line); /* skip CR LF from last chunk */
1714 
1715  s->chunksize = strtoull(line, NULL, 16);
1716 
1718  "Chunked encoding data size: %"PRIu64"\n",
1719  s->chunksize);
1720 
1721  if (!s->chunksize && s->multiple_requests) {
1722  http_get_line(s, line, sizeof(line)); // read empty chunk
1723  s->chunkend = 1;
1724  return 0;
1725  }
1726  else if (!s->chunksize) {
1727  av_log(h, AV_LOG_DEBUG, "Last chunk received, closing conn\n");
1728  ffurl_closep(&s->hd);
1729  return 0;
1730  }
1731  else if (s->chunksize == UINT64_MAX) {
1732  av_log(h, AV_LOG_ERROR, "Invalid chunk size %"PRIu64"\n",
1733  s->chunksize);
1734  return AVERROR(EINVAL);
1735  }
1736  }
1737  size = FFMIN(size, s->chunksize);
1738  }
1739 
1740  /* read bytes from input buffer first */
1741  len = s->buf_end - s->buf_ptr;
1742  if (len > 0) {
1743  if (len > size)
1744  len = size;
1745  memcpy(buf, s->buf_ptr, len);
1746  s->buf_ptr += len;
1747  } else {
1748  uint64_t file_end = s->end_off ? s->end_off : s->filesize;
1749  uint64_t target_end = s->range_end ? s->range_end : file_end;
1750  if ((!s->willclose || s->chunksize == UINT64_MAX) && s->off >= file_end)
1751  return AVERROR_EOF;
1752  if (s->off == target_end && target_end < file_end)
1753  return AVERROR(EAGAIN); /* reached end of content range */
1754  len = ffurl_read(s->hd, buf, size);
1755  if ((!len || len == AVERROR_EOF) &&
1756  (!s->willclose || s->chunksize == UINT64_MAX) && s->off < target_end) {
1758  "Stream ends prematurely at %"PRIu64", should be %"PRIu64"\n",
1759  s->off, target_end
1760  );
1761  return AVERROR(EIO);
1762  }
1763  }
1764  if (len > 0) {
1765  s->off += len;
1766  if (s->chunksize > 0 && s->chunksize != UINT64_MAX) {
1767  av_assert0(s->chunksize >= len);
1768  s->chunksize -= len;
1769  }
1770  }
1771  return len;
1772 }
1773 
1774 #if CONFIG_ZLIB
1775 #define DECOMPRESS_BUF_SIZE (256 * 1024)
1776 static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size)
1777 {
1778  HTTPContext *s = h->priv_data;
1779  int ret;
1780 
1781  if (!s->inflate_buffer) {
1782  s->inflate_buffer = av_malloc(DECOMPRESS_BUF_SIZE);
1783  if (!s->inflate_buffer)
1784  return AVERROR(ENOMEM);
1785  }
1786 
1787  if (s->inflate_stream.avail_in == 0) {
1788  int read = http_buf_read(h, s->inflate_buffer, DECOMPRESS_BUF_SIZE);
1789  if (read <= 0)
1790  return read;
1791  s->inflate_stream.next_in = s->inflate_buffer;
1792  s->inflate_stream.avail_in = read;
1793  }
1794 
1795  s->inflate_stream.avail_out = size;
1796  s->inflate_stream.next_out = buf;
1797 
1798  ret = inflate(&s->inflate_stream, Z_SYNC_FLUSH);
1799  if (ret != Z_OK && ret != Z_STREAM_END)
1800  av_log(h, AV_LOG_WARNING, "inflate return value: %d, %s\n",
1801  ret, s->inflate_stream.msg);
1802 
1803  return size - s->inflate_stream.avail_out;
1804 }
1805 #endif /* CONFIG_ZLIB */
1806 
1807 static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect);
1808 
1809 static int http_read_stream(URLContext *h, uint8_t *buf, int size)
1810 {
1811  HTTPContext *s = h->priv_data;
1812  int err, read_ret;
1813  int64_t seek_ret;
1814  int reconnect_delay = 0;
1815  int reconnect_delay_total = 0;
1816  int conn_attempts = 1;
1817 
1818  if (!s->hd)
1819  return AVERROR_EOF;
1820 
1821  if (s->end_chunked_post && !s->end_header) {
1822  err = http_read_header(h);
1823  if (err < 0)
1824  return err;
1825  }
1826 
1827 #if CONFIG_ZLIB
1828  if (s->compressed)
1829  return http_buf_read_compressed(h, buf, size);
1830 #endif /* CONFIG_ZLIB */
1831  read_ret = http_buf_read(h, buf, size);
1832  while (read_ret < 0) {
1833  uint64_t target = h->is_streamed ? 0 : s->off;
1834  bool is_premature = s->filesize > 0 && s->off < s->filesize;
1835 
1836  if (read_ret == AVERROR_EXIT)
1837  break;
1838  else if (read_ret == AVERROR(EAGAIN)) {
1839  /* send new request for more data on existing connection */
1841  if (s->willclose)
1842  ffurl_closep(&s->hd);
1843  s->partial_requests = 0; /* continue streaming uninterrupted from now on */
1844  read_ret = http_open_cnx(h, &options);
1846  if (read_ret == 0)
1847  goto retry;
1848  }
1849 
1850  if (h->is_streamed && !s->reconnect_streamed)
1851  break;
1852 
1853  if (!(s->reconnect && is_premature) &&
1854  !(s->reconnect_at_eof && read_ret == AVERROR_EOF)) {
1855  if (is_premature)
1856  return AVERROR(EIO);
1857  else
1858  break;
1859  }
1860 
1861  if (reconnect_delay > s->reconnect_delay_max || (s->reconnect_max_retries >= 0 && conn_attempts > s->reconnect_max_retries) ||
1862  reconnect_delay_total > s->reconnect_delay_total_max)
1863  return AVERROR(EIO);
1864 
1865  av_log(h, AV_LOG_WARNING, "Will reconnect at %"PRIu64" in %d second(s), error=%s.\n", s->off, reconnect_delay, av_err2str(read_ret));
1866  err = ff_network_sleep_interruptible(1000U*1000*reconnect_delay, &h->interrupt_callback);
1867  if (err != AVERROR(ETIMEDOUT))
1868  return err;
1869  reconnect_delay_total += reconnect_delay;
1870  reconnect_delay = 1 + 2*reconnect_delay;
1871  conn_attempts++;
1872  seek_ret = http_seek_internal(h, target, SEEK_SET, 1);
1873  if (seek_ret >= 0 && seek_ret != target) {
1874  av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRIu64".\n", target);
1875  return read_ret;
1876  }
1877 
1878 retry:
1879  read_ret = http_buf_read(h, buf, size);
1880  }
1881 
1882  return read_ret;
1883 }
1884 
1885 // Like http_read_stream(), but no short reads.
1886 // Assumes partial reads are an error.
1887 static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
1888 {
1889  int pos = 0;
1890  while (pos < size) {
1891  int len = http_read_stream(h, buf + pos, size - pos);
1892  if (len < 0)
1893  return len;
1894  pos += len;
1895  }
1896  return pos;
1897 }
1898 
1899 static void update_metadata(URLContext *h, char *data)
1900 {
1901  char *key;
1902  char *val;
1903  char *end;
1904  char *next = data;
1905  HTTPContext *s = h->priv_data;
1906 
1907  while (*next) {
1908  key = next;
1909  val = strstr(key, "='");
1910  if (!val)
1911  break;
1912  end = strstr(val, "';");
1913  if (!end)
1914  break;
1915 
1916  *val = '\0';
1917  *end = '\0';
1918  val += 2;
1919 
1920  av_dict_set(&s->metadata, key, val, 0);
1921  av_log(h, AV_LOG_VERBOSE, "Metadata update for %s: %s\n", key, val);
1922 
1923  next = end + 2;
1924  }
1925 }
1926 
1927 static int store_icy(URLContext *h, int size)
1928 {
1929  HTTPContext *s = h->priv_data;
1930  /* until next metadata packet */
1931  uint64_t remaining;
1932 
1933  if (s->icy_metaint < s->icy_data_read)
1934  return AVERROR_INVALIDDATA;
1935  remaining = s->icy_metaint - s->icy_data_read;
1936 
1937  if (!remaining) {
1938  /* The metadata packet is variable sized. It has a 1 byte header
1939  * which sets the length of the packet (divided by 16). If it's 0,
1940  * the metadata doesn't change. After the packet, icy_metaint bytes
1941  * of normal data follows. */
1942  uint8_t ch;
1943  int len = http_read_stream_all(h, &ch, 1);
1944  if (len < 0)
1945  return len;
1946  if (ch > 0) {
1947  char data[255 * 16 + 1];
1948  int ret;
1949  len = ch * 16;
1951  if (ret < 0)
1952  return ret;
1953  data[len] = 0;
1954  if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
1955  return ret;
1957  }
1958  s->icy_data_read = 0;
1959  remaining = s->icy_metaint;
1960  }
1961 
1962  return FFMIN(size, remaining);
1963 }
1964 
1965 static int http_read(URLContext *h, uint8_t *buf, int size)
1966 {
1967  HTTPContext *s = h->priv_data;
1968 
1969  if (s->icy_metaint > 0) {
1970  size = store_icy(h, size);
1971  if (size < 0)
1972  return size;
1973  }
1974 
1975  size = http_read_stream(h, buf, size);
1976  if (size > 0)
1977  s->icy_data_read += size;
1978  return size;
1979 }
1980 
1981 /* used only when posting data */
1982 static int http_write(URLContext *h, const uint8_t *buf, int size)
1983 {
1984  char temp[11] = ""; /* 32-bit hex + CRLF + nul */
1985  int ret;
1986  char crlf[] = "\r\n";
1987  HTTPContext *s = h->priv_data;
1988 
1989  if (!s->chunked_post) {
1990  /* non-chunked data is sent without any special encoding */
1991  return ffurl_write(s->hd, buf, size);
1992  }
1993 
1994  /* silently ignore zero-size data since chunk encoding that would
1995  * signal EOF */
1996  if (size > 0) {
1997  /* upload data using chunked encoding */
1998  snprintf(temp, sizeof(temp), "%x\r\n", size);
1999 
2000  if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 ||
2001  (ret = ffurl_write(s->hd, buf, size)) < 0 ||
2002  (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0)
2003  return ret;
2004  }
2005  return size;
2006 }
2007 
2008 static int http_shutdown(URLContext *h, int flags)
2009 {
2010  int ret = 0;
2011  char footer[] = "0\r\n\r\n";
2012  HTTPContext *s = h->priv_data;
2013 
2014  /* signal end of chunked encoding if used */
2015  if (((flags & AVIO_FLAG_WRITE) && s->chunked_post) ||
2016  ((flags & AVIO_FLAG_READ) && s->chunked_post && s->listen)) {
2017  ret = ffurl_write(s->hd, footer, sizeof(footer) - 1);
2018  ret = ret > 0 ? 0 : ret;
2019  /* flush the receive buffer when it is write only mode */
2020  if (!(flags & AVIO_FLAG_READ)) {
2021  char buf[1024];
2022  int read_ret;
2023  s->hd->flags |= AVIO_FLAG_NONBLOCK;
2024  read_ret = ffurl_read(s->hd, buf, sizeof(buf));
2025  s->hd->flags &= ~AVIO_FLAG_NONBLOCK;
2026  if (read_ret < 0 && read_ret != AVERROR(EAGAIN)) {
2027  av_log(h, AV_LOG_ERROR, "URL read error: %s\n", av_err2str(read_ret));
2028  ret = read_ret;
2029  }
2030  }
2031  s->end_chunked_post = 1;
2032  }
2033 
2034  return ret;
2035 }
2036 
2038 {
2039  int ret = 0;
2040  HTTPContext *s = h->priv_data;
2041 
2042 #if CONFIG_ZLIB
2043  inflateEnd(&s->inflate_stream);
2044  av_freep(&s->inflate_buffer);
2045 #endif /* CONFIG_ZLIB */
2046 
2047  if (s->hd && !s->end_chunked_post)
2048  /* Close the write direction by sending the end of chunked encoding. */
2049  ret = http_shutdown(h, h->flags);
2050 
2051  if (s->hd)
2052  ffurl_closep(&s->hd);
2053  av_dict_free(&s->chained_options);
2054  av_dict_free(&s->cookie_dict);
2055  av_dict_free(&s->redirect_cache);
2056  av_freep(&s->new_location);
2057  av_freep(&s->uri);
2058 
2059  av_log(h, AV_LOG_DEBUG, "Statistics: %d connection%s, %d request%s, %d retr%s, %d reconnection%s, %d redirect%s\n",
2060  s->nb_connections, s->nb_connections == 1 ? "" : "s",
2061  s->nb_requests, s->nb_requests == 1 ? "" : "s",
2062  s->nb_retries, s->nb_retries == 1 ? "y" : "ies",
2063  s->nb_reconnects, s->nb_reconnects == 1 ? "" : "s",
2064  s->nb_redirects, s->nb_redirects == 1 ? "" : "s");
2065 
2066  if (s->nb_requests > 0) {
2067  av_log(h, AV_LOG_DEBUG, "Latency: %.2f ms avg, %.2f ms max\n",
2068  1e-3 * s->sum_latency / s->nb_requests,
2069  1e-3 * s->max_latency);
2070  }
2071  return ret;
2072 }
2073 
2074 static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect)
2075 {
2076  HTTPContext *s = h->priv_data;
2077  URLContext *old_hd = NULL;
2078  uint64_t old_off = s->off;
2079  uint8_t old_buf[BUFFER_SIZE];
2080  int old_buf_size, ret;
2082  uint8_t discard[4096];
2083 
2084  if (whence == AVSEEK_SIZE)
2085  return s->filesize;
2086  else if ((s->filesize == UINT64_MAX && whence == SEEK_END))
2087  return AVERROR(ENOSYS);
2088 
2089  if (whence == SEEK_CUR)
2090  off += s->off;
2091  else if (whence == SEEK_END)
2092  off += s->filesize;
2093  else if (whence != SEEK_SET)
2094  return AVERROR(EINVAL);
2095  if (off < 0)
2096  return AVERROR(EINVAL);
2097  if (!force_reconnect && off == s->off)
2098  return s->off;
2099  s->off = off;
2100 
2101  if (s->off && h->is_streamed)
2102  return AVERROR(ENOSYS);
2103 
2104  /* do not try to make a new connection if seeking past the end of the file */
2105  if (s->end_off || s->filesize != UINT64_MAX) {
2106  uint64_t end_pos = s->end_off ? s->end_off : s->filesize;
2107  if (s->off >= end_pos)
2108  return s->off;
2109  }
2110 
2111  /* if the location changed (redirect), revert to the original uri */
2112  if (strcmp(s->uri, s->location)) {
2113  char *new_uri;
2114  new_uri = av_strdup(s->uri);
2115  if (!new_uri)
2116  return AVERROR(ENOMEM);
2117  av_free(s->location);
2118  s->location = new_uri;
2119  }
2120 
2121  /* we save the old context in case the seek fails */
2122  old_buf_size = s->buf_end - s->buf_ptr;
2123  memcpy(old_buf, s->buf_ptr, old_buf_size);
2124 
2125  /* try to reuse existing connection for small seeks */
2126  uint64_t remaining = s->range_end - old_off - old_buf_size;
2127  if (!s->willclose && s->range_end && remaining <= ffurl_get_short_seek(h)) {
2128  /* drain remaining data left on the wire from previous request */
2129  av_log(h, AV_LOG_DEBUG, "Soft-seeking to offset %"PRIu64" by draining "
2130  "%"PRIu64" remaining byte(s)\n", s->off, remaining);
2131  while (remaining) {
2132  int ret = ffurl_read(s->hd, discard, FFMIN(remaining, sizeof(discard)));
2133  if (ret < 0 || ret == AVERROR_EOF || (ret == 0 && remaining)) {
2134  /* connection broken or stuck, need to reopen */
2135  ffurl_closep(&s->hd);
2136  break;
2137  }
2138  remaining -= ret;
2139  }
2140  } else {
2141  /* can't soft seek; always open new connection */
2142  old_hd = s->hd;
2143  s->hd = NULL;
2144  }
2145 
2146  /* if it fails, continue on old connection */
2147  if ((ret = http_open_cnx(h, &options)) < 0) {
2149  memcpy(s->buffer, old_buf, old_buf_size);
2150  s->buf_ptr = s->buffer;
2151  s->buf_end = s->buffer + old_buf_size;
2152  s->hd = old_hd;
2153  s->off = old_off;
2154  return ret;
2155  }
2157  ffurl_close(old_hd);
2158  return off;
2159 }
2160 
2161 static int64_t http_seek(URLContext *h, int64_t off, int whence)
2162 {
2163  return http_seek_internal(h, off, whence, 0);
2164 }
2165 
2167 {
2168  HTTPContext *s = h->priv_data;
2169  return ffurl_get_file_handle(s->hd);
2170 }
2171 
2173 {
2174  HTTPContext *s = h->priv_data;
2175  if (s->short_seek_size >= 1)
2176  return s->short_seek_size;
2177  return ffurl_get_short_seek(s->hd);
2178 }
2179 
2180 #define HTTP_CLASS(flavor) \
2181 static const AVClass flavor ## _context_class = { \
2182  .class_name = # flavor, \
2183  .item_name = av_default_item_name, \
2184  .option = options, \
2185  .version = LIBAVUTIL_VERSION_INT, \
2186 }
2187 
2188 #if CONFIG_HTTP_PROTOCOL
2189 HTTP_CLASS(http);
2190 
2191 const URLProtocol ff_http_protocol = {
2192  .name = "http",
2193  .url_open2 = http_open,
2194  .url_accept = http_accept,
2195  .url_handshake = http_handshake,
2196  .url_read = http_read,
2197  .url_write = http_write,
2198  .url_seek = http_seek,
2199  .url_close = http_close,
2200  .url_get_file_handle = http_get_file_handle,
2201  .url_get_short_seek = http_get_short_seek,
2202  .url_shutdown = http_shutdown,
2203  .priv_data_size = sizeof(HTTPContext),
2204  .priv_data_class = &http_context_class,
2206  .default_whitelist = "http,https,tls,rtp,tcp,udp,crypto,httpproxy,data"
2207 };
2208 #endif /* CONFIG_HTTP_PROTOCOL */
2209 
2210 #if CONFIG_HTTPS_PROTOCOL
2211 HTTP_CLASS(https);
2212 
2214  .name = "https",
2215  .url_open2 = http_open,
2216  .url_read = http_read,
2217  .url_write = http_write,
2218  .url_seek = http_seek,
2219  .url_close = http_close,
2220  .url_get_file_handle = http_get_file_handle,
2221  .url_get_short_seek = http_get_short_seek,
2222  .url_shutdown = http_shutdown,
2223  .priv_data_size = sizeof(HTTPContext),
2224  .priv_data_class = &https_context_class,
2226  .default_whitelist = "http,https,tls,rtp,tcp,udp,crypto,httpproxy"
2227 };
2228 #endif /* CONFIG_HTTPS_PROTOCOL */
2229 
2230 #if CONFIG_HTTPPROXY_PROTOCOL
2231 static int http_proxy_close(URLContext *h)
2232 {
2233  HTTPContext *s = h->priv_data;
2234  if (s->hd)
2235  ffurl_closep(&s->hd);
2236  return 0;
2237 }
2238 
2239 static int http_proxy_open(URLContext *h, const char *uri, int flags)
2240 {
2241  HTTPContext *s = h->priv_data;
2242  char hostname[1024], hoststr[1024];
2243  char auth[1024], pathbuf[1024], *path;
2244  char lower_url[100];
2245  int port, ret = 0, auth_attempts = 0;
2246  HTTPAuthType cur_auth_type;
2247  char *authstr;
2248 
2249  if( s->seekable == 1 )
2250  h->is_streamed = 0;
2251  else
2252  h->is_streamed = 1;
2253 
2254  av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
2255  pathbuf, sizeof(pathbuf), uri);
2256  ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
2257  path = pathbuf;
2258  if (*path == '/')
2259  path++;
2260 
2261  ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port,
2262  NULL);
2263 redo:
2264  ret = ffurl_open_whitelist(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
2265  &h->interrupt_callback, NULL,
2266  h->protocol_whitelist, h->protocol_blacklist, h);
2267  if (ret < 0)
2268  return ret;
2269 
2270  authstr = ff_http_auth_create_response(&s->proxy_auth_state, auth,
2271  path, "CONNECT");
2272  snprintf(s->buffer, sizeof(s->buffer),
2273  "CONNECT %s HTTP/1.1\r\n"
2274  "Host: %s\r\n"
2275  "Connection: close\r\n"
2276  "%s%s"
2277  "\r\n",
2278  path,
2279  hoststr,
2280  authstr ? "Proxy-" : "", authstr ? authstr : "");
2281  av_freep(&authstr);
2282 
2283  if ((ret = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
2284  goto fail;
2285 
2286  s->buf_ptr = s->buffer;
2287  s->buf_end = s->buffer;
2288  s->line_count = 0;
2289  s->filesize = UINT64_MAX;
2290  cur_auth_type = s->proxy_auth_state.auth_type;
2291 
2292  /* Note: This uses buffering, potentially reading more than the
2293  * HTTP header. If tunneling a protocol where the server starts
2294  * the conversation, we might buffer part of that here, too.
2295  * Reading that requires using the proper ffurl_read() function
2296  * on this URLContext, not using the fd directly (as the tls
2297  * protocol does). This shouldn't be an issue for tls though,
2298  * since the client starts the conversation there, so there
2299  * is no extra data that we might buffer up here.
2300  */
2301  ret = http_read_header(h);
2302  if (ret < 0)
2303  goto fail;
2304 
2305  auth_attempts++;
2306  if (s->http_code == 407 &&
2307  (cur_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
2308  s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && auth_attempts < 2) {
2309  ffurl_closep(&s->hd);
2310  goto redo;
2311  }
2312 
2313  if (s->http_code < 400)
2314  return 0;
2315  ret = ff_http_averror(s->http_code, AVERROR(EIO));
2316 
2317 fail:
2318  http_proxy_close(h);
2319  return ret;
2320 }
2321 
2322 static int http_proxy_write(URLContext *h, const uint8_t *buf, int size)
2323 {
2324  HTTPContext *s = h->priv_data;
2325  return ffurl_write(s->hd, buf, size);
2326 }
2327 
2329  .name = "httpproxy",
2330  .url_open = http_proxy_open,
2331  .url_read = http_buf_read,
2332  .url_write = http_proxy_write,
2333  .url_close = http_proxy_close,
2334  .url_get_file_handle = http_get_file_handle,
2335  .priv_data_size = sizeof(HTTPContext),
2337 };
2338 #endif /* CONFIG_HTTPPROXY_PROTOCOL */
redirect_cache_get
static char * redirect_cache_get(HTTPContext *s)
Definition: http.c:359
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:32
flags
const SwsFlags flags[]
Definition: swscale.c:61
HTTP_AUTH_BASIC
@ HTTP_AUTH_BASIC
HTTP 1.0 Basic auth from RFC 1945 (also in RFC 2617)
Definition: httpauth.h:30
av_isxdigit
static av_const int av_isxdigit(int c)
Locale-independent conversion of ASCII isxdigit.
Definition: avstring.h:247
HTTPContext::http_code
int http_code
Definition: http.c:77
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
http_open_cnx
static int http_open_cnx(URLContext *h, AVDictionary **options)
Definition: http.c:401
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
WHITESPACES
#define WHITESPACES
Definition: http.c:64
av_bprint_is_complete
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:218
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame 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. Frame references ownership and permissions
opt.h
http_write_reply
static int http_write_reply(URLContext *h, int status_code)
Definition: http.c:613
URL_PROTOCOL_FLAG_NETWORK
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:33
AVERROR_HTTP_OTHER_4XX
#define AVERROR_HTTP_OTHER_4XX
Definition: error.h:83
parse_icy
static int parse_icy(HTTPContext *s, const char *tag, const char *p)
Definition: http.c:964
message
Definition: api-threadmessage-test.c:47
HTTPContext::http_proxy
char * http_proxy
Definition: http.c:86
av_stristr
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:58
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
AVIO_FLAG_READ_WRITE
#define AVIO_FLAG_READ_WRITE
read-write pseudo flag
Definition: avio.h:619
av_dict_count
int av_dict_count(const AVDictionary *m)
Get number of entries in dictionary.
Definition: dict.c:37
HTTPContext::initial_request_size
uint64_t initial_request_size
Definition: http.c:149
bprint_escaped_path
static void bprint_escaped_path(AVBPrint *bp, const char *path)
Escape unsafe characters in path in order to pass them safely to the HTTP request.
Definition: http.c:1496
http_listen
static int http_listen(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition: http.c:734
int64_t
long long int64_t
Definition: coverity.c:34
av_asprintf
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:115
ffurl_write
static int ffurl_write(URLContext *h, const uint8_t *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition: url.h:202
HTTPContext::seekable
int seekable
Control seekability, 0 = disable, 1 = enable, -1 = probe.
Definition: http.c:96
av_strcasecmp
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:208
av_isspace
static av_const int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.h:218
HTTPContext::nb_requests
int nb_requests
Definition: http.c:153
HTTPContext::partial_requests
int partial_requests
Definition: http.c:150
http_read
static int http_read(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1965
http_seek_internal
static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect)
Definition: http.c:2074
parse_cache_control
static void parse_cache_control(HTTPContext *s, const char *p)
Definition: http.c:1142
HTTPContext::new_location
char * new_location
Definition: http.c:142
READ_HEADERS
@ READ_HEADERS
Definition: http.c:67
AVOption
AVOption.
Definition: opt.h:429
AVERROR_HTTP_SERVER_ERROR
#define AVERROR_HTTP_SERVER_ERROR
Definition: error.h:84
AVSEEK_SIZE
#define AVSEEK_SIZE
Passing this as the "whence" parameter to a seek function causes it to return the filesize without se...
Definition: avio.h:468
data
const char data[16]
Definition: mxf.c:149
WRITE_REPLY_HEADERS
@ WRITE_REPLY_HEADERS
Definition: http.c:68
NEEDS_ESCAPE
#define NEEDS_ESCAPE(ch)
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
freeenv_utf8
static void freeenv_utf8(char *var)
Definition: getenv_utf8.h:72
http_get_line
static int http_get_line(HTTPContext *s, char *line, int line_size)
Definition: http.c:861
ffurl_close
int ffurl_close(URLContext *h)
Definition: avio.c:612
AVDictionary
Definition: dict.c:32
HTTPContext::end_header
int end_header
Definition: http.c:101
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
HTTPContext::chained_options
AVDictionary * chained_options
Definition: http.c:124
parse_location
static int parse_location(HTTPContext *s, const char *p)
Definition: http.c:900
http_read_stream
static int http_read_stream(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1809
ff_http_auth_create_response
char * ff_http_auth_create_response(HTTPAuthState *state, const char *auth, const char *path, const char *method)
Definition: httpauth.c:240
HTTPContext::chunkend
int chunkend
Definition: http.c:80
av_strlcatf
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:103
URLProtocol
Definition: url.h:51
MAX_DATE_LEN
#define MAX_DATE_LEN
Definition: http.c:63
os_support.h
HTTPContext::hd
URLContext * hd
Definition: http.c:74
HTTPContext::buf_ptr
unsigned char * buf_ptr
Definition: http.c:75
ff_httpproxy_protocol
const URLProtocol ff_httpproxy_protocol
HTTPContext::nb_redirects
int nb_redirects
Definition: http.c:156
AVERROR_HTTP_UNAUTHORIZED
#define AVERROR_HTTP_UNAUTHORIZED
Definition: error.h:79
HTTPContext::referer
char * referer
Definition: http.c:91
get_cookies
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:1339
HTTPContext::http_version
char * http_version
Definition: http.c:89
AV_OPT_TYPE_BINARY
@ AV_OPT_TYPE_BINARY
Underlying C type is a uint8_t* that is either NULL or points to an array allocated with the av_mallo...
Definition: opt.h:286
av_bprint_init_for_buffer
void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
Init a print buffer using a pre-existing buffer.
Definition: bprint.c:85
macros.h
fail
#define fail()
Definition: checkasm.h:218
ffurl_get_short_seek
int ffurl_get_short_seek(void *urlcontext)
Return the current short seek threshold value for this URL.
Definition: avio.c:839
check_http_code
static int check_http_code(URLContext *h, int http_code, const char *end)
Definition: http.c:885
HTTPContext::headers
char * headers
Definition: http.c:87
DEFAULT_USER_AGENT
#define DEFAULT_USER_AGENT
Definition: http.c:165
inflate
static void inflate(uint8_t *dst, const uint8_t *p1, int width, int threshold, const uint8_t *coordinates[], int coord, int maxc)
Definition: vf_neighbor.c:194
cookie_string
static int cookie_string(AVDictionary *dict, char **cookies)
Definition: http.c:1110
has_header
static int has_header(const char *str, const char *header)
Definition: http.c:1423
redirect_cache_set
static int redirect_cache_set(HTTPContext *s, const char *source, const char *dest, int64_t expiry)
Definition: http.c:383
val
static double val(void *priv, double ch)
Definition: aeval.c:77
av_timegm
time_t av_timegm(struct tm *tm)
Convert the decomposed UTC time in tm to a time_t value.
Definition: parseutils.c:573
av_opt_set
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
Definition: opt.c:835
SPACE_CHARS
#define SPACE_CHARS
Definition: dnn_backend_tf.c:356
URLContext::priv_data
void * priv_data
Definition: url.h:38
AV_DICT_DONT_STRDUP_VAL
#define AV_DICT_DONT_STRDUP_VAL
Take ownership of a value that's been allocated with av_malloc() or another memory allocation functio...
Definition: dict.h:79
MAX_REDIRECTS
#define MAX_REDIRECTS
Definition: http.c:59
avassert.h
HTTPContext::listen
int listen
Definition: http.c:134
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
AVERROR_HTTP_NOT_FOUND
#define AVERROR_HTTP_NOT_FOUND
Definition: error.h:81
HTTPContext::is_connected_server
int is_connected_server
Definition: http.c:139
E
#define E
Definition: http.c:164
av_dict_get
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:60
ffurl_open_whitelist
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist, const char *blacklist, URLContext *parent)
Create an URLContext for accessing to the resource indicated by url, and open it.
Definition: avio.c:363
s
#define s(width, name)
Definition: cbs_vp9.c:198
HTTPContext::buf_end
unsigned char * buf_end
Definition: http.c:75
HTTPContext::cookies
char * cookies
holds newline ( ) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
Definition: http.c:108
AVDictionaryEntry::key
char * key
Definition: dict.h:91
BUFFER_SIZE
#define BUFFER_SIZE
Definition: http.c:58
av_strtok
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:179
ff_url_join
int ff_url_join(char *str, int size, const char *proto, const char *authorization, const char *hostname, int port, const char *fmt,...)
Definition: url.c:40
AV_OPT_TYPE_INT64
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
Definition: opt.h:263
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
AVIO_FLAG_WRITE
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:618
HTTPContext::off
uint64_t off
Definition: http.c:81
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
HTTPContext::post_datalen
int post_datalen
Definition: http.c:105
HTTPContext::reconnect_on_network_error
int reconnect_on_network_error
Definition: http.c:130
av_stristart
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:47
key
const char * key
Definition: hwcontext_opencl.c:189
D
#define D
Definition: http.c:163
HTTPContext::respect_retry_after
int respect_retry_after
Definition: http.c:145
parse_cookie
static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
Definition: http.c:1048
HTTPContext::end_chunked_post
int end_chunked_post
Definition: http.c:99
ff_http_match_no_proxy
int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
Definition: network.c:549
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
ff_http_auth_handle_header
void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, const char *value)
Definition: httpauth.c:90
parse_content_encoding
static int parse_content_encoding(URLContext *h, const char *p)
Definition: http.c:930
handle_http_errors
static void handle_http_errors(URLContext *h, int error)
Definition: http.c:692
HTTPContext::buffer
unsigned char buffer[BUFFER_SIZE]
Definition: http.c:75
ff_http_do_new_request
int ff_http_do_new_request(URLContext *h, const char *uri)
Send a new HTTP request, reusing the old connection.
Definition: http.c:520
ffurl_accept
int ffurl_accept(URLContext *s, URLContext **c)
Accept an URLContext c on an URLContext s.
Definition: avio.c:265
internal.h
opts
static AVDictionary * opts
Definition: movenc.c:51
http_read_stream_all
static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1887
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
metadata
Stream codec metadata
Definition: ogg-flac-chained-meta.txt:2
NULL
#define NULL
Definition: coverity.c:32
http_get_short_seek
static int http_get_short_seek(URLContext *h)
Definition: http.c:2172
av_match_list
int av_match_list(const char *name, const char *list, char separator)
Check if a name is in a list.
Definition: avstring.c:445
HTTPContext::multiple_requests
int multiple_requests
Definition: http.c:103
ff_http_init_auth_state
void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
Initialize the authentication state based on another HTTP URLContext.
Definition: http.c:216
AV_OPT_TYPE_DICT
@ AV_OPT_TYPE_DICT
Underlying C type is AVDictionary*.
Definition: opt.h:290
HTTPContext::metadata
AVDictionary * metadata
Definition: http.c:118
parseutils.h
HTTPContext::sum_latency
int sum_latency
Definition: http.c:157
ff_http_do_new_request2
int ff_http_do_new_request2(URLContext *h, const char *uri, AVDictionary **opts)
Send a new HTTP request, reusing the old connection.
Definition: http.c:524
HTTPContext::proxy_auth_state
HTTPAuthState proxy_auth_state
Definition: http.c:85
getenv_utf8
static char * getenv_utf8(const char *varname)
Definition: getenv_utf8.h:67
AVERROR_HTTP_TOO_MANY_REQUESTS
#define AVERROR_HTTP_TOO_MANY_REQUESTS
Definition: error.h:82
options
Definition: swscale.c:43
http_buf_read
static int http_buf_read(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1694
http_shutdown
static int http_shutdown(URLContext *h, int flags)
Definition: http.c:2008
process_line
static int process_line(URLContext *h, char *line, int line_count, int *parsed_http_code)
Definition: http.c:1169
HTTPContext::filesize
uint64_t filesize
Definition: http.c:81
time.h
parse_content_range
static void parse_content_range(URLContext *h, const char *p)
Definition: http.c:913
AVERROR_HTTP_BAD_REQUEST
#define AVERROR_HTTP_BAD_REQUEST
Definition: error.h:78
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
HTTPContext::nb_reconnects
int nb_reconnects
Definition: http.c:155
HTTPContext::line_count
int line_count
Definition: http.c:76
HTTPAuthState
HTTP Authentication state structure.
Definition: httpauth.h:55
source
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a source
Definition: filter_design.txt:256
http
s EdgeDetect Foobar g libavfilter vf_edgedetect c libavfilter vf_foobar c edit libavfilter and add an entry for foobar following the pattern of the other filters edit libavfilter allfilters and add an entry for foobar following the pattern of the other filters configure make j< whatever > ffmpeg ffmpeg i http
Definition: writing_filters.txt:29
HTTPContext::range_end
uint64_t range_end
Definition: http.c:81
ff_http_averror
int ff_http_averror(int status_code, int default_averror)
Definition: http.c:589
av_strncasecmp
int av_strncasecmp(const char *a, const char *b, size_t n)
Locale-independent case-insensitive compare.
Definition: avstring.c:218
HTTPContext::filesize_from_content_range
uint64_t filesize_from_content_range
Definition: http.c:144
HTTPContext::reconnect_max_retries
int reconnect_max_retries
Definition: http.c:147
HTTPContext::reconnect_streamed
int reconnect_streamed
Definition: http.c:131
parse_http_date
static int parse_http_date(const char *date_str, struct tm *buf)
Definition: http.c:986
HTTPContext::method
char * method
Definition: http.c:127
HTTPContext::uri
char * uri
Definition: http.c:82
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:122
parse_expires
static void parse_expires(HTTPContext *s, const char *p)
Definition: http.c:1133
HTTPContext::nb_connections
int nb_connections
Definition: http.c:152
size
int size
Definition: twinvq_data.h:10344
av_reallocp
int av_reallocp(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory through a pointer to a pointer.
Definition: mem.c:188
HTTPContext::reconnect_delay_total_max
int reconnect_delay_total_max
Definition: http.c:148
URLProtocol::name
const char * name
Definition: url.h:52
HTTPContext::max_redirects
int max_redirects
Definition: http.c:159
http_write
static int http_write(URLContext *h, const uint8_t *buf, int size)
Definition: http.c:1982
HTTPContext::icy_data_read
uint64_t icy_data_read
Definition: http.c:113
header
static const uint8_t header[24]
Definition: sdr2.c:68
diff
static av_always_inline int diff(const struct color_info *a, const struct color_info *b, const int trans_thresh)
Definition: vf_paletteuse.c:166
HTTPContext
Definition: http.c:72
getenv_utf8.h
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
line
Definition: graph2dot.c:48
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:233
av_strstart
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:36
HTTPContext::icy_metadata_packet
char * icy_metadata_packet
Definition: http.c:117
version
version
Definition: libkvazaar.c:313
ff_http_protocol
const URLProtocol ff_http_protocol
HTTPContext::icy
int icy
Definition: http.c:111
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:221
update_metadata
static void update_metadata(URLContext *h, char *data)
Definition: http.c:1899
AV_OPT_FLAG_READONLY
#define AV_OPT_FLAG_READONLY
The option may not be set through the AVOptions API, only read.
Definition: opt.h:368
ffurl_alloc
int ffurl_alloc(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb)
Create a URLContext for accessing to the resource indicated by url, but do not initiate the connectio...
Definition: avio.c:350
HTTPContext::is_mediagateway
int is_mediagateway
Definition: http.c:107
HTTPContext::reconnect_at_eof
int reconnect_at_eof
Definition: http.c:129
httpauth.h
http_should_reconnect
static int http_should_reconnect(HTTPContext *s, int err)
Definition: http.c:325
bprint.h
http_handshake
static int http_handshake(URLContext *c)
Definition: http.c:698
HTTP_AUTH_NONE
@ HTTP_AUTH_NONE
No authentication specified.
Definition: httpauth.h:29
URLContext
Definition: url.h:35
http_open
static int http_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition: http.c:766
HTTPContext::nb_retries
int nb_retries
Definition: http.c:154
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
http_connect
static int http_connect(URLContext *h, const char *path, const char *local_path, const char *hoststr, const char *auth, const char *proxyauth)
Definition: http.c:1520
ff_network_sleep_interruptible
int ff_network_sleep_interruptible(int64_t timeout, AVIOInterruptCB *int_cb)
Waits for up to 'timeout' microseconds.
Definition: network.c:95
parse_set_cookie
static int parse_set_cookie(const char *set_cookie, AVDictionary **dict)
Definition: http.c:1011
http_seek
static int64_t http_seek(URLContext *h, int64_t off, int whence)
Definition: http.c:2161
HTTPContext::max_latency
int max_latency
Definition: http.c:158
HTTPContext::end_off
uint64_t end_off
Definition: http.c:81
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
HTTPContext::mime_type
char * mime_type
Definition: http.c:88
av_url_split
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.
Definition: utils.c:361
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
http_open_cnx_internal
static int http_open_cnx_internal(URLContext *h, AVDictionary **options)
Definition: http.c:226
url.h
HTTPContext::icy_metaint
uint64_t icy_metaint
Definition: http.c:115
http_close
static int http_close(URLContext *h)
Definition: http.c:2037
HTTPContext::resource
char * resource
Definition: http.c:135
len
int len
Definition: vorbis_enc_data.h:426
HTTPContext::reconnect
int reconnect
Definition: http.c:128
OFFSET
#define OFFSET(x)
Definition: http.c:162
version.h
ffurl_closep
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition: avio.c:589
HTTPContext::handshake_step
HandshakeState handshake_step
Definition: http.c:138
ff_https_protocol
const URLProtocol ff_https_protocol
tag
uint32_t tag
Definition: movenc.c:2032
ret
ret
Definition: filter_design.txt:187
ff_http_get_new_location
const char * ff_http_get_new_location(URLContext *h)
Definition: http.c:607
HandshakeState
HandshakeState
Definition: http.c:65
av_malloc
void * av_malloc(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:98
URLContext::interrupt_callback
AVIOInterruptCB interrupt_callback
Definition: url.h:44
pos
unsigned int pos
Definition: spdifenc.c:414
avformat.h
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
network.h
HTTPContext::chunked_post
int chunked_post
Definition: http.c:97
HTTPContext::cookie_dict
AVDictionary * cookie_dict
Definition: http.c:110
AV_DICT_MATCH_CASE
#define AV_DICT_MATCH_CASE
Only get an entry with exact-case key match.
Definition: dict.h:74
U
#define U(x)
Definition: vpx_arith.h:37
HTTPContext::reconnect_delay_max
int reconnect_delay_max
Definition: http.c:132
av_small_strptime
char * av_small_strptime(const char *p, const char *fmt, struct tm *dt)
Simplified version of strptime.
Definition: parseutils.c:494
HTTPContext::content_type
char * content_type
Definition: http.c:92
MAX_URL_SIZE
#define MAX_URL_SIZE
Definition: internal.h:30
HTTPContext::location
char * location
Definition: http.c:83
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:259
http_read_header
static int http_read_header(URLContext *h)
Definition: http.c:1431
av_get_token
char * av_get_token(const char **buf, const char *term)
Unescape the given string until a non escaped terminating char, and return the token corresponding to...
Definition: avstring.c:143
AVERROR_HTTP_FORBIDDEN
#define AVERROR_HTTP_FORBIDDEN
Definition: error.h:80
HTTP_CLASS
#define HTTP_CLASS(flavor)
Definition: http.c:2180
temp
else temp
Definition: vf_mcdeint.c:271
body
static void body(uint32_t ABCD[4], const uint8_t *src, size_t nblocks)
Definition: md5.c:103
http_get_file_handle
static int http_get_file_handle(URLContext *h)
Definition: http.c:2166
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
HTTP_SINGLE
#define HTTP_SINGLE
Definition: http.c:61
HTTPContext::expires
int64_t expires
Definition: http.c:141
HTTPContext::retry_after
unsigned int retry_after
Definition: http.c:146
HTTPContext::is_akamai
int is_akamai
Definition: http.c:106
https
s EdgeDetect Foobar g libavfilter vf_edgedetect c libavfilter vf_foobar c edit libavfilter and add an entry for foobar following the pattern of the other filters edit libavfilter allfilters and add an entry for foobar following the pattern of the other filters configure make j< whatever > ffmpeg ffmpeg i you should get a foobar png with Lena edge detected That s your new playground is ready Some little details about what s going which in turn will define variables for the build system and the and we are assuming vf_foobar is as well We are also assuming vf_foobar is not an edge detector so you can update the boilerplate with your credits Doxy Next chunk is the Doxygen about the file See https
Definition: writing_filters.txt:66
av_gettime
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:39
av_dict_set_int
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
Convenience wrapper for av_dict_set() that converts the value to a string and stores it.
Definition: dict.c:177
HTTPAuthType
HTTPAuthType
Authentication types, ordered from weakest to strongest.
Definition: httpauth.h:28
AVIO_FLAG_READ
#define AVIO_FLAG_READ
read-only
Definition: avio.h:617
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:272
HTTPContext::reply_code
int reply_code
Definition: http.c:136
FINISH
@ FINISH
Definition: http.c:69
mem.h
HTTPContext::auth_state
HTTPAuthState auth_state
Definition: http.c:84
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVDictionaryEntry
Definition: dict.h:90
headers
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 DBG Preprocess x86 external assembler files to a dbg asm file in the object which then gets compiled Helps in developing those assembler files DESTDIR Destination directory for the install useful to prepare packages or install FFmpeg in cross environments GEN Set to ‘1’ to generate the missing or mismatched references Makefile builds all the libraries and the executables fate Run the fate test note that you must have installed it fate list List all fate regression test targets fate list failing List the fate tests that failed the last time they were executed fate clear reports Remove the test reports from previous test libraries and programs examples Build all examples located in doc examples checkheaders Check headers dependencies alltools Build all tools in tools directory config Reconfigure the project with the current configuration tools target_dec_< decoder > _fuzzer Build fuzzer to fuzz the specified decoder tools target_bsf_< filter > _fuzzer Build fuzzer to fuzz the specified bitstream filter Useful standard make this is useful to reduce unneeded rebuilding when changing headers
Definition: build_system.txt:64
ffurl_handshake
int ffurl_handshake(URLContext *c)
Perform one step of the protocol handshake to accept a new client.
Definition: avio.c:284
ff_make_absolute_url
int ff_make_absolute_url(char *buf, int size, const char *base, const char *rel)
Convert a relative url into an absolute url, given a base url.
Definition: url.c:321
AV_OPT_FLAG_EXPORT
#define AV_OPT_FLAG_EXPORT
The option is intended for exporting values to the caller.
Definition: opt.h:363
MAX_CACHED_REDIRECTS
#define MAX_CACHED_REDIRECTS
Definition: http.c:60
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:327
AVIO_FLAG_NONBLOCK
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:636
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_dict_set
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:86
av_dict_copy
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:247
http_getc
static int http_getc(HTTPContext *s)
Definition: http.c:844
http_accept
static int http_accept(URLContext *s, URLContext **c)
Definition: http.c:820
HTTPContext::send_expect_100
int send_expect_100
Definition: http.c:126
av_strlcpy
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:85
LOWER_PROTO
@ LOWER_PROTO
Definition: http.c:66
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
HTTPContext::chunksize
uint64_t chunksize
Definition: http.c:79
h
h
Definition: vp9dsp_template.c:2070
AVERROR_EXIT
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:58
HTTPContext::icy_metadata_headers
char * icy_metadata_headers
Definition: http.c:116
av_opt_set_dict
int av_opt_set_dict(void *obj, AVDictionary **options)
Set all the options from a given dictionary on an object.
Definition: opt.c:1990
AVDictionaryEntry::value
char * value
Definition: dict.h:92
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:276
av_strndup
char * av_strndup(const char *s, size_t len)
Duplicate a substring of a string.
Definition: mem.c:284
http.h
HTTPContext::willclose
int willclose
Definition: http.c:95
av_bprint_append_data
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:148
HTTPContext::redirect_cache
AVDictionary * redirect_cache
Definition: http.c:143
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition: opt.h:299
snprintf
#define snprintf
Definition: snprintf.h:34
HTTPContext::user_agent
char * user_agent
Definition: http.c:90
store_icy
static int store_icy(URLContext *h, int size)
Definition: http.c:1927
av_dict_iterate
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition: dict.c:42
ffurl_get_file_handle
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition: avio.c:815
src
#define src
Definition: vp8dsp.c:248
line
The official guide to swscale for confused that consecutive non overlapping rectangles of slice_bottom special converter These generally are unscaled converters of common like for each output line the vertical scaler pulls lines from a ring buffer When the ring buffer does not contain the wanted line
Definition: swscale.txt:40
read
static uint32_t BS_FUNC() read(BSCTX *bc, unsigned int n)
Return n bits from the buffer, n has to be in the 0-32 range.
Definition: bitstream_template.h:239
AV_DICT_DONT_STRDUP_KEY
#define AV_DICT_DONT_STRDUP_KEY
Take ownership of a key that's been allocated with av_malloc() or another memory allocation function.
Definition: dict.h:77
HTTPContext::post_data
uint8_t * post_data
Definition: http.c:104
HTTPContext::reconnect_on_http_error
char * reconnect_on_http_error
Definition: http.c:133
HTTPContext::short_seek_size
int short_seek_size
Definition: http.c:140
ffurl_read
static int ffurl_read(URLContext *h, uint8_t *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition: url.h:181
HTTPContext::is_multi_client
int is_multi_client
Definition: http.c:137