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->off = 0;
571  s->icy_data_read = 0;
572 
573  av_free(s->location);
574  s->location = av_strdup(uri);
575  if (!s->location)
576  return AVERROR(ENOMEM);
577 
578  av_free(s->uri);
579  s->uri = av_strdup(uri);
580  if (!s->uri)
581  return AVERROR(ENOMEM);
582 
583  if ((ret = av_opt_set_dict(s, opts)) < 0)
584  return ret;
585 
586  av_log(s, AV_LOG_INFO, "Opening \'%s\' for %s\n", uri, h->flags & AVIO_FLAG_WRITE ? "writing" : "reading");
587  ret = http_open_cnx(h, &options);
589  return ret;
590 }
591 
592 int ff_http_averror(int status_code, int default_averror)
593 {
594  switch (status_code) {
595  case 400: return AVERROR_HTTP_BAD_REQUEST;
596  case 401: return AVERROR_HTTP_UNAUTHORIZED;
597  case 403: return AVERROR_HTTP_FORBIDDEN;
598  case 404: return AVERROR_HTTP_NOT_FOUND;
599  case 429: return AVERROR_HTTP_TOO_MANY_REQUESTS;
600  default: break;
601  }
602  if (status_code >= 400 && status_code <= 499)
603  return AVERROR_HTTP_OTHER_4XX;
604  else if (status_code >= 500)
606  else
607  return default_averror;
608 }
609 
611 {
612  HTTPContext *s = h->priv_data;
613  return s->new_location;
614 }
615 
616 static int http_write_reply(URLContext* h, int status_code)
617 {
618  int ret, body = 0, reply_code, message_len;
619  const char *reply_text, *content_type;
620  HTTPContext *s = h->priv_data;
621  char message[BUFFER_SIZE];
622  content_type = "text/plain";
623 
624  if (status_code < 0)
625  body = 1;
626  switch (status_code) {
628  case 400:
629  reply_code = 400;
630  reply_text = "Bad Request";
631  break;
633  case 403:
634  reply_code = 403;
635  reply_text = "Forbidden";
636  break;
638  case 404:
639  reply_code = 404;
640  reply_text = "Not Found";
641  break;
643  case 429:
644  reply_code = 429;
645  reply_text = "Too Many Requests";
646  break;
647  case 200:
648  reply_code = 200;
649  reply_text = "OK";
650  content_type = s->content_type ? s->content_type : "application/octet-stream";
651  break;
653  case 500:
654  reply_code = 500;
655  reply_text = "Internal server error";
656  break;
657  default:
658  return AVERROR(EINVAL);
659  }
660  if (body) {
661  s->chunked_post = 0;
662  message_len = snprintf(message, sizeof(message),
663  "HTTP/1.1 %03d %s\r\n"
664  "Content-Type: %s\r\n"
665  "Content-Length: %zu\r\n"
666  "%s"
667  "\r\n"
668  "%03d %s\r\n",
669  reply_code,
670  reply_text,
671  content_type,
672  strlen(reply_text) + 6, // 3 digit status code + space + \r\n
673  s->headers ? s->headers : "",
674  reply_code,
675  reply_text);
676  } else {
677  s->chunked_post = 1;
678  message_len = snprintf(message, sizeof(message),
679  "HTTP/1.1 %03d %s\r\n"
680  "Content-Type: %s\r\n"
681  "Transfer-Encoding: chunked\r\n"
682  "%s"
683  "\r\n",
684  reply_code,
685  reply_text,
686  content_type,
687  s->headers ? s->headers : "");
688  }
689  av_log(h, AV_LOG_TRACE, "HTTP reply header: \n%s----\n", message);
690  if ((ret = ffurl_write(s->hd, message, message_len)) < 0)
691  return ret;
692  return 0;
693 }
694 
696 {
697  av_assert0(error < 0);
699 }
700 
702 {
703  int ret, err;
704  HTTPContext *ch = c->priv_data;
705  URLContext *cl = ch->hd;
706  switch (ch->handshake_step) {
707  case LOWER_PROTO:
708  av_log(c, AV_LOG_TRACE, "Lower protocol\n");
709  if ((ret = ffurl_handshake(cl)) > 0)
710  return 2 + ret;
711  if (ret < 0)
712  return ret;
714  ch->is_connected_server = 1;
715  return 2;
716  case READ_HEADERS:
717  av_log(c, AV_LOG_TRACE, "Read headers\n");
718  if ((err = http_read_header(c)) < 0) {
719  handle_http_errors(c, err);
720  return err;
721  }
723  return 1;
724  case WRITE_REPLY_HEADERS:
725  av_log(c, AV_LOG_TRACE, "Reply code: %d\n", ch->reply_code);
726  if ((err = http_write_reply(c, ch->reply_code)) < 0)
727  return err;
728  ch->handshake_step = FINISH;
729  return 1;
730  case FINISH:
731  return 0;
732  }
733  // this should never be reached.
734  return AVERROR(EINVAL);
735 }
736 
737 static int http_listen(URLContext *h, const char *uri, int flags,
738  AVDictionary **options) {
739  HTTPContext *s = h->priv_data;
740  int ret;
741  char hostname[1024], proto[10];
742  char lower_url[100];
743  const char *lower_proto = "tcp";
744  int port;
745  av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
746  NULL, 0, uri);
747  if (!strcmp(proto, "https"))
748  lower_proto = "tls";
749  ff_url_join(lower_url, sizeof(lower_url), lower_proto, NULL, hostname, port,
750  NULL);
751  if ((ret = av_dict_set_int(options, "listen", s->listen, 0)) < 0)
752  goto fail;
753  if ((ret = ffurl_open_whitelist(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
754  &h->interrupt_callback, options,
755  h->protocol_whitelist, h->protocol_blacklist, h
756  )) < 0)
757  goto fail;
758  s->handshake_step = LOWER_PROTO;
759  if (s->listen == HTTP_SINGLE) { /* single client */
760  s->reply_code = 200;
761  while ((ret = http_handshake(h)) > 0);
762  }
763 fail:
764  av_dict_free(&s->chained_options);
765  av_dict_free(&s->cookie_dict);
766  return ret;
767 }
768 
769 static int http_open(URLContext *h, const char *uri, int flags,
771 {
772  HTTPContext *s = h->priv_data;
773  int ret;
774 
775  if( s->seekable == 1 )
776  h->is_streamed = 0;
777  else
778  h->is_streamed = 1;
779 
780  s->initial_requests = s->seekable != 0 && s->initial_request_size > 0;
781  s->filesize = UINT64_MAX;
782 
783  s->location = av_strdup(uri);
784  if (!s->location)
785  return AVERROR(ENOMEM);
786 
787  s->uri = av_strdup(uri);
788  if (!s->uri)
789  return AVERROR(ENOMEM);
790 
791  if (options)
792  av_dict_copy(&s->chained_options, *options, 0);
793 
794  if (s->headers) {
795  int len = strlen(s->headers);
796  if (len < 2 || strcmp("\r\n", s->headers + len - 2)) {
798  "No trailing CRLF found in HTTP header. Adding it.\n");
799  ret = av_reallocp(&s->headers, len + 3);
800  if (ret < 0)
801  goto bail_out;
802  s->headers[len] = '\r';
803  s->headers[len + 1] = '\n';
804  s->headers[len + 2] = '\0';
805  }
806  }
807 
808  if (s->listen) {
809  return http_listen(h, uri, flags, options);
810  }
812 bail_out:
813  if (ret < 0) {
814  av_dict_free(&s->chained_options);
815  av_dict_free(&s->cookie_dict);
816  av_dict_free(&s->redirect_cache);
817  av_freep(&s->new_location);
818  av_freep(&s->uri);
819  }
820  return ret;
821 }
822 
824 {
825  int ret;
826  HTTPContext *sc = s->priv_data;
827  HTTPContext *cc;
828  URLContext *sl = sc->hd;
829  URLContext *cl = NULL;
830 
831  av_assert0(sc->listen);
832  if ((ret = ffurl_alloc(c, s->filename, s->flags, &sl->interrupt_callback)) < 0)
833  goto fail;
834  cc = (*c)->priv_data;
835  if ((ret = ffurl_accept(sl, &cl)) < 0)
836  goto fail;
837  cc->hd = cl;
838  cc->is_multi_client = 1;
839  return 0;
840 fail:
841  if (c) {
842  ffurl_closep(c);
843  }
844  return ret;
845 }
846 
847 static int http_getc(HTTPContext *s)
848 {
849  int len;
850  if (s->buf_ptr >= s->buf_end) {
851  len = ffurl_read(s->hd, s->buffer, BUFFER_SIZE);
852  if (len < 0) {
853  return len;
854  } else if (len == 0) {
855  return AVERROR_EOF;
856  } else {
857  s->buf_ptr = s->buffer;
858  s->buf_end = s->buffer + len;
859  }
860  }
861  return *s->buf_ptr++;
862 }
863 
864 static int http_get_line(HTTPContext *s, char *line, int line_size)
865 {
866  int ch;
867  char *q;
868 
869  q = line;
870  for (;;) {
871  ch = http_getc(s);
872  if (ch < 0)
873  return ch;
874  if (ch == '\n') {
875  /* process line */
876  if (q > line && q[-1] == '\r')
877  q--;
878  *q = '\0';
879 
880  return 0;
881  } else {
882  if ((q - line) < line_size - 1)
883  *q++ = ch;
884  }
885  }
886 }
887 
888 static int check_http_code(URLContext *h, int http_code, const char *end)
889 {
890  HTTPContext *s = h->priv_data;
891  /* error codes are 4xx and 5xx, but regard 401 as a success, so we
892  * don't abort until all headers have been parsed. */
893  if (http_code >= 400 && http_code < 600 &&
894  (http_code != 401 || s->auth_state.auth_type != HTTP_AUTH_NONE) &&
895  (http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) {
896  end += strspn(end, SPACE_CHARS);
897  av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n", http_code, end);
898  return ff_http_averror(http_code, AVERROR(EIO));
899  }
900  return 0;
901 }
902 
903 static int parse_location(HTTPContext *s, const char *p)
904 {
905  char redirected_location[MAX_URL_SIZE];
906  ff_make_absolute_url(redirected_location, sizeof(redirected_location),
907  s->location, p);
908  av_freep(&s->new_location);
909  s->new_location = av_strdup(redirected_location);
910  if (!s->new_location)
911  return AVERROR(ENOMEM);
912  return 0;
913 }
914 
915 /* "bytes $from-$to/$document_size" */
916 static void parse_content_range(URLContext *h, const char *p)
917 {
918  HTTPContext *s = h->priv_data;
919  const char *slash, *end;
920 
921  if (!strncmp(p, "bytes ", 6)) {
922  p += 6;
923  s->off = strtoull(p, NULL, 10);
924  if ((end = strchr(p, '-')) && strlen(end) > 0)
925  s->range_end = strtoull(end + 1, NULL, 10) + 1;
926  if ((slash = strchr(p, '/')) && strlen(slash) > 0)
927  s->filesize_from_content_range = strtoull(slash + 1, NULL, 10);
928  }
929  if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647))
930  h->is_streamed = 0; /* we _can_ in fact seek */
931 }
932 
933 static int parse_content_encoding(URLContext *h, const char *p)
934 {
935  if (!av_strncasecmp(p, "gzip", 4) ||
936  !av_strncasecmp(p, "deflate", 7)) {
937 #if CONFIG_ZLIB
938  HTTPContext *s = h->priv_data;
939 
940  s->compressed = 1;
941  inflateEnd(&s->inflate_stream);
942  if (inflateInit2(&s->inflate_stream, 32 + 15) != Z_OK) {
943  av_log(h, AV_LOG_WARNING, "Error during zlib initialisation: %s\n",
944  s->inflate_stream.msg);
945  return AVERROR(ENOSYS);
946  }
947  if (zlibCompileFlags() & (1 << 17)) {
949  "Your zlib was compiled without gzip support.\n");
950  return AVERROR(ENOSYS);
951  }
952 #else
954  "Compressed (%s) content, need zlib with gzip support\n", p);
955  return AVERROR(ENOSYS);
956 #endif /* CONFIG_ZLIB */
957  } else if (!av_strncasecmp(p, "identity", 8)) {
958  // The normal, no-encoding case (although servers shouldn't include
959  // the header at all if this is the case).
960  } else {
961  av_log(h, AV_LOG_WARNING, "Unknown content coding: %s\n", p);
962  }
963  return 0;
964 }
965 
966 // Concat all Icy- header lines
967 static int parse_icy(HTTPContext *s, const char *tag, const char *p)
968 {
969  int len = 4 + strlen(p) + strlen(tag);
970  int is_first = !s->icy_metadata_headers;
971  int ret;
972 
973  av_dict_set(&s->metadata, tag, p, 0);
974 
975  if (s->icy_metadata_headers)
976  len += strlen(s->icy_metadata_headers);
977 
978  if ((ret = av_reallocp(&s->icy_metadata_headers, len)) < 0)
979  return ret;
980 
981  if (is_first)
982  *s->icy_metadata_headers = '\0';
983 
984  av_strlcatf(s->icy_metadata_headers, len, "%s: %s\n", tag, p);
985 
986  return 0;
987 }
988 
989 static int parse_http_date(const char *date_str, struct tm *buf)
990 {
991  char date_buf[MAX_DATE_LEN];
992  int i, j, date_buf_len = MAX_DATE_LEN-1;
993  char *date;
994 
995  // strip off any punctuation or whitespace
996  for (i = 0, j = 0; date_str[i] != '\0' && j < date_buf_len; i++) {
997  if ((date_str[i] >= '0' && date_str[i] <= '9') ||
998  (date_str[i] >= 'A' && date_str[i] <= 'Z') ||
999  (date_str[i] >= 'a' && date_str[i] <= 'z')) {
1000  date_buf[j] = date_str[i];
1001  j++;
1002  }
1003  }
1004  date_buf[j] = '\0';
1005  date = date_buf;
1006 
1007  // move the string beyond the day of week
1008  while ((*date < '0' || *date > '9') && *date != '\0')
1009  date++;
1010 
1011  return av_small_strptime(date, "%d%b%Y%H%M%S", buf) ? 0 : AVERROR(EINVAL);
1012 }
1013 
1014 static int parse_set_cookie(const char *set_cookie, AVDictionary **dict)
1015 {
1016  char *param, *next_param, *cstr, *back;
1017  char *saveptr = NULL;
1018 
1019  if (!set_cookie[0])
1020  return 0;
1021 
1022  if (!(cstr = av_strdup(set_cookie)))
1023  return AVERROR(EINVAL);
1024 
1025  // strip any trailing whitespace
1026  back = &cstr[strlen(cstr)-1];
1027  while (strchr(WHITESPACES, *back)) {
1028  *back='\0';
1029  if (back == cstr)
1030  break;
1031  back--;
1032  }
1033 
1034  next_param = cstr;
1035  while ((param = av_strtok(next_param, ";", &saveptr))) {
1036  char *name, *value;
1037  next_param = NULL;
1038  param += strspn(param, WHITESPACES);
1039  if ((name = av_strtok(param, "=", &value))) {
1040  if (av_dict_set(dict, name, value, 0) < 0) {
1041  av_free(cstr);
1042  return -1;
1043  }
1044  }
1045  }
1046 
1047  av_free(cstr);
1048  return 0;
1049 }
1050 
1051 static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
1052 {
1053  AVDictionary *new_params = NULL;
1054  const AVDictionaryEntry *e, *cookie_entry;
1055  char *eql, *name;
1056 
1057  // ensure the cookie is parsable
1058  if (parse_set_cookie(p, &new_params))
1059  return -1;
1060 
1061  // if there is no cookie value there is nothing to parse
1062  cookie_entry = av_dict_iterate(new_params, NULL);
1063  if (!cookie_entry || !cookie_entry->value) {
1064  av_dict_free(&new_params);
1065  return -1;
1066  }
1067 
1068  // ensure the cookie is not expired or older than an existing value
1069  if ((e = av_dict_get(new_params, "expires", NULL, 0)) && e->value) {
1070  struct tm new_tm = {0};
1071  if (!parse_http_date(e->value, &new_tm)) {
1072  AVDictionaryEntry *e2;
1073 
1074  // if the cookie has already expired ignore it
1075  if (av_timegm(&new_tm) < av_gettime() / 1000000) {
1076  av_dict_free(&new_params);
1077  return 0;
1078  }
1079 
1080  // only replace an older cookie with the same name
1081  e2 = av_dict_get(*cookies, cookie_entry->key, NULL, 0);
1082  if (e2 && e2->value) {
1083  AVDictionary *old_params = NULL;
1084  if (!parse_set_cookie(p, &old_params)) {
1085  e2 = av_dict_get(old_params, "expires", NULL, 0);
1086  if (e2 && e2->value) {
1087  struct tm old_tm = {0};
1088  if (!parse_http_date(e->value, &old_tm)) {
1089  if (av_timegm(&new_tm) < av_timegm(&old_tm)) {
1090  av_dict_free(&new_params);
1091  av_dict_free(&old_params);
1092  return -1;
1093  }
1094  }
1095  }
1096  }
1097  av_dict_free(&old_params);
1098  }
1099  }
1100  }
1101  av_dict_free(&new_params);
1102 
1103  // duplicate the cookie name (dict will dupe the value)
1104  if (!(eql = strchr(p, '='))) return AVERROR(EINVAL);
1105  if (!(name = av_strndup(p, eql - p))) return AVERROR(ENOMEM);
1106 
1107  // add the cookie to the dictionary
1108  av_dict_set(cookies, name, eql, AV_DICT_DONT_STRDUP_KEY);
1109 
1110  return 0;
1111 }
1112 
1113 static int cookie_string(AVDictionary *dict, char **cookies)
1114 {
1115  const AVDictionaryEntry *e = NULL;
1116  int len = 1;
1117 
1118  // determine how much memory is needed for the cookies string
1119  while ((e = av_dict_iterate(dict, e)))
1120  len += strlen(e->key) + strlen(e->value) + 1;
1121 
1122  // reallocate the cookies
1123  e = NULL;
1124  if (*cookies) av_free(*cookies);
1125  *cookies = av_malloc(len);
1126  if (!*cookies) return AVERROR(ENOMEM);
1127  *cookies[0] = '\0';
1128 
1129  // write out the cookies
1130  while ((e = av_dict_iterate(dict, e)))
1131  av_strlcatf(*cookies, len, "%s%s\n", e->key, e->value);
1132 
1133  return 0;
1134 }
1135 
1136 static void parse_expires(HTTPContext *s, const char *p)
1137 {
1138  struct tm tm;
1139 
1140  if (!parse_http_date(p, &tm)) {
1141  s->expires = av_timegm(&tm);
1142  }
1143 }
1144 
1145 static void parse_cache_control(HTTPContext *s, const char *p)
1146 {
1147  char *age;
1148  int offset;
1149 
1150  /* give 'Expires' higher priority over 'Cache-Control' */
1151  if (s->expires) {
1152  return;
1153  }
1154 
1155  if (av_stristr(p, "no-cache") || av_stristr(p, "no-store")) {
1156  s->expires = -1;
1157  return;
1158  }
1159 
1160  age = av_stristr(p, "s-maxage=");
1161  offset = 9;
1162  if (!age) {
1163  age = av_stristr(p, "max-age=");
1164  offset = 8;
1165  }
1166 
1167  if (age) {
1168  s->expires = time(NULL) + atoi(age + offset);
1169  }
1170 }
1171 
1172 static int process_line(URLContext *h, char *line, int line_count, int *parsed_http_code)
1173 {
1174  HTTPContext *s = h->priv_data;
1175  const char *auto_method = h->flags & AVIO_FLAG_READ ? "POST" : "GET";
1176  char *tag, *p, *end, *method, *resource, *version;
1177  int ret;
1178 
1179  /* end of header */
1180  if (line[0] == '\0') {
1181  s->end_header = 1;
1182  return 0;
1183  }
1184 
1185  p = line;
1186  if (line_count == 0) {
1187  if (s->is_connected_server) {
1188  // HTTP method
1189  method = p;
1190  while (*p && !av_isspace(*p))
1191  p++;
1192  *(p++) = '\0';
1193  av_log(h, AV_LOG_TRACE, "Received method: %s\n", method);
1194  if (s->method) {
1195  if (av_strcasecmp(s->method, method)) {
1196  av_log(h, AV_LOG_ERROR, "Received and expected HTTP method do not match. (%s expected, %s received)\n",
1197  s->method, method);
1198  return ff_http_averror(400, AVERROR(EIO));
1199  }
1200  } else {
1201  // use autodetected HTTP method to expect
1202  av_log(h, AV_LOG_TRACE, "Autodetected %s HTTP method\n", auto_method);
1203  if (av_strcasecmp(auto_method, method)) {
1204  av_log(h, AV_LOG_ERROR, "Received and autodetected HTTP method did not match "
1205  "(%s autodetected %s received)\n", auto_method, method);
1206  return ff_http_averror(400, AVERROR(EIO));
1207  }
1208  if (!(s->method = av_strdup(method)))
1209  return AVERROR(ENOMEM);
1210  }
1211 
1212  // HTTP resource
1213  while (av_isspace(*p))
1214  p++;
1215  resource = p;
1216  while (*p && !av_isspace(*p))
1217  p++;
1218  *(p++) = '\0';
1219  av_log(h, AV_LOG_TRACE, "Requested resource: %s\n", resource);
1220  if (!(s->resource = av_strdup(resource)))
1221  return AVERROR(ENOMEM);
1222 
1223  // HTTP version
1224  while (av_isspace(*p))
1225  p++;
1226  version = p;
1227  while (*p && !av_isspace(*p))
1228  p++;
1229  *p = '\0';
1230  if (av_strncasecmp(version, "HTTP/", 5)) {
1231  av_log(h, AV_LOG_ERROR, "Malformed HTTP version string.\n");
1232  return ff_http_averror(400, AVERROR(EIO));
1233  }
1234  av_log(h, AV_LOG_TRACE, "HTTP version string: %s\n", version);
1235  } else {
1236  if (av_strncasecmp(p, "HTTP/1.0", 8) == 0)
1237  s->willclose = 1;
1238  while (*p != '/' && *p != '\0')
1239  p++;
1240  while (*p == '/')
1241  p++;
1242  av_freep(&s->http_version);
1243  s->http_version = av_strndup(p, 3);
1244  while (!av_isspace(*p) && *p != '\0')
1245  p++;
1246  while (av_isspace(*p))
1247  p++;
1248  s->http_code = strtol(p, &end, 10);
1249 
1250  av_log(h, AV_LOG_TRACE, "http_code=%d\n", s->http_code);
1251 
1252  *parsed_http_code = 1;
1253 
1254  if ((ret = check_http_code(h, s->http_code, end)) < 0)
1255  return ret;
1256  }
1257  } else {
1258  while (*p != '\0' && *p != ':')
1259  p++;
1260  if (*p != ':')
1261  return 1;
1262 
1263  *p = '\0';
1264  tag = line;
1265  p++;
1266  while (av_isspace(*p))
1267  p++;
1268  if (!av_strcasecmp(tag, "Location")) {
1269  if ((ret = parse_location(s, p)) < 0)
1270  return ret;
1271  } else if (!av_strcasecmp(tag, "Content-Length") &&
1272  s->filesize == UINT64_MAX) {
1273  s->filesize = strtoull(p, NULL, 10);
1274  } else if (!av_strcasecmp(tag, "Content-Range")) {
1276  } else if (!av_strcasecmp(tag, "Accept-Ranges") &&
1277  !strncmp(p, "bytes", 5) &&
1278  s->seekable == -1) {
1279  h->is_streamed = 0;
1280  } else if (!av_strcasecmp(tag, "Transfer-Encoding") &&
1281  !av_strncasecmp(p, "chunked", 7)) {
1282  s->filesize = UINT64_MAX;
1283  s->chunksize = 0;
1284  } else if (!av_strcasecmp(tag, "WWW-Authenticate")) {
1285  ff_http_auth_handle_header(&s->auth_state, tag, p);
1286  } else if (!av_strcasecmp(tag, "Authentication-Info")) {
1287  ff_http_auth_handle_header(&s->auth_state, tag, p);
1288  } else if (!av_strcasecmp(tag, "Proxy-Authenticate")) {
1289  ff_http_auth_handle_header(&s->proxy_auth_state, tag, p);
1290  } else if (!av_strcasecmp(tag, "Connection")) {
1291  if (!strcmp(p, "close"))
1292  s->willclose = 1;
1293  } else if (!av_strcasecmp(tag, "Server")) {
1294  if (!av_strcasecmp(p, "AkamaiGHost")) {
1295  s->is_akamai = 1;
1296  } else if (!av_strncasecmp(p, "MediaGateway", 12)) {
1297  s->is_mediagateway = 1;
1298  }
1299  } else if (!av_strcasecmp(tag, "Content-Type")) {
1300  av_free(s->mime_type);
1301  s->mime_type = av_get_token((const char **)&p, ";");
1302  } else if (!av_strcasecmp(tag, "Set-Cookie")) {
1303  if (parse_cookie(s, p, &s->cookie_dict))
1304  av_log(h, AV_LOG_WARNING, "Unable to parse '%s'\n", p);
1305  } else if (!av_strcasecmp(tag, "Icy-MetaInt")) {
1306  s->icy_metaint = strtoull(p, NULL, 10);
1307  } else if (!av_strncasecmp(tag, "Icy-", 4)) {
1308  if ((ret = parse_icy(s, tag, p)) < 0)
1309  return ret;
1310  } else if (!av_strcasecmp(tag, "Content-Encoding")) {
1311  if ((ret = parse_content_encoding(h, p)) < 0)
1312  return ret;
1313  } else if (!av_strcasecmp(tag, "Expires")) {
1314  parse_expires(s, p);
1315  } else if (!av_strcasecmp(tag, "Cache-Control")) {
1317  } else if (!av_strcasecmp(tag, "Retry-After")) {
1318  /* The header can be either an integer that represents seconds, or a date. */
1319  struct tm tm;
1320  int date_ret = parse_http_date(p, &tm);
1321  if (!date_ret) {
1322  time_t retry = av_timegm(&tm);
1323  int64_t now = av_gettime() / 1000000;
1324  int64_t diff = ((int64_t) retry) - now;
1325  s->retry_after = (unsigned int) FFMAX(0, diff);
1326  } else {
1327  s->retry_after = strtoul(p, NULL, 10);
1328  }
1329  }
1330  }
1331  return 1;
1332 }
1333 
1334 /**
1335  * Create a string containing cookie values for use as a HTTP cookie header
1336  * field value for a particular path and domain from the cookie values stored in
1337  * the HTTP protocol context. The cookie string is stored in *cookies, and may
1338  * be NULL if there are no valid cookies.
1339  *
1340  * @return a negative value if an error condition occurred, 0 otherwise
1341  */
1342 static int get_cookies(HTTPContext *s, char **cookies, const char *path,
1343  const char *domain)
1344 {
1345  // cookie strings will look like Set-Cookie header field values. Multiple
1346  // Set-Cookie fields will result in multiple values delimited by a newline
1347  int ret = 0;
1348  char *cookie, *set_cookies, *next;
1349  char *saveptr = NULL;
1350 
1351  // destroy any cookies in the dictionary.
1352  av_dict_free(&s->cookie_dict);
1353 
1354  if (!s->cookies)
1355  return 0;
1356 
1357  next = set_cookies = av_strdup(s->cookies);
1358  if (!next)
1359  return AVERROR(ENOMEM);
1360 
1361  *cookies = NULL;
1362  while ((cookie = av_strtok(next, "\n", &saveptr)) && !ret) {
1363  AVDictionary *cookie_params = NULL;
1364  const AVDictionaryEntry *cookie_entry, *e;
1365 
1366  next = NULL;
1367  // store the cookie in a dict in case it is updated in the response
1368  if (parse_cookie(s, cookie, &s->cookie_dict))
1369  av_log(s, AV_LOG_WARNING, "Unable to parse '%s'\n", cookie);
1370 
1371  // continue on to the next cookie if this one cannot be parsed
1372  if (parse_set_cookie(cookie, &cookie_params))
1373  goto skip_cookie;
1374 
1375  // if the cookie has no value, skip it
1376  cookie_entry = av_dict_iterate(cookie_params, NULL);
1377  if (!cookie_entry || !cookie_entry->value)
1378  goto skip_cookie;
1379 
1380  // if the cookie has expired, don't add it
1381  if ((e = av_dict_get(cookie_params, "expires", NULL, 0)) && e->value) {
1382  struct tm tm_buf = {0};
1383  if (!parse_http_date(e->value, &tm_buf)) {
1384  if (av_timegm(&tm_buf) < av_gettime() / 1000000)
1385  goto skip_cookie;
1386  }
1387  }
1388 
1389  // if no domain in the cookie assume it applied to this request
1390  if ((e = av_dict_get(cookie_params, "domain", NULL, 0)) && e->value) {
1391  // find the offset comparison is on the min domain (b.com, not a.b.com)
1392  int domain_offset = strlen(domain) - strlen(e->value);
1393  if (domain_offset < 0)
1394  goto skip_cookie;
1395 
1396  // match the cookie domain
1397  if (av_strcasecmp(&domain[domain_offset], e->value))
1398  goto skip_cookie;
1399  }
1400 
1401  // if a cookie path is provided, ensure the request path is within that path
1402  e = av_dict_get(cookie_params, "path", NULL, 0);
1403  if (e && av_strncasecmp(path, e->value, strlen(e->value)))
1404  goto skip_cookie;
1405 
1406  // cookie parameters match, so copy the value
1407  if (!*cookies) {
1408  *cookies = av_asprintf("%s=%s", cookie_entry->key, cookie_entry->value);
1409  } else {
1410  char *tmp = *cookies;
1411  *cookies = av_asprintf("%s; %s=%s", tmp, cookie_entry->key, cookie_entry->value);
1412  av_free(tmp);
1413  }
1414  if (!*cookies)
1415  ret = AVERROR(ENOMEM);
1416 
1417  skip_cookie:
1418  av_dict_free(&cookie_params);
1419  }
1420 
1421  av_free(set_cookies);
1422 
1423  return ret;
1424 }
1425 
1426 static inline int has_header(const char *str, const char *header)
1427 {
1428  /* header + 2 to skip over CRLF prefix. (make sure you have one!) */
1429  if (!str)
1430  return 0;
1431  return av_stristart(str, header + 2, NULL) || av_stristr(str, header);
1432 }
1433 
1435 {
1436  HTTPContext *s = h->priv_data;
1437  char line[MAX_URL_SIZE];
1438  int err = 0, http_err = 0;
1439 
1440  av_freep(&s->new_location);
1441  s->expires = 0;
1442  s->chunksize = UINT64_MAX;
1443  s->filesize_from_content_range = UINT64_MAX;
1444 
1445  for (;;) {
1446  int parsed_http_code = 0;
1447 
1448  if ((err = http_get_line(s, line, sizeof(line))) < 0) {
1449  av_log(h, AV_LOG_ERROR, "Error reading HTTP response: %s\n",
1450  av_err2str(err));
1451  return err;
1452  }
1453 
1454  av_log(h, AV_LOG_TRACE, "header='%s'\n", line);
1455 
1456  err = process_line(h, line, s->line_count, &parsed_http_code);
1457  if (err < 0) {
1458  if (parsed_http_code) {
1459  http_err = err;
1460  } else {
1461  /* Prefer to return HTTP code error if we've already seen one. */
1462  if (http_err)
1463  return http_err;
1464  else
1465  return err;
1466  }
1467  }
1468  if (err == 0)
1469  break;
1470  s->line_count++;
1471  }
1472  if (http_err)
1473  return http_err;
1474 
1475  // filesize from Content-Range can always be used, even if using chunked Transfer-Encoding
1476  if (s->filesize_from_content_range != UINT64_MAX)
1477  s->filesize = s->filesize_from_content_range;
1478 
1479  if (s->seekable == -1 && s->is_mediagateway && s->filesize == 2000000000)
1480  h->is_streamed = 1; /* we can in fact _not_ seek */
1481 
1482  if (h->is_streamed)
1483  s->initial_requests = 0; /* unable to use partial requests */
1484 
1485  // add any new cookies into the existing cookie string
1486  cookie_string(s->cookie_dict, &s->cookies);
1487  av_dict_free(&s->cookie_dict);
1488 
1489  return err;
1490 }
1491 
1492 /**
1493  * Escape unsafe characters in path in order to pass them safely to the HTTP
1494  * request. Insipred by the algorithm in GNU wget:
1495  * - escape "%" characters not followed by two hex digits
1496  * - escape all "unsafe" characters except which are also "reserved"
1497  * - pass through everything else
1498  */
1499 static void bprint_escaped_path(AVBPrint *bp, const char *path)
1500 {
1501 #define NEEDS_ESCAPE(ch) \
1502  ((ch) <= ' ' || (ch) >= '\x7f' || \
1503  (ch) == '"' || (ch) == '%' || (ch) == '<' || (ch) == '>' || (ch) == '\\' || \
1504  (ch) == '^' || (ch) == '`' || (ch) == '{' || (ch) == '}' || (ch) == '|')
1505  while (*path) {
1506  char buf[1024];
1507  char *q = buf;
1508  while (*path && q - buf < sizeof(buf) - 4) {
1509  if (path[0] == '%' && av_isxdigit(path[1]) && av_isxdigit(path[2])) {
1510  *q++ = *path++;
1511  *q++ = *path++;
1512  *q++ = *path++;
1513  } else if (NEEDS_ESCAPE(*path)) {
1514  q += snprintf(q, 4, "%%%02X", (uint8_t)*path++);
1515  } else {
1516  *q++ = *path++;
1517  }
1518  }
1519  av_bprint_append_data(bp, buf, q - buf);
1520  }
1521 }
1522 
1523 static int http_connect(URLContext *h, const char *path, const char *local_path,
1524  const char *hoststr, const char *auth,
1525  const char *proxyauth)
1526 {
1527  HTTPContext *s = h->priv_data;
1528  int post, err;
1529  AVBPrint request;
1530  char *authstr = NULL, *proxyauthstr = NULL;
1531  uint64_t off = s->off;
1532  const char *method;
1533  int send_expect_100 = 0;
1534 
1535  av_bprint_init_for_buffer(&request, s->buffer, sizeof(s->buffer));
1536 
1537  /* send http header */
1538  post = h->flags & AVIO_FLAG_WRITE;
1539 
1540  if (s->post_data) {
1541  /* force POST method and disable chunked encoding when
1542  * custom HTTP post data is set */
1543  post = 1;
1544  s->chunked_post = 0;
1545  }
1546 
1547  if (s->method)
1548  method = s->method;
1549  else
1550  method = post ? "POST" : "GET";
1551 
1552  authstr = ff_http_auth_create_response(&s->auth_state, auth,
1553  local_path, method);
1554  proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth,
1555  local_path, method);
1556 
1557  if (post && !s->post_data) {
1558  if (s->send_expect_100 != -1) {
1559  send_expect_100 = s->send_expect_100;
1560  } else {
1561  send_expect_100 = 0;
1562  /* The user has supplied authentication but we don't know the auth type,
1563  * send Expect: 100-continue to get the 401 response including the
1564  * WWW-Authenticate header, or an 100 continue if no auth actually
1565  * is needed. */
1566  if (auth && *auth &&
1567  s->auth_state.auth_type == HTTP_AUTH_NONE &&
1568  s->http_code != 401)
1569  send_expect_100 = 1;
1570  }
1571  }
1572 
1573  av_bprintf(&request, "%s ", method);
1574  bprint_escaped_path(&request, path);
1575  av_bprintf(&request, " HTTP/1.1\r\n");
1576 
1577  if (post && s->chunked_post)
1578  av_bprintf(&request, "Transfer-Encoding: chunked\r\n");
1579  /* set default headers if needed */
1580  if (!has_header(s->headers, "\r\nUser-Agent: "))
1581  av_bprintf(&request, "User-Agent: %s\r\n", s->user_agent);
1582  if (s->referer) {
1583  /* set default headers if needed */
1584  if (!has_header(s->headers, "\r\nReferer: "))
1585  av_bprintf(&request, "Referer: %s\r\n", s->referer);
1586  }
1587  if (!has_header(s->headers, "\r\nAccept: "))
1588  av_bprintf(&request, "Accept: */*\r\n");
1589  // Note: we send the Range header on purpose, even when we're probing,
1590  // since it allows us to detect more reliably if a (non-conforming)
1591  // server supports seeking by analysing the reply headers.
1592  if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->end_off || s->seekable != 0)) {
1593  av_bprintf(&request, "Range: bytes=%"PRIu64"-", s->off);
1594  if ((s->initial_requests || s->request_size) && s->seekable != 0) {
1595  uint64_t req_size = s->initial_requests ? s->initial_request_size : s->request_size;
1596  uint64_t target_off = s->off + req_size;
1597  if (target_off < s->off) /* overflow */
1598  target_off = UINT64_MAX;
1599  if (s->end_off)
1600  target_off = FFMIN(target_off, s->end_off);
1601  if (target_off != UINT64_MAX)
1602  av_bprintf(&request, "%"PRId64, target_off - 1);
1603  } else if (s->end_off)
1604  av_bprintf(&request, "%"PRId64, s->end_off - 1);
1605  av_bprintf(&request, "\r\n");
1606  }
1607  if (send_expect_100 && !has_header(s->headers, "\r\nExpect: "))
1608  av_bprintf(&request, "Expect: 100-continue\r\n");
1609 
1610  if (!has_header(s->headers, "\r\nConnection: "))
1611  av_bprintf(&request, "Connection: %s\r\n", s->multiple_requests ? "keep-alive" : "close");
1612 
1613  if (!has_header(s->headers, "\r\nHost: "))
1614  av_bprintf(&request, "Host: %s\r\n", hoststr);
1615  if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data)
1616  av_bprintf(&request, "Content-Length: %d\r\n", s->post_datalen);
1617 
1618  if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
1619  av_bprintf(&request, "Content-Type: %s\r\n", s->content_type);
1620  if (!has_header(s->headers, "\r\nCookie: ") && s->cookies) {
1621  char *cookies = NULL;
1622  if (!get_cookies(s, &cookies, path, hoststr) && cookies) {
1623  av_bprintf(&request, "Cookie: %s\r\n", cookies);
1624  av_free(cookies);
1625  }
1626  }
1627  if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy)
1628  av_bprintf(&request, "Icy-MetaData: 1\r\n");
1629 
1630  /* now add in custom headers */
1631  if (s->headers)
1632  av_bprintf(&request, "%s", s->headers);
1633 
1634  if (authstr)
1635  av_bprintf(&request, "%s", authstr);
1636  if (proxyauthstr)
1637  av_bprintf(&request, "Proxy-%s", proxyauthstr);
1638  av_bprintf(&request, "\r\n");
1639 
1640  av_log(h, AV_LOG_DEBUG, "request: %s\n", request.str);
1641 
1642  if (!av_bprint_is_complete(&request)) {
1643  av_log(h, AV_LOG_ERROR, "overlong headers\n");
1644  err = AVERROR(EINVAL);
1645  goto done;
1646  }
1647 
1648  if ((err = ffurl_write(s->hd, request.str, request.len)) < 0)
1649  goto done;
1650 
1651  if (s->post_data)
1652  if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0)
1653  goto done;
1654 
1655  /* init input buffer */
1656  s->buf_ptr = s->buffer;
1657  s->buf_end = s->buffer;
1658  s->line_count = 0;
1659  s->off = 0;
1660  s->icy_data_read = 0;
1661  s->filesize = UINT64_MAX;
1662  s->willclose = 0;
1663  s->end_chunked_post = 0;
1664  s->end_header = 0;
1665 #if CONFIG_ZLIB
1666  s->compressed = 0;
1667 #endif
1668  if (post && !s->post_data && !send_expect_100) {
1669  /* Pretend that it did work. We didn't read any header yet, since
1670  * we've still to send the POST data, but the code calling this
1671  * function will check http_code after we return. */
1672  s->http_code = 200;
1673  err = 0;
1674  goto done;
1675  }
1676 
1677  /* wait for header */
1678  int64_t latency = av_gettime();
1679  err = http_read_header(h);
1680  latency = av_gettime() - latency;
1681  if (err < 0)
1682  goto done;
1683 
1684  s->nb_requests++;
1685  s->sum_latency += latency;
1686  s->max_latency = FFMAX(s->max_latency, latency);
1687 
1688  if (s->new_location)
1689  s->off = off;
1690 
1691  if (off != s->off) {
1693  "Unexpected offset: expected %"PRIu64", got %"PRIu64"\n",
1694  off, s->off);
1695  err = AVERROR(EIO);
1696  goto done;
1697  }
1698 
1699  err = 0;
1700 done:
1701  av_freep(&authstr);
1702  av_freep(&proxyauthstr);
1703  return err;
1704 }
1705 
1706 static int http_buf_read(URLContext *h, uint8_t *buf, int size)
1707 {
1708  HTTPContext *s = h->priv_data;
1709  int len;
1710 
1711  if (!s->hd)
1712  return AVERROR(EIO);
1713 
1714  if (s->chunksize != UINT64_MAX) {
1715  if (s->chunkend) {
1716  return AVERROR_EOF;
1717  }
1718  if (!s->chunksize) {
1719  char line[32];
1720  int err;
1721 
1722  do {
1723  if ((err = http_get_line(s, line, sizeof(line))) < 0)
1724  return err;
1725  } while (!*line); /* skip CR LF from last chunk */
1726 
1727  s->chunksize = strtoull(line, NULL, 16);
1728 
1730  "Chunked encoding data size: %"PRIu64"\n",
1731  s->chunksize);
1732 
1733  if (!s->chunksize && s->multiple_requests) {
1734  http_get_line(s, line, sizeof(line)); // read empty chunk
1735  s->chunkend = 1;
1736  return 0;
1737  }
1738  else if (!s->chunksize) {
1739  av_log(h, AV_LOG_DEBUG, "Last chunk received, closing conn\n");
1740  ffurl_closep(&s->hd);
1741  return 0;
1742  }
1743  else if (s->chunksize == UINT64_MAX) {
1744  av_log(h, AV_LOG_ERROR, "Invalid chunk size %"PRIu64"\n",
1745  s->chunksize);
1746  return AVERROR(EINVAL);
1747  }
1748  }
1749  size = FFMIN(size, s->chunksize);
1750  }
1751 
1752  /* read bytes from input buffer first */
1753  len = s->buf_end - s->buf_ptr;
1754  if (len > 0) {
1755  if (len > size)
1756  len = size;
1757  memcpy(buf, s->buf_ptr, len);
1758  s->buf_ptr += len;
1759  } else {
1760  uint64_t file_end = s->end_off ? s->end_off : s->filesize;
1761  uint64_t target_end = s->range_end ? s->range_end : file_end;
1762  if ((!s->willclose || s->chunksize == UINT64_MAX) && s->off >= file_end)
1763  return AVERROR_EOF;
1764  if (s->off == target_end && target_end < file_end)
1765  return AVERROR(EAGAIN); /* reached end of content range */
1766  len = ffurl_read(s->hd, buf, size);
1767  if ((!len || len == AVERROR_EOF) &&
1768  (!s->willclose || s->chunksize == UINT64_MAX) && s->off < target_end) {
1770  "Stream ends prematurely at %"PRIu64", should be %"PRIu64"\n",
1771  s->off, target_end
1772  );
1773  return AVERROR(EIO);
1774  }
1775  }
1776  if (len > 0) {
1777  s->off += len;
1778  if (s->chunksize > 0 && s->chunksize != UINT64_MAX) {
1779  av_assert0(s->chunksize >= len);
1780  s->chunksize -= len;
1781  }
1782  }
1783  return len;
1784 }
1785 
1786 #if CONFIG_ZLIB
1787 #define DECOMPRESS_BUF_SIZE (256 * 1024)
1788 static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size)
1789 {
1790  HTTPContext *s = h->priv_data;
1791  int ret;
1792 
1793  if (!s->inflate_buffer) {
1794  s->inflate_buffer = av_malloc(DECOMPRESS_BUF_SIZE);
1795  if (!s->inflate_buffer)
1796  return AVERROR(ENOMEM);
1797  }
1798 
1799  if (s->inflate_stream.avail_in == 0) {
1800  int read = http_buf_read(h, s->inflate_buffer, DECOMPRESS_BUF_SIZE);
1801  if (read <= 0)
1802  return read;
1803  s->inflate_stream.next_in = s->inflate_buffer;
1804  s->inflate_stream.avail_in = read;
1805  }
1806 
1807  s->inflate_stream.avail_out = size;
1808  s->inflate_stream.next_out = buf;
1809 
1810  ret = inflate(&s->inflate_stream, Z_SYNC_FLUSH);
1811  if (ret != Z_OK && ret != Z_STREAM_END)
1812  av_log(h, AV_LOG_WARNING, "inflate return value: %d, %s\n",
1813  ret, s->inflate_stream.msg);
1814 
1815  return size - s->inflate_stream.avail_out;
1816 }
1817 #endif /* CONFIG_ZLIB */
1818 
1819 static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect);
1820 
1821 static int http_read_stream(URLContext *h, uint8_t *buf, int size)
1822 {
1823  HTTPContext *s = h->priv_data;
1824  int err, read_ret;
1825  int64_t seek_ret;
1826  int reconnect_delay = 0;
1827  int reconnect_delay_total = 0;
1828  int conn_attempts = 1;
1829 
1830  if (!s->hd)
1831  return AVERROR_EOF;
1832 
1833  if (s->end_chunked_post && !s->end_header) {
1834  err = http_read_header(h);
1835  if (err < 0)
1836  return err;
1837  }
1838 
1839 #if CONFIG_ZLIB
1840  if (s->compressed)
1841  return http_buf_read_compressed(h, buf, size);
1842 #endif /* CONFIG_ZLIB */
1843 
1844 retry:
1845  read_ret = http_buf_read(h, buf, size);
1846  while (read_ret < 0) {
1847  uint64_t target = h->is_streamed ? 0 : s->off;
1848  bool is_premature = s->filesize > 0 && s->off < s->filesize;
1849 
1850  if (read_ret == AVERROR_EXIT)
1851  break;
1852  else if (read_ret == AVERROR(EAGAIN)) {
1853  /* send new request for more data on existing connection */
1855  if (s->willclose)
1856  ffurl_closep(&s->hd);
1857  s->initial_requests = 0; /* continue streaming uninterrupted from now on */
1858  read_ret = http_open_cnx(h, &options);
1860  if (read_ret == 0)
1861  goto retry;
1862  }
1863 
1864  if (h->is_streamed && !s->reconnect_streamed)
1865  break;
1866 
1867  if (!(s->reconnect && is_premature) &&
1868  !(s->reconnect_at_eof && read_ret == AVERROR_EOF)) {
1869  if (is_premature)
1870  return AVERROR(EIO);
1871  else
1872  break;
1873  }
1874 
1875  if (reconnect_delay > s->reconnect_delay_max || (s->reconnect_max_retries >= 0 && conn_attempts > s->reconnect_max_retries) ||
1876  reconnect_delay_total > s->reconnect_delay_total_max)
1877  return AVERROR(EIO);
1878 
1879  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));
1880  err = ff_network_sleep_interruptible(1000U*1000*reconnect_delay, &h->interrupt_callback);
1881  if (err != AVERROR(ETIMEDOUT))
1882  return err;
1883  reconnect_delay_total += reconnect_delay;
1884  reconnect_delay = 1 + 2*reconnect_delay;
1885  conn_attempts++;
1886  seek_ret = http_seek_internal(h, target, SEEK_SET, 1);
1887  if (seek_ret >= 0 && seek_ret != target) {
1888  ffurl_closep(&s->hd);
1889  av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRIu64".\n", target);
1890  return read_ret;
1891  }
1892 
1893  read_ret = http_buf_read(h, buf, size);
1894  }
1895 
1896  return read_ret;
1897 }
1898 
1899 // Like http_read_stream(), but no short reads.
1900 // Assumes partial reads are an error.
1901 static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
1902 {
1903  int pos = 0;
1904  while (pos < size) {
1905  int len = http_read_stream(h, buf + pos, size - pos);
1906  if (len < 0)
1907  return len;
1908  pos += len;
1909  }
1910  return pos;
1911 }
1912 
1913 static void update_metadata(URLContext *h, char *data)
1914 {
1915  char *key;
1916  char *val;
1917  char *end;
1918  char *next = data;
1919  HTTPContext *s = h->priv_data;
1920 
1921  while (*next) {
1922  key = next;
1923  val = strstr(key, "='");
1924  if (!val)
1925  break;
1926  end = strstr(val, "';");
1927  if (!end)
1928  break;
1929 
1930  *val = '\0';
1931  *end = '\0';
1932  val += 2;
1933 
1934  av_dict_set(&s->metadata, key, val, 0);
1935  av_log(h, AV_LOG_VERBOSE, "Metadata update for %s: %s\n", key, val);
1936 
1937  next = end + 2;
1938  }
1939 }
1940 
1941 static int store_icy(URLContext *h, int size)
1942 {
1943  HTTPContext *s = h->priv_data;
1944  /* until next metadata packet */
1945  uint64_t remaining;
1946 
1947  if (s->icy_metaint < s->icy_data_read)
1948  return AVERROR_INVALIDDATA;
1949  remaining = s->icy_metaint - s->icy_data_read;
1950 
1951  if (!remaining) {
1952  /* The metadata packet is variable sized. It has a 1 byte header
1953  * which sets the length of the packet (divided by 16). If it's 0,
1954  * the metadata doesn't change. After the packet, icy_metaint bytes
1955  * of normal data follows. */
1956  uint8_t ch;
1957  int len = http_read_stream_all(h, &ch, 1);
1958  if (len < 0)
1959  return len;
1960  if (ch > 0) {
1961  char data[255 * 16 + 1];
1962  int ret;
1963  len = ch * 16;
1965  if (ret < 0)
1966  return ret;
1967  data[len] = 0;
1968  if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
1969  return ret;
1971  }
1972  s->icy_data_read = 0;
1973  remaining = s->icy_metaint;
1974  }
1975 
1976  return FFMIN(size, remaining);
1977 }
1978 
1979 static int http_read(URLContext *h, uint8_t *buf, int size)
1980 {
1981  HTTPContext *s = h->priv_data;
1982 
1983  if (s->icy_metaint > 0) {
1984  size = store_icy(h, size);
1985  if (size < 0)
1986  return size;
1987  }
1988 
1989  size = http_read_stream(h, buf, size);
1990  if (size > 0)
1991  s->icy_data_read += size;
1992  return size;
1993 }
1994 
1995 /* used only when posting data */
1996 static int http_write(URLContext *h, const uint8_t *buf, int size)
1997 {
1998  char temp[11] = ""; /* 32-bit hex + CRLF + nul */
1999  int ret;
2000  char crlf[] = "\r\n";
2001  HTTPContext *s = h->priv_data;
2002 
2003  if (!s->chunked_post) {
2004  /* non-chunked data is sent without any special encoding */
2005  return ffurl_write(s->hd, buf, size);
2006  }
2007 
2008  /* silently ignore zero-size data since chunk encoding that would
2009  * signal EOF */
2010  if (size > 0) {
2011  /* upload data using chunked encoding */
2012  snprintf(temp, sizeof(temp), "%x\r\n", size);
2013 
2014  if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 ||
2015  (ret = ffurl_write(s->hd, buf, size)) < 0 ||
2016  (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0)
2017  return ret;
2018  }
2019  return size;
2020 }
2021 
2022 static int http_shutdown(URLContext *h, int flags)
2023 {
2024  int ret = 0;
2025  char footer[] = "0\r\n\r\n";
2026  HTTPContext *s = h->priv_data;
2027 
2028  /* signal end of chunked encoding if used */
2029  if (((flags & AVIO_FLAG_WRITE) && s->chunked_post) ||
2030  ((flags & AVIO_FLAG_READ) && s->chunked_post && s->listen)) {
2031  ret = ffurl_write(s->hd, footer, sizeof(footer) - 1);
2032  ret = ret > 0 ? 0 : ret;
2033  /* flush the receive buffer when it is write only mode */
2034  if (!(flags & AVIO_FLAG_READ)) {
2035  char buf[1024];
2036  int read_ret;
2037  s->hd->flags |= AVIO_FLAG_NONBLOCK;
2038  read_ret = ffurl_read(s->hd, buf, sizeof(buf));
2039  s->hd->flags &= ~AVIO_FLAG_NONBLOCK;
2040  if (read_ret < 0 && read_ret != AVERROR(EAGAIN)) {
2041  av_log(h, AV_LOG_ERROR, "URL read error: %s\n", av_err2str(read_ret));
2042  ret = read_ret;
2043  }
2044  }
2045  s->end_chunked_post = 1;
2046  }
2047 
2048  return ret;
2049 }
2050 
2052 {
2053  int ret = 0;
2054  HTTPContext *s = h->priv_data;
2055 
2056 #if CONFIG_ZLIB
2057  inflateEnd(&s->inflate_stream);
2058  av_freep(&s->inflate_buffer);
2059 #endif /* CONFIG_ZLIB */
2060 
2061  if (s->hd && !s->end_chunked_post)
2062  /* Close the write direction by sending the end of chunked encoding. */
2063  ret = http_shutdown(h, h->flags);
2064 
2065  if (s->hd)
2066  ffurl_closep(&s->hd);
2067  av_dict_free(&s->chained_options);
2068  av_dict_free(&s->cookie_dict);
2069  av_dict_free(&s->redirect_cache);
2070  av_freep(&s->new_location);
2071  av_freep(&s->uri);
2072 
2073  av_log(h, AV_LOG_DEBUG, "Statistics: %d connection%s, %d request%s, %d retr%s, %d reconnection%s, %d redirect%s\n",
2074  s->nb_connections, s->nb_connections == 1 ? "" : "s",
2075  s->nb_requests, s->nb_requests == 1 ? "" : "s",
2076  s->nb_retries, s->nb_retries == 1 ? "y" : "ies",
2077  s->nb_reconnects, s->nb_reconnects == 1 ? "" : "s",
2078  s->nb_redirects, s->nb_redirects == 1 ? "" : "s");
2079 
2080  if (s->nb_requests > 0) {
2081  av_log(h, AV_LOG_DEBUG, "Latency: %.2f ms avg, %.2f ms max\n",
2082  1e-3 * s->sum_latency / s->nb_requests,
2083  1e-3 * s->max_latency);
2084  }
2085  return ret;
2086 }
2087 
2088 static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect)
2089 {
2090  HTTPContext *s = h->priv_data;
2091  URLContext *old_hd = NULL;
2092  uint64_t old_off = s->off;
2093  uint8_t old_buf[BUFFER_SIZE];
2094  int old_buf_size, ret;
2096  uint8_t discard[4096];
2097 
2098  if (whence == AVSEEK_SIZE)
2099  return s->filesize;
2100  else if ((s->filesize == UINT64_MAX && whence == SEEK_END))
2101  return AVERROR(ENOSYS);
2102 
2103  if (whence == SEEK_CUR)
2104  off += s->off;
2105  else if (whence == SEEK_END)
2106  off += s->filesize;
2107  else if (whence != SEEK_SET)
2108  return AVERROR(EINVAL);
2109  if (off < 0)
2110  return AVERROR(EINVAL);
2111  if (!force_reconnect && off == s->off)
2112  return s->off;
2113  s->off = off;
2114 
2115  if (s->off && h->is_streamed)
2116  return AVERROR(ENOSYS);
2117 
2118  /* do not try to make a new connection if seeking past the end of the file */
2119  if (s->end_off || s->filesize != UINT64_MAX) {
2120  uint64_t end_pos = s->end_off ? s->end_off : s->filesize;
2121  if (s->off >= end_pos)
2122  return s->off;
2123  }
2124 
2125  /* if the location changed (redirect), revert to the original uri */
2126  if (strcmp(s->uri, s->location)) {
2127  char *new_uri;
2128  new_uri = av_strdup(s->uri);
2129  if (!new_uri)
2130  return AVERROR(ENOMEM);
2131  av_free(s->location);
2132  s->location = new_uri;
2133  }
2134 
2135  /* we save the old context in case the seek fails */
2136  old_buf_size = s->buf_end - s->buf_ptr;
2137  memcpy(old_buf, s->buf_ptr, old_buf_size);
2138 
2139  /* try to reuse existing connection for small seeks */
2140  uint64_t remaining = s->range_end - old_off - old_buf_size;
2141  if (s->hd && !s->willclose && s->range_end && remaining <= ffurl_get_short_seek(h)) {
2142  /* drain remaining data left on the wire from previous request */
2143  av_log(h, AV_LOG_DEBUG, "Soft-seeking to offset %"PRIu64" by draining "
2144  "%"PRIu64" remaining byte(s)\n", s->off, remaining);
2145  while (remaining) {
2146  ret = ffurl_read(s->hd, discard, FFMIN(remaining, sizeof(discard)));
2147  if (ret < 0 || ret == AVERROR_EOF || (ret == 0 && remaining)) {
2148  /* connection broken or stuck, need to reopen */
2149  ffurl_closep(&s->hd);
2150  break;
2151  }
2152  remaining -= ret;
2153  }
2154  } else {
2155  /* can't soft seek; always open new connection */
2156  old_hd = s->hd;
2157  s->hd = NULL;
2158  }
2159 
2160  /* if it fails, continue on old connection */
2161  if ((ret = http_open_cnx(h, &options)) < 0) {
2163  memcpy(s->buffer, old_buf, old_buf_size);
2164  s->buf_ptr = s->buffer;
2165  s->buf_end = s->buffer + old_buf_size;
2166  s->hd = old_hd;
2167  s->off = old_off;
2168  return ret;
2169  }
2171  ffurl_close(old_hd);
2172  return off;
2173 }
2174 
2175 static int64_t http_seek(URLContext *h, int64_t off, int whence)
2176 {
2177  return http_seek_internal(h, off, whence, 0);
2178 }
2179 
2181 {
2182  HTTPContext *s = h->priv_data;
2183  return ffurl_get_file_handle(s->hd);
2184 }
2185 
2187 {
2188  HTTPContext *s = h->priv_data;
2189  if (s->short_seek_size >= 1)
2190  return s->short_seek_size;
2191  return ffurl_get_short_seek(s->hd);
2192 }
2193 
2194 #define HTTP_CLASS(flavor) \
2195 static const AVClass flavor ## _context_class = { \
2196  .class_name = # flavor, \
2197  .item_name = av_default_item_name, \
2198  .option = http_options, \
2199  .version = LIBAVUTIL_VERSION_INT, \
2200 }
2201 
2202 #if CONFIG_HTTP_PROTOCOL
2203 HTTP_CLASS(http);
2204 
2205 const URLProtocol ff_http_protocol = {
2206  .name = "http",
2207  .url_open2 = http_open,
2208  .url_accept = http_accept,
2209  .url_handshake = http_handshake,
2210  .url_read = http_read,
2211  .url_write = http_write,
2212  .url_seek = http_seek,
2213  .url_close = http_close,
2214  .url_get_file_handle = http_get_file_handle,
2215  .url_get_short_seek = http_get_short_seek,
2216  .url_shutdown = http_shutdown,
2217  .priv_data_size = sizeof(HTTPContext),
2218  .priv_data_class = &http_context_class,
2220  .default_whitelist = "http,https,tls,rtp,tcp,udp,crypto,httpproxy,data"
2221 };
2222 #endif /* CONFIG_HTTP_PROTOCOL */
2223 
2224 #if CONFIG_HTTPS_PROTOCOL
2225 HTTP_CLASS(https);
2226 
2228  .name = "https",
2229  .url_open2 = http_open,
2230  .url_read = http_read,
2231  .url_write = http_write,
2232  .url_seek = http_seek,
2233  .url_close = http_close,
2234  .url_get_file_handle = http_get_file_handle,
2235  .url_get_short_seek = http_get_short_seek,
2236  .url_shutdown = http_shutdown,
2237  .priv_data_size = sizeof(HTTPContext),
2238  .priv_data_class = &https_context_class,
2240  .default_whitelist = "http,https,tls,rtp,tcp,udp,crypto,httpproxy"
2241 };
2242 #endif /* CONFIG_HTTPS_PROTOCOL */
2243 
2244 #if CONFIG_HTTPPROXY_PROTOCOL
2245 static int http_proxy_close(URLContext *h)
2246 {
2247  HTTPContext *s = h->priv_data;
2248  if (s->hd)
2249  ffurl_closep(&s->hd);
2250  return 0;
2251 }
2252 
2253 static int http_proxy_open(URLContext *h, const char *uri, int flags)
2254 {
2255  HTTPContext *s = h->priv_data;
2256  char hostname[1024], hoststr[1024];
2257  char auth[1024], pathbuf[1024], *path;
2258  char lower_url[100];
2259  int port, ret = 0, auth_attempts = 0;
2260  HTTPAuthType cur_auth_type;
2261  char *authstr;
2262 
2263  if( s->seekable == 1 )
2264  h->is_streamed = 0;
2265  else
2266  h->is_streamed = 1;
2267 
2268  av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
2269  pathbuf, sizeof(pathbuf), uri);
2270  ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
2271  path = pathbuf;
2272  if (*path == '/')
2273  path++;
2274 
2275  ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port,
2276  NULL);
2277 redo:
2278  ret = ffurl_open_whitelist(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
2279  &h->interrupt_callback, NULL,
2280  h->protocol_whitelist, h->protocol_blacklist, h);
2281  if (ret < 0)
2282  return ret;
2283 
2284  authstr = ff_http_auth_create_response(&s->proxy_auth_state, auth,
2285  path, "CONNECT");
2286  snprintf(s->buffer, sizeof(s->buffer),
2287  "CONNECT %s HTTP/1.1\r\n"
2288  "Host: %s\r\n"
2289  "Connection: close\r\n"
2290  "%s%s"
2291  "\r\n",
2292  path,
2293  hoststr,
2294  authstr ? "Proxy-" : "", authstr ? authstr : "");
2295  av_freep(&authstr);
2296 
2297  if ((ret = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
2298  goto fail;
2299 
2300  s->buf_ptr = s->buffer;
2301  s->buf_end = s->buffer;
2302  s->line_count = 0;
2303  s->filesize = UINT64_MAX;
2304  cur_auth_type = s->proxy_auth_state.auth_type;
2305 
2306  /* Note: This uses buffering, potentially reading more than the
2307  * HTTP header. If tunneling a protocol where the server starts
2308  * the conversation, we might buffer part of that here, too.
2309  * Reading that requires using the proper ffurl_read() function
2310  * on this URLContext, not using the fd directly (as the tls
2311  * protocol does). This shouldn't be an issue for tls though,
2312  * since the client starts the conversation there, so there
2313  * is no extra data that we might buffer up here.
2314  */
2315  ret = http_read_header(h);
2316  if (ret < 0)
2317  goto fail;
2318 
2319  auth_attempts++;
2320  if (s->http_code == 407 &&
2321  (cur_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
2322  s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && auth_attempts < 2) {
2323  ffurl_closep(&s->hd);
2324  goto redo;
2325  }
2326 
2327  if (s->http_code < 400)
2328  return 0;
2329  ret = ff_http_averror(s->http_code, AVERROR(EIO));
2330 
2331 fail:
2332  http_proxy_close(h);
2333  return ret;
2334 }
2335 
2336 static int http_proxy_write(URLContext *h, const uint8_t *buf, int size)
2337 {
2338  HTTPContext *s = h->priv_data;
2339  return ffurl_write(s->hd, buf, size);
2340 }
2341 
2343  .name = "httpproxy",
2344  .url_open = http_proxy_open,
2345  .url_read = http_buf_read,
2346  .url_write = http_proxy_write,
2347  .url_close = http_proxy_close,
2348  .url_get_file_handle = http_get_file_handle,
2349  .priv_data_size = sizeof(HTTPContext),
2351 };
2352 #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:62
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:616
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:967
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:1499
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:737
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:1979
http_seek_internal
static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect)
Definition: http.c:2088
parse_cache_control
static void parse_cache_control(HTTPContext *s, const char *p)
Definition: http.c:1145
HTTPContext::new_location
char * new_location
Definition: http.c:142
READ_HEADERS
@ READ_HEADERS
Definition: http.c:67
AVOption
AVOption.
Definition: opt.h:429
AVERROR_HTTP_SERVER_ERROR
#define AVERROR_HTTP_SERVER_ERROR
Definition: error.h:84
AVSEEK_SIZE
#define AVSEEK_SIZE
Passing this as the "whence" parameter to a seek function causes it to return the filesize without se...
Definition: avio.h:468
data
const char data[16]
Definition: mxf.c:149
WRITE_REPLY_HEADERS
@ WRITE_REPLY_HEADERS
Definition: http.c:68
NEEDS_ESCAPE
#define NEEDS_ESCAPE(ch)
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
freeenv_utf8
static void freeenv_utf8(char *var)
Definition: getenv_utf8.h:72
http_get_line
static int http_get_line(HTTPContext *s, char *line, int line_size)
Definition: http.c:864
ffurl_close
int ffurl_close(URLContext *h)
Definition: avio.c:612
AVDictionary
Definition: dict.c:32
HTTPContext::end_header
int end_header
Definition: http.c:101
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
HTTPContext::chained_options
AVDictionary * chained_options
Definition: http.c:124
parse_location
static int parse_location(HTTPContext *s, const char *p)
Definition: http.c:903
http_read_stream
static int http_read_stream(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1821
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:1342
HTTPContext::http_version
char * http_version
Definition: http.c:89
AV_OPT_TYPE_BINARY
@ AV_OPT_TYPE_BINARY
Underlying C type is a uint8_t* that is either NULL or points to an array allocated with the av_mallo...
Definition: opt.h:286
av_bprint_init_for_buffer
void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
Init a print buffer using a pre-existing buffer.
Definition: bprint.c:85
macros.h
fail
#define fail()
Definition: checkasm.h:220
ffurl_get_short_seek
int ffurl_get_short_seek(void *urlcontext)
Return the current short seek threshold value for this URL.
Definition: avio.c:839
check_http_code
static int check_http_code(URLContext *h, int http_code, const char *end)
Definition: http.c:888
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:1113
has_header
static int has_header(const char *str, const char *header)
Definition: http.c:1426
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:825
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:363
s
#define s(width, name)
Definition: cbs_vp9.c:198
HTTPContext::buf_end
unsigned char * buf_end
Definition: http.c:75
HTTPContext::cookies
char * cookies
holds newline ( ) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
Definition: http.c:108
AVDictionaryEntry::key
char * key
Definition: dict.h:91
BUFFER_SIZE
#define BUFFER_SIZE
Definition: http.c:58
av_strtok
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition: avstring.c:179
ff_url_join
int ff_url_join(char *str, int size, const char *proto, const char *authorization, const char *hostname, int port, const char *fmt,...)
Definition: url.c:40
AV_OPT_TYPE_INT64
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
Definition: opt.h:263
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
AVIO_FLAG_WRITE
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:618
HTTPContext::off
uint64_t off
Definition: http.c:81
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
HTTPContext::post_datalen
int post_datalen
Definition: http.c:105
HTTPContext::reconnect_on_network_error
int reconnect_on_network_error
Definition: http.c:130
av_stristart
int av_stristart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str independent of case.
Definition: avstring.c:47
key
const char * key
Definition: hwcontext_opencl.c:189
D
#define D
Definition: http.c: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:1051
HTTPContext::end_chunked_post
int end_chunked_post
Definition: http.c:99
ff_http_match_no_proxy
int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
Definition: network.c:549
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
ff_http_auth_handle_header
void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, const char *value)
Definition: httpauth.c:90
parse_content_encoding
static int parse_content_encoding(URLContext *h, const char *p)
Definition: http.c:933
handle_http_errors
static void handle_http_errors(URLContext *h, int error)
Definition: http.c:695
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:265
internal.h
opts
static AVDictionary * opts
Definition: movenc.c:51
http_read_stream_all
static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1901
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:2186
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:290
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:44
http_buf_read
static int http_buf_read(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1706
http_shutdown
static int http_shutdown(URLContext *h, int flags)
Definition: http.c:2022
process_line
static int process_line(URLContext *h, char *line, int line_count, int *parsed_http_code)
Definition: http.c:1172
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:916
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:592
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:989
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:1136
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:1996
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:1913
AV_OPT_FLAG_READONLY
#define AV_OPT_FLAG_READONLY
The option may not be set through the AVOptions API, only read.
Definition: opt.h:368
ffurl_alloc
int ffurl_alloc(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb)
Create a URLContext for accessing to the resource indicated by url, but do not initiate the connectio...
Definition: avio.c:350
HTTPContext::is_mediagateway
int is_mediagateway
Definition: http.c:107
HTTPContext::reconnect_at_eof
int reconnect_at_eof
Definition: http.c:129
httpauth.h
http_should_reconnect
static int http_should_reconnect(HTTPContext *s, int err)
Definition: http.c:327
bprint.h
http_handshake
static int http_handshake(URLContext *c)
Definition: http.c:701
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:769
HTTPContext::nb_retries
int nb_retries
Definition: http.c:155
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:1523
ff_network_sleep_interruptible
int ff_network_sleep_interruptible(int64_t timeout, AVIOInterruptCB *int_cb)
Waits for up to 'timeout' microseconds.
Definition: network.c:95
parse_set_cookie
static int parse_set_cookie(const char *set_cookie, AVDictionary **dict)
Definition: http.c:1014
http_seek
static int64_t http_seek(URLContext *h, int64_t off, int whence)
Definition: http.c:2175
HTTPContext::end_off
uint64_t end_off
Definition: http.c:81
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
HTTPContext::mime_type
char * mime_type
Definition: http.c:88
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:2051
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:589
HTTPContext::handshake_step
HandshakeState handshake_step
Definition: http.c:138
ff_https_protocol
const URLProtocol ff_https_protocol
tag
uint32_t tag
Definition: movenc.c:2032
ret
ret
Definition: filter_design.txt:187
ff_http_get_new_location
const char * ff_http_get_new_location(URLContext *h)
Definition: http.c:610
HandshakeState
HandshakeState
Definition: http.c:65
av_malloc
void * av_malloc(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:98
URLContext::interrupt_callback
AVIOInterruptCB interrupt_callback
Definition: url.h:44
pos
unsigned int pos
Definition: spdifenc.c:414
avformat.h
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
network.h
HTTPContext::chunked_post
int chunked_post
Definition: http.c:97
HTTPContext::cookie_dict
AVDictionary * cookie_dict
Definition: http.c:110
AV_DICT_MATCH_CASE
#define AV_DICT_MATCH_CASE
Only get an entry with exact-case key match.
Definition: dict.h:74
U
#define U(x)
Definition: vpx_arith.h:37
HTTPContext::reconnect_delay_max
int reconnect_delay_max
Definition: http.c:132
av_small_strptime
char * av_small_strptime(const char *p, const char *fmt, struct tm *dt)
Simplified version of strptime.
Definition: parseutils.c:494
HTTPContext::content_type
char * content_type
Definition: http.c:92
MAX_URL_SIZE
#define MAX_URL_SIZE
Definition: internal.h:30
HTTPContext::location
char * location
Definition: http.c:83
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:259
http_read_header
static int http_read_header(URLContext *h)
Definition: http.c:1434
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:2194
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:2180
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
https
s EdgeDetect Foobar g libavfilter vf_edgedetect c libavfilter vf_foobar c edit libavfilter and add an entry for foobar following the pattern of the other filters edit libavfilter allfilters and add an entry for foobar following the pattern of the other filters configure make j< whatever > ffmpeg ffmpeg i you should get a foobar png with Lena edge detected That s your new playground is ready Some little details about what s going which in turn will define variables for the build system and the and we are assuming vf_foobar is as well We are also assuming vf_foobar is not an edge detector so you can update the boilerplate with your credits Doxy Next chunk is the Doxygen about the file See https
Definition: writing_filters.txt:66
av_gettime
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:39
av_dict_set_int
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
Convenience wrapper for av_dict_set() that converts the value to a string and stores it.
Definition: dict.c:177
HTTPAuthType
HTTPAuthType
Authentication types, ordered from weakest to strongest.
Definition: httpauth.h:28
AVIO_FLAG_READ
#define AVIO_FLAG_READ
read-only
Definition: avio.h:617
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:272
HTTPContext::reply_code
int reply_code
Definition: http.c:136
FINISH
@ FINISH
Definition: http.c:69
mem.h
HTTPContext::auth_state
HTTPAuthState auth_state
Definition: http.c:84
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVDictionaryEntry
Definition: dict.h:90
headers
FFmpeg currently uses a custom build this text attempts to document some of its obscure features and options Makefile the full command issued by make and its output will be shown on the screen DBG Preprocess x86 external assembler files to a dbg asm file in the object which then gets compiled Helps in developing those assembler files DESTDIR Destination directory for the install useful to prepare packages or install FFmpeg in cross environments GEN Set to ‘1’ to generate the missing or mismatched references Makefile builds all the libraries and the executables fate Run the fate test note that you must have installed it fate list List all fate regression test targets fate list failing List the fate tests that failed the last time they were executed fate clear reports Remove the test reports from previous test libraries and programs examples Build all examples located in doc examples checkheaders Check headers dependencies alltools Build all tools in tools directory config Reconfigure the project with the current configuration tools target_dec_< decoder > _fuzzer Build fuzzer to fuzz the specified decoder tools target_bsf_< filter > _fuzzer Build fuzzer to fuzz the specified bitstream filter Useful standard make this is useful to reduce unneeded rebuilding when changing headers
Definition: build_system.txt:64
ffurl_handshake
int ffurl_handshake(URLContext *c)
Perform one step of the protocol handshake to accept a new client.
Definition: avio.c:284
ff_make_absolute_url
int ff_make_absolute_url(char *buf, int size, const char *base, const char *rel)
Convert a relative url into an absolute url, given a base url.
Definition: url.c:321
AV_OPT_FLAG_EXPORT
#define AV_OPT_FLAG_EXPORT
The option is intended for exporting values to the caller.
Definition: opt.h:363
MAX_CACHED_REDIRECTS
#define MAX_CACHED_REDIRECTS
Definition: http.c:60
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:327
AVIO_FLAG_NONBLOCK
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:636
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_dict_set
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:86
av_dict_copy
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:247
http_getc
static int http_getc(HTTPContext *s)
Definition: http.c:847
http_accept
static int http_accept(URLContext *s, URLContext **c)
Definition: http.c:823
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:1980
AVDictionaryEntry::value
char * value
Definition: dict.h:92
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:276
av_strndup
char * av_strndup(const char *s, size_t len)
Duplicate a substring of a string.
Definition: mem.c:284
http.h
HTTPContext::willclose
int willclose
Definition: http.c:95
av_bprint_append_data
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:148
HTTPContext::redirect_cache
AVDictionary * redirect_cache
Definition: http.c:143
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:299
snprintf
#define snprintf
Definition: snprintf.h:34
HTTPContext::user_agent
char * user_agent
Definition: http.c:90
store_icy
static int store_icy(URLContext *h, int size)
Definition: http.c:1941
av_dict_iterate
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition: dict.c:42
ffurl_get_file_handle
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition: avio.c:815
src
#define src
Definition: vp8dsp.c:248
line
The official guide to swscale for confused that consecutive non overlapping rectangles of slice_bottom special converter These generally are unscaled converters of common like for each output line the vertical scaler pulls lines from a ring buffer When the ring buffer does not contain the wanted line
Definition: swscale.txt:40
read
static uint32_t BS_FUNC() read(BSCTX *bc, unsigned int n)
Return n bits from the buffer, n has to be in the 0-32 range.
Definition: bitstream_template.h:239
AV_DICT_DONT_STRDUP_KEY
#define AV_DICT_DONT_STRDUP_KEY
Take ownership of a key that's been allocated with av_malloc() or another memory allocation function.
Definition: dict.h:77
HTTPContext::post_data
uint8_t * post_data
Definition: http.c:104
HTTPContext::reconnect_on_http_error
char * reconnect_on_http_error
Definition: http.c:133
HTTPContext::short_seek_size
int short_seek_size
Definition: http.c:140
ffurl_read
static int ffurl_read(URLContext *h, uint8_t *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition: url.h:181
HTTPContext::is_multi_client
int is_multi_client
Definition: http.c:137