mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
lavf/http: add HTTP protocol cookie support
Signed-off-by: Stefano Sabatini <stefasab@gmail.com>
This commit is contained in:
parent
d012059e7b
commit
0b80a12184
@ -64,6 +64,7 @@ typedef struct {
|
||||
int is_akamai;
|
||||
int rw_timeout;
|
||||
char *mime_type;
|
||||
char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
|
||||
} HTTPContext;
|
||||
|
||||
#define OFFSET(x) offsetof(HTTPContext, x)
|
||||
@ -80,6 +81,7 @@ static const AVOption options[] = {
|
||||
{"post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D|E },
|
||||
{"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
|
||||
{"mime_type", "set MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 },
|
||||
{"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, {0}, 0, 0, 0 },
|
||||
{NULL}
|
||||
};
|
||||
#define HTTP_CLASS(flavor)\
|
||||
@ -359,11 +361,117 @@ static int process_line(URLContext *h, char *line, int line_count,
|
||||
s->is_akamai = 1;
|
||||
} else if (!av_strcasecmp (tag, "Content-Type")) {
|
||||
av_free(s->mime_type); s->mime_type = av_strdup(p);
|
||||
} else if (!av_strcasecmp (tag, "Set-Cookie")) {
|
||||
if (!s->cookies) {
|
||||
if (!(s->cookies = av_strdup(p)))
|
||||
return AVERROR(ENOMEM);
|
||||
} else {
|
||||
char *tmp = s->cookies;
|
||||
size_t str_size = strlen(tmp) + strlen(p) + 2;
|
||||
if (!(s->cookies = av_malloc(str_size))) {
|
||||
s->cookies = tmp;
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
snprintf(s->cookies, str_size, "%s\n%s", tmp, p);
|
||||
av_free(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string containing cookie values for use as a HTTP cookie header
|
||||
* field value for a particular path and domain from the cookie values stored in
|
||||
* the HTTP protocol context. The cookie string is stored in *cookies.
|
||||
*
|
||||
* @return a negative value if an error condition occurred, 0 otherwise
|
||||
*/
|
||||
static int get_cookies(HTTPContext *s, char **cookies, const char *path,
|
||||
const char *domain)
|
||||
{
|
||||
// cookie strings will look like Set-Cookie header field values. Multiple
|
||||
// Set-Cookie fields will result in multiple values delimited by a newline
|
||||
int ret = 0;
|
||||
char *next, *cookie, *set_cookies = av_strdup(s->cookies), *cset_cookies = set_cookies;
|
||||
|
||||
if (!set_cookies) return AVERROR(EINVAL);
|
||||
|
||||
*cookies = NULL;
|
||||
while ((cookie = av_strtok(set_cookies, "\n", &next))) {
|
||||
int domain_offset = 0;
|
||||
char *param, *next_param, *cdomain = NULL, *cpath = NULL, *cvalue = NULL;
|
||||
set_cookies = NULL;
|
||||
|
||||
while ((param = av_strtok(cookie, "; ", &next_param))) {
|
||||
cookie = NULL;
|
||||
if (!av_strncasecmp("path=", param, 5)) {
|
||||
cpath = av_strdup(¶m[5]);
|
||||
} else if (!av_strncasecmp("domain=", param, 7)) {
|
||||
cdomain = av_strdup(¶m[7]);
|
||||
} else if (!av_strncasecmp("secure", param, 6) ||
|
||||
!av_strncasecmp("comment", param, 7) ||
|
||||
!av_strncasecmp("max-age", param, 7) ||
|
||||
!av_strncasecmp("version", param, 7)) {
|
||||
// ignore Comment, Max-Age, Secure and Version
|
||||
} else {
|
||||
cvalue = av_strdup(param);
|
||||
}
|
||||
}
|
||||
|
||||
// ensure all of the necessary values are valid
|
||||
if (!cdomain || !cpath || !cvalue) {
|
||||
av_log(s, AV_LOG_WARNING,
|
||||
"Invalid cookie found, no value, path or domain specified\n");
|
||||
goto done_cookie;
|
||||
}
|
||||
|
||||
// check if the request path matches the cookie path
|
||||
if (av_strncasecmp(path, cpath, strlen(cpath)))
|
||||
goto done_cookie;
|
||||
|
||||
// the domain should be at least the size of our cookie domain
|
||||
domain_offset = strlen(domain) - strlen(cdomain);
|
||||
if (domain_offset < 0)
|
||||
goto done_cookie;
|
||||
|
||||
// match the cookie domain
|
||||
if (av_strcasecmp(&domain[domain_offset], cdomain))
|
||||
goto done_cookie;
|
||||
|
||||
// cookie parameters match, so copy the value
|
||||
if (!*cookies) {
|
||||
if (!(*cookies = av_strdup(cvalue))) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto done_cookie;
|
||||
}
|
||||
} else {
|
||||
char *tmp = *cookies;
|
||||
size_t str_size = strlen(cvalue) + strlen(*cookies) + 3;
|
||||
if (!(*cookies = av_malloc(str_size))) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto done_cookie;
|
||||
}
|
||||
snprintf(*cookies, str_size, "%s; %s", tmp, cvalue);
|
||||
av_free(tmp);
|
||||
}
|
||||
|
||||
done_cookie:
|
||||
av_free(cdomain);
|
||||
av_free(cpath);
|
||||
av_free(cvalue);
|
||||
if (ret < 0) {
|
||||
if (*cookies) av_freep(cookies);
|
||||
av_free(cset_cookies);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
av_free(cset_cookies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int has_header(const char *str, const char *header)
|
||||
{
|
||||
/* header + 2 to skip over CRLF prefix. (make sure you have one!) */
|
||||
@ -460,6 +568,14 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
|
||||
if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
|
||||
len += av_strlcatf(headers + len, sizeof(headers) - len,
|
||||
"Content-Type: %s\r\n", s->content_type);
|
||||
if (!has_header(s->headers, "\r\nCookie: ") && s->cookies) {
|
||||
char *cookies = NULL;
|
||||
if (!get_cookies(s, &cookies, path, hoststr)) {
|
||||
len += av_strlcatf(headers + len, sizeof(headers) - len,
|
||||
"Cookie: %s\r\n", cookies);
|
||||
av_free(cookies);
|
||||
}
|
||||
}
|
||||
|
||||
/* now add in custom headers */
|
||||
if (s->headers)
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
#define LIBAVFORMAT_VERSION_MAJOR 54
|
||||
#define LIBAVFORMAT_VERSION_MINOR 60
|
||||
#define LIBAVFORMAT_VERSION_MICRO 100
|
||||
#define LIBAVFORMAT_VERSION_MICRO 101
|
||||
|
||||
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
||||
LIBAVFORMAT_VERSION_MINOR, \
|
||||
|
Loading…
Reference in New Issue
Block a user