Commit 9f1dae94 authored by Martin Storsjö's avatar Martin Storsjö

http: Add a new protocol for opening connections via http proxies

This opens a plain TCP connection through the proxy via the
CONNECT HTTP method. Normally, this is allowed for connections
on port 443, but can in general be used to allow connections
to any port (depending on proxy configuration), and could thus
be used to tunnel any TCP connection via a HTTP proxy.
Signed-off-by: 's avatarMartin Storsjö <martin@martin.st>
parent bf7723a6
...@@ -242,6 +242,7 @@ void av_register_all(void) ...@@ -242,6 +242,7 @@ void av_register_all(void)
REGISTER_PROTOCOL (FILE, file); REGISTER_PROTOCOL (FILE, file);
REGISTER_PROTOCOL (GOPHER, gopher); REGISTER_PROTOCOL (GOPHER, gopher);
REGISTER_PROTOCOL (HTTP, http); REGISTER_PROTOCOL (HTTP, http);
REGISTER_PROTOCOL (HTTPPROXY, httpproxy);
REGISTER_PROTOCOL (HTTPS, https); REGISTER_PROTOCOL (HTTPS, https);
REGISTER_PROTOCOL (MMSH, mmsh); REGISTER_PROTOCOL (MMSH, mmsh);
REGISTER_PROTOCOL (MMST, mmst); REGISTER_PROTOCOL (MMST, mmst);
......
...@@ -578,3 +578,118 @@ URLProtocol ff_https_protocol = { ...@@ -578,3 +578,118 @@ URLProtocol ff_https_protocol = {
.priv_data_class = &https_context_class, .priv_data_class = &https_context_class,
}; };
#endif #endif
#if CONFIG_HTTPPROXY_PROTOCOL
static int http_proxy_close(URLContext *h)
{
HTTPContext *s = h->priv_data;
if (s->hd)
ffurl_close(s->hd);
return 0;
}
static int http_proxy_open(URLContext *h, const char *uri, int flags)
{
HTTPContext *s = h->priv_data;
char hostname[1024], hoststr[1024];
char auth[1024], pathbuf[1024], *path;
char line[1024], lower_url[100];
int port, ret = 0;
HTTPAuthType cur_auth_type;
char *authstr;
h->is_streamed = 1;
av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
pathbuf, sizeof(pathbuf), uri);
ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
path = pathbuf;
if (*path == '/')
path++;
ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port,
NULL);
redo:
ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
&h->interrupt_callback, NULL);
if (ret < 0)
return ret;
authstr = ff_http_auth_create_response(&s->proxy_auth_state, auth,
path, "CONNECT");
snprintf(s->buffer, sizeof(s->buffer),
"CONNECT %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Connection: close\r\n"
"%s%s"
"\r\n",
path,
hoststr,
authstr ? "Proxy-" : "", authstr ? authstr : "");
av_freep(&authstr);
if ((ret = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
goto fail;
s->buf_ptr = s->buffer;
s->buf_end = s->buffer;
s->line_count = 0;
s->filesize = -1;
cur_auth_type = s->proxy_auth_state.auth_type;
for (;;) {
int new_loc;
// Note: This uses buffering, potentially reading more than the
// HTTP header. If tunneling a protocol where the server starts
// the conversation, we might buffer part of that here, too.
// Reading that requires using the proper ffurl_read() function
// on this URLContext, not using the fd directly (as the tls
// protocol does). This shouldn't be an issue for tls though,
// since the client starts the conversation there, so there
// is no extra data that we might buffer up here.
if (http_get_line(s, line, sizeof(line)) < 0) {
ret = AVERROR(EIO);
goto fail;
}
av_dlog(h, "header='%s'\n", line);
ret = process_line(h, line, s->line_count, &new_loc);
if (ret < 0)
goto fail;
if (ret == 0)
break;
s->line_count++;
}
if (s->http_code == 407 && cur_auth_type == HTTP_AUTH_NONE &&
s->proxy_auth_state.auth_type != HTTP_AUTH_NONE) {
ffurl_close(s->hd);
s->hd = NULL;
goto redo;
}
if (s->http_code < 400)
return 0;
ret = AVERROR(EIO);
fail:
http_proxy_close(h);
return ret;
}
static int http_proxy_write(URLContext *h, const uint8_t *buf, int size)
{
HTTPContext *s = h->priv_data;
return ffurl_write(s->hd, buf, size);
}
URLProtocol ff_httpproxy_protocol = {
.name = "httpproxy",
.url_open = http_proxy_open,
.url_read = http_buf_read,
.url_write = http_proxy_write,
.url_close = http_proxy_close,
.url_get_file_handle = http_get_file_handle,
.priv_data_size = sizeof(HTTPContext),
};
#endif
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include "libavutil/avutil.h" #include "libavutil/avutil.h"
#define LIBAVFORMAT_VERSION_MAJOR 53 #define LIBAVFORMAT_VERSION_MAJOR 53
#define LIBAVFORMAT_VERSION_MINOR 14 #define LIBAVFORMAT_VERSION_MINOR 15
#define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_MICRO 0
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment