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 is_akamai;
|
||||||
int rw_timeout;
|
int rw_timeout;
|
||||||
char *mime_type;
|
char *mime_type;
|
||||||
|
char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
|
||||||
} HTTPContext;
|
} HTTPContext;
|
||||||
|
|
||||||
#define OFFSET(x) offsetof(HTTPContext, x)
|
#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 },
|
{"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 },
|
{"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 },
|
{"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}
|
{NULL}
|
||||||
};
|
};
|
||||||
#define HTTP_CLASS(flavor)\
|
#define HTTP_CLASS(flavor)\
|
||||||
@ -359,11 +361,117 @@ static int process_line(URLContext *h, char *line, int line_count,
|
|||||||
s->is_akamai = 1;
|
s->is_akamai = 1;
|
||||||
} else if (!av_strcasecmp (tag, "Content-Type")) {
|
} else if (!av_strcasecmp (tag, "Content-Type")) {
|
||||||
av_free(s->mime_type); s->mime_type = av_strdup(p);
|
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;
|
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)
|
static inline int has_header(const char *str, const char *header)
|
||||||
{
|
{
|
||||||
/* header + 2 to skip over CRLF prefix. (make sure you have one!) */
|
/* 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)
|
if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
|
||||||
len += av_strlcatf(headers + len, sizeof(headers) - len,
|
len += av_strlcatf(headers + len, sizeof(headers) - len,
|
||||||
"Content-Type: %s\r\n", s->content_type);
|
"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 */
|
/* now add in custom headers */
|
||||||
if (s->headers)
|
if (s->headers)
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_MAJOR 54
|
#define LIBAVFORMAT_VERSION_MAJOR 54
|
||||||
#define LIBAVFORMAT_VERSION_MINOR 60
|
#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, \
|
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
||||||
LIBAVFORMAT_VERSION_MINOR, \
|
LIBAVFORMAT_VERSION_MINOR, \
|
||||||
|
Loading…
Reference in New Issue
Block a user