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