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