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