X-Git-Url: http://code.vuplus.com/gitweb/?a=blobdiff_plain;f=xbmc%2Ffilesystem%2FCurlFile.cpp;h=4808465c1dfc9e7e7712f03a9e11bb3d7784e615;hb=f92a074a74a570f52e546ba4f28d9346bf8ddd31;hp=b6b8eb12fb8ad8eaab14859a230f0d5c136ba504;hpb=44824bc8e71b5a37fd8ef70692c55a080e51044f;p=vuplus_xbmc diff --git a/xbmc/filesystem/CurlFile.cpp b/xbmc/filesystem/CurlFile.cpp index b6b8eb1..4808465 100644 --- a/xbmc/filesystem/CurlFile.cpp +++ b/xbmc/filesystem/CurlFile.cpp @@ -25,6 +25,7 @@ #include "settings/AdvancedSettings.h" #include "settings/Settings.h" #include "File.h" +#include "threads/SystemClock.h" #include #include @@ -50,9 +51,6 @@ using namespace XCURL; #define XMIN(a,b) ((a)<(b)?(a):(b)) #define FITS_INT(a) (((a) <= INT_MAX) && ((a) >= INT_MIN)) -#define dllselect select - - curl_proxytype proxyType2CUrlProxyType[] = { CURLPROXY_HTTP, CURLPROXY_SOCKS4, @@ -396,6 +394,7 @@ CCurlFile::CCurlFile() m_username = ""; m_password = ""; m_httpauth = ""; + m_cipherlist = ""; m_proxytype = PROXY_HTTP; m_state = new CReadState(); m_oldState = NULL; @@ -419,9 +418,9 @@ void CCurlFile::Close() delete m_oldState; m_oldState = NULL; - m_url.Empty(); - m_referer.Empty(); - m_cookie.Empty(); + m_url.clear(); + m_referer.clear(); + m_cookie.clear(); m_opened = false; m_forWrite = false; @@ -474,7 +473,7 @@ void CCurlFile::SetCommonOptions(CReadState* state) g_curlInterface.easy_setopt(h, CURLOPT_COOKIEJAR, strCookieFile.c_str()); // Set custom cookie if requested - if (!m_cookie.IsEmpty()) + if (!m_cookie.empty()) g_curlInterface.easy_setopt(h, CURLOPT_COOKIE, m_cookie.c_str()); g_curlInterface.easy_setopt(h, CURLOPT_COOKIELIST, "FLUSH"); @@ -512,7 +511,7 @@ void CCurlFile::SetCommonOptions(CReadState* state) } // setup Referer header if needed - if (!m_referer.IsEmpty()) + if (!m_referer.empty()) g_curlInterface.easy_setopt(h, CURLOPT_REFERER, m_referer.c_str()); else { @@ -607,6 +606,10 @@ void CCurlFile::SetCommonOptions(CReadState* state) // the 302 response's body length, which cause the next read request failed, so we ignore // content-length for shoutcast file to workaround this. g_curlInterface.easy_setopt(h, CURLOPT_IGNORE_CONTENT_LENGTH, 1); + + // Setup allowed TLS/SSL ciphers. New versions of cURL may deprecate things that are still in use. + if (!m_cipherlist.empty()) + g_curlInterface.easy_setopt(h, CURLOPT_SSL_CIPHER_LIST, m_cipherlist.c_str()); } void CCurlFile::SetRequestHeaders(CReadState* state) @@ -646,7 +649,8 @@ void CCurlFile::SetCorrectHeaders(CReadState* state) && !h.GetValue("Content-Disposition").empty() ) { CStdString strValue = h.GetValue("Content-Disposition"); - if (strValue.Find("filename=") > -1 && strValue.Find(".flv") > -1) + if (strValue.find("filename=") != std::string::npos && + strValue.find(".flv") != std::string::npos) h.AddParam("Content-Type", "video/flv"); } } @@ -660,10 +664,10 @@ void CCurlFile::ParseAndCorrectUrl(CURL &url2) || strProtocol.Equals("ftps") ) { // we was using url optons for urls, keep the old code work and warning - if (!url2.GetOptions().IsEmpty()) + if (!url2.GetOptions().empty()) { CLog::Log(LOGWARNING, "%s: ftp url option is deprecated, please switch to use protocol option (change '?' to '|'), url: [%s]", __FUNCTION__, url2.GetRedacted().c_str()); - url2.SetProtocolOptions(url2.GetOptions().Mid(1)); + url2.SetProtocolOptions(url2.GetOptions().substr(1)); /* ftp has no options */ url2.SetOptions(""); } @@ -673,7 +677,7 @@ void CCurlFile::ParseAndCorrectUrl(CURL &url2) /* url encoded. if handed from ftpdirectory */ /* it won't be so let's handle that case */ - CStdString partial, filename(url2.GetFileName()); + CStdString filename(url2.GetFileName()); std::vector array; // if server sent us the filename in non-utf8, we need send back with same encoding. @@ -682,19 +686,17 @@ void CCurlFile::ParseAndCorrectUrl(CURL &url2) /* TODO: create a tokenizer that doesn't skip empty's */ StringUtils::Tokenize(filename, array, "/"); - filename.Empty(); + filename.clear(); for(std::vector::iterator it = array.begin(); it != array.end(); it++) { if(it != array.begin()) filename += "/"; - partial = *it; - CURL::Encode(partial); - filename += partial; + filename += CURL::Encode(*it); } /* make sure we keep slashes */ - if(url2.GetFileName().Right(1) == "/") + if(StringUtils::EndsWith(url2.GetFileName(), "/")) filename += "/"; url2.SetFileName(filename); @@ -703,14 +705,14 @@ void CCurlFile::ParseAndCorrectUrl(CURL &url2) if (url2.HasProtocolOption("auth")) { m_ftpauth = url2.GetProtocolOption("auth"); - if(m_ftpauth.IsEmpty()) + if(m_ftpauth.empty()) m_ftpauth = "any"; } m_ftpport = ""; if (url2.HasProtocolOption("active")) { m_ftpport = url2.GetProtocolOption("active"); - if(m_ftpport.IsEmpty()) + if(m_ftpport.empty()) m_ftpport = "-"; } m_ftppasvip = url2.HasProtocolOption("pasvip") && url2.GetProtocolOption("pasvip") != "0"; @@ -721,11 +723,11 @@ void CCurlFile::ParseAndCorrectUrl(CURL &url2) if (CSettings::Get().GetBool("network.usehttpproxy") && !CSettings::Get().GetString("network.httpproxyserver").empty() && CSettings::Get().GetInt("network.httpproxyport") > 0 - && m_proxy.IsEmpty()) + && m_proxy.empty()) { m_proxy = CSettings::Get().GetString("network.httpproxyserver"); - m_proxy.AppendFormat(":%d", CSettings::Get().GetInt("network.httpproxyport")); - if (CSettings::Get().GetString("network.httpproxyusername").length() > 0 && m_proxyuserpass.IsEmpty()) + m_proxy += StringUtils::Format(":%d", CSettings::Get().GetInt("network.httpproxyport")); + if (CSettings::Get().GetString("network.httpproxyusername").length() > 0 && m_proxyuserpass.empty()) { m_proxyuserpass = CSettings::Get().GetString("network.httpproxyusername"); m_proxyuserpass += ":" + CSettings::Get().GetString("network.httpproxypassword"); @@ -743,8 +745,6 @@ void CCurlFile::ParseAndCorrectUrl(CURL &url2) url2.GetProtocolOptions(options); if (options.size() > 0) { - // clear protocol options - url2.SetProtocolOptions(""); // set xbmc headers for(std::map::const_iterator it = options.begin(); it != options.end(); ++it) { @@ -754,7 +754,7 @@ void CCurlFile::ParseAndCorrectUrl(CURL &url2) if(name.Equals("auth")) { m_httpauth = value; - if(m_httpauth.IsEmpty()) + if(m_httpauth.empty()) m_httpauth = "any"; } else if (name.Equals("Referer")) @@ -771,11 +771,18 @@ void CCurlFile::ParseAndCorrectUrl(CURL &url2) m_seekable = false; else if (name.Equals("Accept-Charset")) SetAcceptCharset(value); + else if (name.Equals("HttpProxy")) + SetStreamProxy(value, PROXY_HTTP); + else if (name.Equals("SSLCipherList")) + m_cipherlist = value; else SetRequestHeader(name, value); } } } + + // Unset the protocol options to have an url without protocol options + url2.SetProtocolOptions(""); if (m_username.length() > 0 && m_password.length() > 0) m_url = url2.GetWithoutUserDetails(); @@ -783,6 +790,17 @@ void CCurlFile::ParseAndCorrectUrl(CURL &url2) m_url = url2.Get(); } +void CCurlFile::SetStreamProxy(const CStdString &proxy, ProxyType type) +{ + CURL url(proxy); + m_proxy = url.GetWithoutUserDetails(); + m_proxyuserpass = url.GetUserName(); + if (!url.GetPassWord().empty()) + m_proxyuserpass += ":" + url.GetPassWord(); + m_proxytype = type; + CLog::Log(LOGDEBUG, "Overriding proxy from URL parameter: %s, type %d", m_proxy.c_str(), proxyType2CUrlProxyType[m_proxytype]); +} + bool CCurlFile::Post(const CStdString& strURL, const CStdString& strPostData, CStdString& strHTML) { m_postdata = strPostData; @@ -856,12 +874,9 @@ bool CCurlFile::Download(const CStdString& strURL, const CStdString& strFileName } // Detect whether we are "online" or not! Very simple and dirty! -bool CCurlFile::IsInternet(bool checkDNS /* = true */) +bool CCurlFile::IsInternet() { CStdString strURL = "http://www.google.com"; - if (!checkDNS) - strURL = "http://74.125.19.103"; // www.google.com ip - bool found = Exists(strURL); Close(); @@ -1119,6 +1134,10 @@ bool CCurlFile::Exists(const CURL& url) int64_t CCurlFile::Seek(int64_t iFilePosition, int iWhence) { int64_t nextPos = m_state->m_filePos; + + if(!m_seekable) + return -1; + switch(iWhence) { case SEEK_SET: @@ -1143,28 +1162,31 @@ int64_t CCurlFile::Seek(int64_t iFilePosition, int iWhence) if(m_state->Seek(nextPos)) return nextPos; - if (m_oldState && m_oldState->Seek(nextPos)) + if (m_multisession) { - CReadState *tmp = m_state; - m_state = m_oldState; - m_oldState = tmp; - return nextPos; - } - - if(!m_seekable) - return -1; - - CReadState* oldstate = NULL; - if(m_multisession) - { - CURL url(m_url); - oldstate = m_oldState; - m_oldState = m_state; - m_state = new CReadState(); - - g_curlInterface.easy_aquire(url.GetProtocol(), url.GetHostName(), &m_state->m_easyHandle, &m_state->m_multiHandle ); - - m_state->m_fileSize = m_oldState->m_fileSize; + if (!m_oldState) + { + CURL url(m_url); + m_oldState = m_state; + m_state = new CReadState(); + m_state->m_fileSize = m_oldState->m_fileSize; + g_curlInterface.easy_aquire(url.GetProtocol(), + url.GetHostName(), + &m_state->m_easyHandle, + &m_state->m_multiHandle ); + } + else + { + CReadState *tmp; + tmp = m_state; + m_state = m_oldState; + m_oldState = tmp; + + if (m_state->Seek(nextPos)) + return nextPos; + + m_state->Disconnect(); + } } else m_state->Disconnect(); @@ -1181,18 +1203,26 @@ int64_t CCurlFile::Seek(int64_t iFilePosition, int iWhence) long response = m_state->Connect(m_bufferSize); if(response < 0 && (m_state->m_fileSize == 0 || m_state->m_fileSize != m_state->m_filePos)) { - m_seekable = false; - if(m_multisession && m_oldState) + if(m_multisession) { - delete m_state; - m_state = m_oldState; - m_oldState = oldstate; + if (m_oldState) + { + delete m_state; + m_state = m_oldState; + m_oldState = NULL; + } + // Retry without mutlisession + m_multisession = false; + return Seek(iFilePosition, iWhence); } - return -1; + else + { + m_seekable = false; + return -1; + } } SetCorrectHeaders(m_state); - delete oldstate; return m_state->m_filePos; } @@ -1496,14 +1526,33 @@ bool CCurlFile::CReadState::FillBuffer(unsigned int want) if (CURLM_OK != g_curlInterface.multi_timeout(m_multiHandle, &timeout) || timeout == -1) timeout = 200; - struct timeval t = { timeout / 1000, (timeout % 1000) * 1000 }; + XbmcThreads::EndTime endTime(timeout); + int rc; - /* Wait until data is available or a timeout occurs. - We call dllselect(maxfd + 1, ...), specially in case of (maxfd == -1), - we call dllselect(0, ...), which is basically equal to sleep. */ - if (SOCKET_ERROR == dllselect(maxfd + 1, &fdread, &fdwrite, &fdexcep, &t)) + do { - CLog::Log(LOGERROR, "CCurlFile::FillBuffer - Failed with socket error"); + unsigned int time_left = endTime.MillisLeft(); + struct timeval t = { time_left / 1000, (time_left % 1000) * 1000 }; + + // Wait until data is available or a timeout occurs. + rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &t); +#ifdef TARGET_WINDOWS + } while(rc == SOCKET_ERROR && WSAGetLastError() == WSAEINTR); +#else + } while(rc == SOCKET_ERROR && errno == EINTR); +#endif + + if(rc == SOCKET_ERROR) + { +#ifdef TARGET_WINDOWS + char buf[256]; + strerror_s(buf, 256, WSAGetLastError()); + CLog::Log(LOGERROR, "CCurlFile::FillBuffer - Failed with socket error:%s", buf); +#else + char const * str = strerror(errno); + CLog::Log(LOGERROR, "CCurlFile::FillBuffer - Failed with socket error:%s", str); +#endif + return false; } } @@ -1546,9 +1595,7 @@ void CCurlFile::SetRequestHeader(CStdString header, CStdString value) void CCurlFile::SetRequestHeader(CStdString header, long value) { - CStdString buffer; - buffer.Format("%ld", value); - m_requestheaders[header] = buffer; + m_requestheaders[header] = StringUtils::Format("%ld", value); } std::string CCurlFile::GetServerReportedCharset(void) @@ -1582,7 +1629,7 @@ bool CCurlFile::GetHttpHeader(const CURL &url, CHttpHeader &headers) bool CCurlFile::GetMimeType(const CURL &url, CStdString &content, CStdString useragent) { CCurlFile file; - if (!useragent.IsEmpty()) + if (!useragent.empty()) file.SetUserAgent(useragent); struct __stat64 buffer;