From: Derek Buitenhuis <derek.buitenhuis@gmail.com>
To: ffmpeg-devel@ffmpeg.org
Subject: [FFmpeg-devel] [PATCH v3 2/2] avformat/http: Add support for Retry-After header
Date: Thu, 25 Apr 2024 15:23:30 +0100
Message-ID: <20240425142330.288815-3-derek.buitenhuis@gmail.com> (raw)
In-Reply-To: <20240425142330.288815-1-derek.buitenhuis@gmail.com>
429 and 503 codes can, and often do (e.g. all Google Cloud
Storage URLs can), return a Retry-After header with the error,
indicating how long to wait, asd either a date, or in seconds,
before retrying again. If it is not respected by, for example,
using our default backoff stratetgy instead, chances of success
are very unlikely.
Some references:
* https://datatracker.ietf.org/doc/html/rfc6585
* https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.3
This adds an AVOption to respect that header.
Signed-off-by: Derek Buitenhuis <derek.buitenhuis@gmail.com>
---
doc/protocols.texi | 5 +++++
libavformat/http.c | 24 ++++++++++++++++++++++++
libavformat/version.h | 2 +-
3 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/doc/protocols.texi b/doc/protocols.texi
index 571d78ec43..ed70af4b33 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -569,6 +569,11 @@ Set the maximum number of times to retry a connection. Default unset.
@item reconnect_delay_total_max
Set the maximum total delay in seconds after which to give up reconnecting.
+@item respect_retry_after
+If enabled, and a Retry-After header is encountered, its requested reconnection
+delay will be honored, rather than using exponential backoff. Useful for 429 and
+503 errors. Default enabled.
+
@item listen
If set to 1 enables experimental HTTP server. This can be used to send data when
used as an output option, or read data from a client with HTTP POST when used as
diff --git a/libavformat/http.c b/libavformat/http.c
index d324674e97..1a67068a44 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -31,6 +31,7 @@
#include "libavutil/avstring.h"
#include "libavutil/bprint.h"
#include "libavutil/getenv_utf8.h"
+#include "libavutil/macros.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "libavutil/time.h"
@@ -138,6 +139,8 @@ typedef struct HTTPContext {
char *new_location;
AVDictionary *redirect_cache;
uint64_t filesize_from_content_range;
+ int respect_retry_after;
+ unsigned int retry_after;
int reconnect_max_retries;
int reconnect_delay_total_max;
} HTTPContext;
@@ -180,6 +183,7 @@ static const AVOption options[] = {
{ "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 },
{ "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 },
{ "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 },
+ { "respect_retry_after", "respect the Retry-After header when retrying connections", OFFSET(respect_retry_after), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D },
{ "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, D | E },
{ "resource", "The resource requested by a client", OFFSET(resource), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
{ "reply_code", "The http status code to return to a client", OFFSET(reply_code), AV_OPT_TYPE_INT, { .i64 = 200}, INT_MIN, 599, E},
@@ -393,6 +397,14 @@ redo:
reconnect_delay_total > s->reconnect_delay_total_max)
goto fail;
+ /* Both fields here are in seconds. */
+ if (s->respect_retry_after && s->retry_after > 0) {
+ reconnect_delay = s->retry_after;
+ if (reconnect_delay > s->reconnect_delay_max)
+ goto fail;
+ s->retry_after = 0;
+ }
+
av_log(h, AV_LOG_WARNING, "Will reconnect at %"PRIu64" in %d second(s).\n", off, reconnect_delay);
ret = ff_network_sleep_interruptible(1000U * 1000 * reconnect_delay, &h->interrupt_callback);
if (ret != AVERROR(ETIMEDOUT))
@@ -1241,6 +1253,18 @@ static int process_line(URLContext *h, char *line, int line_count, int *parsed_h
parse_expires(s, p);
} else if (!av_strcasecmp(tag, "Cache-Control")) {
parse_cache_control(s, p);
+ } else if (!av_strcasecmp(tag, "Retry-After")) {
+ /* The header can be either an integer that represents seconds, or a date. */
+ struct tm tm;
+ int date_ret = parse_http_date(p, &tm);
+ if (!date_ret) {
+ time_t retry = av_timegm(&tm);
+ int64_t now = av_gettime() / 1000000;
+ int64_t diff = ((int64_t) retry) - now;
+ s->retry_after = (unsigned int) FFMAX(0, diff);
+ } else {
+ s->retry_after = strtoul(p, NULL, 10);
+ }
}
}
return 1;
diff --git a/libavformat/version.h b/libavformat/version.h
index 41dbd4ad01..5310326bda 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -32,7 +32,7 @@
#include "version_major.h"
#define LIBAVFORMAT_VERSION_MINOR 3
-#define LIBAVFORMAT_VERSION_MICRO 102
+#define LIBAVFORMAT_VERSION_MICRO 103
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2024-04-25 14:24 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-25 14:23 [FFmpeg-devel] [PATCH v3 0/2] HTTP Retry-After Support Derek Buitenhuis
2024-04-25 14:23 ` [FFmpeg-devel] [PATCH v3 1/2] avformat/http: Rename parse_set_cookie_expiry_time to parse_http_date Derek Buitenhuis
2024-04-25 14:23 ` Derek Buitenhuis [this message]
2024-04-25 20:22 ` [FFmpeg-devel] [PATCH v3 0/2] HTTP Retry-After Support Martin Storsjö
2024-04-26 12:01 ` Derek Buitenhuis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240425142330.288815-3-derek.buitenhuis@gmail.com \
--to=derek.buitenhuis@gmail.com \
--cc=ffmpeg-devel@ffmpeg.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git