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