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