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