summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2011-11-11 11:21:42 +0200
committerMartin Storsjö <martin@martin.st>2011-11-11 14:07:57 +0200
commitb911518d1c17223aa7fb83ace08b2bd41c203da0 (patch)
tree29468e43b6e93c65d6f8e03fd4feb36fc399081e
parentb01f5ba2070e022e6cf6c1fa8410367e90e33b60 (diff)
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>
-rw-r--r--libavformat/http.c75
-rw-r--r--libavformat/httpauth.c2
2 files changed, 53 insertions, 24 deletions
diff --git a/libavformat/http.c b/libavformat/http.c
index 093bb822dc..a8a76882dd 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -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);
diff --git a/libavformat/httpauth.c b/libavformat/httpauth.c
index 1dda1ac8f0..c8b8ace3c2 100644
--- a/libavformat/httpauth.c
+++ b/libavformat/httpauth.c
@@ -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) {