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