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;
126  int listen;
127  char *resource;
132 } HTTPContext;
133 
134 #define OFFSET(x) offsetof(HTTPContext, x)
135 #define D AV_OPT_FLAG_DECODING_PARAM
136 #define E AV_OPT_FLAG_ENCODING_PARAM
137 #define DEFAULT_USER_AGENT "Lavf/" AV_STRINGIFY(LIBAVFORMAT_VERSION)
138 
139 static const AVOption options[] = {
140  { "seekable", "control seekability of connection", OFFSET(seekable), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, D },
141  { "chunked_post", "use chunked transfer-encoding for posts", OFFSET(chunked_post), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E },
142  { "http_proxy", "set HTTP proxy to tunnel through", OFFSET(http_proxy), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
143  { "headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
144  { "content_type", "set a specific content type for the POST messages", OFFSET(content_type), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
145  { "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D },
146  { "referer", "override referer header", OFFSET(referer), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D },
147 #if FF_API_HTTP_USER_AGENT
148  { "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 },
149 #endif
150  { "multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D | E },
151  { "post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D | E },
152  { "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 },
153  { "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 },
154  { "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 },
155  { "icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D },
156  { "icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT },
157  { "icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT },
158  { "metadata", "metadata read from the bitstream", OFFSET(metadata), AV_OPT_TYPE_DICT, {0}, 0, 0, AV_OPT_FLAG_EXPORT },
159  { "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"},
160  { "none", "No auth method set, autodetect", 0, AV_OPT_TYPE_CONST, { .i64 = HTTP_AUTH_NONE }, 0, 0, D | E, "auth_type"},
161  { "basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, { .i64 = HTTP_AUTH_BASIC }, 0, 0, D | E, "auth_type"},
162  { "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 },
163  { "location", "The actual location of the data received", OFFSET(location), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
164  { "offset", "initial byte offset", OFFSET(off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
165  { "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 },
166  { "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 },
167  { "reconnect", "auto reconnect after disconnect before EOF", OFFSET(reconnect), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
168  { "reconnect_at_eof", "auto reconnect at EOF", OFFSET(reconnect_at_eof), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
169  { "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 },
170  { "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 },
171  { "reconnect_streamed", "auto reconnect streamed / non seekable streams", OFFSET(reconnect_streamed), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
172  { "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 },
173  { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, D | E },
174  { "resource", "The resource requested by a client", OFFSET(resource), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
175  { "reply_code", "The http status code to return to a client", OFFSET(reply_code), AV_OPT_TYPE_INT, { .i64 = 200}, INT_MIN, 599, E},
176  { NULL }
177 };
178 
179 static int http_connect(URLContext *h, const char *path, const char *local_path,
180  const char *hoststr, const char *auth,
181  const char *proxyauth, int *new_location);
182 static int http_read_header(URLContext *h, int *new_location);
183 static int http_shutdown(URLContext *h, int flags);
184 
186 {
187  memcpy(&((HTTPContext *)dest->priv_data)->auth_state,
188  &((HTTPContext *)src->priv_data)->auth_state,
189  sizeof(HTTPAuthState));
190  memcpy(&((HTTPContext *)dest->priv_data)->proxy_auth_state,
191  &((HTTPContext *)src->priv_data)->proxy_auth_state,
192  sizeof(HTTPAuthState));
193 }
194 
196 {
197  const char *path, *proxy_path, *lower_proto = "tcp", *local_path;
198  char *hashmark;
199  char hostname[1024], hoststr[1024], proto[10];
200  char auth[1024], proxyauth[1024] = "";
201  char path1[MAX_URL_SIZE], sanitized_path[MAX_URL_SIZE];
202  char buf[1024], urlbuf[MAX_URL_SIZE];
203  int port, use_proxy, err, location_changed = 0;
204  HTTPContext *s = h->priv_data;
205 
206  av_url_split(proto, sizeof(proto), auth, sizeof(auth),
207  hostname, sizeof(hostname), &port,
208  path1, sizeof(path1), s->location);
209  ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
210 
211  proxy_path = s->http_proxy ? s->http_proxy : getenv("http_proxy");
212  use_proxy = !ff_http_match_no_proxy(getenv("no_proxy"), hostname) &&
213  proxy_path && av_strstart(proxy_path, "http://", NULL);
214 
215  if (!strcmp(proto, "https")) {
216  lower_proto = "tls";
217  use_proxy = 0;
218  if (port < 0)
219  port = 443;
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,
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 */
299 static int http_open_cnx(URLContext *h, AVDictionary **options)
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) &&
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;
396  AVDictionary *options = NULL;
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);
443  av_dict_free(&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 
538 static void handle_http_errors(URLContext *h, int error)
539 {
540  av_assert0(error < 0);
541  http_write_reply(h, error);
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,
599  )) < 0)
600  goto fail;
602  if (s->listen == HTTP_SINGLE) { /* single client */
603  s->reply_code = 200;
604  while ((ret = http_handshake(h)) > 0);
605  }
606 fail:
608  return ret;
609 }
610 
611 static int http_open(URLContext *h, const char *uri, int flags,
612  AVDictionary **options)
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  }
646  ret = http_open_cnx(h, options);
647 bail_out:
648  if (ret < 0)
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")) {
1079  } else if (!av_strcasecmp(tag, "Authentication-Info")) {
1081  } else if (!av_strcasecmp(tag, "Proxy-Authenticate")) {
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.
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
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 &&
1319  s->http_code != 401)
1320  send_expect_100 = 1;
1321  }
1322  }
1323 
1324 #if FF_API_HTTP_USER_AGENT
1325  if (strcmp(s->user_agent_deprecated, DEFAULT_USER_AGENT)) {
1326  s->user_agent = av_strdup(s->user_agent_deprecated);
1327  }
1328 #endif
1329 
1330  av_bprintf(&request, "%s ", method);
1331  bprint_escaped_path(&request, path);
1332  av_bprintf(&request, " HTTP/1.1\r\n");
1333 
1334  if (post && s->chunked_post)
1335  av_bprintf(&request, "Transfer-Encoding: chunked\r\n");
1336  /* set default headers if needed */
1337  if (!has_header(s->headers, "\r\nUser-Agent: "))
1338  av_bprintf(&request, "User-Agent: %s\r\n", s->user_agent);
1339  if (s->referer) {
1340  /* set default headers if needed */
1341  if (!has_header(s->headers, "\r\nReferer: "))
1342  av_bprintf(&request, "Referer: %s\r\n", s->referer);
1343  }
1344  if (!has_header(s->headers, "\r\nAccept: "))
1345  av_bprintf(&request, "Accept: */*\r\n");
1346  // Note: we send this on purpose even when s->off is 0 when we're probing,
1347  // since it allows us to detect more reliably if a (non-conforming)
1348  // server supports seeking by analysing the reply headers.
1349  if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->end_off || s->seekable == -1)) {
1350  av_bprintf(&request, "Range: bytes=%"PRIu64"-", s->off);
1351  if (s->end_off)
1352  av_bprintf(&request, "%"PRId64, s->end_off - 1);
1353  av_bprintf(&request, "\r\n");
1354  }
1355  if (send_expect_100 && !has_header(s->headers, "\r\nExpect: "))
1356  av_bprintf(&request, "Expect: 100-continue\r\n");
1357 
1358  if (!has_header(s->headers, "\r\nConnection: "))
1359  av_bprintf(&request, "Connection: %s\r\n", s->multiple_requests ? "keep-alive" : "close");
1360 
1361  if (!has_header(s->headers, "\r\nHost: "))
1362  av_bprintf(&request, "Host: %s\r\n", hoststr);
1363  if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data)
1364  av_bprintf(&request, "Content-Length: %d\r\n", s->post_datalen);
1365 
1366  if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
1367  av_bprintf(&request, "Content-Type: %s\r\n", s->content_type);
1368  if (!has_header(s->headers, "\r\nCookie: ") && s->cookies) {
1369  char *cookies = NULL;
1370  if (!get_cookies(s, &cookies, path, hoststr) && cookies) {
1371  av_bprintf(&request, "Cookie: %s\r\n", cookies);
1372  av_free(cookies);
1373  }
1374  }
1375  if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy)
1376  av_bprintf(&request, "Icy-MetaData: 1\r\n");
1377 
1378  /* now add in custom headers */
1379  if (s->headers)
1380  av_bprintf(&request, "%s", s->headers);
1381 
1382  if (authstr)
1383  av_bprintf(&request, "%s", authstr);
1384  if (proxyauthstr)
1385  av_bprintf(&request, "Proxy-%s", proxyauthstr);
1386  av_bprintf(&request, "\r\n");
1387 
1388  av_log(h, AV_LOG_DEBUG, "request: %s\n", request.str);
1389 
1390  if (!av_bprint_is_complete(&request)) {
1391  av_log(h, AV_LOG_ERROR, "overlong headers\n");
1392  err = AVERROR(EINVAL);
1393  goto done;
1394  }
1395 
1396  if ((err = ffurl_write(s->hd, request.str, request.len)) < 0)
1397  goto done;
1398 
1399  if (s->post_data)
1400  if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0)
1401  goto done;
1402 
1403  /* init input buffer */
1404  s->buf_ptr = s->buffer;
1405  s->buf_end = s->buffer;
1406  s->line_count = 0;
1407  s->off = 0;
1408  s->icy_data_read = 0;
1409  s->filesize = UINT64_MAX;
1410  s->willclose = 0;
1411  s->end_chunked_post = 0;
1412  s->end_header = 0;
1413 #if CONFIG_ZLIB
1414  s->compressed = 0;
1415 #endif
1416  if (post && !s->post_data && !send_expect_100) {
1417  /* Pretend that it did work. We didn't read any header yet, since
1418  * we've still to send the POST data, but the code calling this
1419  * function will check http_code after we return. */
1420  s->http_code = 200;
1421  err = 0;
1422  goto done;
1423  }
1424 
1425  /* wait for header */
1426  err = http_read_header(h, new_location);
1427  if (err < 0)
1428  goto done;
1429 
1430  if (*new_location)
1431  s->off = off;
1432 
1433  err = (off == s->off) ? 0 : -1;
1434 done:
1435  av_freep(&authstr);
1436  av_freep(&proxyauthstr);
1437  return err;
1438 }
1439 
1440 static int http_buf_read(URLContext *h, uint8_t *buf, int size)
1441 {
1442  HTTPContext *s = h->priv_data;
1443  int len;
1444 
1445  if (s->chunksize != UINT64_MAX) {
1446  if (s->chunkend) {
1447  return AVERROR_EOF;
1448  }
1449  if (!s->chunksize) {
1450  char line[32];
1451  int err;
1452 
1453  do {
1454  if ((err = http_get_line(s, line, sizeof(line))) < 0)
1455  return err;
1456  } while (!*line); /* skip CR LF from last chunk */
1457 
1458  s->chunksize = strtoull(line, NULL, 16);
1459 
1460  av_log(h, AV_LOG_TRACE,
1461  "Chunked encoding data size: %"PRIu64"\n",
1462  s->chunksize);
1463 
1464  if (!s->chunksize && s->multiple_requests) {
1465  http_get_line(s, line, sizeof(line)); // read empty chunk
1466  s->chunkend = 1;
1467  return 0;
1468  }
1469  else if (!s->chunksize) {
1470  av_log(h, AV_LOG_DEBUG, "Last chunk received, closing conn\n");
1471  ffurl_closep(&s->hd);
1472  return 0;
1473  }
1474  else if (s->chunksize == UINT64_MAX) {
1475  av_log(h, AV_LOG_ERROR, "Invalid chunk size %"PRIu64"\n",
1476  s->chunksize);
1477  return AVERROR(EINVAL);
1478  }
1479  }
1480  size = FFMIN(size, s->chunksize);
1481  }
1482 
1483  /* read bytes from input buffer first */
1484  len = s->buf_end - s->buf_ptr;
1485  if (len > 0) {
1486  if (len > size)
1487  len = size;
1488  memcpy(buf, s->buf_ptr, len);
1489  s->buf_ptr += len;
1490  } else {
1491  uint64_t target_end = s->end_off ? s->end_off : s->filesize;
1492  if ((!s->willclose || s->chunksize == UINT64_MAX) && s->off >= target_end)
1493  return AVERROR_EOF;
1494  len = ffurl_read(s->hd, buf, size);
1495  if ((!len || len == AVERROR_EOF) &&
1496  (!s->willclose || s->chunksize == UINT64_MAX) && s->off < target_end) {
1497  av_log(h, AV_LOG_ERROR,
1498  "Stream ends prematurely at %"PRIu64", should be %"PRIu64"\n",
1499  s->off, target_end
1500  );
1501  return AVERROR(EIO);
1502  }
1503  }
1504  if (len > 0) {
1505  s->off += len;
1506  if (s->chunksize > 0 && s->chunksize != UINT64_MAX) {
1507  av_assert0(s->chunksize >= len);
1508  s->chunksize -= len;
1509  }
1510  }
1511  return len;
1512 }
1513 
1514 #if CONFIG_ZLIB
1515 #define DECOMPRESS_BUF_SIZE (256 * 1024)
1516 static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size)
1517 {
1518  HTTPContext *s = h->priv_data;
1519  int ret;
1520 
1521  if (!s->inflate_buffer) {
1522  s->inflate_buffer = av_malloc(DECOMPRESS_BUF_SIZE);
1523  if (!s->inflate_buffer)
1524  return AVERROR(ENOMEM);
1525  }
1526 
1527  if (s->inflate_stream.avail_in == 0) {
1528  int read = http_buf_read(h, s->inflate_buffer, DECOMPRESS_BUF_SIZE);
1529  if (read <= 0)
1530  return read;
1531  s->inflate_stream.next_in = s->inflate_buffer;
1532  s->inflate_stream.avail_in = read;
1533  }
1534 
1535  s->inflate_stream.avail_out = size;
1536  s->inflate_stream.next_out = buf;
1537 
1538  ret = inflate(&s->inflate_stream, Z_SYNC_FLUSH);
1539  if (ret != Z_OK && ret != Z_STREAM_END)
1540  av_log(h, AV_LOG_WARNING, "inflate return value: %d, %s\n",
1541  ret, s->inflate_stream.msg);
1542 
1543  return size - s->inflate_stream.avail_out;
1544 }
1545 #endif /* CONFIG_ZLIB */
1546 
1547 static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect);
1548 
1549 static int http_read_stream(URLContext *h, uint8_t *buf, int size)
1550 {
1551  HTTPContext *s = h->priv_data;
1552  int err, new_location, read_ret;
1553  int64_t seek_ret;
1554  int reconnect_delay = 0;
1555 
1556  if (!s->hd)
1557  return AVERROR_EOF;
1558 
1559  if (s->end_chunked_post && !s->end_header) {
1560  err = http_read_header(h, &new_location);
1561  if (err < 0)
1562  return err;
1563  }
1564 
1565 #if CONFIG_ZLIB
1566  if (s->compressed)
1567  return http_buf_read_compressed(h, buf, size);
1568 #endif /* CONFIG_ZLIB */
1569  read_ret = http_buf_read(h, buf, size);
1570  while (read_ret < 0) {
1571  uint64_t target = h->is_streamed ? 0 : s->off;
1572 
1573  if (read_ret == AVERROR_EXIT)
1574  break;
1575 
1576  if (h->is_streamed && !s->reconnect_streamed)
1577  break;
1578 
1579  if (!(s->reconnect && s->filesize > 0 && s->off < s->filesize) &&
1580  !(s->reconnect_at_eof && read_ret == AVERROR_EOF))
1581  break;
1582 
1583  if (reconnect_delay > s->reconnect_delay_max)
1584  return AVERROR(EIO);
1585 
1586  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));
1587  err = ff_network_sleep_interruptible(1000U*1000*reconnect_delay, &h->interrupt_callback);
1588  if (err != AVERROR(ETIMEDOUT))
1589  return err;
1590  reconnect_delay = 1 + 2*reconnect_delay;
1591  seek_ret = http_seek_internal(h, target, SEEK_SET, 1);
1592  if (seek_ret >= 0 && seek_ret != target) {
1593  av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRIu64".\n", target);
1594  return read_ret;
1595  }
1596 
1597  read_ret = http_buf_read(h, buf, size);
1598  }
1599 
1600  return read_ret;
1601 }
1602 
1603 // Like http_read_stream(), but no short reads.
1604 // Assumes partial reads are an error.
1605 static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
1606 {
1607  int pos = 0;
1608  while (pos < size) {
1609  int len = http_read_stream(h, buf + pos, size - pos);
1610  if (len < 0)
1611  return len;
1612  pos += len;
1613  }
1614  return pos;
1615 }
1616 
1617 static void update_metadata(URLContext *h, char *data)
1618 {
1619  char *key;
1620  char *val;
1621  char *end;
1622  char *next = data;
1623  HTTPContext *s = h->priv_data;
1624 
1625  while (*next) {
1626  key = next;
1627  val = strstr(key, "='");
1628  if (!val)
1629  break;
1630  end = strstr(val, "';");
1631  if (!end)
1632  break;
1633 
1634  *val = '\0';
1635  *end = '\0';
1636  val += 2;
1637 
1638  av_dict_set(&s->metadata, key, val, 0);
1639  av_log(h, AV_LOG_VERBOSE, "Metadata update for %s: %s\n", key, val);
1640 
1641  next = end + 2;
1642  }
1643 }
1644 
1645 static int store_icy(URLContext *h, int size)
1646 {
1647  HTTPContext *s = h->priv_data;
1648  /* until next metadata packet */
1649  uint64_t remaining;
1650 
1651  if (s->icy_metaint < s->icy_data_read)
1652  return AVERROR_INVALIDDATA;
1653  remaining = s->icy_metaint - s->icy_data_read;
1654 
1655  if (!remaining) {
1656  /* The metadata packet is variable sized. It has a 1 byte header
1657  * which sets the length of the packet (divided by 16). If it's 0,
1658  * the metadata doesn't change. After the packet, icy_metaint bytes
1659  * of normal data follows. */
1660  uint8_t ch;
1661  int len = http_read_stream_all(h, &ch, 1);
1662  if (len < 0)
1663  return len;
1664  if (ch > 0) {
1665  char data[255 * 16 + 1];
1666  int ret;
1667  len = ch * 16;
1668  ret = http_read_stream_all(h, data, len);
1669  if (ret < 0)
1670  return ret;
1671  data[len + 1] = 0;
1672  if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
1673  return ret;
1674  update_metadata(h, data);
1675  }
1676  s->icy_data_read = 0;
1677  remaining = s->icy_metaint;
1678  }
1679 
1680  return FFMIN(size, remaining);
1681 }
1682 
1683 static int http_read(URLContext *h, uint8_t *buf, int size)
1684 {
1685  HTTPContext *s = h->priv_data;
1686 
1687  if (s->icy_metaint > 0) {
1688  size = store_icy(h, size);
1689  if (size < 0)
1690  return size;
1691  }
1692 
1693  size = http_read_stream(h, buf, size);
1694  if (size > 0)
1695  s->icy_data_read += size;
1696  return size;
1697 }
1698 
1699 /* used only when posting data */
1700 static int http_write(URLContext *h, const uint8_t *buf, int size)
1701 {
1702  char temp[11] = ""; /* 32-bit hex + CRLF + nul */
1703  int ret;
1704  char crlf[] = "\r\n";
1705  HTTPContext *s = h->priv_data;
1706 
1707  if (!s->chunked_post) {
1708  /* non-chunked data is sent without any special encoding */
1709  return ffurl_write(s->hd, buf, size);
1710  }
1711 
1712  /* silently ignore zero-size data since chunk encoding that would
1713  * signal EOF */
1714  if (size > 0) {
1715  /* upload data using chunked encoding */
1716  snprintf(temp, sizeof(temp), "%x\r\n", size);
1717 
1718  if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 ||
1719  (ret = ffurl_write(s->hd, buf, size)) < 0 ||
1720  (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0)
1721  return ret;
1722  }
1723  return size;
1724 }
1725 
1726 static int http_shutdown(URLContext *h, int flags)
1727 {
1728  int ret = 0;
1729  char footer[] = "0\r\n\r\n";
1730  HTTPContext *s = h->priv_data;
1731 
1732  /* signal end of chunked encoding if used */
1733  if (((flags & AVIO_FLAG_WRITE) && s->chunked_post) ||
1734  ((flags & AVIO_FLAG_READ) && s->chunked_post && s->listen)) {
1735  ret = ffurl_write(s->hd, footer, sizeof(footer) - 1);
1736  ret = ret > 0 ? 0 : ret;
1737  /* flush the receive buffer when it is write only mode */
1738  if (!(flags & AVIO_FLAG_READ)) {
1739  char buf[1024];
1740  int read_ret;
1741  s->hd->flags |= AVIO_FLAG_NONBLOCK;
1742  read_ret = ffurl_read(s->hd, buf, sizeof(buf));
1743  s->hd->flags &= ~AVIO_FLAG_NONBLOCK;
1744  if (read_ret < 0 && read_ret != AVERROR(EAGAIN)) {
1745  av_log(h, AV_LOG_ERROR, "URL read error: %s\n", av_err2str(read_ret));
1746  ret = read_ret;
1747  }
1748  }
1749  s->end_chunked_post = 1;
1750  }
1751 
1752  return ret;
1753 }
1754 
1755 static int http_close(URLContext *h)
1756 {
1757  int ret = 0;
1758  HTTPContext *s = h->priv_data;
1759 
1760 #if CONFIG_ZLIB
1761  inflateEnd(&s->inflate_stream);
1762  av_freep(&s->inflate_buffer);
1763 #endif /* CONFIG_ZLIB */
1764 
1765  if (s->hd && !s->end_chunked_post)
1766  /* Close the write direction by sending the end of chunked encoding. */
1767  ret = http_shutdown(h, h->flags);
1768 
1769  if (s->hd)
1770  ffurl_closep(&s->hd);
1772  return ret;
1773 }
1774 
1775 static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect)
1776 {
1777  HTTPContext *s = h->priv_data;
1778  URLContext *old_hd = s->hd;
1779  uint64_t old_off = s->off;
1780  uint8_t old_buf[BUFFER_SIZE];
1781  int old_buf_size, ret;
1782  AVDictionary *options = NULL;
1783 
1784  if (whence == AVSEEK_SIZE)
1785  return s->filesize;
1786  else if (!force_reconnect &&
1787  ((whence == SEEK_CUR && off == 0) ||
1788  (whence == SEEK_SET && off == s->off)))
1789  return s->off;
1790  else if ((s->filesize == UINT64_MAX && whence == SEEK_END))
1791  return AVERROR(ENOSYS);
1792 
1793  if (whence == SEEK_CUR)
1794  off += s->off;
1795  else if (whence == SEEK_END)
1796  off += s->filesize;
1797  else if (whence != SEEK_SET)
1798  return AVERROR(EINVAL);
1799  if (off < 0)
1800  return AVERROR(EINVAL);
1801  s->off = off;
1802 
1803  if (s->off && h->is_streamed)
1804  return AVERROR(ENOSYS);
1805 
1806  /* do not try to make a new connection if seeking past the end of the file */
1807  if (s->end_off || s->filesize != UINT64_MAX) {
1808  uint64_t end_pos = s->end_off ? s->end_off : s->filesize;
1809  if (s->off >= end_pos)
1810  return s->off;
1811  }
1812 
1813  /* we save the old context in case the seek fails */
1814  old_buf_size = s->buf_end - s->buf_ptr;
1815  memcpy(old_buf, s->buf_ptr, old_buf_size);
1816  s->hd = NULL;
1817 
1818  /* if it fails, continue on old connection */
1819  if ((ret = http_open_cnx(h, &options)) < 0) {
1820  av_dict_free(&options);
1821  memcpy(s->buffer, old_buf, old_buf_size);
1822  s->buf_ptr = s->buffer;
1823  s->buf_end = s->buffer + old_buf_size;
1824  s->hd = old_hd;
1825  s->off = old_off;
1826  return ret;
1827  }
1828  av_dict_free(&options);
1829  ffurl_close(old_hd);
1830  return off;
1831 }
1832 
1833 static int64_t http_seek(URLContext *h, int64_t off, int whence)
1834 {
1835  return http_seek_internal(h, off, whence, 0);
1836 }
1837 
1839 {
1840  HTTPContext *s = h->priv_data;
1841  return ffurl_get_file_handle(s->hd);
1842 }
1843 
1845 {
1846  HTTPContext *s = h->priv_data;
1847  return ffurl_get_short_seek(s->hd);
1848 }
1849 
1850 #define HTTP_CLASS(flavor) \
1851 static const AVClass flavor ## _context_class = { \
1852  .class_name = # flavor, \
1853  .item_name = av_default_item_name, \
1854  .option = options, \
1855  .version = LIBAVUTIL_VERSION_INT, \
1856 }
1857 
1858 #if CONFIG_HTTP_PROTOCOL
1859 HTTP_CLASS(http);
1860 
1861 const URLProtocol ff_http_protocol = {
1862  .name = "http",
1863  .url_open2 = http_open,
1864  .url_accept = http_accept,
1865  .url_handshake = http_handshake,
1866  .url_read = http_read,
1867  .url_write = http_write,
1868  .url_seek = http_seek,
1869  .url_close = http_close,
1870  .url_get_file_handle = http_get_file_handle,
1871  .url_get_short_seek = http_get_short_seek,
1872  .url_shutdown = http_shutdown,
1873  .priv_data_size = sizeof(HTTPContext),
1874  .priv_data_class = &http_context_class,
1876  .default_whitelist = "http,https,tls,rtp,tcp,udp,crypto,httpproxy,data"
1877 };
1878 #endif /* CONFIG_HTTP_PROTOCOL */
1879 
1880 #if CONFIG_HTTPS_PROTOCOL
1881 HTTP_CLASS(https);
1882 
1884  .name = "https",
1885  .url_open2 = http_open,
1886  .url_read = http_read,
1887  .url_write = http_write,
1888  .url_seek = http_seek,
1889  .url_close = http_close,
1890  .url_get_file_handle = http_get_file_handle,
1891  .url_get_short_seek = http_get_short_seek,
1892  .url_shutdown = http_shutdown,
1893  .priv_data_size = sizeof(HTTPContext),
1894  .priv_data_class = &https_context_class,
1896  .default_whitelist = "http,https,tls,rtp,tcp,udp,crypto,httpproxy"
1897 };
1898 #endif /* CONFIG_HTTPS_PROTOCOL */
1899 
1900 #if CONFIG_HTTPPROXY_PROTOCOL
1901 static int http_proxy_close(URLContext *h)
1902 {
1903  HTTPContext *s = h->priv_data;
1904  if (s->hd)
1905  ffurl_closep(&s->hd);
1906  return 0;
1907 }
1908 
1909 static int http_proxy_open(URLContext *h, const char *uri, int flags)
1910 {
1911  HTTPContext *s = h->priv_data;
1912  char hostname[1024], hoststr[1024];
1913  char auth[1024], pathbuf[1024], *path;
1914  char lower_url[100];
1915  int port, ret = 0, attempts = 0;
1916  HTTPAuthType cur_auth_type;
1917  char *authstr;
1918  int new_loc;
1919 
1920  if( s->seekable == 1 )
1921  h->is_streamed = 0;
1922  else
1923  h->is_streamed = 1;
1924 
1925  av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
1926  pathbuf, sizeof(pathbuf), uri);
1927  ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
1928  path = pathbuf;
1929  if (*path == '/')
1930  path++;
1931 
1932  ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port,
1933  NULL);
1934 redo:
1935  ret = ffurl_open_whitelist(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
1936  &h->interrupt_callback, NULL,
1938  if (ret < 0)
1939  return ret;
1940 
1941  authstr = ff_http_auth_create_response(&s->proxy_auth_state, auth,
1942  path, "CONNECT");
1943  snprintf(s->buffer, sizeof(s->buffer),
1944  "CONNECT %s HTTP/1.1\r\n"
1945  "Host: %s\r\n"
1946  "Connection: close\r\n"
1947  "%s%s"
1948  "\r\n",
1949  path,
1950  hoststr,
1951  authstr ? "Proxy-" : "", authstr ? authstr : "");
1952  av_freep(&authstr);
1953 
1954  if ((ret = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
1955  goto fail;
1956 
1957  s->buf_ptr = s->buffer;
1958  s->buf_end = s->buffer;
1959  s->line_count = 0;
1960  s->filesize = UINT64_MAX;
1961  cur_auth_type = s->proxy_auth_state.auth_type;
1962 
1963  /* Note: This uses buffering, potentially reading more than the
1964  * HTTP header. If tunneling a protocol where the server starts
1965  * the conversation, we might buffer part of that here, too.
1966  * Reading that requires using the proper ffurl_read() function
1967  * on this URLContext, not using the fd directly (as the tls
1968  * protocol does). This shouldn't be an issue for tls though,
1969  * since the client starts the conversation there, so there
1970  * is no extra data that we might buffer up here.
1971  */
1972  ret = http_read_header(h, &new_loc);
1973  if (ret < 0)
1974  goto fail;
1975 
1976  attempts++;
1977  if (s->http_code == 407 &&
1978  (cur_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
1979  s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 2) {
1980  ffurl_closep(&s->hd);
1981  goto redo;
1982  }
1983 
1984  if (s->http_code < 400)
1985  return 0;
1986  ret = ff_http_averror(s->http_code, AVERROR(EIO));
1987 
1988 fail:
1989  http_proxy_close(h);
1990  return ret;
1991 }
1992 
1993 static int http_proxy_write(URLContext *h, const uint8_t *buf, int size)
1994 {
1995  HTTPContext *s = h->priv_data;
1996  return ffurl_write(s->hd, buf, size);
1997 }
1998 
2000  .name = "httpproxy",
2001  .url_open = http_proxy_open,
2002  .url_read = http_buf_read,
2003  .url_write = http_proxy_write,
2004  .url_close = http_proxy_close,
2005  .url_get_file_handle = http_get_file_handle,
2006  .priv_data_size = sizeof(HTTPContext),
2007  .flags = URL_PROTOCOL_FLAG_NETWORK,
2008 };
2009 #endif /* CONFIG_HTTPPROXY_PROTOCOL */
static int http_get_line(HTTPContext *s, char *line, int line_size)
Definition: http.c:694
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:4753
static void update_metadata(URLContext *h, char *data)
Definition: http.c:1617
static void parse_content_range(URLContext *h, const char *p)
Definition: http.c:747
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:1274
#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:320
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:1755
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:580
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:677
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:131
#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
int reconnect_on_network_error
Definition: http.c:122
#define MAX_URL_SIZE
Definition: internal.h:30
static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
Definition: http.c:880
#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:1838
static int http_buf_read(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1440
uint8_t
#define av_malloc(s)
int post_datalen
Definition: http.c:97
char * reconnect_on_http_error
Definition: http.c:125
AVOptions.
int ff_http_averror(int status_code, int default_averror)
Definition: http.c:447
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:1211
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:299
char * av_small_strptime(const char *p, const char *fmt, struct tm *dt)
Simplified version of strptime.
Definition: parseutils.c:489
static int http_should_reconnect(HTTPContext *s, int err)
Definition: http.c:265
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:137
#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:185
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:195
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
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:255
int ff_http_get_shutdown_status(URLContext *h)
Get the HTTP shutdown response status, be used after http_shutdown.
Definition: http.c:373
int is_multi_client
Definition: http.c:129
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:1775
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:124
#define E
Definition: http.c:136
const char * protocol_whitelist
Definition: url.h:49
static int http_write(URLContext *h, const uint8_t *buf, int size)
Definition: http.c:1700
int av_match_list(const char *name, const char *list, char separator)
Check if a name is in a list.
Definition: avstring.c:451
static const AVOption options[]
Definition: http.c:139
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:544
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:134
#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:1250
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:113
static int store_icy(URLContext *h, int size)
Definition: http.c:1645
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:1844
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:123
static int http_read(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1683
#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:1656
HandshakeState handshake_step
Definition: http.c:130
#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:1203
char * mime_type
Definition: http.c:77
#define SIZE_SPECIFIER
Definition: internal.h:191
#define flags(name, subs,...)
Definition: cbs_av1.c:561
#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:965
int ff_http_do_new_request(URLContext *h, const char *uri)
Send a new HTTP request, reusing the old connection.
Definition: http.c:389
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:762
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:1119
int http_code
Definition: http.c:67
char * filename
specified URL
Definition: url.h:42
int listen
Definition: http.c:126
static int http_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition: http.c:611
#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:942
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:733
char * resource
Definition: http.c:127
char * location
Definition: http.c:72
static int http_shutdown(URLContext *h, int flags)
Definition: http.c:1726
static int http_write_reply(URLContext *h, int status_code)
Definition: http.c:464
#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:135
#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:796
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:818
static int http_read_stream(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1549
#define av_freep(p)
static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
Definition: http.c:1605
#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:538
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:843
static int64_t http_seek(URLContext *h, int64_t off, int whence)
Definition: http.c:1833
static double val(void *priv, double ch)
Definition: aeval.c:76
int reply_code
Definition: http.c:128
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:653
int i
Definition: input.c:407
GLuint buffer
Definition: opengl_enc.c:101
#define HTTP_CLASS(flavor)
Definition: http.c:1850
No authentication specified.
Definition: httpauth.h:29
static int check_http_code(URLContext *h, int http_code, const char *end)
Definition: http.c:718
const char * name
Definition: opengl_enc.c:102
static uint8_t tmp[11]
Definition: aes_ctr.c:27