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