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