[FFmpeg-cvslog] http: Add a new protocol for opening connections via http proxies

Martin Storsjö git at videolan.org
Sat Nov 19 02:09:42 CET 2011


ffmpeg | branch: master | Martin Storsjö <martin at martin.st> | Thu Nov 10 14:53:16 2011 +0200| [9f1dae944e2cf72800eb79b32e831b59fd6afdb0] | committer: 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: Martin Storsjö <martin at martin.st>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=9f1dae944e2cf72800eb79b32e831b59fd6afdb0
---

 libavformat/allformats.c |    1 +
 libavformat/http.c       |  115 ++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/version.h    |    2 +-
 3 files changed, 117 insertions(+), 1 deletions(-)

diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 00924c8..bee2f5f 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -242,6 +242,7 @@ void av_register_all(void)
     REGISTER_PROTOCOL (FILE, file);
     REGISTER_PROTOCOL (GOPHER, gopher);
     REGISTER_PROTOCOL (HTTP, http);
+    REGISTER_PROTOCOL (HTTPPROXY, httpproxy);
     REGISTER_PROTOCOL (HTTPS, https);
     REGISTER_PROTOCOL (MMSH, mmsh);
     REGISTER_PROTOCOL (MMST, mmst);
diff --git a/libavformat/http.c b/libavformat/http.c
index d5bf96b..5941925 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -578,3 +578,118 @@ URLProtocol ff_https_protocol = {
     .priv_data_class     = &https_context_class,
 };
 #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
diff --git a/libavformat/version.h b/libavformat/version.h
index ec5d1fd..6c1db42 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -24,7 +24,7 @@
 #include "libavutil/avutil.h"
 
 #define LIBAVFORMAT_VERSION_MAJOR 53
-#define LIBAVFORMAT_VERSION_MINOR 14
+#define LIBAVFORMAT_VERSION_MINOR 15
 #define LIBAVFORMAT_VERSION_MICRO  0
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \



More information about the ffmpeg-cvslog mailing list