[vlc-devel] [PATCH] demux: adaptive: fix http request with IPv6 reference

Xie Zhigang zighouse at hotmail.com
Sat Dec 19 09:53:48 UTC 2020


VLC doesn't play hls streams over IPv6 addresses, and here is my patch.
To test it, provide an hls stream on your pC, for example of mine:

 (IPv4 version) http://127.0.0.1/hls/1_1080p.m3u8

It is happy to play this url with VLC, but fails on IPv6 url:

 (IPv6 version) http://[::1]/hls/1_1080p.m3u8

For here, "::1" is IPv6 local loopback address. And according to RFC2732,
it should use IPv6 reference as host in URLs, as "[::1]".
IPv6 referenced URLs are ok for other players: gst-player-1.0, ffplay, etc.

---
 modules/demux/adaptive/http/ConnectionParams.cpp | 62 +++++++++++++++++++++++-
 modules/demux/adaptive/http/ConnectionParams.hpp | 2 +
 modules/demux/adaptive/http/HTTPConnection.cpp | 14 +++++-
 3 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/modules/demux/adaptive/http/ConnectionParams.cpp b/modules/demux/adaptive/http/ConnectionParams.cpp
index 6e3f221..9a632a8 100644
--- a/modules/demux/adaptive/http/ConnectionParams.cpp
+++ b/modules/demux/adaptive/http/ConnectionParams.cpp
@@ -69,7 +69,10 @@ void ConnectionParams::setPath(const std::string &path_)
     os << scheme << "://";
     if(!hostname.empty())
     {
- os << hostname;
+ if (ipv6)
+ os << '[' << hostname << ']';
+ else
+ os << hostname;
         if( (port != 80 && scheme != "http") ||
             (port != 443 && scheme != "https") )
             os << ":" << port;
@@ -88,6 +91,60 @@ bool ConnectionParams::isLocal() const
     return scheme != "http" && scheme != "https";
 }

+bool isIPv6() const;
+{
+ return ipv6;
+}
+
+static int is_ipv6_addr (const char * host)
+{
+ const char * p;
+ unsigned colons = 0, nums = 0, decs = 0, dots = 0;
+ if (!host)
+ {
+ return 0;
+ }
+ for (p = host; *p; p++)
+ {
+ char c = *p;
+ if (c == ':')
+ {
+ colons ++;
+ if (nums > 4)
+ {
+ return 0;
+ }
+ nums = 0;
+ decs = 0;
+ }
+ else if (('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'))
+ {
+ if ('0' <= c && c <= '9')
+ {
+ decs ++;
+ }
+ nums ++;
+ }
+ else if (c == '.')
+ {
+ dots ++;
+ if (nums != decs)
+ {
+ return 0;
+ }
+ if (nums == 0 || 3 < nums)
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ return 2 <= colons && colons <= 7 && (dots == 0 || dots == 3);
+}
+
 void ConnectionParams::parse()
 {
     vlc_url_t url_components;
@@ -108,7 +165,10 @@ void ConnectionParams::parse()
     port = url_components.i_port ? url_components.i_port :
                          ((scheme == "https") ? 443 : 80);
     if(url_components.psz_host)
+ {
         hostname = url_components.psz_host;
+ ipv6 = is_ipv6_addr(url_components.psz_host);
+ }

     vlc_UrlClean(&url_components);
 }
diff --git a/modules/demux/adaptive/http/ConnectionParams.hpp b/modules/demux/adaptive/http/ConnectionParams.hpp
index fb9f9d9..868bd97 100644
--- a/modules/demux/adaptive/http/ConnectionParams.hpp
+++ b/modules/demux/adaptive/http/ConnectionParams.hpp
@@ -62,6 +62,7 @@ namespace adaptive
                 bool isLocal() const;
                 void setPath(const std::string &);
                 uint16_t getPort() const;
+ bool isIPv6() const;

             private:
                 void parse();
@@ -70,6 +71,7 @@ namespace adaptive
                 std::string hostname;
                 std::string path;
                 uint16_t port;
+ bool ipv6;
         };
     }
 }
diff --git a/modules/demux/adaptive/http/HTTPConnection.cpp b/modules/demux/adaptive/http/HTTPConnection.cpp
index 36354c5..e103440 100644
--- a/modules/demux/adaptive/http/HTTPConnection.cpp
+++ b/modules/demux/adaptive/http/HTTPConnection.cpp
@@ -432,11 +432,21 @@ std::string HTTPConnection::buildRequestHeader(const std::string &path) const
     if((params.getScheme() == "http" && params.getPort() != 80) ||
             (params.getScheme() == "https" && params.getPort() != 443))
     {
- req << "Host: " << params.getHostname() << ":" << params.getPort() << "\r\n";
+ req << "Host: ";
+ if (params.isIPv6())
+ req << '[' << params.getHostname() << ']';
+ else
+ req << params.getHostname();
+ req << ":" << params.getPort() << "\r\n";
     }
     else
     {
- req << "Host: " << params.getHostname() << "\r\n";
+ req << "Host: ";
+ if (params.isIPv6())
+ req << '[' << params.getHostname() << ']';
+ else
+ req << params.getHostname();
+ req << "\r\n";
     }
     if(authStorage)
     {
--
2.7.4

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20201219/eb89a627/attachment.html>


More information about the vlc-devel mailing list