Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support per-stream proxies in HLS streams (attempt 3) #9398

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions xbmc/FileItem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include "URL.h"
#include "settings/AdvancedSettings.h"
#include "settings/Settings.h"
#include "utils/Proxy.h"
#include "utils/RegExp.h"
#include "utils/log.h"
#include "utils/Variant.h"
Expand Down Expand Up @@ -1566,6 +1567,37 @@ bool CFileItem::IsPath(const std::string& path, bool ignoreURLOptions /* = false
return URIUtils::PathEquals(m_strPath, path, false, ignoreURLOptions);
}

CProxy CFileItem::GetProxy() const
{
CProxy proxy;
if (HasProperty("proxy.type"))
{
const std::string value = GetProperty("proxy.type").asString();
if (value == "http")
proxy.SetType(CProxy::ProxyHttp);
else if (value == "socks4")
proxy.SetType(CProxy::ProxySocks4);
else if (value == "socks4a")
proxy.SetType(CProxy::ProxySocks4A);
else if (value == "socks5")
proxy.SetType(CProxy::ProxySocks5);
else if (value == "socks5-remote")
proxy.SetType(CProxy::ProxySocks5Remote);
else
CLog::Log(LOGERROR,"Invalid proxy type \"%s\"", value.c_str());
}
if (HasProperty("proxy.host"))
proxy.SetHost(GetProperty("proxy.host").asString());
if (HasProperty("proxy.port"))
proxy.SetPort(GetProperty("proxy.port").asInteger());
if (HasProperty("proxy.user"))
proxy.SetUser(GetProperty("proxy.user").asString());
if (HasProperty("proxy.password"))
proxy.SetPassword(GetProperty("proxy.password").asString());

return proxy;
}

void CFileItem::SetCueDocument(const CCueDocumentPtr& cuePtr)
{
m_cueDocument = cuePtr;
Expand Down
3 changes: 3 additions & 0 deletions xbmc/FileItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "utils/ISerializable.h"
#include "utils/ISortable.h"
#include "utils/SortUtils.h"
#include "utils/Proxy.h"
#include "XBDateTime.h"

namespace MUSIC_INFO
Expand Down Expand Up @@ -130,6 +131,8 @@ class CFileItem :
void SetPath(const std::string &path) { m_strPath = path; };
bool IsPath(const std::string& path, bool ignoreURLOptions = false) const;

CProxy GetProxy() const;

/*! \brief reset class to it's default values as per construction.
Free's all allocated memory.
\sa Initialize
Expand Down
34 changes: 30 additions & 4 deletions xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "DVDDemuxFFmpeg.h"

#include <sstream>
#include <utility>

#include "commons/Exception.h"
Expand Down Expand Up @@ -230,9 +231,9 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo, bool filein
{
// special stream type that makes avformat handle file opening
// allows internal ffmpeg protocols to be used
CURL url = m_pInput->GetURL();
AVDictionary *options = GetFFMpegOptionsFromInput();

AVDictionary *options = GetFFMpegOptionsFromURL(url);
CURL url = m_pInput->GetURL();

int result=-1;
if (url.IsProtocol("mms"))
Expand Down Expand Up @@ -599,9 +600,9 @@ void CDVDDemuxFFmpeg::SetSpeed(int iSpeed)
}
}

AVDictionary *CDVDDemuxFFmpeg::GetFFMpegOptionsFromURL(const CURL &url)
AVDictionary *CDVDDemuxFFmpeg::GetFFMpegOptionsFromInput()
{

const CURL url = m_pInput->GetURL();
AVDictionary *options = NULL;

if (url.IsProtocol("http") || url.IsProtocol("https"))
Expand Down Expand Up @@ -638,6 +639,31 @@ AVDictionary *CDVDDemuxFFmpeg::GetFFMpegOptionsFromURL(const CURL &url)
av_dict_set(&options, "cookies", cookies.c_str(), 0);

}

const CProxy proxy = m_pInput->GetProxy();
if (proxy)
{
if (proxy.GetType() == CProxy::ProxyHttp)
{
std::ostringstream urlStream;

urlStream << "http://";

if (!proxy.GetUser().empty()) {
urlStream << proxy.GetUser();
if (!proxy.GetPassword().empty())
urlStream << ":" << proxy.GetPassword();
urlStream << "@";
}

urlStream << proxy.GetHost();
if (proxy.GetPort())
urlStream << ':' << proxy.GetPort();

av_dict_set(&options, "http_proxy", urlStream.str().c_str(), 0);
}
}

return options;
}

Expand Down
2 changes: 1 addition & 1 deletion xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux
bool IsVideoReady();
void ResetVideoStreams();

AVDictionary *GetFFMpegOptionsFromURL(const CURL &url);
AVDictionary *GetFFMpegOptionsFromInput();
double ConvertTimestamp(int64_t pts, int den, int num);
void UpdateCurrentPTS();
bool IsProgramChange();
Expand Down
5 changes: 0 additions & 5 deletions xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,3 @@ std::string CDVDInputStream::GetFileName()
url.SetProtocolOptions("");
return url.Get();
}

CURL CDVDInputStream::GetURL()
{
return m_item.GetURL();
}
6 changes: 5 additions & 1 deletion xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@

#include <string>
#include <vector>

#include "utils/BitstreamStats.h"
#include "utils/Proxy.h"
#include "filesystem/IFileTypes.h"

#include "FileItem.h"
Expand Down Expand Up @@ -149,14 +151,16 @@ class CDVDInputStream
virtual int64_t GetLength() = 0;
virtual std::string& GetContent() { return m_content; };
virtual std::string GetFileName();
virtual CURL GetURL();
virtual ENextStream NextStream() { return NEXTSTREAM_NONE; }
virtual void Abort() {}
virtual int GetBlockSize() { return 0; }
virtual void ResetScanTimeout(unsigned int iTimeoutMs) { }
virtual bool CanSeek() { return true; }
virtual bool CanPause() { return true; }

CURL GetURL() { return m_item.GetURL(); }
CProxy GetProxy() { return m_item.GetProxy(); }

/*! \brief Indicate expected read rate in bytes per second.
* This could be used to throttle caching rate. Should
* be seen as only a hint
Expand Down
11 changes: 6 additions & 5 deletions xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamFFmpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,19 @@ bool CDVDInputStreamFFmpeg::IsEOF()

bool CDVDInputStreamFFmpeg::Open()
{
std::string selected;
if (m_item.IsInternetStream() && (m_item.IsType(".m3u8") || m_item.GetMimeType() == "application/vnd.apple.mpegurl"))
{
// get the available bandwidth and determine the most appropriate stream
int bandwidth = CSettings::GetInstance().GetInt(CSettings::SETTING_NETWORK_BANDWIDTH);
if(bandwidth <= 0)
bandwidth = INT_MAX;
selected = PLAYLIST::CPlayListM3U::GetBestBandwidthStream(m_item.GetPath(), bandwidth);
if (selected.compare(m_item.GetPath()) != 0)
const CURL playlist_url = m_item.GetURL();
const CProxy proxy = m_item.GetProxy();
const CURL selected = PLAYLIST::CPlayListM3U::GetBestBandwidthStream(playlist_url, bandwidth, proxy);
if (selected.Get().compare(playlist_url.Get()) != 0)
{
CLog::Log(LOGINFO, "CDVDInputStreamFFmpeg: Auto-selecting %s based on configured bandwidth.", selected.c_str());
m_item.SetPath(selected.c_str());
CLog::Log(LOGINFO, "CDVDInputStreamFFmpeg: Auto-selecting %s based on configured bandwidth.", selected.Get().c_str());
m_item.SetURL(selected);
}
}

Expand Down
47 changes: 29 additions & 18 deletions xbmc/filesystem/CurlFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <vector>
#include <climits>
#include <cassert>
#include <sstream>

#ifdef TARGET_POSIX
#include <errno.h>
Expand Down Expand Up @@ -406,6 +407,7 @@ CCurlFile::~CCurlFile()

CCurlFile::CCurlFile()
: m_writeOffset(0)
, m_proxy()
, m_overflowBuffer(NULL)
, m_overflowSize(0)
{
Expand All @@ -428,7 +430,6 @@ CCurlFile::CCurlFile()
m_password = "";
m_httpauth = "";
m_cipherlist = "";
m_proxytype = PROXY_HTTP;
m_state = new CReadState();
m_oldState = NULL;
m_skipshout = false;
Expand Down Expand Up @@ -607,13 +608,20 @@ void CCurlFile::SetCommonOptions(CReadState* state)
if (g_advancedSettings.m_curlDisableIPV6)
g_curlInterface.easy_setopt(h, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);

if (m_proxy.length() > 0)
if (m_proxy)
{
g_curlInterface.easy_setopt(h, CURLOPT_PROXY, m_proxy.c_str());
g_curlInterface.easy_setopt(h, CURLOPT_PROXYTYPE, proxyType2CUrlProxyType[m_proxytype]);
if (m_proxyuserpass.length() > 0)
g_curlInterface.easy_setopt(h, CURLOPT_PROXYUSERPWD, m_proxyuserpass.c_str());

std::ostringstream hostport;
if (!m_proxy.GetHost().empty()) {
hostport << m_proxy.GetHost();
if (m_proxy.GetPort())
hostport << ':' << m_proxy.GetPort();
}
g_curlInterface.easy_setopt(h, CURLOPT_PROXY, hostport.str().c_str());
g_curlInterface.easy_setopt(h, CURLOPT_PROXYTYPE, proxyType2CUrlProxyType[m_proxy.GetType()]);
const std::string userpass =
m_proxy.GetUser() + std::string(":") + m_proxy.GetPassword();
if (!userpass.empty())
g_curlInterface.easy_setopt(h, CURLOPT_PROXYUSERPWD, userpass.c_str());
}
if (m_customrequest.length() > 0)
g_curlInterface.easy_setopt(h, CURLOPT_CUSTOMREQUEST, m_customrequest.c_str());
Expand Down Expand Up @@ -754,20 +762,23 @@ void CCurlFile::ParseAndCorrectUrl(CURL &url2)
else if( url2.IsProtocol("http")
|| url2.IsProtocol("https"))
{
if (CSettings::GetInstance().GetBool(CSettings::SETTING_NETWORK_USEHTTPPROXY)
&& !CSettings::GetInstance().GetString(CSettings::SETTING_NETWORK_HTTPPROXYSERVER).empty()
&& CSettings::GetInstance().GetInt(CSettings::SETTING_NETWORK_HTTPPROXYPORT) > 0
&& m_proxy.empty())
const CSettings &s = CSettings::GetInstance();
if (s.GetBool(CSettings::SETTING_NETWORK_USEHTTPPROXY)
&& !s.GetString(CSettings::SETTING_NETWORK_HTTPPROXYSERVER).empty()
&& s.GetInt(CSettings::SETTING_NETWORK_HTTPPROXYPORT) > 0
&& !m_proxy)
{
m_proxy = CSettings::GetInstance().GetString(CSettings::SETTING_NETWORK_HTTPPROXYSERVER);
m_proxy += StringUtils::Format(":%d", CSettings::GetInstance().GetInt(CSettings::SETTING_NETWORK_HTTPPROXYPORT));
if (CSettings::GetInstance().GetString(CSettings::SETTING_NETWORK_HTTPPROXYUSERNAME).length() > 0 && m_proxyuserpass.empty())
m_proxy.SetHost(s.GetString(CSettings::SETTING_NETWORK_HTTPPROXYSERVER));
m_proxy.SetPort(s.GetInt(CSettings::SETTING_NETWORK_HTTPPROXYPORT));
if (s.GetString(CSettings::SETTING_NETWORK_HTTPPROXYUSERNAME).length() > 0
&& m_proxy.GetUser().empty()
&& m_proxy.GetPassword().empty())
{
m_proxyuserpass = CSettings::GetInstance().GetString(CSettings::SETTING_NETWORK_HTTPPROXYUSERNAME);
m_proxyuserpass += ":" + CSettings::GetInstance().GetString(CSettings::SETTING_NETWORK_HTTPPROXYPASSWORD);
m_proxy.SetUser(s.GetString(CSettings::SETTING_NETWORK_HTTPPROXYUSERNAME));
m_proxy.SetPassword(s.GetString(CSettings::SETTING_NETWORK_HTTPPROXYPASSWORD));
}
m_proxytype = (ProxyType)CSettings::GetInstance().GetInt(CSettings::SETTING_NETWORK_HTTPPROXYTYPE);
CLog::Log(LOGDEBUG, "Using proxy %s, type %d", m_proxy.c_str(), proxyType2CUrlProxyType[m_proxytype]);
m_proxy.SetType((CProxy::Type)s.GetInt(CSettings::SETTING_NETWORK_HTTPPROXYTYPE));
CLog::Log(LOGDEBUG, "Using proxy %s, type %d", m_proxy.GetHost().c_str(), proxyType2CUrlProxyType[m_proxy.GetType()]);
}

// get username and password
Expand Down
18 changes: 3 additions & 15 deletions xbmc/filesystem/CurlFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <map>
#include <string>
#include "utils/HttpHeader.h"
#include "utils/Proxy.h"

namespace XCURL
{
Expand All @@ -37,15 +38,6 @@ namespace XFILE
class CCurlFile : public IFile
{
public:
typedef enum
{
PROXY_HTTP = 0,
PROXY_SOCKS4,
PROXY_SOCKS4A,
PROXY_SOCKS5,
PROXY_SOCKS5_REMOTE,
} ProxyType;

CCurlFile();
virtual ~CCurlFile();
virtual bool Open(const CURL& url);
Expand All @@ -64,6 +56,7 @@ namespace XFILE
virtual int IoControl(EIoControl request, void* param);
virtual std::string GetContentCharset(void) { return GetServerReportedCharset(); }
virtual double GetDownloadSpeed();
virtual void SetProxy(const CProxy &proxy) { m_proxy = proxy; };

bool Post(const std::string& strURL, const std::string& strPostData, std::string& strHTML);
bool Get(const std::string& strURL, std::string& strHTML);
Expand All @@ -73,9 +66,6 @@ namespace XFILE
void Cancel();
void Reset();
void SetUserAgent(const std::string& sUserAgent) { m_userAgent = sUserAgent; }
void SetProxy(const std::string &proxy) { m_proxy = proxy; }
void SetProxyUserPass(const std::string &proxyuserpass) { m_proxyuserpass = proxyuserpass; }
void SetProxyType(ProxyType proxytype) { m_proxytype = proxytype; }
void SetCustomRequest(const std::string &request) { m_customrequest = request; }
void UseOldHttpVersion(bool bUse) { m_useOldHttpVersion = bUse; }
void SetAcceptEncoding(const std::string& encoding) { m_acceptencoding = encoding; }
Expand Down Expand Up @@ -164,9 +154,7 @@ namespace XFILE

std::string m_url;
std::string m_userAgent;
std::string m_proxy;
std::string m_proxyuserpass;
ProxyType m_proxytype;
CProxy m_proxy;
std::string m_customrequest;
std::string m_acceptencoding;
std::string m_acceptCharset;
Expand Down
2 changes: 2 additions & 0 deletions xbmc/filesystem/File.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ bool CFile::Open(const CURL& file, const unsigned int flags)
if (!m_pFile)
return false;

m_pFile->SetProxy(m_proxy);

try
{
if (!m_pFile->Open(url))
Expand Down
5 changes: 5 additions & 0 deletions xbmc/filesystem/File.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <stdio.h>
#include <string>
#include "utils/auto_buffer.h"
#include "utils/Proxy.h"
#include "IFileTypes.h"
#include "PlatformDefs.h"
#include "URL.h"
Expand Down Expand Up @@ -64,6 +65,9 @@ class CFile
bool CURLAddOption(XFILE::CURLOPTIONTYPE type, const char* name, const char * value);
bool CURLOpen(unsigned int flags);

void SetProxy(const CProxy &proxy) { m_proxy = proxy; };
const CProxy& GetProxy() const { return m_proxy; };

bool Open(const CURL& file, const unsigned int flags = 0);
bool OpenForWrite(const CURL& file, bool bOverWrite = false);
ssize_t LoadFile(const CURL &file, auto_buffer& outputBuffer);
Expand Down Expand Up @@ -174,6 +178,7 @@ class CFile
private:
unsigned int m_flags;
CURL m_curl;
CProxy m_proxy;
IFile* m_pFile;
CFileStreamBuffer* m_pBuffer;
BitstreamStats* m_bitStreamStats;
Expand Down
4 changes: 1 addition & 3 deletions xbmc/filesystem/FileCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,8 @@ bool CFileCache::Open(const CURL& url)

CLog::Log(LOGDEBUG,"CFileCache::Open - opening <%s> using cache", url.GetFileName().c_str());

m_sourcePath = url.Get();

// opening the source file.
if (!m_source.Open(m_sourcePath, READ_NO_CACHE | READ_TRUNCATED | READ_CHUNKED))
if (!m_source.Open(url, READ_NO_CACHE | READ_TRUNCATED | READ_CHUNKED))
{
CLog::Log(LOGERROR,"%s - failed to open source <%s>", __FUNCTION__, url.GetRedacted().c_str());
Close();
Expand Down
1 change: 0 additions & 1 deletion xbmc/filesystem/FileCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ namespace XFILE
bool m_bDeleteCache;
int m_seekPossible;
CFile m_source;
std::string m_sourcePath;
CEvent m_seekEvent;
CEvent m_seekEnded;
int64_t m_nSeekResult;
Expand Down
Loading