FFmpeg
Loading...
Searching...
No Matches
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 <stdbool.h>
23
24#include "config.h"
25#include "config_components.h"
26
27#include <string.h>
28#include <time.h>
29#if CONFIG_ZLIB
30#include <zlib.h>
31#endif /* CONFIG_ZLIB */
32
33#include "libavutil/avassert.h"
34#include "libavutil/avstring.h"
35#include "libavutil/bprint.h"
37#include "libavutil/macros.h"
38#include "libavutil/mem.h"
39#include "libavutil/opt.h"
40#include "libavutil/time.h"
42
43#include "avformat.h"
44#include "http.h"
45#include "httpauth.h"
46#include "internal.h"
47#include "network.h"
48#include "os_support.h"
49#include "url.h"
50#include "version.h"
51
52/* XXX: POST protocol is not completely implemented because ffmpeg uses
53 * only a subset of it. */
54
55/* The IO buffer size is unrelated to the max URL size in itself, but needs
56 * to be large enough to fit the full request headers (including long
57 * path names). */
58#define BUFFER_SIZE (MAX_URL_SIZE + HTTP_HEADERS_SIZE)
59#define MAX_REDIRECTS 8
60#define MAX_CACHED_REDIRECTS 32
61#define HTTP_SINGLE 1
62#define HTTP_MUTLI 2
63#define MAX_DATE_LEN 19
64#define WHITESPACES " \n\t\r"
71
72typedef struct HTTPContext {
73 const AVClass *class;
74 unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
75
76 /*************************
77 * Configuration options *
78 *************************/
79 uint64_t off, end_off; /* `off` is also mutated by seeking / reading */
80 char *location;
82 char *headers;
83 char *mime_type;
86 char *referer;
88 int seekable; /**< Control seekability, 0 = disable, 1 = enable, -1 = probe. */
90 int multiple_requests; /**< A flag which indicates if we use persistent connections. */
91 uint8_t *post_data;
93 char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
94 char *host;
95 int icy;
99 /* -1 = try to send if applicable, 0 = always disabled, 1 = always enabled */
101 char *method;
111 char *resource;
116 uint64_t request_size;
118
119 /**********************
120 * Context-wide state *
121 **********************/
122 HTTPAuthState auth_state; /* auth_state.auth_type is also a config option */
124 uint64_t filesize;
125 uint64_t oc_filesize; /* Complete size (200 Content-Length or Content-Range total) */
126 int end_of_resource; /* The end of an unknown-size resource was reached */
129 /* A dictionary containing cookies keyed by cookie name */
133
134 /* Connection statistics */
140 int64_t sum_latency; /* divide by nb_requests */
142
143 /************************
144 * Per-connection state *
145 ************************/
147 char *uri;
151 /* Used if "Transfer-Encoding: chunked" otherwise -1. */
152 uint64_t chunksize;
154 uint64_t range_end;
155 /* Set if the server correctly handles Connection: close and will close
156 * the connection after feeding us the content. */
158 /* A flag which indicates if the end of chunked encoding has been sent. */
160 /* A flag which indicates we have finished to read POST reply. */
162 /* how much data was read since the last ICY metadata packet */
164 /* after how many bytes of read data a new metadata packet will be found */
165 uint64_t icy_metaint;
166#if CONFIG_ZLIB
167 int compressed;
168 z_stream inflate_stream;
169 uint8_t *inflate_buffer;
170#endif /* CONFIG_ZLIB */
171 unsigned int retry_after;
172 int initial_requests; /* whether or not to limit requests to initial_request_size */
173
174 /* Temporary during header parsing */
176 /* Reply is a partial response with unknown total ("bytes A-B/" + '*'). */
179
180 /******************
181 * Listener state *
182 ******************/
183 /* URLContext *hd; */
188
189#define OFFSET(x) offsetof(HTTPContext, x)
190#define D AV_OPT_FLAG_DECODING_PARAM
191#define E AV_OPT_FLAG_ENCODING_PARAM
192#define DEFAULT_USER_AGENT "Lavf/" AV_STRINGIFY(LIBAVFORMAT_VERSION)
193
194static const AVOption http_options[] = {
195 { "seekable", "control seekability of connection", OFFSET(seekable), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, D },
196 { "chunked_post", "use chunked transfer-encoding for posts", OFFSET(chunked_post), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E },
197 { "http_proxy", "set HTTP proxy to tunnel through", OFFSET(http_proxy), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
198 { "headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
199 { "content_type", "set a specific content type for the POST messages", OFFSET(content_type), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
200 { "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D },
201 { "referer", "override referer header", OFFSET(referer), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D },
202 { "multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, D | E },
203 { "request_size", "size (in bytes) of requests to make", OFFSET(request_size), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
204 { "initial_request_size", "size (in bytes) of initial requests made during probing / header parsing", OFFSET(initial_request_size), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
205 { "post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D | E },
206 { "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 },
207 { "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 },
208 { "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 },
209 { "icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D },
210 { "icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT },
211 { "icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT },
212 { "metadata", "metadata read from the bitstream", OFFSET(metadata), AV_OPT_TYPE_DICT, {0}, 0, 0, AV_OPT_FLAG_EXPORT },
213 { "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, .unit = "auth_type"},
214 { "none", "No auth method set, autodetect", 0, AV_OPT_TYPE_CONST, { .i64 = HTTP_AUTH_NONE }, 0, 0, D | E, .unit = "auth_type"},
215 { "basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, { .i64 = HTTP_AUTH_BASIC }, 0, 0, D | E, .unit = "auth_type"},
216 { "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 },
217 { "location", "The actual location of the data received", OFFSET(location), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
218 { "offset", "initial byte offset", OFFSET(off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
219 { "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 },
220 { "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 },
221 { "reconnect", "auto reconnect after disconnect before EOF", OFFSET(reconnect), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
222 { "reconnect_at_eof", "auto reconnect at EOF", OFFSET(reconnect_at_eof), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
223 { "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 },
224 { "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 },
225 { "reconnect_streamed", "auto reconnect streamed / non seekable streams", OFFSET(reconnect_streamed), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
226 { "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 },
227 { "reconnect_max_retries", "the max number of times to retry a connection", OFFSET(reconnect_max_retries), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, D },
228 { "reconnect_delay_total_max", "max total reconnect delay in seconds after which to give up", OFFSET(reconnect_delay_total_max), AV_OPT_TYPE_INT, { .i64 = 256 }, 0, UINT_MAX/1000/1000, D },
229 { "respect_retry_after", "respect the Retry-After header when retrying connections", OFFSET(respect_retry_after), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D },
230 { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, D | E },
231 { "resource", "The resource requested by a client", OFFSET(resource), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
232 { "reply_code", "The http status code to return to a client", OFFSET(reply_code), AV_OPT_TYPE_INT, { .i64 = 200}, INT_MIN, 599, E},
233 { "short_seek_size", "Threshold to favor readahead over seek.", OFFSET(short_seek_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D },
234 { "max_redirects", "Maximum number of redirects", OFFSET(max_redirects), AV_OPT_TYPE_INT, { .i64 = MAX_REDIRECTS }, 0, INT_MAX, D },
235 { NULL }
236};
237
238static int http_connect(URLContext *h, const char *path, const char *local_path,
239 const char *hoststr, const char *auth,
240 const char *proxyauth);
241static int http_read_header(URLContext *h);
242static int http_shutdown(URLContext *h, int flags);
243
245{
246 memcpy(&((HTTPContext *)dest->priv_data)->auth_state,
247 &((HTTPContext *)src->priv_data)->auth_state,
248 sizeof(HTTPAuthState));
249 memcpy(&((HTTPContext *)dest->priv_data)->proxy_auth_state,
250 &((HTTPContext *)src->priv_data)->proxy_auth_state,
251 sizeof(HTTPAuthState));
252}
253
255{
256 const char *path, *proxy_path, *lower_proto = "tcp", *local_path;
257 char *env_http_proxy, *env_no_proxy;
258 char *hashmark;
259 char hostname[1024], hoststr[1024], proto[10], tmp_host[1024];
260 char auth[1024], proxyauth[1024] = "";
261 char path1[MAX_URL_SIZE], sanitized_path[MAX_URL_SIZE + 1];
262 char buf[1024], urlbuf[MAX_URL_SIZE];
263 int port, use_proxy, err = 0;
264 HTTPContext *s = h->priv_data;
265
266 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
267 hostname, sizeof(hostname), &port,
268 path1, sizeof(path1), s->location);
269
270 av_freep(&s->host);
271 s->host = av_strdup(hostname);
272 if (!s->host)
273 return AVERROR(ENOMEM);
274
275 av_strlcpy(tmp_host, hostname, sizeof(tmp_host));
276 // In case of an IPv6 address, we need to strip the Zone ID,
277 // if any. We do it at the first % sign, as percent encoding
278 // can be used in the Zone ID itself.
279 if (strchr(tmp_host, ':'))
280 tmp_host[strcspn(tmp_host, "%")] = '\0';
281 ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, tmp_host, port, NULL);
282
283 env_http_proxy = getenv_utf8("http_proxy");
284 proxy_path = s->http_proxy ? s->http_proxy : env_http_proxy;
285
286 env_no_proxy = getenv_utf8("no_proxy");
287 use_proxy = !ff_http_match_no_proxy(env_no_proxy, hostname) &&
288 proxy_path && av_strstart(proxy_path, "http://", NULL);
289 freeenv_utf8(env_no_proxy);
290
291 if (h->protocol_whitelist && av_match_list(proto, h->protocol_whitelist, ',') <= 0) {
292 av_log(h, AV_LOG_ERROR, "Protocol '%s' not on whitelist '%s'!\n", proto, h->protocol_whitelist);
293 return AVERROR(EINVAL);
294 }
295
296 if (h->protocol_blacklist && av_match_list(proto, h->protocol_blacklist, ',') > 0) {
297 av_log(h, AV_LOG_ERROR, "Protocol '%s' on blacklist '%s'!\n", proto, h->protocol_blacklist);
298 return AVERROR(EINVAL);
299 }
300
301 if (!strcmp(proto, "https")) {
302 lower_proto = "tls";
303 use_proxy = 0;
304 if (port < 0)
305 port = 443;
306 /* pass http_proxy to underlying protocol */
307 if (s->http_proxy) {
308 err = av_dict_set(options, "http_proxy", s->http_proxy, 0);
309 if (err < 0)
310 goto end;
311 }
312 } else if (strcmp(proto, "http")) {
313 err = AVERROR(EINVAL);
314 goto end;
315 }
316
317 if (port < 0)
318 port = 80;
319
320 hashmark = strchr(path1, '#');
321 if (hashmark)
322 *hashmark = '\0';
323
324 if (path1[0] == '\0') {
325 path = "/";
326 } else if (path1[0] == '?') {
327 snprintf(sanitized_path, sizeof(sanitized_path), "/%s", path1);
328 path = sanitized_path;
329 } else {
330 path = path1;
331 }
332 local_path = path;
333 if (use_proxy) {
334 /* Reassemble the request URL without auth string - we don't
335 * want to leak the auth to the proxy. */
336 ff_url_join(urlbuf, sizeof(urlbuf), proto, NULL, hostname, port, "%s",
337 path1);
338 path = urlbuf;
339 av_url_split(NULL, 0, proxyauth, sizeof(proxyauth),
340 hostname, sizeof(hostname), &port, NULL, 0, proxy_path);
341 }
342
343 ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL);
344
345 if (!s->hd) {
346 s->nb_connections++;
348 &h->interrupt_callback, options,
349 h->protocol_whitelist, h->protocol_blacklist, h);
350 }
351
352end:
353 freeenv_utf8(env_http_proxy);
354 return err < 0 ? err : http_connect(
355 h, path, local_path, hoststr, auth, proxyauth);
356}
357
359{
360 const char *status_group;
361 char http_code[4];
362
363 switch (err) {
370 status_group = "4xx";
371 break;
372
374 status_group = "5xx";
375 break;
376
377 default:
378 return s->reconnect_on_network_error;
379 }
380
381 if (!s->reconnect_on_http_error)
382 return 0;
383
384 if (av_match_list(status_group, s->reconnect_on_http_error, ',') > 0)
385 return 1;
386
387 snprintf(http_code, sizeof(http_code), "%d", s->http_code);
388
389 return av_match_list(http_code, s->reconnect_on_http_error, ',') > 0;
390}
391
393{
395 int64_t expiry;
396 char *delim;
397
398 re = av_dict_get(s->redirect_cache, s->location, NULL, AV_DICT_MATCH_CASE);
399 if (!re) {
400 return NULL;
401 }
402
403 delim = strchr(re->value, ';');
404 if (!delim) {
405 return NULL;
406 }
407
408 expiry = strtoll(re->value, NULL, 10);
409 if (time(NULL) > expiry) {
410 return NULL;
411 }
412
413 return delim + 1;
414}
415
416static int redirect_cache_set(HTTPContext *s, const char *source, const char *dest, int64_t expiry)
417{
418 char *value;
419 int ret;
420
421 value = av_asprintf("%"PRIi64";%s", expiry, dest);
422 if (!value) {
423 return AVERROR(ENOMEM);
424 }
425
426 ret = av_dict_set(&s->redirect_cache, source, value, AV_DICT_MATCH_CASE | AV_DICT_DONT_STRDUP_VAL);
427 if (ret < 0)
428 return ret;
429
430 return 0;
431}
432
433/* The redirects that http_open_cnx() follows. */
434static int is_redirect(int http_code)
435{
436 return http_code == 301 || http_code == 302 || http_code == 303 ||
437 http_code == 307 || http_code == 308;
438}
439
440/* A 416 reply for a resource of unknown size marks its end, unless it states
441 * a length past the refused offset. */
442static int is_end_of_resource(HTTPContext *s, int err, uint64_t off)
443{
444 return err == AVERROR_HTTP_OTHER_4XX && s->http_code == 416 &&
445 s->oc_filesize == UINT64_MAX &&
446 (s->filesize_from_content_range == UINT64_MAX ||
447 s->filesize_from_content_range <= off);
448}
449
450/* Return non zero if error. With end_is_eof, the caller reports the end of a
451 * resource of unknown size as EOF, and the 416 that marks it is retried only
452 * if reconnect_on_http_error lists 416 by number. */
453static int http_open_cnx(URLContext *h, AVDictionary **options, int end_is_eof)
454{
455 HTTPAuthType cur_auth_type, cur_proxy_auth_type;
456 HTTPContext *s = h->priv_data;
457 int ret, conn_attempts = 1, auth_attempts = 0, redirects = 0;
458 int reconnect_delay = 0;
459 int reconnect_delay_total = 0;
460 uint64_t off = s->off;
461 uint64_t filesize = s->filesize;
462 uint64_t oc_filesize = s->oc_filesize;
463 char *cached;
464
465redo:
466 /* every attempt starts with the complete size known before the call */
467 s->oc_filesize = oc_filesize;
468
469 cached = redirect_cache_get(s);
470 if (cached) {
471 if (redirects++ >= s->max_redirects) {
472 ret = AVERROR(EIO);
473 goto fail;
474 }
475
476 av_free(s->location);
477 s->location = av_strdup(cached);
478 if (!s->location) {
479 ret = AVERROR(ENOMEM);
480 goto fail;
481 }
482 goto redo;
483 }
484
485 av_dict_copy(options, s->chained_options, 0);
486
487 cur_auth_type = s->auth_state.auth_type;
488 cur_proxy_auth_type = s->auth_state.auth_type;
489
490 off = s->off;
491 s->http_code = 0;
493 if (ret < 0) {
494 if (!http_should_reconnect(s, ret) ||
495 (end_is_eof && is_end_of_resource(s, ret, off) &&
496 !av_match_list("416", s->reconnect_on_http_error, ',')) ||
497 reconnect_delay > s->reconnect_delay_max ||
498 (s->reconnect_max_retries >= 0 && conn_attempts > s->reconnect_max_retries) ||
499 reconnect_delay_total > s->reconnect_delay_total_max)
500 goto fail;
501
502 /* Both fields here are in seconds. */
503 if (s->respect_retry_after && s->retry_after > 0) {
504 reconnect_delay = s->retry_after;
505 if (reconnect_delay > s->reconnect_delay_max)
506 goto fail;
507 s->retry_after = 0;
508 s->nb_retries++;
509 }
510
511 av_log(h, AV_LOG_WARNING, "Will %s at %"PRIu64" in %d second(s).\n",
512 s->willclose ? "reconnect" : "retry", off, reconnect_delay);
513 ret = ff_network_sleep_interruptible(1000U * 1000 * reconnect_delay, &h->interrupt_callback);
514 if (ret != AVERROR(ETIMEDOUT))
515 goto fail;
516 reconnect_delay_total += reconnect_delay;
517 reconnect_delay = 1 + 2 * reconnect_delay;
518 s->nb_reconnects++;
519 conn_attempts++;
520
521 /* restore the offset (http_connect resets it) */
522 s->off = off;
523
524 ffurl_closep(&s->hd);
525 goto redo;
526 }
527
528 auth_attempts++;
529 if (s->http_code == 401) {
530 if ((cur_auth_type == HTTP_AUTH_NONE || s->auth_state.stale) &&
531 s->auth_state.auth_type != HTTP_AUTH_NONE && auth_attempts < 4) {
532 ffurl_closep(&s->hd);
533 goto redo;
534 } else
535 goto fail;
536 }
537 if (s->http_code == 407) {
538 if ((cur_proxy_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
539 s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && auth_attempts < 4) {
540 ffurl_closep(&s->hd);
541 goto redo;
542 } else
543 goto fail;
544 }
545 if (is_redirect(s->http_code) && s->new_location) {
546 /* url moved, get next */
547 ffurl_closep(&s->hd);
548 if (redirects++ >= s->max_redirects) {
549 ret = AVERROR(EIO);
550 goto fail;
551 }
552
553 if (!s->expires) {
554 s->expires = (s->http_code == 301 || s->http_code == 308) ? INT64_MAX : -1;
555 }
556
557 if (s->expires > time(NULL) && av_dict_count(s->redirect_cache) < MAX_CACHED_REDIRECTS) {
558 redirect_cache_set(s, s->location, s->new_location, s->expires);
559 }
560
561 av_free(s->location);
562 s->location = s->new_location;
563 s->new_location = NULL;
564 s->nb_redirects++;
565
566 /* Restart the authentication process with the new target, which
567 * might use a different auth mechanism. */
568 memset(&s->auth_state, 0, sizeof(s->auth_state));
569 auth_attempts = 0;
570 goto redo;
571 }
572 return 0;
573
574fail:
575 s->off = off;
576 s->filesize = filesize;
577 s->oc_filesize = oc_filesize;
578 if (s->hd)
579 ffurl_closep(&s->hd);
580 if (ret < 0)
581 return ret;
582 return ff_http_averror(s->http_code, AVERROR(EIO));
583}
584
585int ff_http_do_new_request(URLContext *h, const char *uri) {
586 return ff_http_do_new_request2(h, uri, NULL);
587}
588
590{
591 HTTPContext *s = h->priv_data;
593 int ret;
594 char hostname1[1024], hostname2[1024], proto1[10], proto2[10];
595 int port1, port2;
596
597 if (!h->prot ||
598 !(!strcmp(h->prot->name, "http") ||
599 !strcmp(h->prot->name, "https")))
600 return AVERROR(EINVAL);
601
602 av_url_split(proto1, sizeof(proto1), NULL, 0,
603 hostname1, sizeof(hostname1), &port1,
604 NULL, 0, s->location);
605 av_url_split(proto2, sizeof(proto2), NULL, 0,
606 hostname2, sizeof(hostname2), &port2,
607 NULL, 0, uri);
608 if (strcmp(proto1, proto2) != 0) {
609 av_log(h, AV_LOG_INFO, "Cannot reuse HTTP connection for different protocol %s vs %s\n",
610 proto1, proto2);
611 return AVERROR(EINVAL);
612 }
613 if (port1 != port2 || strncmp(hostname1, hostname2, sizeof(hostname2)) != 0) {
614 av_log(h, AV_LOG_INFO, "Cannot reuse HTTP connection for different host: %s:%d != %s:%d\n",
615 hostname1, port1,
616 hostname2, port2
617 );
618 return AVERROR(EINVAL);
619 }
620
621 if (!s->end_chunked_post) {
622 ret = http_shutdown(h, h->flags);
623 if (ret < 0)
624 return ret;
625 }
626
627 if (s->willclose)
628 return AVERROR_EOF;
629
630 s->end_chunked_post = 0;
631 s->chunkend = 0;
632 s->range_end = 0;
633 s->off = 0;
634 s->oc_filesize = UINT64_MAX;
635 s->end_of_resource = 0;
636 s->icy_data_read = 0;
637
638 av_free(s->location);
639 s->location = av_strdup(uri);
640 if (!s->location)
641 return AVERROR(ENOMEM);
642
643 av_free(s->uri);
644 s->uri = av_strdup(uri);
645 if (!s->uri)
646 return AVERROR(ENOMEM);
647
648 if ((ret = av_opt_set_dict(s, opts)) < 0)
649 return ret;
650
651 av_log(s, AV_LOG_INFO, "Opening \'%s\' for %s\n", uri, h->flags & AVIO_FLAG_WRITE ? "writing" : "reading");
652 ret = http_open_cnx(h, &options, 0);
654 return ret;
655}
656
658{
659 HTTPContext *s = h->priv_data;
660 return s->new_location;
661}
662
663static int http_write_reply(URLContext* h, int status_code)
664{
665 int ret, body = 0, reply_code, message_len;
666 const char *reply_text, *content_type;
667 HTTPContext *s = h->priv_data;
668 char message[BUFFER_SIZE];
669 content_type = "text/plain";
670
671 if (status_code < 0)
672 body = 1;
673 switch (status_code) {
675 case 400:
676 reply_code = 400;
677 reply_text = "Bad Request";
678 break;
680 case 403:
681 reply_code = 403;
682 reply_text = "Forbidden";
683 break;
685 case 404:
686 reply_code = 404;
687 reply_text = "Not Found";
688 break;
690 case 429:
691 reply_code = 429;
692 reply_text = "Too Many Requests";
693 break;
694 case 200:
695 reply_code = 200;
696 reply_text = "OK";
697 content_type = s->content_type ? s->content_type : "application/octet-stream";
698 break;
700 case 500:
701 reply_code = 500;
702 reply_text = "Internal server error";
703 break;
704 default:
705 return AVERROR(EINVAL);
706 }
707 if (body) {
708 s->chunked_post = 0;
709 message_len = snprintf(message, sizeof(message),
710 "HTTP/1.1 %03d %s\r\n"
711 "Content-Type: %s\r\n"
712 "Content-Length: %zu\r\n"
713 "%s"
714 "\r\n"
715 "%03d %s\r\n",
716 reply_code,
717 reply_text,
718 content_type,
719 strlen(reply_text) + 6, // 3 digit status code + space + \r\n
720 s->headers ? s->headers : "",
721 reply_code,
722 reply_text);
723 } else {
724 s->chunked_post = 1;
725 message_len = snprintf(message, sizeof(message),
726 "HTTP/1.1 %03d %s\r\n"
727 "Content-Type: %s\r\n"
728 "Transfer-Encoding: chunked\r\n"
729 "%s"
730 "\r\n",
731 reply_code,
732 reply_text,
733 content_type,
734 s->headers ? s->headers : "");
735 }
736 av_log(h, AV_LOG_TRACE, "HTTP reply header: \n%s----\n", message);
737 if ((ret = ffurl_write(s->hd, message, message_len)) < 0)
738 return ret;
739 return 0;
740}
741
743{
744 av_assert0(error < 0);
746}
747
749{
750 int ret, err;
751 HTTPContext *ch = c->priv_data;
752 URLContext *cl = ch->hd;
753 switch (ch->handshake_step) {
754 case LOWER_PROTO:
755 av_log(c, AV_LOG_TRACE, "Lower protocol\n");
756 if ((ret = ffurl_handshake(cl)) > 0)
757 return 2 + ret;
758 if (ret < 0)
759 return ret;
761 ch->is_connected_server = 1;
762 return 2;
763 case READ_HEADERS:
764 av_log(c, AV_LOG_TRACE, "Read headers\n");
765 if ((err = http_read_header(c)) < 0) {
766 handle_http_errors(c, err);
767 return err;
768 }
770 return 1;
772 av_log(c, AV_LOG_TRACE, "Reply code: %d\n", ch->reply_code);
773 if ((err = http_write_reply(c, ch->reply_code)) < 0)
774 return err;
776 return 1;
777 case FINISH:
778 return 0;
779 }
780 // this should never be reached.
781 return AVERROR(EINVAL);
782}
783
784static int http_listen(URLContext *h, const char *uri, int flags,
786 HTTPContext *s = h->priv_data;
787 int ret;
788 char hostname[1024], proto[10];
789 char lower_url[100];
790 const char *lower_proto = "tcp";
791 int port;
792 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
793 NULL, 0, uri);
794 if (!strcmp(proto, "https"))
795 lower_proto = "tls";
796 ff_url_join(lower_url, sizeof(lower_url), lower_proto, NULL, hostname, port,
797 NULL);
798 if ((ret = av_dict_set_int(options, "listen", s->listen, 0)) < 0)
799 goto fail;
800 if ((ret = ffurl_open_whitelist(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
801 &h->interrupt_callback, options,
802 h->protocol_whitelist, h->protocol_blacklist, h
803 )) < 0)
804 goto fail;
805 s->handshake_step = LOWER_PROTO;
806 if (s->listen == HTTP_SINGLE) { /* single client */
807 s->reply_code = 200;
808 while ((ret = http_handshake(h)) > 0);
809 }
810fail:
811 av_dict_free(&s->chained_options);
812 av_dict_free(&s->cookie_dict);
813 return ret;
814}
815
816static int http_open(URLContext *h, const char *uri, int flags,
818{
819 HTTPContext *s = h->priv_data;
820 int ret;
821
822 if( s->seekable == 1 )
823 h->is_streamed = 0;
824 else
825 h->is_streamed = 1;
826
827 s->initial_requests = s->seekable != 0 && s->initial_request_size > 0;
828 s->filesize = UINT64_MAX;
829 s->oc_filesize = UINT64_MAX;
830 s->end_of_resource = 0;
831
832 s->location = av_strdup(uri);
833 if (!s->location)
834 return AVERROR(ENOMEM);
835
836 s->uri = av_strdup(uri);
837 if (!s->uri)
838 return AVERROR(ENOMEM);
839
840 if (options)
841 av_dict_copy(&s->chained_options, *options, 0);
842
843 if (s->headers) {
844 int len = strlen(s->headers);
845 if (len < 2 || strcmp("\r\n", s->headers + len - 2)) {
847 "No trailing CRLF found in HTTP header. Adding it.\n");
848 ret = av_reallocp(&s->headers, len + 3);
849 if (ret < 0)
850 goto bail_out;
851 s->headers[len] = '\r';
852 s->headers[len + 1] = '\n';
853 s->headers[len + 2] = '\0';
854 }
855 }
856
857 if (s->listen) {
858 return http_listen(h, uri, flags, options);
859 }
860 ret = http_open_cnx(h, options, 0);
861bail_out:
862 if (ret < 0) {
863 av_dict_free(&s->chained_options);
864 av_dict_free(&s->cookie_dict);
865 av_dict_free(&s->redirect_cache);
866 av_freep(&s->new_location);
867 av_freep(&s->uri);
868 av_freep(&s->host);
869 }
870 return ret;
871}
872
874{
875 int ret;
876 HTTPContext *sc = s->priv_data;
877 HTTPContext *cc;
878 URLContext *sl = sc->hd;
879 URLContext *cl = NULL;
880
881 av_assert0(sc->listen);
882 if ((ret = ffurl_alloc(c, s->filename, s->flags, &sl->interrupt_callback)) < 0)
883 goto fail;
884 cc = (*c)->priv_data;
885 if ((ret = ffurl_accept(sl, &cl)) < 0)
886 goto fail;
887 cc->hd = cl;
888 cc->is_multi_client = 1;
889 return 0;
890fail:
891 if (c) {
893 }
894 return ret;
895}
896
898{
899 int len;
900 if (s->buf_ptr >= s->buf_end) {
901 len = ffurl_read(s->hd, s->buffer, BUFFER_SIZE);
902 if (len < 0) {
903 return len;
904 } else if (len == 0) {
905 return AVERROR_EOF;
906 } else {
907 s->buf_ptr = s->buffer;
908 s->buf_end = s->buffer + len;
909 }
910 }
911 return *s->buf_ptr++;
912}
913
914static int http_get_line(HTTPContext *s, char *line, int line_size)
915{
916 int ch;
917 char *q;
918
919 q = line;
920 for (;;) {
921 ch = http_getc(s);
922 if (ch < 0)
923 return ch;
924 if (ch == '\n') {
925 /* process line */
926 if (q > line && q[-1] == '\r')
927 q--;
928 *q = '\0';
929
930 return 0;
931 } else {
932 if ((q - line) < line_size - 1)
933 *q++ = ch;
934 }
935 }
936}
937
938int ff_http_parse_status_line(void *logctx, const char *line, HTTPStatusLine *st)
939{
940 const char *p;
941
942 memset(st, 0, sizeof(*st));
943
944 if (!av_strstart(line, "HTTP/", &p) ||
945 !av_isdigit(p[0]) || p[1] != '.' || !av_isdigit(p[2]) ||
946 !av_isspace(p[3])) {
947 av_log(logctx, AV_LOG_ERROR, "Malformed HTTP status line.\n");
948 return AVERROR_INVALIDDATA;
949 }
950
951 av_strlcpy(st->version, p, sizeof(st->version));
952 st->willclose = !strcmp(st->version, "1.0");
953
954 p += 3;
955 while (av_isspace(*p))
956 p++;
957
958 /* RFC 9112 mandates a space after the code, but a bare "HTTP/1.1 200"
959 * is common enough in the wild to be worth accepting. */
960 if (!av_isdigit(p[0]) || !av_isdigit(p[1]) || !av_isdigit(p[2]) ||
961 (p[3] && !av_isspace(p[3]))) {
962 av_log(logctx, AV_LOG_ERROR, "Malformed HTTP status code.\n");
963 return AVERROR_INVALIDDATA;
964 }
965
966 st->code = 100 * (p[0] - '0') + 10 * (p[1] - '0') + p[2] - '0';
967 if (st->code < 100 || st->code > 599) {
968 av_log(logctx, AV_LOG_ERROR, "HTTP status code %d out of range.\n",
969 st->code);
970 return AVERROR_INVALIDDATA;
971 }
972 p += 3;
973 while (av_isspace(*p))
974 p++;
975 st->reason = p;
976
977 av_log(logctx, AV_LOG_TRACE, "http_code=%d\n", st->code);
978
979 return 0;
980}
981
982static int check_http_code(URLContext *h, int http_code, const char *end)
983{
984 HTTPContext *s = h->priv_data;
985 /* error codes are 4xx and 5xx, but regard 401 as a success, so we
986 * don't abort until all headers have been parsed. */
987 if (http_code >= 400 && http_code < 600 &&
988 (http_code != 401 || s->auth_state.auth_type != HTTP_AUTH_NONE) &&
989 (http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) {
990 av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n", http_code, end);
991 return ff_http_averror(http_code, AVERROR(EIO));
992 }
993 return 0;
994}
995
996static int parse_location(HTTPContext *s, const char *p)
997{
998 char redirected_location[MAX_URL_SIZE];
999 ff_make_absolute_url(redirected_location, sizeof(redirected_location),
1000 s->location, p);
1001 av_freep(&s->new_location);
1002 s->new_location = av_strdup(redirected_location);
1003 if (!s->new_location)
1004 return AVERROR(ENOMEM);
1005 return 0;
1006}
1007
1008/* "bytes $from-$to/$document_size" */
1009static int parse_content_range(URLContext *h, const char *p)
1010{
1011 HTTPContext *s = h->priv_data;
1012 const char *slash, *end;
1013
1014 if (!strncmp(p, "bytes ", 6)) {
1015 p += 6;
1016 s->off = strtoull(p, NULL, 10);
1017 s->range_end = 0;
1018 if ((end = strchr(p, '-')) && strlen(end) > 0) {
1019 s->range_end = strtoull(end + 1, NULL, 10) + 1;
1020 if (s->range_end <= s->off) {
1021 av_log(h, AV_LOG_ERROR, "Invalid Content-Range: end %"PRIu64" before start %"PRIu64"\n",
1022 s->range_end - 1, s->off);
1023 return AVERROR_INVALIDDATA;
1024 }
1025 }
1026 if ((slash = strchr(p, '/')) && strlen(slash) > 0) {
1027 if (av_isdigit(slash[1]))
1028 s->filesize_from_content_range = strtoull(slash + 1, NULL, 10);
1029 else
1030 s->content_range_unknown_size = 1; /* unknown total size */
1031 }
1032 }
1033 if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647))
1034 h->is_streamed = 0; /* we _can_ in fact seek */
1035 return 0;
1036}
1037
1038static int parse_content_encoding(URLContext *h, const char *p)
1039{
1040 if (!av_strncasecmp(p, "gzip", 4) ||
1041 !av_strncasecmp(p, "deflate", 7)) {
1042#if CONFIG_ZLIB
1043 HTTPContext *s = h->priv_data;
1044
1045 s->compressed = 1;
1046 inflateEnd(&s->inflate_stream);
1047 if (inflateInit2(&s->inflate_stream, 32 + 15) != Z_OK) {
1048 av_log(h, AV_LOG_WARNING, "Error during zlib initialisation: %s\n",
1049 s->inflate_stream.msg);
1050 return AVERROR(ENOSYS);
1051 }
1052 if (zlibCompileFlags() & (1 << 17)) {
1054 "Your zlib was compiled without gzip support.\n");
1055 return AVERROR(ENOSYS);
1056 }
1057#else
1059 "Compressed (%s) content, need zlib with gzip support\n", p);
1060 return AVERROR(ENOSYS);
1061#endif /* CONFIG_ZLIB */
1062 } else if (!av_strncasecmp(p, "identity", 8)) {
1063 // The normal, no-encoding case (although servers shouldn't include
1064 // the header at all if this is the case).
1065 } else {
1066 av_log(h, AV_LOG_WARNING, "Unknown content coding: %s\n", p);
1067 }
1068 return 0;
1069}
1070
1071// Concat all Icy- header lines
1072static int parse_icy(HTTPContext *s, const char *tag, const char *p)
1073{
1074 int len = 4 + strlen(p) + strlen(tag);
1075 int is_first = !s->icy_metadata_headers;
1076 int ret;
1077
1078 av_dict_set(&s->metadata, tag, p, 0);
1079
1080 if (s->icy_metadata_headers)
1081 len += strlen(s->icy_metadata_headers);
1082
1083 if ((ret = av_reallocp(&s->icy_metadata_headers, len)) < 0)
1084 return ret;
1085
1086 if (is_first)
1087 *s->icy_metadata_headers = '\0';
1088
1089 av_strlcatf(s->icy_metadata_headers, len, "%s: %s\n", tag, p);
1090
1091 return 0;
1092}
1093
1094static int parse_http_date(const char *date_str, struct tm *buf)
1095{
1096 char date_buf[MAX_DATE_LEN];
1097 int i, j, date_buf_len = MAX_DATE_LEN-1;
1098 char *date;
1099
1100 // strip off any punctuation or whitespace
1101 for (i = 0, j = 0; date_str[i] != '\0' && j < date_buf_len; i++) {
1102 if ((date_str[i] >= '0' && date_str[i] <= '9') ||
1103 (date_str[i] >= 'A' && date_str[i] <= 'Z') ||
1104 (date_str[i] >= 'a' && date_str[i] <= 'z')) {
1105 date_buf[j] = date_str[i];
1106 j++;
1107 }
1108 }
1109 date_buf[j] = '\0';
1110 date = date_buf;
1111
1112 // move the string beyond the day of week
1113 while ((*date < '0' || *date > '9') && *date != '\0')
1114 date++;
1115
1116 return av_small_strptime(date, "%d%b%Y%H%M%S", buf) ? 0 : AVERROR(EINVAL);
1117}
1118
1119static int parse_set_cookie(const char *set_cookie, AVDictionary **dict)
1120{
1121 char *param, *next_param, *cstr, *back;
1122 char *saveptr = NULL;
1123
1124 if (!set_cookie[0])
1125 return 0;
1126
1127 if (!(cstr = av_strdup(set_cookie)))
1128 return AVERROR(EINVAL);
1129
1130 // strip any trailing whitespace
1131 back = &cstr[strlen(cstr)-1];
1132 while (strchr(WHITESPACES, *back)) {
1133 *back='\0';
1134 if (back == cstr)
1135 break;
1136 back--;
1137 }
1138
1139 next_param = cstr;
1140 while ((param = av_strtok(next_param, ";", &saveptr))) {
1141 char *name, *value;
1142 next_param = NULL;
1143 param += strspn(param, WHITESPACES);
1144 if ((name = av_strtok(param, "=", &value))) {
1145 char *end = name + strlen(name);
1146 while (end > name && strchr(WHITESPACES, end[-1]))
1147 *--end = '\0';
1148 if (av_dict_set(dict, name, value ? value : "", 0) < 0) {
1149 av_free(cstr);
1150 return -1;
1151 }
1152 }
1153 }
1154
1155 av_free(cstr);
1156 return 0;
1157}
1158
1159static const char *cookie_domain(const AVDictionary *cookie_params)
1160{
1161 const AVDictionaryEntry *e = av_dict_get(cookie_params, "domain", NULL, 0);
1162 const char *domain = e ? e->value + (e->value[0] == '.') : "";
1163
1164 return *domain ? domain : NULL;
1165}
1166
1167static int host_is_ip_literal(const char *host)
1168{
1169 return !host[strspn(host, "0123456789.")] || strchr(host, ':');
1170}
1171
1172static int host_in_cookie_domain(const char *host, const char *domain)
1173{
1174 int offset = strlen(host) - strlen(domain);
1175
1176 return offset >= 0 && !av_strcasecmp(host + offset, domain) &&
1177 (!offset || (host[offset - 1] == '.' && !host_is_ip_literal(host)));
1178}
1179
1180static int parse_cookie(HTTPContext *s, const char *p, const char *host,
1181 AVDictionary **cookies)
1182{
1183 AVDictionary *new_params = NULL;
1184 const AVDictionaryEntry *e, *cookie_entry;
1185 const char *eql;
1186 char *name, *value;
1187 int len;
1188
1189 // ensure the cookie is parsable
1190 if (parse_set_cookie(p, &new_params)) {
1191 av_dict_free(&new_params);
1192 return -1;
1193 }
1194
1195 // if there is no cookie value there is nothing to parse
1196 cookie_entry = av_dict_iterate(new_params, NULL);
1197 if (!cookie_entry || !cookie_entry->value) {
1198 av_dict_free(&new_params);
1199 return -1;
1200 }
1201
1202 // ensure the cookie is not expired or older than an existing value
1203 if ((e = av_dict_get(new_params, "expires", NULL, 0)) && e->value) {
1204 struct tm new_tm = {0};
1205 if (!parse_http_date(e->value, &new_tm)) {
1207
1208 // if the cookie has already expired ignore it
1209 if (av_timegm(&new_tm) < av_gettime() / 1000000) {
1210 av_dict_free(&new_params);
1211 return 0;
1212 }
1213
1214 // only replace an older cookie with the same name
1215 e2 = av_dict_get(*cookies, cookie_entry->key, NULL, 0);
1216 if (e2 && e2->value) {
1217 AVDictionary *old_params = NULL;
1218 if (!parse_set_cookie(p, &old_params)) {
1219 e2 = av_dict_get(old_params, "expires", NULL, 0);
1220 if (e2 && e2->value) {
1221 struct tm old_tm = {0};
1222 if (!parse_http_date(e->value, &old_tm)) {
1223 if (av_timegm(&new_tm) < av_timegm(&old_tm)) {
1224 av_dict_free(&new_params);
1225 av_dict_free(&old_params);
1226 return -1;
1227 }
1228 }
1229 }
1230 }
1231 av_dict_free(&old_params);
1232 }
1233 }
1234 }
1235 const char *domain = host ? cookie_domain(new_params) : NULL;
1236 int host_only = host && !domain;
1237 if (domain && !host_in_cookie_domain(host, domain)) {
1238 av_log(s, AV_LOG_WARNING, "Ignoring cookie for domain %s set by %s\n", domain, host);
1239 av_dict_free(&new_params);
1240 return 0;
1241 }
1242 av_dict_free(&new_params);
1243
1244 // duplicate the cookie name (dict will dupe the value)
1245 if (!(eql = strchr(p, '='))) return AVERROR(EINVAL);
1246 if (!(name = av_strndup(p, eql - p))) return AVERROR(ENOMEM);
1247
1248 // add the cookie to the dictionary
1249 len = strlen(eql);
1250 while (len && strchr(WHITESPACES, eql[len - 1]))
1251 len--;
1252 value = av_asprintf("%.*s%s%s", len, eql, host_only ? "; @hostonly=" : "", host_only ? host : "");
1253 if (!value) {
1254 av_free(name);
1255 return AVERROR(ENOMEM);
1256 }
1258
1259 return 0;
1260}
1261
1262static int cookie_string(AVDictionary *dict, char **cookies)
1263{
1264 const AVDictionaryEntry *e = NULL;
1265 int len = 1;
1266
1267 // determine how much memory is needed for the cookies string
1268 while ((e = av_dict_iterate(dict, e)))
1269 len += strlen(e->key) + strlen(e->value) + 1;
1270
1271 // reallocate the cookies
1272 e = NULL;
1273 if (*cookies) av_free(*cookies);
1274 *cookies = av_malloc(len);
1275 if (!*cookies) return AVERROR(ENOMEM);
1276 *cookies[0] = '\0';
1277
1278 // write out the cookies
1279 while ((e = av_dict_iterate(dict, e)))
1280 av_strlcatf(*cookies, len, "%s%s\n", e->key, e->value);
1281
1282 return 0;
1283}
1284
1285static void parse_expires(HTTPContext *s, const char *p)
1286{
1287 struct tm tm;
1288
1289 if (!parse_http_date(p, &tm)) {
1290 s->expires = av_timegm(&tm);
1291 }
1292}
1293
1294static void parse_cache_control(HTTPContext *s, const char *p)
1295{
1296 char *age;
1297 int offset;
1298
1299 /* give 'Expires' higher priority over 'Cache-Control' */
1300 if (s->expires) {
1301 return;
1302 }
1303
1304 if (av_stristr(p, "no-cache") || av_stristr(p, "no-store")) {
1305 s->expires = -1;
1306 return;
1307 }
1308
1309 age = av_stristr(p, "s-maxage=");
1310 offset = 9;
1311 if (!age) {
1312 age = av_stristr(p, "max-age=");
1313 offset = 8;
1314 }
1315
1316 if (age) {
1317 s->expires = time(NULL) + atoi(age + offset);
1318 }
1319}
1320
1321static int process_line(URLContext *h, char *line, int line_count, int *parsed_http_code)
1322{
1323 HTTPContext *s = h->priv_data;
1324 const char *auto_method = h->flags & AVIO_FLAG_READ ? "POST" : "GET";
1325 char *tag, *p, *method, *resource, *version;
1326 int ret;
1327
1328 /* end of header */
1329 if (line[0] == '\0') {
1330 s->end_header = 1;
1331 return 0;
1332 }
1333
1334 p = line;
1335 if (line_count == 0) {
1336 if (s->is_connected_server) {
1337 // HTTP method
1338 method = p;
1339 while (*p && !av_isspace(*p))
1340 p++;
1341 if (!av_isspace(*p))
1343 *(p++) = '\0';
1344 av_log(h, AV_LOG_TRACE, "Received method: %s\n", method);
1345 if (s->method) {
1346 if (av_strcasecmp(s->method, method)) {
1347 av_log(h, AV_LOG_ERROR, "Received and expected HTTP method do not match. (%s expected, %s received)\n",
1348 s->method, method);
1350 }
1351 } else {
1352 // use autodetected HTTP method to expect
1353 av_log(h, AV_LOG_TRACE, "Autodetected %s HTTP method\n", auto_method);
1354 if (av_strcasecmp(auto_method, method)) {
1355 av_log(h, AV_LOG_ERROR, "Received and autodetected HTTP method did not match "
1356 "(%s autodetected %s received)\n", auto_method, method);
1358 }
1359 if (!(s->method = av_strdup(method)))
1360 return AVERROR(ENOMEM);
1361 }
1362
1363 // HTTP resource
1364 while (av_isspace(*p))
1365 p++;
1366 resource = p;
1367 while (*p && !av_isspace(*p))
1368 p++;
1369 if (!av_isspace(*p))
1371 *(p++) = '\0';
1372 av_log(h, AV_LOG_TRACE, "Requested resource: %s\n", resource);
1373 if (!(s->resource = av_strdup(resource)))
1374 return AVERROR(ENOMEM);
1375
1376 // HTTP version
1377 while (av_isspace(*p))
1378 p++;
1379 version = p;
1380 while (*p && !av_isspace(*p))
1381 p++;
1382 *p = '\0';
1383 if (av_strncasecmp(version, "HTTP/", 5)) {
1384 av_log(h, AV_LOG_ERROR, "Malformed HTTP version string.\n");
1386 }
1387 av_log(h, AV_LOG_TRACE, "HTTP version string: %s\n", version);
1388 } else {
1389 HTTPStatusLine st;
1390
1391 if ((ret = ff_http_parse_status_line(h, p, &st)) < 0)
1392 return ret;
1393
1394 /* Only ever set: a keep-alive decision made earlier must survive. */
1395 if (st.willclose)
1396 s->willclose = 1;
1397
1398 av_freep(&s->http_version);
1399 if (!(s->http_version = av_strdup(st.version)))
1400 return AVERROR(ENOMEM);
1401
1402 s->http_code = st.code;
1403
1404 *parsed_http_code = 1;
1405
1406 if ((ret = check_http_code(h, s->http_code, st.reason)) < 0)
1407 return ret;
1408 }
1409 } else {
1410 while (*p != '\0' && *p != ':')
1411 p++;
1412 if (*p != ':')
1413 return 1;
1414
1415 *p = '\0';
1416 tag = line;
1417 p++;
1418 while (av_isspace(*p))
1419 p++;
1420 if (!av_strcasecmp(tag, "Location")) {
1421 if ((ret = parse_location(s, p)) < 0)
1422 return ret;
1423 } else if (!av_strcasecmp(tag, "Content-Length") &&
1424 s->filesize == UINT64_MAX) {
1425 s->filesize = strtoull(p, NULL, 10);
1426 } else if (!av_strcasecmp(tag, "Content-Range")) {
1427 if ((ret = parse_content_range(h, p)) < 0)
1428 return ret;
1429 } else if (!av_strcasecmp(tag, "Accept-Ranges") &&
1430 !strncmp(p, "bytes", 5) &&
1431 s->seekable == -1) {
1432 h->is_streamed = 0;
1433 } else if (!av_strcasecmp(tag, "Transfer-Encoding") &&
1434 !av_strncasecmp(p, "chunked", 7)) {
1435 s->filesize = UINT64_MAX;
1436 s->chunksize = 0;
1437 } else if (!av_strcasecmp(tag, "WWW-Authenticate")) {
1438 ff_http_auth_handle_header(&s->auth_state, tag, p);
1439 } else if (!av_strcasecmp(tag, "Authentication-Info")) {
1440 ff_http_auth_handle_header(&s->auth_state, tag, p);
1441 } else if (!av_strcasecmp(tag, "Proxy-Authenticate")) {
1442 ff_http_auth_handle_header(&s->proxy_auth_state, tag, p);
1443 } else if (!av_strcasecmp(tag, "Connection")) {
1444 if (!av_strcasecmp(p, "close"))
1445 s->willclose = 1;
1446 } else if (!av_strcasecmp(tag, "Server")) {
1447 if (!av_strcasecmp(p, "AkamaiGHost")) {
1448 s->is_akamai = 1;
1449 } else if (!av_strncasecmp(p, "MediaGateway", 12)) {
1450 s->is_mediagateway = 1;
1451 }
1452 } else if (!av_strcasecmp(tag, "Content-Type")) {
1453 av_free(s->mime_type);
1454 s->mime_type = av_get_token((const char **)&p, ";");
1455 } else if (!av_strcasecmp(tag, "Set-Cookie")) {
1456 if (parse_cookie(s, p, s->host, &s->cookie_dict))
1457 av_log(h, AV_LOG_WARNING, "Unable to parse '%s'\n", p);
1458 } else if (!av_strcasecmp(tag, "Icy-MetaInt")) {
1459 s->icy_metaint = strtoull(p, NULL, 10);
1460 } else if (!av_strncasecmp(tag, "Icy-", 4)) {
1461 if ((ret = parse_icy(s, tag, p)) < 0)
1462 return ret;
1463 } else if (!av_strcasecmp(tag, "Content-Encoding")) {
1464 if ((ret = parse_content_encoding(h, p)) < 0)
1465 return ret;
1466 } else if (!av_strcasecmp(tag, "Expires")) {
1467 parse_expires(s, p);
1468 } else if (!av_strcasecmp(tag, "Cache-Control")) {
1470 } else if (!av_strcasecmp(tag, "Retry-After")) {
1471 /* The header can be either an integer that represents seconds, or a date. */
1472 struct tm tm;
1473 int date_ret = parse_http_date(p, &tm);
1474 if (!date_ret) {
1475 time_t retry = av_timegm(&tm);
1476 int64_t now = av_gettime() / 1000000;
1477 int64_t diff = ((int64_t) retry) - now;
1478 s->retry_after = (unsigned int) FFMAX(0, diff);
1479 } else {
1480 s->retry_after = strtoul(p, NULL, 10);
1481 }
1482 }
1483 }
1484 return 1;
1485}
1486
1487/**
1488 * Create a string containing cookie values for use as a HTTP cookie header
1489 * field value for a particular path and domain from the cookie values stored in
1490 * the HTTP protocol context. The cookie string is stored in *cookies, and may
1491 * be NULL if there are no valid cookies.
1492 *
1493 * @return a negative value if an error condition occurred, 0 otherwise
1494 */
1495static int get_cookies(HTTPContext *s, char **cookies, const char *path)
1496{
1497 // cookie strings will look like Set-Cookie header field values. Multiple
1498 // Set-Cookie fields will result in multiple values delimited by a newline
1499 int ret = 0;
1500 char *cookie, *set_cookies, *next;
1501 char *saveptr = NULL;
1502
1503 // destroy any cookies in the dictionary.
1504 av_dict_free(&s->cookie_dict);
1505
1506 if (!s->cookies)
1507 return 0;
1508
1509 next = set_cookies = av_strdup(s->cookies);
1510 if (!next)
1511 return AVERROR(ENOMEM);
1512
1513 *cookies = NULL;
1514 while ((cookie = av_strtok(next, "\n", &saveptr)) && !ret) {
1515 AVDictionary *cookie_params = NULL;
1516 const AVDictionaryEntry *cookie_entry, *e;
1517 const char *domain, *eql;
1518
1519 next = NULL;
1520 // store the cookie in a dict in case it is updated in the response
1521 if (parse_cookie(s, cookie, NULL, &s->cookie_dict))
1522 av_log(s, AV_LOG_WARNING, "Unable to parse '%s'\n", cookie);
1523
1524 // continue on to the next cookie if this one cannot be parsed
1525 if (parse_set_cookie(cookie, &cookie_params))
1526 goto skip_cookie;
1527
1528 // if the cookie has no value, skip it
1529 cookie_entry = av_dict_iterate(cookie_params, NULL);
1530 eql = strchr(cookie, '=');
1531 if (!cookie_entry || !eql || eql == cookie + strspn(cookie, WHITESPACES) ||
1532 memchr(cookie, ';', eql - cookie))
1533 goto skip_cookie;
1534
1535 for (e = cookie_entry; (e = av_dict_iterate(cookie_params, e)); )
1536 if (!av_strcasecmp(e->key, "secure") && !av_stristart(s->location, "https:", NULL))
1537 goto skip_cookie;
1538
1539 // if the cookie has expired, don't add it
1540 if ((e = av_dict_get(cookie_params, "expires", NULL, 0)) && e->value) {
1541 struct tm tm_buf = {0};
1542 if (!parse_http_date(e->value, &tm_buf)) {
1543 if (av_timegm(&tm_buf) < av_gettime() / 1000000)
1544 goto skip_cookie;
1545 }
1546 }
1547
1548 // if no domain in the cookie assume it applied to this request
1549 domain = cookie_domain(cookie_params);
1550 if (domain && !host_in_cookie_domain(s->host, domain))
1551 goto skip_cookie;
1552
1553 if ((e = av_dict_get(cookie_params, "@hostonly", NULL, 0)) && av_strcasecmp(e->value, s->host))
1554 goto skip_cookie;
1555
1556 // if a cookie path is provided, ensure the request path is within that path
1557 e = av_dict_get(cookie_params, "path", NULL, 0);
1558 if (e) {
1559 size_t len = strlen(e->value);
1560 if (strncmp(path, e->value, len) ||
1561 (len && path[len] && path[len] != '/' && path[len] != '?' &&
1562 e->value[len - 1] != '/'))
1563 goto skip_cookie;
1564 }
1565
1566 // cookie parameters match, so copy the value
1567 if (!*cookies) {
1568 *cookies = av_asprintf("%s=%s", cookie_entry->key, cookie_entry->value);
1569 } else {
1570 char *tmp = *cookies;
1571 *cookies = av_asprintf("%s; %s=%s", tmp, cookie_entry->key, cookie_entry->value);
1572 av_free(tmp);
1573 }
1574 if (!*cookies)
1575 ret = AVERROR(ENOMEM);
1576
1577 skip_cookie:
1578 av_dict_free(&cookie_params);
1579 }
1580
1581 av_free(set_cookies);
1582
1583 return ret;
1584}
1585
1586static inline int has_header(const char *str, const char *header)
1587{
1588 /* header + 2 to skip over CRLF prefix. (make sure you have one!) */
1589 if (!str)
1590 return 0;
1591 return av_stristart(str, header + 2, NULL) || av_stristr(str, header);
1592}
1593
1595{
1596 HTTPContext *s = h->priv_data;
1597 char line[MAX_URL_SIZE];
1598 int err = 0, http_err = 0;
1599
1600 av_freep(&s->new_location);
1601 s->expires = 0;
1602 s->chunksize = UINT64_MAX;
1603 s->filesize_from_content_range = UINT64_MAX;
1604 s->content_range_unknown_size = 0;
1605
1606 for (;;) {
1607 int parsed_http_code = 0;
1608
1609 if ((err = http_get_line(s, line, sizeof(line))) < 0) {
1610 av_log(h, AV_LOG_ERROR, "Error reading HTTP response: %s\n",
1611 av_err2str(err));
1612 return err;
1613 }
1614
1615 av_log(h, AV_LOG_TRACE, "header='%s'\n", line);
1616
1617 err = process_line(h, line, s->line_count, &parsed_http_code);
1618 if (err < 0) {
1619 if (parsed_http_code) {
1620 http_err = err;
1621 } else {
1622 /* Prefer to return HTTP code error if we've already seen one. */
1623 if (http_err)
1624 return http_err;
1625 else
1626 return err;
1627 }
1628 }
1629 if (err == 0)
1630 break;
1631 s->line_count++;
1632 }
1633 if (http_err)
1634 return http_err;
1635
1636 // filesize from Content-Range can always be used, even if using chunked Transfer-Encoding
1637 if (s->filesize_from_content_range != UINT64_MAX)
1638 s->filesize = s->filesize_from_content_range;
1639 else if (s->content_range_unknown_size)
1640 s->filesize = s->oc_filesize;
1641
1642 /* Remember a concrete complete size for later unknown-total ("*") replies. */
1643 if (s->filesize_from_content_range != UINT64_MAX)
1644 s->oc_filesize = s->filesize_from_content_range;
1645 else if (s->http_code == 200 && s->filesize != UINT64_MAX)
1646 s->oc_filesize = s->filesize;
1647
1648 if (s->seekable == -1 && s->is_mediagateway && s->filesize == 2000000000)
1649 h->is_streamed = 1; /* we can in fact _not_ seek */
1650
1651 if (h->is_streamed)
1652 s->initial_requests = 0; /* unable to use partial requests */
1653
1654 // add any new cookies into the existing cookie string
1655 cookie_string(s->cookie_dict, &s->cookies);
1656 av_dict_free(&s->cookie_dict);
1657
1658 return err;
1659}
1660
1661/**
1662 * Escape unsafe characters in path in order to pass them safely to the HTTP
1663 * request. Insipred by the algorithm in GNU wget:
1664 * - escape "%" characters not followed by two hex digits
1665 * - escape all "unsafe" characters except which are also "reserved"
1666 * - pass through everything else
1667 */
1668static void bprint_escaped_path(AVBPrint *bp, const char *path)
1669{
1670#define NEEDS_ESCAPE(ch) \
1671 ((ch) <= ' ' || (ch) >= '\x7f' || \
1672 (ch) == '"' || (ch) == '%' || (ch) == '<' || (ch) == '>' || (ch) == '\\' || \
1673 (ch) == '^' || (ch) == '`' || (ch) == '{' || (ch) == '}' || (ch) == '|')
1674 while (*path) {
1675 char buf[1024];
1676 char *q = buf;
1677 while (*path && q - buf < sizeof(buf) - 4) {
1678 if (path[0] == '%' && av_isxdigit(path[1]) && av_isxdigit(path[2])) {
1679 *q++ = *path++;
1680 *q++ = *path++;
1681 *q++ = *path++;
1682 } else if (NEEDS_ESCAPE(*path)) {
1683 q += snprintf(q, 4, "%%%02X", (uint8_t)*path++);
1684 } else {
1685 *q++ = *path++;
1686 }
1687 }
1688 av_bprint_append_data(bp, buf, q - buf);
1689 }
1690}
1691
1692static uint64_t request_size(URLContext *h)
1693{
1694 HTTPContext *s = h->priv_data;
1695 if (s->initial_requests)
1696 return s->initial_request_size;
1697 return s->request_size;
1698}
1699
1700static int http_connect(URLContext *h, const char *path, const char *local_path,
1701 const char *hoststr, const char *auth,
1702 const char *proxyauth)
1703{
1704 HTTPContext *s = h->priv_data;
1705 int post, err;
1706 AVBPrint request;
1707 char *authstr = NULL, *proxyauthstr = NULL;
1708 uint64_t off = s->off;
1709 const char *method;
1710 int send_expect_100 = 0;
1711 int keep_alive = 1;
1712
1713 av_bprint_init_for_buffer(&request, s->buffer, sizeof(s->buffer));
1714
1715 /* send http header */
1716 post = h->flags & AVIO_FLAG_WRITE;
1717
1718 if (s->post_data) {
1719 /* force POST method and disable chunked encoding when
1720 * custom HTTP post data is set */
1721 post = 1;
1722 s->chunked_post = 0;
1723 }
1724
1725 if (s->method)
1726 method = s->method;
1727 else
1728 method = post ? "POST" : "GET";
1729
1730 authstr = ff_http_auth_create_response(&s->auth_state, auth,
1731 local_path, method);
1732 proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth,
1733 local_path, method);
1734
1735 if (post && !s->post_data) {
1736 if (s->send_expect_100 != -1) {
1737 send_expect_100 = s->send_expect_100;
1738 } else {
1739 send_expect_100 = 0;
1740 /* The user has supplied authentication but we don't know the auth type,
1741 * send Expect: 100-continue to get the 401 response including the
1742 * WWW-Authenticate header, or an 100 continue if no auth actually
1743 * is needed. */
1744 if (auth && *auth &&
1745 s->auth_state.auth_type == HTTP_AUTH_NONE)
1746 send_expect_100 = 1;
1747 }
1748 }
1749
1750 av_bprintf(&request, "%s ", method);
1751 bprint_escaped_path(&request, path);
1752 av_bprintf(&request, " HTTP/1.1\r\n");
1753
1754 if (post && s->chunked_post)
1755 av_bprintf(&request, "Transfer-Encoding: chunked\r\n");
1756 /* set default headers if needed */
1757 if (!has_header(s->headers, "\r\nUser-Agent: "))
1758 av_bprintf(&request, "User-Agent: %s\r\n", s->user_agent);
1759 if (s->referer) {
1760 /* set default headers if needed */
1761 if (!has_header(s->headers, "\r\nReferer: "))
1762 av_bprintf(&request, "Referer: %s\r\n", s->referer);
1763 }
1764 if (!has_header(s->headers, "\r\nAccept: "))
1765 av_bprintf(&request, "Accept: */*\r\n");
1766 // Note: we send the Range header on purpose, even when we're probing,
1767 // since it allows us to detect more reliably if a (non-conforming)
1768 // server supports seeking by analysing the reply headers.
1769 int is_partial_request = 0;
1770 if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->end_off || s->seekable != 0)) {
1771 av_bprintf(&request, "Range: bytes=%"PRIu64"-", s->off);
1772 uint64_t req_size = request_size(h);
1773 if (req_size && s->seekable != 0) {
1774 uint64_t target_off = s->off + req_size;
1775 if (target_off < s->off) /* overflow */
1776 target_off = UINT64_MAX;
1777 if (s->end_off)
1778 target_off = FFMIN(target_off, s->end_off);
1779 if (target_off != UINT64_MAX) {
1780 av_bprintf(&request, "%"PRId64, target_off - 1);
1781 is_partial_request = 1;
1782 }
1783 } else if (s->end_off)
1784 av_bprintf(&request, "%"PRId64, s->end_off - 1);
1785 av_bprintf(&request, "\r\n");
1786 }
1787 if (send_expect_100 && !has_header(s->headers, "\r\nExpect: "))
1788 av_bprintf(&request, "Expect: 100-continue\r\n");
1789
1790 if (!has_header(s->headers, "\r\nConnection: ")) {
1791 keep_alive = s->multiple_requests > 0;
1792 if (s->multiple_requests < 0 /* auto */ && is_partial_request)
1793 keep_alive = 1;
1794 av_bprintf(&request, "Connection: %s\r\n", keep_alive ? "keep-alive" : "close");
1795 }
1796
1797 if (!has_header(s->headers, "\r\nHost: "))
1798 av_bprintf(&request, "Host: %s\r\n", hoststr);
1799 if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data)
1800 av_bprintf(&request, "Content-Length: %d\r\n", s->post_datalen);
1801
1802 if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
1803 av_bprintf(&request, "Content-Type: %s\r\n", s->content_type);
1804 if (!has_header(s->headers, "\r\nCookie: ") && s->cookies) {
1805 char *cookies = NULL;
1806 if (!get_cookies(s, &cookies, local_path) && cookies) {
1807 av_bprintf(&request, "Cookie: %s\r\n", cookies);
1808 av_free(cookies);
1809 }
1810 }
1811 if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy)
1812 av_bprintf(&request, "Icy-MetaData: 1\r\n");
1813
1814 /* now add in custom headers */
1815 if (s->headers)
1816 av_bprintf(&request, "%s", s->headers);
1817
1818 if (authstr)
1819 av_bprintf(&request, "%s", authstr);
1820 if (proxyauthstr)
1821 av_bprintf(&request, "Proxy-%s", proxyauthstr);
1822 av_bprintf(&request, "\r\n");
1823
1824 av_log(h, AV_LOG_DEBUG, "request: %s\n", request.str);
1825
1826 if (!av_bprint_is_complete(&request)) {
1827 av_log(h, AV_LOG_ERROR, "overlong headers\n");
1828 err = AVERROR(EINVAL);
1829 goto done;
1830 }
1831
1832 if ((err = ffurl_write(s->hd, request.str, request.len)) < 0)
1833 goto done;
1834
1835 if (s->post_data)
1836 if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0)
1837 goto done;
1838
1839 /* init input buffer */
1840 s->buf_ptr = s->buffer;
1841 s->buf_end = s->buffer;
1842 s->line_count = 0;
1843 s->off = 0;
1844 s->icy_data_read = 0;
1845 s->chunkend = 0;
1846 s->filesize = UINT64_MAX;
1847 s->range_end = 0;
1848 s->willclose = !keep_alive;
1849 s->end_chunked_post = 0;
1850 s->end_header = 0;
1851#if CONFIG_ZLIB
1852 s->compressed = 0;
1853#endif
1854 if (post && !s->post_data && !send_expect_100) {
1855 /* Pretend that it did work. We didn't read any header yet, since
1856 * we've still to send the POST data, but the code calling this
1857 * function will check http_code after we return. */
1858 s->http_code = 200;
1859 err = 0;
1860 goto done;
1861 }
1862
1863 /* wait for header */
1864 int64_t latency = av_gettime();
1865 err = http_read_header(h);
1866 latency = av_gettime() - latency;
1867 if (err < 0)
1868 goto done;
1869
1870 s->nb_requests++;
1871 s->sum_latency += latency;
1872 s->max_latency = FFMAX(s->max_latency, latency);
1873
1874 /* Redirects and authentication challenges are answered with another
1875 * request, whose reply is checked instead. */
1876 if ((s->new_location && is_redirect(s->http_code)) ||
1877 s->http_code == 401 || s->http_code == 407)
1878 s->off = off;
1879
1880 if (off != s->off) {
1882 "Unexpected offset: expected %"PRIu64", got %"PRIu64"\n",
1883 off, s->off);
1884 err = AVERROR(EIO);
1885 goto done;
1886 }
1887
1888 err = 0;
1889done:
1890 av_freep(&authstr);
1891 av_freep(&proxyauthstr);
1892 return err;
1893}
1894
1895static uint64_t requested_end(HTTPContext *s)
1896{
1897 return s->end_off ? FFMIN(s->end_off, s->filesize) : s->filesize;
1898}
1899
1900static int http_buf_read(URLContext *h, uint8_t *buf, int size)
1901{
1902 HTTPContext *s = h->priv_data;
1903 int len;
1904
1905 if (!s->hd)
1906 return AVERROR(EIO);
1907
1908 if (s->chunksize != UINT64_MAX) {
1909 if (s->chunkend) {
1910 return AVERROR_EOF;
1911 }
1912 if (!s->chunksize) {
1913 char line[32];
1914 int err;
1915
1916 do {
1917 if ((err = http_get_line(s, line, sizeof(line))) < 0)
1918 return err;
1919 } while (!*line); /* skip CR LF from last chunk */
1920
1921 s->chunksize = strtoull(line, NULL, 16);
1922
1924 "Chunked encoding data size: %"PRIu64"\n",
1925 s->chunksize);
1926
1927 if (!s->chunksize) {
1928 /* a partial reply that ends at its range end is continued */
1929 int more = s->range_end && s->off == s->range_end &&
1930 s->range_end < requested_end(s);
1931 if (s->multiple_requests) {
1932 do {
1933 if ((err = http_get_line(s, line, sizeof(line))) < 0)
1934 return err;
1935 } while (*line);
1936 s->chunkend = !more;
1937 } else {
1938 av_log(h, AV_LOG_DEBUG, "Last chunk received, closing conn\n");
1939 ffurl_closep(&s->hd);
1940 }
1941 return more ? AVERROR(EAGAIN) : 0;
1942 }
1943 else if (s->chunksize == UINT64_MAX) {
1944 av_log(h, AV_LOG_ERROR, "Invalid chunk size %"PRIu64"\n",
1945 s->chunksize);
1946 return AVERROR(EINVAL);
1947 }
1948 }
1949 size = FFMIN(size, s->chunksize);
1950 }
1951
1952 /* read bytes from input buffer first */
1953 len = s->buf_end - s->buf_ptr;
1954 if (len > 0) {
1955 if (len > size)
1956 len = size;
1957 memcpy(buf, s->buf_ptr, len);
1958 s->buf_ptr += len;
1959 } else {
1960 uint64_t file_end = requested_end(s);
1961 uint64_t target_end = s->range_end ? s->range_end : file_end;
1962 if ((!s->willclose || s->chunksize == UINT64_MAX) && s->off >= file_end)
1963 return AVERROR_EOF;
1964 if (s->off == target_end && target_end < file_end)
1965 return AVERROR(EAGAIN); /* reached end of content range */
1966 len = ffurl_read(s->hd, buf, size);
1967 if ((!len || len == AVERROR_EOF) &&
1968 (!s->willclose || s->chunksize == UINT64_MAX) && s->off < target_end) {
1970 "Stream ends prematurely at %"PRIu64", should be %"PRIu64"\n",
1971 s->off, target_end
1972 );
1973 return AVERROR(EIO);
1974 }
1975 }
1976 if (len > 0) {
1977 s->off += len;
1978 if (s->chunksize > 0 && s->chunksize != UINT64_MAX) {
1979 av_assert0(s->chunksize >= len);
1980 s->chunksize -= len;
1981 }
1982 }
1983 return len;
1984}
1985
1986#if CONFIG_ZLIB
1987#define DECOMPRESS_BUF_SIZE (256 * 1024)
1988static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size)
1989{
1990 HTTPContext *s = h->priv_data;
1991 int ret;
1992
1993 if (!s->inflate_buffer) {
1994 s->inflate_buffer = av_malloc(DECOMPRESS_BUF_SIZE);
1995 if (!s->inflate_buffer)
1996 return AVERROR(ENOMEM);
1997 }
1998
1999 if (s->inflate_stream.avail_in == 0) {
2000 int read = http_buf_read(h, s->inflate_buffer, DECOMPRESS_BUF_SIZE);
2001 if (read == AVERROR(EAGAIN)) {
2002 s->chunkend = 1;
2003 return AVERROR_EOF;
2004 }
2005 if (read <= 0)
2006 return read;
2007 s->inflate_stream.next_in = s->inflate_buffer;
2008 s->inflate_stream.avail_in = read;
2009 }
2010
2011 s->inflate_stream.avail_out = size;
2012 s->inflate_stream.next_out = buf;
2013
2014 ret = inflate(&s->inflate_stream, Z_SYNC_FLUSH);
2015 if (ret != Z_OK && ret != Z_STREAM_END)
2016 av_log(h, AV_LOG_WARNING, "inflate return value: %d, %s\n",
2017 ret, s->inflate_stream.msg);
2018
2019 return size - s->inflate_stream.avail_out;
2020}
2021#endif /* CONFIG_ZLIB */
2022
2023/* Record the end of the resource if err is the 416 that marks it. */
2025{
2026 if (!is_end_of_resource(s, err, s->off))
2027 return 0;
2028 s->oc_filesize = s->filesize_from_content_range;
2029 s->filesize = s->oc_filesize;
2030 s->end_of_resource = 1;
2031 return 1;
2032}
2033
2034static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect);
2035
2036static int http_read_stream(URLContext *h, uint8_t *buf, int size)
2037{
2038 HTTPContext *s = h->priv_data;
2039 int err, read_ret;
2040 int64_t seek_ret;
2041 int reconnect_delay = 0;
2042 int reconnect_delay_total = 0;
2043 int conn_attempts = 1;
2044
2045 if (s->end_of_resource)
2046 return AVERROR_EOF;
2047
2048 if (!s->hd)
2049 return s->off < requested_end(s) ? AVERROR(EIO) : AVERROR_EOF;
2050
2051 if (s->end_chunked_post && !s->end_header) {
2052 err = http_read_header(h);
2053 if (err < 0)
2054 return err;
2055 }
2056
2057#if CONFIG_ZLIB
2058 if (s->compressed)
2059 return http_buf_read_compressed(h, buf, size);
2060#endif /* CONFIG_ZLIB */
2061
2062retry:
2063 read_ret = http_buf_read(h, buf, size);
2064 while (read_ret < 0) {
2065 uint64_t target = h->is_streamed ? 0 : s->off;
2066 uint64_t file_end = requested_end(s);
2067 bool is_premature = file_end > 0 && s->off < file_end;
2068
2069 if (read_ret == AVERROR_EXIT)
2070 break;
2071 else if (read_ret == AVERROR(EAGAIN)) {
2072 /* send new request for more data on existing connection */
2074 if (s->willclose)
2075 ffurl_closep(&s->hd);
2076 s->initial_requests = 0; /* continue streaming uninterrupted from now on */
2077 read_ret = http_open_cnx(h, &options, 1);
2079 if (read_ret == 0)
2080 goto retry;
2081 if (http_end_of_resource(s, read_ret)) {
2082 read_ret = AVERROR_EOF;
2083 break;
2084 }
2085 }
2086
2087 if (h->is_streamed && !s->reconnect_streamed)
2088 break;
2089
2090 if (!(s->reconnect && is_premature) &&
2091 !(s->reconnect_at_eof && read_ret == AVERROR_EOF)) {
2092 if (is_premature)
2093 return AVERROR(EIO);
2094 else
2095 break;
2096 }
2097
2098 if (reconnect_delay > s->reconnect_delay_max || (s->reconnect_max_retries >= 0 && conn_attempts > s->reconnect_max_retries) ||
2099 reconnect_delay_total > s->reconnect_delay_total_max)
2100 return AVERROR(EIO);
2101
2102 av_log(h, AV_LOG_WARNING, "Will %s at %"PRIu64" in %d second(s), error=%s.\n", s->willclose ? "reconnect" : "retry",
2103 s->off, reconnect_delay, av_err2str(read_ret));
2104 err = ff_network_sleep_interruptible(1000U*1000*reconnect_delay, &h->interrupt_callback);
2105 if (err != AVERROR(ETIMEDOUT))
2106 return err;
2107 reconnect_delay_total += reconnect_delay;
2108 reconnect_delay = 1 + 2*reconnect_delay;
2109 conn_attempts++;
2110 seek_ret = http_seek_internal(h, target, SEEK_SET, 1);
2111 if (seek_ret >= 0 && seek_ret != target) {
2112 ffurl_closep(&s->hd);
2113 av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRIu64".\n", target);
2114 return read_ret;
2115 }
2116 if (s->end_of_resource) {
2117 read_ret = AVERROR_EOF;
2118 break;
2119 }
2120
2121 read_ret = http_buf_read(h, buf, size);
2122 }
2123
2124 return read_ret;
2125}
2126
2127// Like http_read_stream(), but no short reads.
2128// Assumes partial reads are an error.
2129static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
2130{
2131 int pos = 0;
2132 while (pos < size) {
2133 int len = http_read_stream(h, buf + pos, size - pos);
2134 if (len < 0)
2135 return len;
2136 pos += len;
2137 }
2138 return pos;
2139}
2140
2141static int store_icy(URLContext *h, int size)
2142{
2143 HTTPContext *s = h->priv_data;
2144 /* until next metadata packet */
2145 uint64_t remaining;
2146
2147 if (s->icy_metaint < s->icy_data_read)
2148 return AVERROR_INVALIDDATA;
2149 remaining = s->icy_metaint - s->icy_data_read;
2150
2151 if (!remaining) {
2152 /* The metadata packet is variable sized. It has a 1 byte header
2153 * which sets the length of the packet (divided by 16). If it's 0,
2154 * the metadata doesn't change. After the packet, icy_metaint bytes
2155 * of normal data follows. */
2156 uint8_t ch;
2157 int len = http_read_stream_all(h, &ch, 1);
2158 if (len < 0)
2159 return len;
2160 if (ch > 0) {
2161 char data[255 * 16 + 1];
2162 int ret;
2163 len = ch * 16;
2164 ret = http_read_stream_all(h, data, len);
2165 if (ret < 0)
2166 return ret;
2167 data[len] = 0;
2168 if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
2169 return ret;
2170 ff_http_parse_icy_packet(h, &s->metadata, data);
2171 }
2172 s->icy_data_read = 0;
2173 remaining = s->icy_metaint;
2174 }
2175
2176 return FFMIN(size, remaining);
2177}
2178
2179static int http_read(URLContext *h, uint8_t *buf, int size)
2180{
2181 HTTPContext *s = h->priv_data;
2182
2183 if (s->icy_metaint > 0) {
2184 size = store_icy(h, size);
2185 if (size < 0)
2186 return size;
2187 }
2188
2189 size = http_read_stream(h, buf, size);
2190 if (size > 0)
2191 s->icy_data_read += size;
2192 return size;
2193}
2194
2195/* used only when posting data */
2196static int http_write(URLContext *h, const uint8_t *buf, int size)
2197{
2198 char temp[11] = ""; /* 32-bit hex + CRLF + nul */
2199 int ret;
2200 char crlf[] = "\r\n";
2201 HTTPContext *s = h->priv_data;
2202
2203 if (!s->chunked_post) {
2204 /* non-chunked data is sent without any special encoding */
2205 return ffurl_write(s->hd, buf, size);
2206 }
2207
2208 /* silently ignore zero-size data since chunk encoding that would
2209 * signal EOF */
2210 if (size > 0) {
2211 /* upload data using chunked encoding */
2212 snprintf(temp, sizeof(temp), "%x\r\n", size);
2213
2214 if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 ||
2215 (ret = ffurl_write(s->hd, buf, size)) < 0 ||
2216 (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0)
2217 return ret;
2218 }
2219 return size;
2220}
2221
2223{
2224 int ret = 0;
2225 char footer[] = "0\r\n\r\n";
2226 HTTPContext *s = h->priv_data;
2227
2228 /* signal end of chunked encoding if used */
2229 if (((flags & AVIO_FLAG_WRITE) && s->chunked_post) ||
2230 ((flags & AVIO_FLAG_READ) && s->chunked_post && s->listen)) {
2231 ret = ffurl_write(s->hd, footer, sizeof(footer) - 1);
2232 ret = ret > 0 ? 0 : ret;
2233 /* flush the receive buffer when it is write only mode */
2234 if (!(flags & AVIO_FLAG_READ)) {
2235 char buf[1024];
2236 int read_ret;
2237 s->hd->flags |= AVIO_FLAG_NONBLOCK;
2238 read_ret = ffurl_read(s->hd, buf, sizeof(buf));
2239 s->hd->flags &= ~AVIO_FLAG_NONBLOCK;
2240 if (read_ret < 0 && read_ret != AVERROR(EAGAIN)) {
2241 av_log(h, AV_LOG_ERROR, "URL read error: %s\n", av_err2str(read_ret));
2242 ret = read_ret;
2243 }
2244 }
2245 s->end_chunked_post = 1;
2246 }
2247
2248 return ret;
2249}
2250
2252{
2253 int ret = 0;
2254 HTTPContext *s = h->priv_data;
2255
2256#if CONFIG_ZLIB
2257 inflateEnd(&s->inflate_stream);
2258 av_freep(&s->inflate_buffer);
2259#endif /* CONFIG_ZLIB */
2260
2261 if (s->hd && !s->end_chunked_post)
2262 /* Close the write direction by sending the end of chunked encoding. */
2263 ret = http_shutdown(h, h->flags);
2264
2265 if (s->hd)
2266 ffurl_closep(&s->hd);
2267 av_dict_free(&s->chained_options);
2268 av_dict_free(&s->cookie_dict);
2269 av_dict_free(&s->redirect_cache);
2270 av_freep(&s->new_location);
2271 av_freep(&s->uri);
2272 av_freep(&s->host);
2273
2274 av_log(h, AV_LOG_DEBUG, "Statistics: %d connection%s, %d request%s, %d retr%s, %d reconnection%s, %d redirect%s\n",
2275 s->nb_connections, s->nb_connections == 1 ? "" : "s",
2276 s->nb_requests, s->nb_requests == 1 ? "" : "s",
2277 s->nb_retries, s->nb_retries == 1 ? "y" : "ies",
2278 s->nb_reconnects, s->nb_reconnects == 1 ? "" : "s",
2279 s->nb_redirects, s->nb_redirects == 1 ? "" : "s");
2280
2281 if (s->nb_requests > 0) {
2282 av_log(h, AV_LOG_DEBUG, "Latency: %.2f ms avg, %.2f ms max\n",
2283 1e-3 * s->sum_latency / s->nb_requests,
2284 1e-3 * s->max_latency);
2285 }
2286 return ret;
2287}
2288
2289static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect)
2290{
2291 HTTPContext *s = h->priv_data;
2292 URLContext *old_hd = NULL;
2293 uint64_t old_off = s->off;
2294 uint64_t old_range_end = s->range_end;
2295 uint64_t old_chunksize = s->chunksize;
2296 int old_chunkend = s->chunkend;
2297 int old_willclose = s->willclose;
2298#if CONFIG_ZLIB
2299 int old_compressed = s->compressed;
2300#endif
2301 int old_end_of_resource = s->end_of_resource;
2302 uint8_t old_buf[BUFFER_SIZE];
2303 int old_buf_size, ret;
2305 uint8_t discard[4096];
2306
2307 if (whence == AVSEEK_SIZE)
2308 return s->filesize == UINT64_MAX ? AVERROR(ENOSYS) : s->filesize;
2309 else if ((s->filesize == UINT64_MAX && whence == SEEK_END))
2310 return AVERROR(ENOSYS);
2311
2312 if (whence == SEEK_CUR)
2313 off += s->off;
2314 else if (whence == SEEK_END)
2315 off += s->filesize;
2316 else if (whence != SEEK_SET)
2317 return AVERROR(EINVAL);
2318 if (off < 0)
2319 return AVERROR(EINVAL);
2320 if (!force_reconnect && off == s->off && s->hd)
2321 return s->off;
2322 if (off && h->is_streamed)
2323 return AVERROR(ENOSYS);
2324 s->off = off;
2325 s->end_of_resource = 0;
2326
2327 /* do not try to make a new connection if seeking past the end of the file */
2328 if (s->off >= requested_end(s)) {
2329 /* nothing of the old reply belongs to this offset */
2330 ffurl_closep(&s->hd);
2331 s->buf_ptr = s->buf_end = s->buffer;
2332 return s->off;
2333 }
2334
2335 /* if the location changed (redirect), revert to the original uri */
2336 if (strcmp(s->uri, s->location)) {
2337 char *new_uri;
2338 new_uri = av_strdup(s->uri);
2339 if (!new_uri)
2340 return AVERROR(ENOMEM);
2341 av_free(s->location);
2342 s->location = new_uri;
2343 }
2344
2345 /* we save the old context in case the seek fails */
2346 old_buf_size = s->buf_end - s->buf_ptr;
2347 memcpy(old_buf, s->buf_ptr, old_buf_size);
2348
2349 /* try to reuse existing connection for small seeks */
2350 int short_seek = ffurl_get_short_seek(h);
2351 uint64_t old_read_pos = old_off + old_buf_size;
2352 if (s->hd && !s->willclose && s->range_end && short_seek > 0 &&
2353 old_read_pos + short_seek >= s->range_end)
2354 {
2355 uint64_t remaining = s->range_end - old_read_pos;
2356 av_assert1(remaining <= short_seek);
2357
2358 /* drain remaining data left on the wire from previous request */
2359 av_log(h, AV_LOG_DEBUG, "Soft-seeking to offset %"PRIu64" by draining "
2360 "%"PRIu64" remaining byte(s)\n", s->off, remaining);
2361 while (remaining) {
2362 ret = ffurl_read(s->hd, discard, FFMIN(remaining, sizeof(discard)));
2363 if (ret < 0 || ret == AVERROR_EOF || (ret == 0 && remaining)) {
2364 /* connection broken or stuck, need to reopen */
2365 ffurl_closep(&s->hd);
2366 break;
2367 }
2368 remaining -= ret;
2369 }
2370
2371 ret = http_open_cnx(h, &options, 1);
2372 if (ret >= 0 || http_end_of_resource(s, ret)) {
2373 goto done;
2374 } else {
2375 /* fall back to normal reconnection */
2376 ffurl_closep(&s->hd);
2377 old_hd = NULL;
2378 }
2379 } else {
2380 /* can't soft seek; always open new connection */
2381 old_hd = s->hd;
2382 s->hd = NULL;
2383 }
2384
2385 if ((ret = http_open_cnx(h, &options, 1)) < 0 &&
2386 !http_end_of_resource(s, ret)) {
2387 /* if it fails, continue on old connection if possible */
2388 if (old_hd) {
2389 memcpy(s->buffer, old_buf, old_buf_size);
2390 s->buf_ptr = s->buffer;
2391 s->buf_end = s->buffer + old_buf_size;
2392 s->hd = old_hd;
2393 s->range_end = old_range_end;
2394 s->chunksize = old_chunksize;
2395 s->chunkend = old_chunkend;
2396 s->willclose = old_willclose;
2397#if CONFIG_ZLIB
2398 s->compressed = old_compressed;
2399#endif
2400 }
2401 s->off = old_off;
2402 s->end_of_resource = old_end_of_resource;
2404 return ret;
2405 }
2406
2407done:
2409 ffurl_close(old_hd);
2410 return off;
2411}
2412
2413static int64_t http_seek(URLContext *h, int64_t off, int whence)
2414{
2415 return http_seek_internal(h, off, whence, 0);
2416}
2417
2419{
2420 HTTPContext *s = h->priv_data;
2421 return ffurl_get_file_handle(s->hd);
2422}
2423
2425{
2426 HTTPContext *s = h->priv_data;
2427 if (s->short_seek_size >= 1)
2428 return s->short_seek_size;
2429 return ffurl_get_short_seek(s->hd);
2430}
2431
2432#define HTTP_CLASS(flavor) \
2433static const AVClass flavor ## _context_class = { \
2434 .class_name = # flavor, \
2435 .item_name = av_default_item_name, \
2436 .option = http_options, \
2437 .version = LIBAVUTIL_VERSION_INT, \
2438}
2439
2440#if CONFIG_HTTP_PROTOCOL
2441HTTP_CLASS(http);
2442
2444 .name = "http",
2445 .url_open2 = http_open,
2446 .url_accept = http_accept,
2447 .url_handshake = http_handshake,
2448 .url_read = http_read,
2449 .url_write = http_write,
2450 .url_seek = http_seek,
2451 .url_close = http_close,
2452 .url_get_file_handle = http_get_file_handle,
2453 .url_get_short_seek = http_get_short_seek,
2454 .url_shutdown = http_shutdown,
2455 .priv_data_size = sizeof(HTTPContext),
2456 .priv_data_class = &http_context_class,
2458 .default_whitelist = "http,https,tls,rtp,tcp,udp,crypto,httpproxy,data"
2459};
2460#endif /* CONFIG_HTTP_PROTOCOL */
2461
2462#if CONFIG_HTTPS_PROTOCOL
2463HTTP_CLASS(https);
2464
2466 .name = "https",
2467 .url_open2 = http_open,
2468 .url_read = http_read,
2469 .url_write = http_write,
2470 .url_seek = http_seek,
2471 .url_close = http_close,
2472 .url_get_file_handle = http_get_file_handle,
2473 .url_get_short_seek = http_get_short_seek,
2474 .url_shutdown = http_shutdown,
2475 .priv_data_size = sizeof(HTTPContext),
2476 .priv_data_class = &https_context_class,
2478 .default_whitelist = "http,https,tls,rtp,tcp,udp,crypto,httpproxy"
2479};
2480#endif /* CONFIG_HTTPS_PROTOCOL */
2481
2482#if CONFIG_HTTPPROXY_PROTOCOL
2483static int http_proxy_close(URLContext *h)
2484{
2485 HTTPContext *s = h->priv_data;
2486 if (s->hd)
2487 ffurl_closep(&s->hd);
2488 return 0;
2489}
2490
2491static int http_proxy_open(URLContext *h, const char *uri, int flags)
2492{
2493 HTTPContext *s = h->priv_data;
2494 char hostname[1024], hoststr[1024];
2495 char auth[1024], pathbuf[1024], *path;
2496 char lower_url[100];
2497 int port, ret = 0, auth_attempts = 0;
2498 HTTPAuthType cur_auth_type;
2499 char *authstr;
2500
2501 if( s->seekable == 1 )
2502 h->is_streamed = 0;
2503 else
2504 h->is_streamed = 1;
2505
2506 av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
2507 pathbuf, sizeof(pathbuf), uri);
2508 ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
2509 path = pathbuf;
2510 if (*path == '/')
2511 path++;
2512
2513 ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port,
2514 NULL);
2515redo:
2516 ret = ffurl_open_whitelist(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
2517 &h->interrupt_callback, NULL,
2518 h->protocol_whitelist, h->protocol_blacklist, h);
2519 if (ret < 0)
2520 return ret;
2521
2522 authstr = ff_http_auth_create_response(&s->proxy_auth_state, auth,
2523 path, "CONNECT");
2524 snprintf(s->buffer, sizeof(s->buffer),
2525 "CONNECT %s HTTP/1.1\r\n"
2526 "Host: %s\r\n"
2527 "Connection: close\r\n"
2528 "%s%s"
2529 "\r\n",
2530 path,
2531 hoststr,
2532 authstr ? "Proxy-" : "", authstr ? authstr : "");
2533 av_freep(&authstr);
2534
2535 if ((ret = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
2536 goto fail;
2537
2538 s->buf_ptr = s->buffer;
2539 s->buf_end = s->buffer;
2540 s->line_count = 0;
2541 s->filesize = UINT64_MAX;
2542 cur_auth_type = s->proxy_auth_state.auth_type;
2543
2544 /* Note: This uses buffering, potentially reading more than the
2545 * HTTP header. If tunneling a protocol where the server starts
2546 * the conversation, we might buffer part of that here, too.
2547 * Reading that requires using the proper ffurl_read() function
2548 * on this URLContext, not using the fd directly (as the tls
2549 * protocol does). This shouldn't be an issue for tls though,
2550 * since the client starts the conversation there, so there
2551 * is no extra data that we might buffer up here.
2552 */
2553 ret = http_read_header(h);
2554 if (ret < 0)
2555 goto fail;
2556
2557 auth_attempts++;
2558 if (s->http_code == 407 &&
2559 (cur_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
2560 s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && auth_attempts < 2) {
2561 ffurl_closep(&s->hd);
2562 goto redo;
2563 }
2564
2565 if (s->http_code < 400)
2566 return 0;
2567 ret = ff_http_averror(s->http_code, AVERROR(EIO));
2568
2569fail:
2570 http_proxy_close(h);
2571 return ret;
2572}
2573
2574static int http_proxy_write(URLContext *h, const uint8_t *buf, int size)
2575{
2576 HTTPContext *s = h->priv_data;
2577 return ffurl_write(s->hd, buf, size);
2578}
2579
2581 .name = "httpproxy",
2582 .url_open = http_proxy_open,
2583 .url_read = http_buf_read,
2584 .url_write = http_proxy_write,
2585 .url_close = http_proxy_close,
2586 .url_get_file_handle = http_get_file_handle,
2587 .priv_data_size = sizeof(HTTPContext),
2589};
2590#endif /* CONFIG_HTTPPROXY_PROTOCOL */
static AVDictionary * opts
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition avassert.h:58
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
#define E
Definition avdct.c:34
#define D
Definition avdct.c:35
Main libavformat public API header.
int ffurl_handshake(URLContext *c)
Perform one step of the protocol handshake to accept a new client.
Definition avio.c:296
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:362
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:466
int ffurl_accept(URLContext *s, URLContext **c)
Accept an URLContext c on an URLContext s.
Definition avio.c:277
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition avio.c:663
int ffurl_close(URLContext *h)
Definition avio.c:686
int ffurl_get_short_seek(void *urlcontext)
Return the current short seek threshold value for this URL.
Definition avio.c:913
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition avio.c:889
#define AVIO_FLAG_READ
read-only
Definition avio.h:617
#define AVSEEK_SIZE
Passing this as the "whence" parameter to a seek function causes it to return the filesize without se...
Definition avio.h:468
#define AVIO_FLAG_WRITE
write-only
Definition avio.h:618
#define AVIO_FLAG_READ_WRITE
read-write pseudo flag
Definition avio.h:619
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition avio.h:636
char * av_asprintf(const char *fmt,...)
Definition avstring.c:115
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition avstring.c:103
static uint32_t BS_FUNC read(BSCTX *bc, unsigned int n)
Return n bits from the buffer, n has to be in the 0-32 range.
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:121
AVBPrint public header.
static int FUNC metadata(CodedBitstreamContext *ctx, RWContext *rw, APVRawMetadata *current)
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
double value
Definition eval.c:102
static int64_t filesize(AVIOContext *pb)
Definition ffmpeg_mux.c:52
#define BUFFER_SIZE
static char * getenv_utf8(const char *varname)
Definition getenv_utf8.h:67
static void freeenv_utf8(char *var)
Definition getenv_utf8.h:72
#define WHITESPACES
Definition graphparser.c:35
#define fail
Definition test.h:479
#define AV_OPT_FLAG_READONLY
The option may not be set through the AVOptions API, only read.
Definition opt.h:367
#define AV_OPT_FLAG_EXPORT
The option is intended for exporting values to the caller.
Definition opt.h:362
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_BINARY
Underlying C type is a uint8_t* that is either NULL or points to an array allocated with the av_mallo...
Definition opt.h:285
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
Definition opt.h:262
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_DICT
Underlying C type is AVDictionary*.
Definition opt.h:289
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
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:361
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition bprint.h:218
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition dict.c:236
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:61
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition dict.c:43
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition dict.c:250
#define AV_DICT_DONT_STRDUP_VAL
Take ownership of a value that's been allocated with av_malloc() or another memory allocation functio...
Definition dict.h:79
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:87
#define AV_DICT_DONT_STRDUP_KEY
Take ownership of a key that's been allocated with av_malloc() or another memory allocation function.
Definition dict.h:77
int av_dict_count(const AVDictionary *m)
Get number of entries in dictionary.
Definition dict.c:38
#define AV_DICT_MATCH_CASE
Only get an entry with exact-case key match.
Definition dict.h:74
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:180
#define AVERROR_HTTP_FORBIDDEN
Definition error.h:80
#define AVERROR_HTTP_BAD_REQUEST
Definition error.h:78
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition error.h:58
#define AVERROR_HTTP_SERVER_ERROR
Definition error.h:84
#define AVERROR_HTTP_OTHER_4XX
Definition error.h:83
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR_HTTP_TOO_MANY_REQUESTS
Definition error.h:82
#define AVERROR_EOF
End of file.
Definition error.h:57
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition error.h:122
#define AVERROR_HTTP_UNAUTHORIZED
Definition error.h:79
#define AVERROR(e)
Definition error.h:45
#define AVERROR_HTTP_NOT_FOUND
Definition error.h:81
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition log.h:236
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
char * av_strndup(const char *s, size_t len)
Duplicate a substring of a string.
Definition mem.c:390
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:289
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:58
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:179
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition avstring.c:208
static av_const int av_isdigit(int c)
Locale-independent conversion of ASCII isdigit.
Definition avstring.h:202
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:36
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition avstring.c:85
static av_const int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition avstring.h:218
int av_match_list(const char *name, const char *list, char separator)
Check if a name is in a list.
Definition avstring.c:443
char * av_get_token(const char **buf, const char *term)
Unescape the given string until a non escaped terminating char, and return the token corresponding to...
Definition avstring.c:143
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:47
int av_strncasecmp(const char *a, const char *b, size_t n)
Locale-independent case-insensitive compare.
Definition avstring.c:218
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
Definition opt.c:891
int av_opt_set_dict(void *obj, AVDictionary **options)
Set all the options from a given dictionary on an object.
Definition opt.c:2066
static int http_handshake(URLContext *c)
Definition http.c:748
HandshakeState
Definition http.c:65
@ FINISH
Definition http.c:69
@ LOWER_PROTO
Definition http.c:66
@ READ_HEADERS
Definition http.c:67
@ WRITE_REPLY_HEADERS
Definition http.c:68
static int parse_content_range(URLContext *h, const char *p)
Definition http.c:1009
static int http_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition http.c:816
static int cookie_string(AVDictionary *dict, char **cookies)
Definition http.c:1262
static int redirect_cache_set(HTTPContext *s, const char *source, const char *dest, int64_t expiry)
Definition http.c:416
static const char * cookie_domain(const AVDictionary *cookie_params)
Definition http.c:1159
static int store_icy(URLContext *h, int size)
Definition http.c:2141
static int parse_content_encoding(URLContext *h, const char *p)
Definition http.c:1038
static uint64_t requested_end(HTTPContext *s)
Definition http.c:1895
static int host_is_ip_literal(const char *host)
Definition http.c:1167
static const AVOption http_options[]
Definition http.c:194
static int http_shutdown(URLContext *h, int flags)
Definition http.c:2222
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:589
static int parse_set_cookie(const char *set_cookie, AVDictionary **dict)
Definition http.c:1119
static int http_read_header(URLContext *h)
Definition http.c:1594
static int http_read(URLContext *h, uint8_t *buf, int size)
Definition http.c:2179
static int http_getc(HTTPContext *s)
Definition http.c:897
static uint64_t request_size(URLContext *h)
Definition http.c:1692
static int get_cookies(HTTPContext *s, char **cookies, const char *path)
Create a string containing cookie values for use as a HTTP cookie header field value for a particular...
Definition http.c:1495
static int process_line(URLContext *h, char *line, int line_count, int *parsed_http_code)
Definition http.c:1321
static int http_open_cnx_internal(URLContext *h, AVDictionary **options)
Definition http.c:254
static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect)
Definition http.c:2289
static int http_get_line(HTTPContext *s, char *line, int line_size)
Definition http.c:914
#define MAX_DATE_LEN
Definition http.c:63
static int http_buf_read(URLContext *h, uint8_t *buf, int size)
Definition http.c:1900
static int parse_icy(HTTPContext *s, const char *tag, const char *p)
Definition http.c:1072
static int has_header(const char *str, const char *header)
Definition http.c:1586
static int http_listen(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition http.c:784
static int is_redirect(int http_code)
Definition http.c:434
#define BUFFER_SIZE
Definition http.c:58
static int check_http_code(URLContext *h, int http_code, const char *end)
Definition http.c:982
static int host_in_cookie_domain(const char *host, const char *domain)
Definition http.c:1172
static int http_get_short_seek(URLContext *h)
Definition http.c:2424
static int http_get_file_handle(URLContext *h)
Definition http.c:2418
void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
Initialize the authentication state based on another HTTP URLContext.
Definition http.c:244
static int http_write_reply(URLContext *h, int status_code)
Definition http.c:663
#define HTTP_SINGLE
Definition http.c:61
static int http_should_reconnect(HTTPContext *s, int err)
Definition http.c:358
static char * redirect_cache_get(HTTPContext *s)
Definition http.c:392
static void handle_http_errors(URLContext *h, int error)
Definition http.c:742
static int is_end_of_resource(HTTPContext *s, int err, uint64_t off)
Definition http.c:442
const char * ff_http_get_new_location(URLContext *h)
Definition http.c:657
#define DEFAULT_USER_AGENT
Definition http.c:192
#define HTTP_CLASS(flavor)
Definition http.c:2432
static void parse_cache_control(HTTPContext *s, const char *p)
Definition http.c:1294
static void parse_expires(HTTPContext *s, const char *p)
Definition http.c:1285
static int http_connect(URLContext *h, const char *path, const char *local_path, const char *hoststr, const char *auth, const char *proxyauth)
Definition http.c:1700
static int http_write(URLContext *h, const uint8_t *buf, int size)
Definition http.c:2196
static int http_end_of_resource(HTTPContext *s, int err)
Definition http.c:2024
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:1668
#define MAX_REDIRECTS
Definition http.c:59
int ff_http_parse_status_line(void *logctx, const char *line, HTTPStatusLine *st)
Parse the status line of an HTTP response.
Definition http.c:938
static int64_t http_seek(URLContext *h, int64_t off, int whence)
Definition http.c:2413
#define OFFSET(x)
Definition http.c:189
static int parse_http_date(const char *date_str, struct tm *buf)
Definition http.c:1094
static int http_close(URLContext *h)
Definition http.c:2251
int ff_http_do_new_request(URLContext *h, const char *uri)
Send a new HTTP request, reusing the old connection.
Definition http.c:585
static int http_open_cnx(URLContext *h, AVDictionary **options, int end_is_eof)
Definition http.c:453
#define MAX_CACHED_REDIRECTS
Definition http.c:60
static int http_accept(URLContext *s, URLContext **c)
Definition http.c:873
static int http_read_stream(URLContext *h, uint8_t *buf, int size)
Definition http.c:2036
static int parse_cookie(HTTPContext *s, const char *p, const char *host, AVDictionary **cookies)
Definition http.c:1180
static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
Definition http.c:2129
static int parse_location(HTTPContext *s, const char *p)
Definition http.c:996
static void ff_http_parse_icy_packet(void *logctx, AVDictionary **metadata, char *data)
Split an in-band ICY metadata packet into its "Key='Value';" pairs.
Definition http.h:62
static int ff_http_averror(int status_code, int default_averror)
Definition http.h:120
char * ff_http_auth_create_response(HTTPAuthState *state, const char *auth, const char *path, const char *method)
Definition httpauth.c:240
void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, const char *value)
Definition httpauth.c:93
HTTPAuthType
Authentication types, ordered from weakest to strongest.
Definition httpauth.h:28
@ HTTP_AUTH_NONE
No authentication specified.
Definition httpauth.h:29
@ HTTP_AUTH_BASIC
HTTP 1.0 Basic auth from RFC 1945 (also in RFC 2617)
Definition httpauth.h:30
unsigned offset
Definition libaomenc.c:763
#define MAX_URL_SIZE
Definition internal.h:30
Libavformat version macros.
version
Definition libkvazaar.c:313
Utility Preprocessor macros.
#define FFMIN(a, b)
Definition macros.h:49
#define FFMAX(a, b)
Definition macros.h:47
static void body(uint32_t ABCD[4], const uint8_t *src, size_t nblocks)
Definition md5.c:103
Memory handling functions.
uint32_t tag
Definition movenc.c:2128
char * host
Definition mscl.c:249
const char data[16]
Definition mxf.c:149
int ff_network_sleep_interruptible(int64_t timeout, AVIOInterruptCB *int_cb)
Waits for up to 'timeout' microseconds.
Definition network.c:103
int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
Definition network.c:558
#define av_strdup(s)
Definition ops_static.c:55
#define av_malloc(s)
Definition ops_static.c:52
AVOptions.
miscellaneous OS support macros and functions.
char * av_small_strptime(const char *p, const char *fmt, struct tm *dt)
Simplified version of strptime.
Definition parseutils.c:494
time_t av_timegm(struct tm *tm)
Convert the decomposed UTC time in tm to a time_t value.
Definition parseutils.c:573
misc parsing utilities
const URLProtocol ff_https_protocol
const URLProtocol ff_http_protocol
const URLProtocol ff_httpproxy_protocol
const char * name
Definition qsvenc.c:142
static const uint8_t header[24]
Definition sdr2.c:68
unsigned int pos
Definition spdifenc.c:431
Describe the class of an AVClass context structure.
Definition log.h:76
char * key
Definition dict.h:91
char * value
Definition dict.h:92
AVOption.
Definition opt.h:428
HTTP Authentication state structure.
Definition httpauth.h:55
int64_t sum_latency
Definition http.c:140
HandshakeState handshake_step
Definition http.c:184
int is_akamai
Definition http.c:127
uint64_t chunksize
Definition http.c:152
URLContext * hd
Definition http.c:146
char * resource
Definition http.c:111
char * new_location
Definition http.c:148
int nb_redirects
Definition http.c:139
int nb_retries
Definition http.c:137
char * method
Definition http.c:101
unsigned char * buf_end
Definition http.c:74
int nb_connections
Definition http.c:135
int end_of_resource
Definition http.c:126
int end_chunked_post
Definition http.c:159
uint64_t range_end
Definition http.c:154
int max_redirects
Definition http.c:114
int64_t max_latency
Definition http.c:141
uint64_t off
Definition http.c:79
AVDictionary * chained_options
Definition http.c:131
int initial_requests
Definition http.c:172
int respect_retry_after
Definition http.c:115
uint64_t filesize_from_content_range
Definition http.c:175
char * location
Definition http.c:80
uint64_t icy_metaint
Definition http.c:165
int reply_code
Definition http.c:112
int listen
Definition http.c:110
uint64_t icy_data_read
Definition http.c:163
char * icy_metadata_packet
Definition http.c:97
char * user_agent
Definition http.c:85
char * reconnect_on_http_error
Definition http.c:109
int seekable
Control seekability, 0 = disable, 1 = enable, -1 = probe.
Definition http.c:88
char * headers
Definition http.c:82
int reconnect_delay_total_max
Definition http.c:108
char * uri
Definition http.c:147
int http_code
Definition http.c:149
int end_header
Definition http.c:161
char * referer
Definition http.c:86
char * host
Definition http.c:94
int is_multi_client
Definition http.c:185
AVDictionary * metadata
Definition http.c:98
uint8_t * post_data
Definition http.c:91
unsigned char buffer[BUFFER_SIZE]
Definition http.c:74
char * content_type
Definition http.c:87
AVDictionary * redirect_cache
Definition http.c:132
int nb_requests
Definition http.c:136
int reconnect_on_network_error
Definition http.c:104
char * http_version
Definition http.c:84
int send_expect_100
Definition http.c:100
uint64_t filesize
Definition http.c:124
char * icy_metadata_headers
Definition http.c:96
int willclose
Definition http.c:157
char * mime_type
Definition http.c:83
int short_seek_size
Definition http.c:113
int is_mediagateway
Definition http.c:128
int multiple_requests
A flag which indicates if we use persistent connections.
Definition http.c:90
char * http_proxy
Definition http.c:81
int is_connected_server
Definition http.c:186
int nb_reconnects
Definition http.c:138
HTTPAuthState proxy_auth_state
Definition http.c:123
int reconnect_streamed
Definition http.c:105
int icy
Definition http.c:95
int reconnect
Definition http.c:102
int chunked_post
Definition http.c:89
char * cookies
holds newline ( ) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
Definition http.c:93
uint64_t end_off
Definition http.c:79
int64_t expires
Definition http.c:150
uint64_t request_size
Definition http.c:116
unsigned int retry_after
Definition http.c:171
int post_datalen
Definition http.c:92
HTTPAuthState auth_state
Definition http.c:122
uint64_t oc_filesize
Definition http.c:125
unsigned char * buf_ptr
Definition http.c:74
AVDictionary * cookie_dict
Definition http.c:130
int content_range_unknown_size
Definition http.c:177
int reconnect_max_retries
Definition http.c:106
int reconnect_at_eof
Definition http.c:103
int reconnect_delay_max
Definition http.c:107
uint64_t initial_request_size
Definition http.c:117
int line_count
Definition http.c:178
int chunkend
Definition http.c:153
Parsed form of a response status line.
Definition http.h:37
int code
response status code
Definition http.h:39
const char * reason
reason phrase, points into the parsed line
Definition http.h:40
int willclose
the version implies the connection will close
Definition http.h:41
char version[4]
protocol version, e.g.
Definition http.h:38
void * priv_data
Definition url.h:38
AVIOInterruptCB interrupt_callback
Definition url.h:45
#define av_free(p)
#define av_freep(p)
#define av_log(a,...)
static void error(const char *err)
static uint8_t tmp[40]
Definition aes_ctr.c:52
#define src
Definition vp8dsp.c:248
int64_t av_gettime(void)
Get the current time in microseconds.
Definition time.c:40
int size
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:321
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:40
unbuffered private I/O API
static int ffurl_write(URLContext *h, const uint8_t *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition url.h:205
static int ffurl_read(URLContext *h, uint8_t *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition url.h:184
#define URL_PROTOCOL_FLAG_NETWORK
Definition url.h:33
else temp
Definition vf_mcdeint.c:275
static void inflate(uint8_t *dst, const uint8_t *p1, int width, int threshold, const uint8_t *coordinates[], int coord, int maxc)
static av_always_inline int diff(const struct color_info *a, const struct color_info *b, const int trans_thresh)
int len
static double c[64]