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