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