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