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