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