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