mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
http: Handle proxy authentication
Tested with both Basic and Digest authentication, and tested with both proxy authentication and authentication for the requested resource at the same time. Signed-off-by: Martin Storsjö <martin@martin.st>
This commit is contained in:
parent
b01f5ba207
commit
b911518d1c
@ -47,6 +47,7 @@ typedef struct {
|
||||
int64_t off, filesize;
|
||||
char location[MAX_URL_SIZE];
|
||||
HTTPAuthState auth_state;
|
||||
HTTPAuthState proxy_auth_state;
|
||||
char *headers;
|
||||
int willclose; /**< Set if the server correctly handles Connection: close and will close the connection after feeding us the content. */
|
||||
int chunked_post;
|
||||
@ -71,25 +72,29 @@ static const AVClass flavor ## _context_class = {\
|
||||
HTTP_CLASS(http);
|
||||
HTTP_CLASS(https);
|
||||
|
||||
static int http_connect(URLContext *h, const char *path, const char *hoststr,
|
||||
const char *auth, int *new_location);
|
||||
static int http_connect(URLContext *h, const char *path, const char *local_path,
|
||||
const char *hoststr, const char *auth,
|
||||
const char *proxyauth, int *new_location);
|
||||
|
||||
void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
|
||||
{
|
||||
memcpy(&((HTTPContext*)dest->priv_data)->auth_state,
|
||||
&((HTTPContext*)src->priv_data)->auth_state, sizeof(HTTPAuthState));
|
||||
memcpy(&((HTTPContext*)dest->priv_data)->proxy_auth_state,
|
||||
&((HTTPContext*)src->priv_data)->proxy_auth_state,
|
||||
sizeof(HTTPAuthState));
|
||||
}
|
||||
|
||||
/* return non zero if error */
|
||||
static int http_open_cnx(URLContext *h)
|
||||
{
|
||||
const char *path, *proxy_path, *lower_proto = "tcp";
|
||||
const char *path, *proxy_path, *lower_proto = "tcp", *local_path;
|
||||
char hostname[1024], hoststr[1024], proto[10];
|
||||
char auth[1024];
|
||||
char auth[1024], proxyauth[1024];
|
||||
char path1[1024];
|
||||
char buf[1024];
|
||||
char buf[1024], urlbuf[1024];
|
||||
int port, use_proxy, err, location_changed = 0, redirects = 0;
|
||||
HTTPAuthType cur_auth_type;
|
||||
HTTPAuthType cur_auth_type, cur_proxy_auth_type;
|
||||
HTTPContext *s = h->priv_data;
|
||||
URLContext *hd = NULL;
|
||||
|
||||
@ -105,15 +110,19 @@ static int http_open_cnx(URLContext *h)
|
||||
path1, sizeof(path1), s->location);
|
||||
ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
|
||||
|
||||
if (path1[0] == '\0')
|
||||
path = "/";
|
||||
else
|
||||
path = path1;
|
||||
local_path = path;
|
||||
if (use_proxy) {
|
||||
av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
|
||||
NULL, 0, proxy_path);
|
||||
path = s->location;
|
||||
} else {
|
||||
if (path1[0] == '\0')
|
||||
path = "/";
|
||||
else
|
||||
path = path1;
|
||||
/* Reassemble the request URL without auth string - we don't
|
||||
* want to leak the auth to the proxy. */
|
||||
ff_url_join(urlbuf, sizeof(urlbuf), proto, NULL, hostname, port, "%s",
|
||||
path1);
|
||||
path = urlbuf;
|
||||
av_url_split(NULL, 0, proxyauth, sizeof(proxyauth),
|
||||
hostname, sizeof(hostname), &port, NULL, 0, proxy_path);
|
||||
}
|
||||
if (!strcmp(proto, "https")) {
|
||||
lower_proto = "tls";
|
||||
@ -130,7 +139,8 @@ static int http_open_cnx(URLContext *h)
|
||||
|
||||
s->hd = hd;
|
||||
cur_auth_type = s->auth_state.auth_type;
|
||||
if (http_connect(h, path, hoststr, auth, &location_changed) < 0)
|
||||
cur_proxy_auth_type = s->auth_state.auth_type;
|
||||
if (http_connect(h, path, local_path, hoststr, auth, proxyauth, &location_changed) < 0)
|
||||
goto fail;
|
||||
if (s->http_code == 401) {
|
||||
if (cur_auth_type == HTTP_AUTH_NONE && s->auth_state.auth_type != HTTP_AUTH_NONE) {
|
||||
@ -139,6 +149,14 @@ static int http_open_cnx(URLContext *h)
|
||||
} else
|
||||
goto fail;
|
||||
}
|
||||
if (s->http_code == 407) {
|
||||
if (cur_proxy_auth_type == HTTP_AUTH_NONE &&
|
||||
s->proxy_auth_state.auth_type != HTTP_AUTH_NONE) {
|
||||
ffurl_close(hd);
|
||||
goto redo;
|
||||
} else
|
||||
goto fail;
|
||||
}
|
||||
if ((s->http_code == 301 || s->http_code == 302 || s->http_code == 303 || s->http_code == 307)
|
||||
&& location_changed == 1) {
|
||||
/* url moved, get next */
|
||||
@ -237,7 +255,8 @@ static int process_line(URLContext *h, char *line, int line_count,
|
||||
/* error codes are 4xx and 5xx, but regard 401 as a success, so we
|
||||
* don't abort until all headers have been parsed. */
|
||||
if (s->http_code >= 400 && s->http_code < 600 && (s->http_code != 401
|
||||
|| s->auth_state.auth_type != HTTP_AUTH_NONE)) {
|
||||
|| s->auth_state.auth_type != HTTP_AUTH_NONE) &&
|
||||
(s->http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) {
|
||||
end += strspn(end, SPACE_CHARS);
|
||||
av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n",
|
||||
s->http_code, end);
|
||||
@ -278,6 +297,8 @@ static int process_line(URLContext *h, char *line, int line_count,
|
||||
ff_http_auth_handle_header(&s->auth_state, tag, p);
|
||||
} else if (!av_strcasecmp (tag, "Authentication-Info")) {
|
||||
ff_http_auth_handle_header(&s->auth_state, tag, p);
|
||||
} else if (!av_strcasecmp (tag, "Proxy-Authenticate")) {
|
||||
ff_http_auth_handle_header(&s->proxy_auth_state, tag, p);
|
||||
} else if (!av_strcasecmp (tag, "Connection")) {
|
||||
if (!strcmp(p, "close"))
|
||||
s->willclose = 1;
|
||||
@ -294,22 +315,27 @@ static inline int has_header(const char *str, const char *header)
|
||||
return av_stristart(str, header + 2, NULL) || av_stristr(str, header);
|
||||
}
|
||||
|
||||
static int http_connect(URLContext *h, const char *path, const char *hoststr,
|
||||
const char *auth, int *new_location)
|
||||
static int http_connect(URLContext *h, const char *path, const char *local_path,
|
||||
const char *hoststr, const char *auth,
|
||||
const char *proxyauth, int *new_location)
|
||||
{
|
||||
HTTPContext *s = h->priv_data;
|
||||
int post, err;
|
||||
char line[1024];
|
||||
char headers[1024] = "";
|
||||
char *authstr = NULL;
|
||||
char *authstr = NULL, *proxyauthstr = NULL;
|
||||
int64_t off = s->off;
|
||||
int len = 0;
|
||||
const char *method;
|
||||
|
||||
|
||||
/* send http header */
|
||||
post = h->flags & AVIO_FLAG_WRITE;
|
||||
authstr = ff_http_auth_create_response(&s->auth_state, auth, path,
|
||||
post ? "POST" : "GET");
|
||||
method = post ? "POST" : "GET";
|
||||
authstr = ff_http_auth_create_response(&s->auth_state, auth, local_path,
|
||||
method);
|
||||
proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth,
|
||||
local_path, method);
|
||||
|
||||
/* set default headers if needed */
|
||||
if (!has_header(s->headers, "\r\nUser-Agent: "))
|
||||
@ -337,14 +363,17 @@ static int http_connect(URLContext *h, const char *path, const char *hoststr,
|
||||
"%s"
|
||||
"%s"
|
||||
"%s"
|
||||
"%s%s"
|
||||
"\r\n",
|
||||
post ? "POST" : "GET",
|
||||
method,
|
||||
path,
|
||||
post && s->chunked_post ? "Transfer-Encoding: chunked\r\n" : "",
|
||||
headers,
|
||||
authstr ? authstr : "");
|
||||
authstr ? authstr : "",
|
||||
proxyauthstr ? "Proxy-" : "", proxyauthstr ? proxyauthstr : "");
|
||||
|
||||
av_freep(&authstr);
|
||||
av_freep(&proxyauthstr);
|
||||
if (ffurl_write(s->hd, s->buffer, strlen(s->buffer)) < 0)
|
||||
return AVERROR(EIO);
|
||||
|
||||
|
@ -87,7 +87,7 @@ static void choose_qop(char *qop, int size)
|
||||
void ff_http_auth_handle_header(HTTPAuthState *state, const char *key,
|
||||
const char *value)
|
||||
{
|
||||
if (!strcmp(key, "WWW-Authenticate")) {
|
||||
if (!strcmp(key, "WWW-Authenticate") || !strcmp(key, "Proxy-Authenticate")) {
|
||||
const char *p;
|
||||
if (av_stristart(value, "Basic ", &p) &&
|
||||
state->auth_type <= HTTP_AUTH_BASIC) {
|
||||
|
Loading…
Reference in New Issue
Block a user