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