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,
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 */
262 static int http_open_cnx(URLContext *h, AVDictionary **options)
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;
340  AVDictionary *options = NULL;
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);
387  av_dict_free(&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 
482 static void handle_http_errors(URLContext *h, int error)
483 {
484  av_assert0(error < 0);
485  http_write_reply(h, error);
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,
543  )) < 0)
544  goto fail;
546  if (s->listen == HTTP_SINGLE) { /* single client */
547  s->reply_code = 200;
548  while ((ret = http_handshake(h)) > 0);
549  }
550 fail:
552  return ret;
553 }
554 
555 static int http_open(URLContext *h, const char *uri, int flags,
556  AVDictionary **options)
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  goto bail_out;
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  }
590  ret = http_open_cnx(h, options);
591 bail_out:
592  if (ret < 0)
594  return ret;
595 }
596 
598 {
599  int ret;
600  HTTPContext *sc = s->priv_data;
601  HTTPContext *cc;
602  URLContext *sl = sc->hd;
603  URLContext *cl = NULL;
604 
605  av_assert0(sc->listen);
606  if ((ret = ffurl_alloc(c, s->filename, s->flags, &sl->interrupt_callback)) < 0)
607  goto fail;
608  cc = (*c)->priv_data;
609  if ((ret = ffurl_accept(sl, &cl)) < 0)
610  goto fail;
611  cc->hd = cl;
612  cc->is_multi_client = 1;
613  return 0;
614 fail:
615  if (c) {
616  ffurl_closep(c);
617  }
618  return ret;
619 }
620 
621 static int http_getc(HTTPContext *s)
622 {
623  int len;
624  if (s->buf_ptr >= s->buf_end) {
625  len = ffurl_read(s->hd, s->buffer, BUFFER_SIZE);
626  if (len < 0) {
627  return len;
628  } else if (len == 0) {
629  return AVERROR_EOF;
630  } else {
631  s->buf_ptr = s->buffer;
632  s->buf_end = s->buffer + len;
633  }
634  }
635  return *s->buf_ptr++;
636 }
637 
638 static int http_get_line(HTTPContext *s, char *line, int line_size)
639 {
640  int ch;
641  char *q;
642 
643  q = line;
644  for (;;) {
645  ch = http_getc(s);
646  if (ch < 0)
647  return ch;
648  if (ch == '\n') {
649  /* process line */
650  if (q > line && q[-1] == '\r')
651  q--;
652  *q = '\0';
653 
654  return 0;
655  } else {
656  if ((q - line) < line_size - 1)
657  *q++ = ch;
658  }
659  }
660 }
661 
662 static int check_http_code(URLContext *h, int http_code, const char *end)
663 {
664  HTTPContext *s = h->priv_data;
665  /* error codes are 4xx and 5xx, but regard 401 as a success, so we
666  * don't abort until all headers have been parsed. */
667  if (http_code >= 400 && http_code < 600 &&
668  (http_code != 401 || s->auth_state.auth_type != HTTP_AUTH_NONE) &&
669  (http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) {
670  end += strspn(end, SPACE_CHARS);
671  av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n", http_code, end);
672  return ff_http_averror(http_code, AVERROR(EIO));
673  }
674  return 0;
675 }
676 
677 static int parse_location(HTTPContext *s, const char *p)
678 {
679  char redirected_location[MAX_URL_SIZE], *new_loc;
680  ff_make_absolute_url(redirected_location, sizeof(redirected_location),
681  s->location, p);
682  new_loc = av_strdup(redirected_location);
683  if (!new_loc)
684  return AVERROR(ENOMEM);
685  av_free(s->location);
686  s->location = new_loc;
687  return 0;
688 }
689 
690 /* "bytes $from-$to/$document_size" */
691 static void parse_content_range(URLContext *h, const char *p)
692 {
693  HTTPContext *s = h->priv_data;
694  const char *slash;
695 
696  if (!strncmp(p, "bytes ", 6)) {
697  p += 6;
698  s->off = strtoull(p, NULL, 10);
699  if ((slash = strchr(p, '/')) && strlen(slash) > 0)
700  s->filesize = strtoull(slash + 1, NULL, 10);
701  }
702  if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647))
703  h->is_streamed = 0; /* we _can_ in fact seek */
704 }
705 
706 static int parse_content_encoding(URLContext *h, const char *p)
707 {
708  if (!av_strncasecmp(p, "gzip", 4) ||
709  !av_strncasecmp(p, "deflate", 7)) {
710 #if CONFIG_ZLIB
711  HTTPContext *s = h->priv_data;
712 
713  s->compressed = 1;
714  inflateEnd(&s->inflate_stream);
715  if (inflateInit2(&s->inflate_stream, 32 + 15) != Z_OK) {
716  av_log(h, AV_LOG_WARNING, "Error during zlib initialisation: %s\n",
717  s->inflate_stream.msg);
718  return AVERROR(ENOSYS);
719  }
720  if (zlibCompileFlags() & (1 << 17)) {
722  "Your zlib was compiled without gzip support.\n");
723  return AVERROR(ENOSYS);
724  }
725 #else
727  "Compressed (%s) content, need zlib with gzip support\n", p);
728  return AVERROR(ENOSYS);
729 #endif /* CONFIG_ZLIB */
730  } else if (!av_strncasecmp(p, "identity", 8)) {
731  // The normal, no-encoding case (although servers shouldn't include
732  // the header at all if this is the case).
733  } else {
734  av_log(h, AV_LOG_WARNING, "Unknown content coding: %s\n", p);
735  }
736  return 0;
737 }
738 
739 // Concat all Icy- header lines
740 static int parse_icy(HTTPContext *s, const char *tag, const char *p)
741 {
742  int len = 4 + strlen(p) + strlen(tag);
743  int is_first = !s->icy_metadata_headers;
744  int ret;
745 
746  av_dict_set(&s->metadata, tag, p, 0);
747 
748  if (s->icy_metadata_headers)
749  len += strlen(s->icy_metadata_headers);
750 
751  if ((ret = av_reallocp(&s->icy_metadata_headers, len)) < 0)
752  return ret;
753 
754  if (is_first)
755  *s->icy_metadata_headers = '\0';
756 
757  av_strlcatf(s->icy_metadata_headers, len, "%s: %s\n", tag, p);
758 
759  return 0;
760 }
761 
762 static int parse_set_cookie_expiry_time(const char *exp_str, struct tm *buf)
763 {
764  char exp_buf[MAX_EXPIRY];
765  int i, j, exp_buf_len = MAX_EXPIRY-1;
766  char *expiry;
767 
768  // strip off any punctuation or whitespace
769  for (i = 0, j = 0; exp_str[i] != '\0' && j < exp_buf_len; i++) {
770  if ((exp_str[i] >= '0' && exp_str[i] <= '9') ||
771  (exp_str[i] >= 'A' && exp_str[i] <= 'Z') ||
772  (exp_str[i] >= 'a' && exp_str[i] <= 'z')) {
773  exp_buf[j] = exp_str[i];
774  j++;
775  }
776  }
777  exp_buf[j] = '\0';
778  expiry = exp_buf;
779 
780  // move the string beyond the day of week
781  while ((*expiry < '0' || *expiry > '9') && *expiry != '\0')
782  expiry++;
783 
784  return av_small_strptime(expiry, "%d%b%Y%H%M%S", buf) ? 0 : AVERROR(EINVAL);
785 }
786 
787 static int parse_set_cookie(const char *set_cookie, AVDictionary **dict)
788 {
789  char *param, *next_param, *cstr, *back;
790  char *saveptr = NULL;
791 
792  if (!set_cookie[0])
793  return 0;
794 
795  if (!(cstr = av_strdup(set_cookie)))
796  return AVERROR(EINVAL);
797 
798  // strip any trailing whitespace
799  back = &cstr[strlen(cstr)-1];
800  while (strchr(WHITESPACES, *back)) {
801  *back='\0';
802  if (back == cstr)
803  break;
804  back--;
805  }
806 
807  next_param = cstr;
808  while ((param = av_strtok(next_param, ";", &saveptr))) {
809  char *name, *value;
810  next_param = NULL;
811  param += strspn(param, WHITESPACES);
812  if ((name = av_strtok(param, "=", &value))) {
813  if (av_dict_set(dict, name, value, 0) < 0) {
814  av_free(cstr);
815  return -1;
816  }
817  }
818  }
819 
820  av_free(cstr);
821  return 0;
822 }
823 
824 static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
825 {
826  AVDictionary *new_params = NULL;
827  AVDictionaryEntry *e, *cookie_entry;
828  char *eql, *name;
829 
830  // ensure the cookie is parsable
831  if (parse_set_cookie(p, &new_params))
832  return -1;
833 
834  // if there is no cookie value there is nothing to parse
835  cookie_entry = av_dict_get(new_params, "", NULL, AV_DICT_IGNORE_SUFFIX);
836  if (!cookie_entry || !cookie_entry->value) {
837  av_dict_free(&new_params);
838  return -1;
839  }
840 
841  // ensure the cookie is not expired or older than an existing value
842  if ((e = av_dict_get(new_params, "expires", NULL, 0)) && e->value) {
843  struct tm new_tm = {0};
844  if (!parse_set_cookie_expiry_time(e->value, &new_tm)) {
845  AVDictionaryEntry *e2;
846 
847  // if the cookie has already expired ignore it
848  if (av_timegm(&new_tm) < av_gettime() / 1000000) {
849  av_dict_free(&new_params);
850  return 0;
851  }
852 
853  // only replace an older cookie with the same name
854  e2 = av_dict_get(*cookies, cookie_entry->key, NULL, 0);
855  if (e2 && e2->value) {
856  AVDictionary *old_params = NULL;
857  if (!parse_set_cookie(p, &old_params)) {
858  e2 = av_dict_get(old_params, "expires", NULL, 0);
859  if (e2 && e2->value) {
860  struct tm old_tm = {0};
861  if (!parse_set_cookie_expiry_time(e->value, &old_tm)) {
862  if (av_timegm(&new_tm) < av_timegm(&old_tm)) {
863  av_dict_free(&new_params);
864  av_dict_free(&old_params);
865  return -1;
866  }
867  }
868  }
869  }
870  av_dict_free(&old_params);
871  }
872  }
873  }
874  av_dict_free(&new_params);
875 
876  // duplicate the cookie name (dict will dupe the value)
877  if (!(eql = strchr(p, '='))) return AVERROR(EINVAL);
878  if (!(name = av_strndup(p, eql - p))) return AVERROR(ENOMEM);
879 
880  // add the cookie to the dictionary
881  av_dict_set(cookies, name, eql, AV_DICT_DONT_STRDUP_KEY);
882 
883  return 0;
884 }
885 
886 static int cookie_string(AVDictionary *dict, char **cookies)
887 {
888  AVDictionaryEntry *e = NULL;
889  int len = 1;
890 
891  // determine how much memory is needed for the cookies string
892  while (e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))
893  len += strlen(e->key) + strlen(e->value) + 1;
894 
895  // reallocate the cookies
896  e = NULL;
897  if (*cookies) av_free(*cookies);
898  *cookies = av_malloc(len);
899  if (!*cookies) return AVERROR(ENOMEM);
900  *cookies[0] = '\0';
901 
902  // write out the cookies
903  while (e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))
904  av_strlcatf(*cookies, len, "%s%s\n", e->key, e->value);
905 
906  return 0;
907 }
908 
909 static int process_line(URLContext *h, char *line, int line_count,
910  int *new_location)
911 {
912  HTTPContext *s = h->priv_data;
913  const char *auto_method = h->flags & AVIO_FLAG_READ ? "POST" : "GET";
914  char *tag, *p, *end, *method, *resource, *version;
915  int ret;
916 
917  /* end of header */
918  if (line[0] == '\0') {
919  s->end_header = 1;
920  return 0;
921  }
922 
923  p = line;
924  if (line_count == 0) {
925  if (s->is_connected_server) {
926  // HTTP method
927  method = p;
928  while (*p && !av_isspace(*p))
929  p++;
930  *(p++) = '\0';
931  av_log(h, AV_LOG_TRACE, "Received method: %s\n", method);
932  if (s->method) {
933  if (av_strcasecmp(s->method, method)) {
934  av_log(h, AV_LOG_ERROR, "Received and expected HTTP method do not match. (%s expected, %s received)\n",
935  s->method, method);
936  return ff_http_averror(400, AVERROR(EIO));
937  }
938  } else {
939  // use autodetected HTTP method to expect
940  av_log(h, AV_LOG_TRACE, "Autodetected %s HTTP method\n", auto_method);
941  if (av_strcasecmp(auto_method, method)) {
942  av_log(h, AV_LOG_ERROR, "Received and autodetected HTTP method did not match "
943  "(%s autodetected %s received)\n", auto_method, method);
944  return ff_http_averror(400, AVERROR(EIO));
945  }
946  if (!(s->method = av_strdup(method)))
947  return AVERROR(ENOMEM);
948  }
949 
950  // HTTP resource
951  while (av_isspace(*p))
952  p++;
953  resource = p;
954  while (*p && !av_isspace(*p))
955  p++;
956  *(p++) = '\0';
957  av_log(h, AV_LOG_TRACE, "Requested resource: %s\n", resource);
958  if (!(s->resource = av_strdup(resource)))
959  return AVERROR(ENOMEM);
960 
961  // HTTP version
962  while (av_isspace(*p))
963  p++;
964  version = p;
965  while (*p && !av_isspace(*p))
966  p++;
967  *p = '\0';
968  if (av_strncasecmp(version, "HTTP/", 5)) {
969  av_log(h, AV_LOG_ERROR, "Malformed HTTP version string.\n");
970  return ff_http_averror(400, AVERROR(EIO));
971  }
972  av_log(h, AV_LOG_TRACE, "HTTP version string: %s\n", version);
973  } else {
974  if (av_strncasecmp(p, "HTTP/1.0", 8) == 0)
975  s->willclose = 1;
976  while (*p != '/' && *p != '\0')
977  p++;
978  while (*p == '/')
979  p++;
980  av_freep(&s->http_version);
981  s->http_version = av_strndup(p, 3);
982  while (!av_isspace(*p) && *p != '\0')
983  p++;
984  while (av_isspace(*p))
985  p++;
986  s->http_code = strtol(p, &end, 10);
987 
988  av_log(h, AV_LOG_TRACE, "http_code=%d\n", s->http_code);
989 
990  if ((ret = check_http_code(h, s->http_code, end)) < 0)
991  return ret;
992  }
993  } else {
994  while (*p != '\0' && *p != ':')
995  p++;
996  if (*p != ':')
997  return 1;
998 
999  *p = '\0';
1000  tag = line;
1001  p++;
1002  while (av_isspace(*p))
1003  p++;
1004  if (!av_strcasecmp(tag, "Location")) {
1005  if ((ret = parse_location(s, p)) < 0)
1006  return ret;
1007  *new_location = 1;
1008  } else if (!av_strcasecmp(tag, "Content-Length") &&
1009  s->filesize == UINT64_MAX) {
1010  s->filesize = strtoull(p, NULL, 10);
1011  } else if (!av_strcasecmp(tag, "Content-Range")) {
1012  parse_content_range(h, p);
1013  } else if (!av_strcasecmp(tag, "Accept-Ranges") &&
1014  !strncmp(p, "bytes", 5) &&
1015  s->seekable == -1) {
1016  h->is_streamed = 0;
1017  } else if (!av_strcasecmp(tag, "Transfer-Encoding") &&
1018  !av_strncasecmp(p, "chunked", 7)) {
1019  s->filesize = UINT64_MAX;
1020  s->chunksize = 0;
1021  } else if (!av_strcasecmp(tag, "WWW-Authenticate")) {
1023  } else if (!av_strcasecmp(tag, "Authentication-Info")) {
1025  } else if (!av_strcasecmp(tag, "Proxy-Authenticate")) {
1027  } else if (!av_strcasecmp(tag, "Connection")) {
1028  if (!strcmp(p, "close"))
1029  s->willclose = 1;
1030  } else if (!av_strcasecmp(tag, "Server")) {
1031  if (!av_strcasecmp(p, "AkamaiGHost")) {
1032  s->is_akamai = 1;
1033  } else if (!av_strncasecmp(p, "MediaGateway", 12)) {
1034  s->is_mediagateway = 1;
1035  }
1036  } else if (!av_strcasecmp(tag, "Content-Type")) {
1037  av_free(s->mime_type);
1038  s->mime_type = av_strdup(p);
1039  } else if (!av_strcasecmp(tag, "Set-Cookie")) {
1040  if (parse_cookie(s, p, &s->cookie_dict))
1041  av_log(h, AV_LOG_WARNING, "Unable to parse '%s'\n", p);
1042  } else if (!av_strcasecmp(tag, "Icy-MetaInt")) {
1043  s->icy_metaint = strtoull(p, NULL, 10);
1044  } else if (!av_strncasecmp(tag, "Icy-", 4)) {
1045  if ((ret = parse_icy(s, tag, p)) < 0)
1046  return ret;
1047  } else if (!av_strcasecmp(tag, "Content-Encoding")) {
1048  if ((ret = parse_content_encoding(h, p)) < 0)
1049  return ret;
1050  }
1051  }
1052  return 1;
1053 }
1054 
1055 /**
1056  * Create a string containing cookie values for use as a HTTP cookie header
1057  * field value for a particular path and domain from the cookie values stored in
1058  * the HTTP protocol context. The cookie string is stored in *cookies, and may
1059  * be NULL if there are no valid cookies.
1060  *
1061  * @return a negative value if an error condition occurred, 0 otherwise
1062  */
1063 static int get_cookies(HTTPContext *s, char **cookies, const char *path,
1064  const char *domain)
1065 {
1066  // cookie strings will look like Set-Cookie header field values. Multiple
1067  // Set-Cookie fields will result in multiple values delimited by a newline
1068  int ret = 0;
1069  char *cookie, *set_cookies, *next;
1070  char *saveptr = NULL;
1071 
1072  // destroy any cookies in the dictionary.
1074 
1075  if (!s->cookies)
1076  return 0;
1077 
1078  next = set_cookies = av_strdup(s->cookies);
1079  if (!next)
1080  return AVERROR(ENOMEM);
1081 
1082  *cookies = NULL;
1083  while ((cookie = av_strtok(next, "\n", &saveptr)) && !ret) {
1084  AVDictionary *cookie_params = NULL;
1085  AVDictionaryEntry *cookie_entry, *e;
1086 
1087  next = NULL;
1088  // store the cookie in a dict in case it is updated in the response
1089  if (parse_cookie(s, cookie, &s->cookie_dict))
1090  av_log(s, AV_LOG_WARNING, "Unable to parse '%s'\n", cookie);
1091 
1092  // continue on to the next cookie if this one cannot be parsed
1093  if (parse_set_cookie(cookie, &cookie_params))
1094  goto skip_cookie;
1095 
1096  // if the cookie has no value, skip it
1097  cookie_entry = av_dict_get(cookie_params, "", NULL, AV_DICT_IGNORE_SUFFIX);
1098  if (!cookie_entry || !cookie_entry->value)
1099  goto skip_cookie;
1100 
1101  // if the cookie has expired, don't add it
1102  if ((e = av_dict_get(cookie_params, "expires", NULL, 0)) && e->value) {
1103  struct tm tm_buf = {0};
1104  if (!parse_set_cookie_expiry_time(e->value, &tm_buf)) {
1105  if (av_timegm(&tm_buf) < av_gettime() / 1000000)
1106  goto skip_cookie;
1107  }
1108  }
1109 
1110  // if no domain in the cookie assume it appied to this request
1111  if ((e = av_dict_get(cookie_params, "domain", NULL, 0)) && e->value) {
1112  // find the offset comparison is on the min domain (b.com, not a.b.com)
1113  int domain_offset = strlen(domain) - strlen(e->value);
1114  if (domain_offset < 0)
1115  goto skip_cookie;
1116 
1117  // match the cookie domain
1118  if (av_strcasecmp(&domain[domain_offset], e->value))
1119  goto skip_cookie;
1120  }
1121 
1122  // ensure this cookie matches the path
1123  e = av_dict_get(cookie_params, "path", NULL, 0);
1124  if (!e || av_strncasecmp(path, e->value, strlen(e->value)))
1125  goto skip_cookie;
1126 
1127  // cookie parameters match, so copy the value
1128  if (!*cookies) {
1129  *cookies = av_asprintf("%s=%s", cookie_entry->key, cookie_entry->value);
1130  } else {
1131  char *tmp = *cookies;
1132  *cookies = av_asprintf("%s; %s=%s", tmp, cookie_entry->key, cookie_entry->value);
1133  av_free(tmp);
1134  }
1135  if (!*cookies)
1136  ret = AVERROR(ENOMEM);
1137 
1138  skip_cookie:
1139  av_dict_free(&cookie_params);
1140  }
1141 
1142  av_free(set_cookies);
1143 
1144  return ret;
1145 }
1146 
1147 static inline int has_header(const char *str, const char *header)
1148 {
1149  /* header + 2 to skip over CRLF prefix. (make sure you have one!) */
1150  if (!str)
1151  return 0;
1152  return av_stristart(str, header + 2, NULL) || av_stristr(str, header);
1153 }
1154 
1155 static int http_read_header(URLContext *h, int *new_location)
1156 {
1157  HTTPContext *s = h->priv_data;
1158  char line[MAX_URL_SIZE];
1159  int err = 0;
1160 
1161  s->chunksize = UINT64_MAX;
1162 
1163  for (;;) {
1164  if ((err = http_get_line(s, line, sizeof(line))) < 0)
1165  return err;
1166 
1167  av_log(h, AV_LOG_TRACE, "header='%s'\n", line);
1168 
1169  err = process_line(h, line, s->line_count, new_location);
1170  if (err < 0)
1171  return err;
1172  if (err == 0)
1173  break;
1174  s->line_count++;
1175  }
1176 
1177  if (s->seekable == -1 && s->is_mediagateway && s->filesize == 2000000000)
1178  h->is_streamed = 1; /* we can in fact _not_ seek */
1179 
1180  // add any new cookies into the existing cookie string
1183 
1184  return err;
1185 }
1186 
1187 /**
1188  * Escape unsafe characters in path in order to pass them safely to the HTTP
1189  * request. Insipred by the algorithm in GNU wget:
1190  * - escape "%" characters not followed by two hex digits
1191  * - escape all "unsafe" characters except which are also "reserved"
1192  * - pass through everything else
1193  */
1194 static void bprint_escaped_path(AVBPrint *bp, const char *path)
1195 {
1196 #define NEEDS_ESCAPE(ch) \
1197  ((ch) <= ' ' || (ch) >= '\x7f' || \
1198  (ch) == '"' || (ch) == '%' || (ch) == '<' || (ch) == '>' || (ch) == '\\' || \
1199  (ch) == '^' || (ch) == '`' || (ch) == '{' || (ch) == '}' || (ch) == '|')
1200  while (*path) {
1201  char buf[1024];
1202  char *q = buf;
1203  while (*path && q - buf < sizeof(buf) - 4) {
1204  if (path[0] == '%' && av_isxdigit(path[1]) && av_isxdigit(path[2])) {
1205  *q++ = *path++;
1206  *q++ = *path++;
1207  *q++ = *path++;
1208  } else if (NEEDS_ESCAPE(*path)) {
1209  q += snprintf(q, 4, "%%%02X", (uint8_t)*path++);
1210  } else {
1211  *q++ = *path++;
1212  }
1213  }
1214  av_bprint_append_data(bp, buf, q - buf);
1215  }
1216 }
1217 
1218 static int http_connect(URLContext *h, const char *path, const char *local_path,
1219  const char *hoststr, const char *auth,
1220  const char *proxyauth, int *new_location)
1221 {
1222  HTTPContext *s = h->priv_data;
1223  int post, err;
1224  AVBPrint request;
1225  char *authstr = NULL, *proxyauthstr = NULL;
1226  uint64_t off = s->off;
1227  const char *method;
1228  int send_expect_100 = 0;
1229 
1230  av_bprint_init_for_buffer(&request, s->buffer, sizeof(s->buffer));
1231 
1232  /* send http header */
1233  post = h->flags & AVIO_FLAG_WRITE;
1234 
1235  if (s->post_data) {
1236  /* force POST method and disable chunked encoding when
1237  * custom HTTP post data is set */
1238  post = 1;
1239  s->chunked_post = 0;
1240  }
1241 
1242  if (s->method)
1243  method = s->method;
1244  else
1245  method = post ? "POST" : "GET";
1246 
1247  authstr = ff_http_auth_create_response(&s->auth_state, auth,
1248  local_path, method);
1249  proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth,
1250  local_path, method);
1251 
1252  if (post && !s->post_data) {
1253  if (s->send_expect_100 != -1) {
1254  send_expect_100 = s->send_expect_100;
1255  } else {
1256  send_expect_100 = 0;
1257  /* The user has supplied authentication but we don't know the auth type,
1258  * send Expect: 100-continue to get the 401 response including the
1259  * WWW-Authenticate header, or an 100 continue if no auth actually
1260  * is needed. */
1261  if (auth && *auth &&
1263  s->http_code != 401)
1264  send_expect_100 = 1;
1265  }
1266  }
1267 
1268 #if FF_API_HTTP_USER_AGENT
1269  if (strcmp(s->user_agent_deprecated, DEFAULT_USER_AGENT)) {
1270  s->user_agent = av_strdup(s->user_agent_deprecated);
1271  }
1272 #endif
1273 
1274  av_bprintf(&request, "%s ", method);
1275  bprint_escaped_path(&request, path);
1276  av_bprintf(&request, " HTTP/1.1\r\n");
1277 
1278  if (post && s->chunked_post)
1279  av_bprintf(&request, "Transfer-Encoding: chunked\r\n");
1280  /* set default headers if needed */
1281  if (!has_header(s->headers, "\r\nUser-Agent: "))
1282  av_bprintf(&request, "User-Agent: %s\r\n", s->user_agent);
1283  if (s->referer) {
1284  /* set default headers if needed */
1285  if (!has_header(s->headers, "\r\nReferer: "))
1286  av_bprintf(&request, "Referer: %s\r\n", s->referer);
1287  }
1288  if (!has_header(s->headers, "\r\nAccept: "))
1289  av_bprintf(&request, "Accept: */*\r\n");
1290  // Note: we send this on purpose even when s->off is 0 when we're probing,
1291  // since it allows us to detect more reliably if a (non-conforming)
1292  // server supports seeking by analysing the reply headers.
1293  if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->end_off || s->seekable == -1)) {
1294  av_bprintf(&request, "Range: bytes=%"PRIu64"-", s->off);
1295  if (s->end_off)
1296  av_bprintf(&request, "%"PRId64, s->end_off - 1);
1297  av_bprintf(&request, "\r\n");
1298  }
1299  if (send_expect_100 && !has_header(s->headers, "\r\nExpect: "))
1300  av_bprintf(&request, "Expect: 100-continue\r\n");
1301 
1302  if (!has_header(s->headers, "\r\nConnection: "))
1303  av_bprintf(&request, "Connection: %s\r\n", s->multiple_requests ? "keep-alive" : "close");
1304 
1305  if (!has_header(s->headers, "\r\nHost: "))
1306  av_bprintf(&request, "Host: %s\r\n", hoststr);
1307  if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data)
1308  av_bprintf(&request, "Content-Length: %d\r\n", s->post_datalen);
1309 
1310  if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
1311  av_bprintf(&request, "Content-Type: %s\r\n", s->content_type);
1312  if (!has_header(s->headers, "\r\nCookie: ") && s->cookies) {
1313  char *cookies = NULL;
1314  if (!get_cookies(s, &cookies, path, hoststr) && cookies) {
1315  av_bprintf(&request, "Cookie: %s\r\n", cookies);
1316  av_free(cookies);
1317  }
1318  }
1319  if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy)
1320  av_bprintf(&request, "Icy-MetaData: 1\r\n");
1321 
1322  /* now add in custom headers */
1323  if (s->headers)
1324  av_bprintf(&request, "%s", s->headers);
1325 
1326  if (authstr)
1327  av_bprintf(&request, "%s", authstr);
1328  if (proxyauthstr)
1329  av_bprintf(&request, "Proxy-%s", proxyauthstr);
1330  av_bprintf(&request, "\r\n");
1331 
1332  av_log(h, AV_LOG_DEBUG, "request: %s\n", request.str);
1333 
1334  if (!av_bprint_is_complete(&request)) {
1335  av_log(h, AV_LOG_ERROR, "overlong headers\n");
1336  err = AVERROR(EINVAL);
1337  goto done;
1338  }
1339 
1340  if ((err = ffurl_write(s->hd, request.str, request.len)) < 0)
1341  goto done;
1342 
1343  if (s->post_data)
1344  if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0)
1345  goto done;
1346 
1347  /* init input buffer */
1348  s->buf_ptr = s->buffer;
1349  s->buf_end = s->buffer;
1350  s->line_count = 0;
1351  s->off = 0;
1352  s->icy_data_read = 0;
1353  s->filesize = UINT64_MAX;
1354  s->willclose = 0;
1355  s->end_chunked_post = 0;
1356  s->end_header = 0;
1357 #if CONFIG_ZLIB
1358  s->compressed = 0;
1359 #endif
1360  if (post && !s->post_data && !send_expect_100) {
1361  /* Pretend that it did work. We didn't read any header yet, since
1362  * we've still to send the POST data, but the code calling this
1363  * function will check http_code after we return. */
1364  s->http_code = 200;
1365  err = 0;
1366  goto done;
1367  }
1368 
1369  /* wait for header */
1370  err = http_read_header(h, new_location);
1371  if (err < 0)
1372  goto done;
1373 
1374  if (*new_location)
1375  s->off = off;
1376 
1377  err = (off == s->off) ? 0 : -1;
1378 done:
1379  av_freep(&authstr);
1380  av_freep(&proxyauthstr);
1381  return err;
1382 }
1383 
1384 static int http_buf_read(URLContext *h, uint8_t *buf, int size)
1385 {
1386  HTTPContext *s = h->priv_data;
1387  int len;
1388 
1389  if (s->chunksize != UINT64_MAX) {
1390  if (s->chunkend) {
1391  return AVERROR_EOF;
1392  }
1393  if (!s->chunksize) {
1394  char line[32];
1395  int err;
1396 
1397  do {
1398  if ((err = http_get_line(s, line, sizeof(line))) < 0)
1399  return err;
1400  } while (!*line); /* skip CR LF from last chunk */
1401 
1402  s->chunksize = strtoull(line, NULL, 16);
1403 
1404  av_log(h, AV_LOG_TRACE,
1405  "Chunked encoding data size: %"PRIu64"\n",
1406  s->chunksize);
1407 
1408  if (!s->chunksize && s->multiple_requests) {
1409  http_get_line(s, line, sizeof(line)); // read empty chunk
1410  s->chunkend = 1;
1411  return 0;
1412  }
1413  else if (!s->chunksize) {
1414  av_log(h, AV_LOG_DEBUG, "Last chunk received, closing conn\n");
1415  ffurl_closep(&s->hd);
1416  return 0;
1417  }
1418  else if (s->chunksize == UINT64_MAX) {
1419  av_log(h, AV_LOG_ERROR, "Invalid chunk size %"PRIu64"\n",
1420  s->chunksize);
1421  return AVERROR(EINVAL);
1422  }
1423  }
1424  size = FFMIN(size, s->chunksize);
1425  }
1426 
1427  /* read bytes from input buffer first */
1428  len = s->buf_end - s->buf_ptr;
1429  if (len > 0) {
1430  if (len > size)
1431  len = size;
1432  memcpy(buf, s->buf_ptr, len);
1433  s->buf_ptr += len;
1434  } else {
1435  uint64_t target_end = s->end_off ? s->end_off : s->filesize;
1436  if ((!s->willclose || s->chunksize == UINT64_MAX) && s->off >= target_end)
1437  return AVERROR_EOF;
1438  len = ffurl_read(s->hd, buf, size);
1439  if ((!len || len == AVERROR_EOF) &&
1440  (!s->willclose || s->chunksize == UINT64_MAX) && s->off < target_end) {
1441  av_log(h, AV_LOG_ERROR,
1442  "Stream ends prematurely at %"PRIu64", should be %"PRIu64"\n",
1443  s->off, target_end
1444  );
1445  return AVERROR(EIO);
1446  }
1447  }
1448  if (len > 0) {
1449  s->off += len;
1450  if (s->chunksize > 0 && s->chunksize != UINT64_MAX) {
1451  av_assert0(s->chunksize >= len);
1452  s->chunksize -= len;
1453  }
1454  }
1455  return len;
1456 }
1457 
1458 #if CONFIG_ZLIB
1459 #define DECOMPRESS_BUF_SIZE (256 * 1024)
1460 static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size)
1461 {
1462  HTTPContext *s = h->priv_data;
1463  int ret;
1464 
1465  if (!s->inflate_buffer) {
1466  s->inflate_buffer = av_malloc(DECOMPRESS_BUF_SIZE);
1467  if (!s->inflate_buffer)
1468  return AVERROR(ENOMEM);
1469  }
1470 
1471  if (s->inflate_stream.avail_in == 0) {
1472  int read = http_buf_read(h, s->inflate_buffer, DECOMPRESS_BUF_SIZE);
1473  if (read <= 0)
1474  return read;
1475  s->inflate_stream.next_in = s->inflate_buffer;
1476  s->inflate_stream.avail_in = read;
1477  }
1478 
1479  s->inflate_stream.avail_out = size;
1480  s->inflate_stream.next_out = buf;
1481 
1482  ret = inflate(&s->inflate_stream, Z_SYNC_FLUSH);
1483  if (ret != Z_OK && ret != Z_STREAM_END)
1484  av_log(h, AV_LOG_WARNING, "inflate return value: %d, %s\n",
1485  ret, s->inflate_stream.msg);
1486 
1487  return size - s->inflate_stream.avail_out;
1488 }
1489 #endif /* CONFIG_ZLIB */
1490 
1491 static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect);
1492 
1493 static int http_read_stream(URLContext *h, uint8_t *buf, int size)
1494 {
1495  HTTPContext *s = h->priv_data;
1496  int err, new_location, read_ret;
1497  int64_t seek_ret;
1498  int reconnect_delay = 0;
1499 
1500  if (!s->hd)
1501  return AVERROR_EOF;
1502 
1503  if (s->end_chunked_post && !s->end_header) {
1504  err = http_read_header(h, &new_location);
1505  if (err < 0)
1506  return err;
1507  }
1508 
1509 #if CONFIG_ZLIB
1510  if (s->compressed)
1511  return http_buf_read_compressed(h, buf, size);
1512 #endif /* CONFIG_ZLIB */
1513  read_ret = http_buf_read(h, buf, size);
1514  while (read_ret < 0) {
1515  uint64_t target = h->is_streamed ? 0 : s->off;
1516 
1517  if (read_ret == AVERROR_EXIT)
1518  break;
1519 
1520  if (h->is_streamed && !s->reconnect_streamed)
1521  break;
1522 
1523  if (!(s->reconnect && s->filesize > 0 && s->off < s->filesize) &&
1524  !(s->reconnect_at_eof && read_ret == AVERROR_EOF))
1525  break;
1526 
1527  if (reconnect_delay > s->reconnect_delay_max)
1528  return AVERROR(EIO);
1529 
1530  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));
1531  err = ff_network_sleep_interruptible(1000U*1000*reconnect_delay, &h->interrupt_callback);
1532  if (err != AVERROR(ETIMEDOUT))
1533  return err;
1534  reconnect_delay = 1 + 2*reconnect_delay;
1535  seek_ret = http_seek_internal(h, target, SEEK_SET, 1);
1536  if (seek_ret >= 0 && seek_ret != target) {
1537  av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRIu64".\n", target);
1538  return read_ret;
1539  }
1540 
1541  read_ret = http_buf_read(h, buf, size);
1542  }
1543 
1544  return read_ret;
1545 }
1546 
1547 // Like http_read_stream(), but no short reads.
1548 // Assumes partial reads are an error.
1549 static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
1550 {
1551  int pos = 0;
1552  while (pos < size) {
1553  int len = http_read_stream(h, buf + pos, size - pos);
1554  if (len < 0)
1555  return len;
1556  pos += len;
1557  }
1558  return pos;
1559 }
1560 
1561 static void update_metadata(URLContext *h, char *data)
1562 {
1563  char *key;
1564  char *val;
1565  char *end;
1566  char *next = data;
1567  HTTPContext *s = h->priv_data;
1568 
1569  while (*next) {
1570  key = next;
1571  val = strstr(key, "='");
1572  if (!val)
1573  break;
1574  end = strstr(val, "';");
1575  if (!end)
1576  break;
1577 
1578  *val = '\0';
1579  *end = '\0';
1580  val += 2;
1581 
1582  av_dict_set(&s->metadata, key, val, 0);
1583  av_log(h, AV_LOG_VERBOSE, "Metadata update for %s: %s\n", key, val);
1584 
1585  next = end + 2;
1586  }
1587 }
1588 
1589 static int store_icy(URLContext *h, int size)
1590 {
1591  HTTPContext *s = h->priv_data;
1592  /* until next metadata packet */
1593  uint64_t remaining;
1594 
1595  if (s->icy_metaint < s->icy_data_read)
1596  return AVERROR_INVALIDDATA;
1597  remaining = s->icy_metaint - s->icy_data_read;
1598 
1599  if (!remaining) {
1600  /* The metadata packet is variable sized. It has a 1 byte header
1601  * which sets the length of the packet (divided by 16). If it's 0,
1602  * the metadata doesn't change. After the packet, icy_metaint bytes
1603  * of normal data follows. */
1604  uint8_t ch;
1605  int len = http_read_stream_all(h, &ch, 1);
1606  if (len < 0)
1607  return len;
1608  if (ch > 0) {
1609  char data[255 * 16 + 1];
1610  int ret;
1611  len = ch * 16;
1612  ret = http_read_stream_all(h, data, len);
1613  if (ret < 0)
1614  return ret;
1615  data[len + 1] = 0;
1616  if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
1617  return ret;
1618  update_metadata(h, data);
1619  }
1620  s->icy_data_read = 0;
1621  remaining = s->icy_metaint;
1622  }
1623 
1624  return FFMIN(size, remaining);
1625 }
1626 
1627 static int http_read(URLContext *h, uint8_t *buf, int size)
1628 {
1629  HTTPContext *s = h->priv_data;
1630 
1631  if (s->icy_metaint > 0) {
1632  size = store_icy(h, size);
1633  if (size < 0)
1634  return size;
1635  }
1636 
1637  size = http_read_stream(h, buf, size);
1638  if (size > 0)
1639  s->icy_data_read += size;
1640  return size;
1641 }
1642 
1643 /* used only when posting data */
1644 static int http_write(URLContext *h, const uint8_t *buf, int size)
1645 {
1646  char temp[11] = ""; /* 32-bit hex + CRLF + nul */
1647  int ret;
1648  char crlf[] = "\r\n";
1649  HTTPContext *s = h->priv_data;
1650 
1651  if (!s->chunked_post) {
1652  /* non-chunked data is sent without any special encoding */
1653  return ffurl_write(s->hd, buf, size);
1654  }
1655 
1656  /* silently ignore zero-size data since chunk encoding that would
1657  * signal EOF */
1658  if (size > 0) {
1659  /* upload data using chunked encoding */
1660  snprintf(temp, sizeof(temp), "%x\r\n", size);
1661 
1662  if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 ||
1663  (ret = ffurl_write(s->hd, buf, size)) < 0 ||
1664  (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0)
1665  return ret;
1666  }
1667  return size;
1668 }
1669 
1670 static int http_shutdown(URLContext *h, int flags)
1671 {
1672  int ret = 0;
1673  char footer[] = "0\r\n\r\n";
1674  HTTPContext *s = h->priv_data;
1675 
1676  /* signal end of chunked encoding if used */
1677  if (((flags & AVIO_FLAG_WRITE) && s->chunked_post) ||
1678  ((flags & AVIO_FLAG_READ) && s->chunked_post && s->listen)) {
1679  ret = ffurl_write(s->hd, footer, sizeof(footer) - 1);
1680  ret = ret > 0 ? 0 : ret;
1681  /* flush the receive buffer when it is write only mode */
1682  if (!(flags & AVIO_FLAG_READ)) {
1683  char buf[1024];
1684  int read_ret;
1685  s->hd->flags |= AVIO_FLAG_NONBLOCK;
1686  read_ret = ffurl_read(s->hd, buf, sizeof(buf));
1687  s->hd->flags &= ~AVIO_FLAG_NONBLOCK;
1688  if (read_ret < 0 && read_ret != AVERROR(EAGAIN)) {
1689  av_log(h, AV_LOG_ERROR, "URL read error: %s\n", av_err2str(read_ret));
1690  ret = read_ret;
1691  }
1692  }
1693  s->end_chunked_post = 1;
1694  }
1695 
1696  return ret;
1697 }
1698 
1699 static int http_close(URLContext *h)
1700 {
1701  int ret = 0;
1702  HTTPContext *s = h->priv_data;
1703 
1704 #if CONFIG_ZLIB
1705  inflateEnd(&s->inflate_stream);
1706  av_freep(&s->inflate_buffer);
1707 #endif /* CONFIG_ZLIB */
1708 
1709  if (s->hd && !s->end_chunked_post)
1710  /* Close the write direction by sending the end of chunked encoding. */
1711  ret = http_shutdown(h, h->flags);
1712 
1713  if (s->hd)
1714  ffurl_closep(&s->hd);
1716  return ret;
1717 }
1718 
1719 static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect)
1720 {
1721  HTTPContext *s = h->priv_data;
1722  URLContext *old_hd = s->hd;
1723  uint64_t old_off = s->off;
1724  uint8_t old_buf[BUFFER_SIZE];
1725  int old_buf_size, ret;
1726  AVDictionary *options = NULL;
1727 
1728  if (whence == AVSEEK_SIZE)
1729  return s->filesize;
1730  else if (!force_reconnect &&
1731  ((whence == SEEK_CUR && off == 0) ||
1732  (whence == SEEK_SET && off == s->off)))
1733  return s->off;
1734  else if ((s->filesize == UINT64_MAX && whence == SEEK_END))
1735  return AVERROR(ENOSYS);
1736 
1737  if (whence == SEEK_CUR)
1738  off += s->off;
1739  else if (whence == SEEK_END)
1740  off += s->filesize;
1741  else if (whence != SEEK_SET)
1742  return AVERROR(EINVAL);
1743  if (off < 0)
1744  return AVERROR(EINVAL);
1745  s->off = off;
1746 
1747  if (s->off && h->is_streamed)
1748  return AVERROR(ENOSYS);
1749 
1750  /* do not try to make a new connection if seeking past the end of the file */
1751  if (s->end_off || s->filesize != UINT64_MAX) {
1752  uint64_t end_pos = s->end_off ? s->end_off : s->filesize;
1753  if (s->off >= end_pos)
1754  return s->off;
1755  }
1756 
1757  /* we save the old context in case the seek fails */
1758  old_buf_size = s->buf_end - s->buf_ptr;
1759  memcpy(old_buf, s->buf_ptr, old_buf_size);
1760  s->hd = NULL;
1761 
1762  /* if it fails, continue on old connection */
1763  if ((ret = http_open_cnx(h, &options)) < 0) {
1764  av_dict_free(&options);
1765  memcpy(s->buffer, old_buf, old_buf_size);
1766  s->buf_ptr = s->buffer;
1767  s->buf_end = s->buffer + old_buf_size;
1768  s->hd = old_hd;
1769  s->off = old_off;
1770  return ret;
1771  }
1772  av_dict_free(&options);
1773  ffurl_close(old_hd);
1774  return off;
1775 }
1776 
1777 static int64_t http_seek(URLContext *h, int64_t off, int whence)
1778 {
1779  return http_seek_internal(h, off, whence, 0);
1780 }
1781 
1783 {
1784  HTTPContext *s = h->priv_data;
1785  return ffurl_get_file_handle(s->hd);
1786 }
1787 
1789 {
1790  HTTPContext *s = h->priv_data;
1791  return ffurl_get_short_seek(s->hd);
1792 }
1793 
1794 #define HTTP_CLASS(flavor) \
1795 static const AVClass flavor ## _context_class = { \
1796  .class_name = # flavor, \
1797  .item_name = av_default_item_name, \
1798  .option = options, \
1799  .version = LIBAVUTIL_VERSION_INT, \
1800 }
1801 
1802 #if CONFIG_HTTP_PROTOCOL
1803 HTTP_CLASS(http);
1804 
1805 const URLProtocol ff_http_protocol = {
1806  .name = "http",
1807  .url_open2 = http_open,
1808  .url_accept = http_accept,
1809  .url_handshake = http_handshake,
1810  .url_read = http_read,
1811  .url_write = http_write,
1812  .url_seek = http_seek,
1813  .url_close = http_close,
1814  .url_get_file_handle = http_get_file_handle,
1815  .url_get_short_seek = http_get_short_seek,
1816  .url_shutdown = http_shutdown,
1817  .priv_data_size = sizeof(HTTPContext),
1818  .priv_data_class = &http_context_class,
1820  .default_whitelist = "http,https,tls,rtp,tcp,udp,crypto,httpproxy,data"
1821 };
1822 #endif /* CONFIG_HTTP_PROTOCOL */
1823 
1824 #if CONFIG_HTTPS_PROTOCOL
1825 HTTP_CLASS(https);
1826 
1828  .name = "https",
1829  .url_open2 = http_open,
1830  .url_read = http_read,
1831  .url_write = http_write,
1832  .url_seek = http_seek,
1833  .url_close = http_close,
1834  .url_get_file_handle = http_get_file_handle,
1835  .url_get_short_seek = http_get_short_seek,
1836  .url_shutdown = http_shutdown,
1837  .priv_data_size = sizeof(HTTPContext),
1838  .priv_data_class = &https_context_class,
1840  .default_whitelist = "http,https,tls,rtp,tcp,udp,crypto,httpproxy"
1841 };
1842 #endif /* CONFIG_HTTPS_PROTOCOL */
1843 
1844 #if CONFIG_HTTPPROXY_PROTOCOL
1845 static int http_proxy_close(URLContext *h)
1846 {
1847  HTTPContext *s = h->priv_data;
1848  if (s->hd)
1849  ffurl_closep(&s->hd);
1850  return 0;
1851 }
1852 
1853 static int http_proxy_open(URLContext *h, const char *uri, int flags)
1854 {
1855  HTTPContext *s = h->priv_data;
1856  char hostname[1024], hoststr[1024];
1857  char auth[1024], pathbuf[1024], *path;
1858  char lower_url[100];
1859  int port, ret = 0, attempts = 0;
1860  HTTPAuthType cur_auth_type;
1861  char *authstr;
1862  int new_loc;
1863 
1864  if( s->seekable == 1 )
1865  h->is_streamed = 0;
1866  else
1867  h->is_streamed = 1;
1868 
1869  av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
1870  pathbuf, sizeof(pathbuf), uri);
1871  ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
1872  path = pathbuf;
1873  if (*path == '/')
1874  path++;
1875 
1876  ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port,
1877  NULL);
1878 redo:
1879  ret = ffurl_open_whitelist(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
1880  &h->interrupt_callback, NULL,
1882  if (ret < 0)
1883  return ret;
1884 
1885  authstr = ff_http_auth_create_response(&s->proxy_auth_state, auth,
1886  path, "CONNECT");
1887  snprintf(s->buffer, sizeof(s->buffer),
1888  "CONNECT %s HTTP/1.1\r\n"
1889  "Host: %s\r\n"
1890  "Connection: close\r\n"
1891  "%s%s"
1892  "\r\n",
1893  path,
1894  hoststr,
1895  authstr ? "Proxy-" : "", authstr ? authstr : "");
1896  av_freep(&authstr);
1897 
1898  if ((ret = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
1899  goto fail;
1900 
1901  s->buf_ptr = s->buffer;
1902  s->buf_end = s->buffer;
1903  s->line_count = 0;
1904  s->filesize = UINT64_MAX;
1905  cur_auth_type = s->proxy_auth_state.auth_type;
1906 
1907  /* Note: This uses buffering, potentially reading more than the
1908  * HTTP header. If tunneling a protocol where the server starts
1909  * the conversation, we might buffer part of that here, too.
1910  * Reading that requires using the proper ffurl_read() function
1911  * on this URLContext, not using the fd directly (as the tls
1912  * protocol does). This shouldn't be an issue for tls though,
1913  * since the client starts the conversation there, so there
1914  * is no extra data that we might buffer up here.
1915  */
1916  ret = http_read_header(h, &new_loc);
1917  if (ret < 0)
1918  goto fail;
1919 
1920  attempts++;
1921  if (s->http_code == 407 &&
1922  (cur_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
1923  s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 2) {
1924  ffurl_closep(&s->hd);
1925  goto redo;
1926  }
1927 
1928  if (s->http_code < 400)
1929  return 0;
1930  ret = ff_http_averror(s->http_code, AVERROR(EIO));
1931 
1932 fail:
1933  http_proxy_close(h);
1934  return ret;
1935 }
1936 
1937 static int http_proxy_write(URLContext *h, const uint8_t *buf, int size)
1938 {
1939  HTTPContext *s = h->priv_data;
1940  return ffurl_write(s->hd, buf, size);
1941 }
1942 
1944  .name = "httpproxy",
1945  .url_open = http_proxy_open,
1946  .url_read = http_buf_read,
1947  .url_write = http_proxy_write,
1948  .url_close = http_proxy_close,
1949  .url_get_file_handle = http_get_file_handle,
1950  .priv_data_size = sizeof(HTTPContext),
1951  .flags = URL_PROTOCOL_FLAG_NETWORK,
1952 };
1953 #endif /* CONFIG_HTTPPROXY_PROTOCOL */
static int http_get_line(HTTPContext *s, char *line, int line_size)
Definition: http.c:638
time_t av_timegm(struct tm *tm)
Convert the decomposed UTC time in tm to a time_t value.
Definition: parseutils.c:568
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:4725
static void update_metadata(URLContext *h, char *data)
Definition: http.c:1561
static void parse_content_range(URLContext *h, const char *p)
Definition: http.c:691
AVDictionary * metadata
Definition: http.c:110
#define NULL
Definition: coverity.c:32
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:1218
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:94
version
Definition: libkvazaar.c:317
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:310
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:34
uint8_t * post_data
Definition: http.c:96
AVOption.
Definition: opt.h:248
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
#define AV_OPT_FLAG_EXPORT
The option is intended for exporting values to the caller.
Definition: opt.h:286
#define AV_OPT_FLAG_DEPRECATED
set if option is deprecated, users should refer to AVOption.help text for more information ...
Definition: opt.h:295
HTTPAuthType
Authentication types, ordered from weakest to strongest.
Definition: httpauth.h:28
#define BUFFER_SIZE
Definition: http.c:49
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
static int http_close(URLContext *h)
Definition: http.c:1699
else temp
Definition: vf_mcdeint.c:256
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
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
int is_streamed
true if streamed (no seek possible), default = false
Definition: url.h:45
AVIOInterruptCB interrupt_callback
Definition: url.h:47
HTTPAuthState proxy_auth_state
Definition: http.c:74
Definition: http.c:59
#define AVIO_FLAG_READ
read-only
Definition: avio.h:674
char * icy_metadata_headers
Definition: http.c:108
static av_const int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.h:227
const URLProtocol ff_http_protocol
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:675
int av_strncasecmp(const char *a, const char *b, size_t n)
Locale-independent case-insensitive compare.
Definition: avstring.c:225
uint64_t icy_metaint
Definition: http.c:107
#define AVERROR_HTTP_NOT_FOUND
Definition: error.h:79
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:217
int flags
Definition: url.h:43
static int http_listen(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition: http.c:524
char * content_type
Definition: http.c:84
const char * key
uint64_t filesize
Definition: http.c:71
static void error(const char *err)
static int http_getc(HTTPContext *s)
Definition: http.c:621
HTTP Authentication state structure.
Definition: httpauth.h:55
int auth_type
The currently chosen auth type.
Definition: httpauth.h:59
#define WHITESPACES
Definition: http.c:54
int is_connected_server
Definition: http.c:129
#define AV_DICT_DONT_STRDUP_KEY
Take ownership of a key that&#39;s been allocated with av_malloc() or another memory allocation function...
Definition: dict.h:73
#define HTTP_SINGLE
Definition: http.c:51
#define MAX_URL_SIZE
Definition: internal.h:30
static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
Definition: http.c:824
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
int end_chunked_post
Definition: http.c:91
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
static int http_get_file_handle(URLContext *h)
Definition: http.c:1782
static int http_buf_read(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1384
uint8_t
#define av_malloc(s)
int post_datalen
Definition: http.c:97
AVOptions.
int ff_http_averror(int status_code, int default_averror)
Definition: http.c:391
miscellaneous OS support macros and functions.
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:220
static int http_read_header(URLContext *h, int *new_location)
Definition: http.c:1155
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:92
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
GLsizei GLboolean const GLfloat * value
Definition: opengl_enc.c:108
int is_akamai
Definition: http.c:98
static int http_open_cnx(URLContext *h, AVDictionary **options)
Definition: http.c:262
char * av_small_strptime(const char *p, const char *fmt, struct tm *dt)
Simplified version of strptime.
Definition: parseutils.c:489
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:158
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
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
#define NEEDS_ESCAPE(ch)
uint32_t tag
Definition: movenc.c:1597
#define DEFAULT_USER_AGENT
Definition: http.c:135
#define AVERROR_EOF
End of file.
Definition: error.h:55
void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
Initialize the authentication state based on another HTTP URLContext.
Definition: http.c:181
uint64_t icy_data_read
Definition: http.c:105
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:210
HTTP 1.0 Basic auth from RFC 1945 (also in RFC 2617)
Definition: httpauth.h:30
ptrdiff_t size
Definition: opengl_enc.c:100
static const uint8_t header[24]
Definition: sdr2.c:67
static int http_open_cnx_internal(URLContext *h, AVDictionary **options)
Definition: http.c:191
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
int line_count
Definition: http.c:66
#define av_log(a,...)
unsigned char * buf_end
Definition: http.c:65
static void body(uint32_t ABCD[4], const uint8_t *src, int nblocks)
Definition: md5.c:101
#define U(x)
Definition: vp56_arith.h:37
#define src
Definition: vp8dsp.c:254
int ff_http_get_shutdown_status(URLContext *h)
Get the HTTP shutdown response status, be used after http_shutdown.
Definition: http.c:317
int is_multi_client
Definition: http.c:127
int chunked_post
Definition: http.c:89
static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect)
Definition: http.c:1719
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
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:297
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
int reconnect_delay_max
Definition: http.c:123
#define E
Definition: http.c:134
const char * protocol_whitelist
Definition: url.h:49
static int http_write(URLContext *h, const uint8_t *buf, int size)
Definition: http.c:1644
static const AVOption options[]
Definition: http.c:137
unsigned int pos
Definition: spdifenc.c:410
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:203
static int http_handshake(URLContext *c)
Definition: http.c:488
Definition: graph2dot.c:48
uint64_t off
Definition: http.c:71
simple assert() macros that are a bit more flexible than ISO C assert().
#define OFFSET(x)
Definition: http.c:132
#define fail()
Definition: checkasm.h:123
uint64_t chunksize
Definition: http.c:69
AVDictionary * chained_options
Definition: http.c:116
#define AVERROR_HTTP_SERVER_ERROR
Definition: error.h:81
char * referer
Definition: http.c:80
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:1194
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:113
static int store_icy(URLContext *h, int size)
Definition: http.c:1589
AVDictionary * opts
Definition: movenc.c:50
char * headers
Definition: http.c:76
char * user_agent
Definition: http.c:79
#define AVERROR_HTTP_UNAUTHORIZED
Definition: error.h:77
char * icy_metadata_packet
Definition: http.c:109
int ffurl_get_short_seek(URLContext *h)
Return the current short seek threshold value for this URL.
Definition: avio.c:652
#define FFMIN(a, b)
Definition: common.h:96
static int http_get_short_seek(URLContext *h)
Definition: http.c:1788
const URLProtocol ff_httpproxy_protocol
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:215
int chunkend
Definition: http.c:70
int send_expect_100
Definition: http.c:118
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
int ff_network_sleep_interruptible(int64_t timeout, AVIOInterruptCB *int_cb)
Waits for up to &#39;timeout&#39; microseconds.
Definition: network.c:98
int willclose
Definition: http.c:87
int is_mediagateway
Definition: http.c:99
int ffurl_handshake(URLContext *c)
Perform one step of the protocol handshake to accept a new client.
Definition: avio.c:238
int reconnect
Definition: http.c:120
int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
Definition: network.c:551
#define s(width, name)
Definition: cbs_vp9.c:257
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:181
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:185
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition: avio.c:628
int ffurl_accept(URLContext *s, URLContext **c)
Accept an URLContext c on an URLContext s.
Definition: avio.c:230
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:56
AVDictionary * cookie_dict
Definition: http.c:102
int stale
Auth ok, but needs to be resent with a new nonce.
Definition: httpauth.h:71
offset must point to a pointer immediately followed by an int for the length
Definition: opt.h:231
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition: avio.c:446
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:39
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
int reconnect_streamed
Definition: http.c:122
static int http_read(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1627
#define AV_LOG_INFO
Standard information.
Definition: log.h:205
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
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:253
const char * protocol_blacklist
Definition: url.h:50
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
char * http_proxy
Definition: http.c:75
int av_opt_set_dict(void *obj, AVDictionary **options)
Set all the options from a given dictionary on an object.
Definition: opt.c:1655
HandshakeState handshake_step
Definition: http.c:128
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:693
int seekable
Control seekability, 0 = disable, 1 = enable, -1 = probe.
Definition: http.c:88
#define MAX_EXPIRY
Definition: http.c:53
Definition: url.h:38
#define AVIO_FLAG_READ_WRITE
read-write pseudo flag
Definition: avio.h:676
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
unsigned char buffer[BUFFER_SIZE]
Definition: http.c:65
char * http_version
Definition: http.c:78
Describe the class of an AVClass context structure.
Definition: log.h:67
#define SPACE_CHARS
Definition: internal.h:495
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
void * priv_data
Definition: url.h:41
#define AVERROR_HTTP_OTHER_4XX
Definition: error.h:80
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:101
#define snprintf
Definition: snprintf.h:34
static av_const int av_isxdigit(int c)
Locale-independent conversion of ASCII isxdigit.
Definition: avstring.h:256
int icy
Definition: http.c:103
misc parsing utilities
char * ff_http_auth_create_response(HTTPAuthState *state, const char *auth, const char *path, const char *method)
Definition: httpauth.c:245
const char * name
Definition: url.h:55
URLContext * hd
Definition: http.c:64
static int has_header(const char *str, const char *header)
Definition: http.c:1147
char * mime_type
Definition: http.c:77
#define SIZE_SPECIFIER
Definition: internal.h:229
#define flags(name, subs,...)
Definition: cbs_av1.c:560
#define AVERROR_HTTP_FORBIDDEN
Definition: error.h:78
int ffurl_close(URLContext *h)
Definition: avio.c:469
static int process_line(URLContext *h, char *line, int line_count, int *new_location)
Definition: http.c:909
int ff_http_do_new_request(URLContext *h, const char *uri)
Send a new HTTP request, reusing the old connection.
Definition: http.c:333
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
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
Main libavformat public API header.
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:33
char * cookies
holds newline ( ) delimited Set-Cookie header field values (without the "Set-Cookie: " field name) ...
Definition: http.c:100
#define MAX_REDIRECTS
Definition: http.c:50
static int parse_content_encoding(URLContext *h, const char *p)
Definition: http.c:706
const struct URLProtocol * prot
Definition: url.h:40
int reconnect_at_eof
Definition: http.c:121
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
HandshakeState
Definition: http.c:55
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:1063
int http_code
Definition: http.c:67
char * filename
specified URL
Definition: url.h:42
int listen
Definition: http.c:124
static int http_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition: http.c:555
#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
char * key
Definition: dict.h:86
void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, const char *value)
Definition: httpauth.c:90
int multiple_requests
Definition: http.c:95
HTTPAuthState auth_state
Definition: http.c:73
#define av_free(p)
static int cookie_string(AVDictionary *dict, char **cookies)
Definition: http.c:886
char * value
Definition: dict.h:87
const URLProtocol ff_https_protocol
int len
static int parse_location(HTTPContext *s, const char *p)
Definition: http.c:677
char * resource
Definition: http.c:125
char * location
Definition: http.c:72
static int http_shutdown(URLContext *h, int flags)
Definition: http.c:1670
static int http_write_reply(URLContext *h, int status_code)
Definition: http.c:408
#define AV_OPT_FLAG_READONLY
The option may not be set through the AVOptions API, only read.
Definition: opt.h:291
int end_header
Definition: http.c:93
unsigned char * buf_ptr
Definition: http.c:65
#define D
Definition: http.c:133
#define AVERROR_HTTP_BAD_REQUEST
Definition: error.h:76
char * method
Definition: http.c:119
static int parse_icy(HTTPContext *s, const char *tag, const char *p)
Definition: http.c:740
uint64_t end_off
Definition: http.c:71
static int parse_set_cookie_expiry_time(const char *exp_str, struct tm *buf)
Definition: http.c:762
static int http_read_stream(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1493
#define av_freep(p)
static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1549
#define AV_DICT_IGNORE_SUFFIX
Return first entry in a dictionary whose first part corresponds to the search key, ignoring the suffix of the found key string.
Definition: dict.h:70
unbuffered private I/O API
static void handle_http_errors(URLContext *h, int error)
Definition: http.c:482
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
static int parse_set_cookie(const char *set_cookie, AVDictionary **dict)
Definition: http.c:787
static int64_t http_seek(URLContext *h, int64_t off, int whence)
Definition: http.c:1777
static double val(void *priv, double ch)
Definition: aeval.c:76
int reply_code
Definition: http.c:126
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
Definition: opt.c:465
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
char * av_strndup(const char *s, size_t len)
Duplicate a substring of a string.
Definition: mem.c:265
static int http_accept(URLContext *s, URLContext **c)
Definition: http.c:597
int i
Definition: input.c:407
GLuint buffer
Definition: opengl_enc.c:101
#define HTTP_CLASS(flavor)
Definition: http.c:1794
No authentication specified.
Definition: httpauth.h:29
static int check_http_code(URLContext *h, int http_code, const char *end)
Definition: http.c:662
const char * name
Definition: opengl_enc.c:102
static uint8_t tmp[11]
Definition: aes_ctr.c:26