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