TEST_F(TestWebServer, CanNotGetNonExistingFile) { std::string result; CCurlFile curl; ASSERT_FALSE(curl.Get(GetUrlOfTestFile("file_does_not_exist"), result)); ASSERT_TRUE(result.empty()); }
TEST_F(TestWebServer, CanGetJsonRpcResponse) { // initialized JSON-RPC JSONRPC::CJSONRPC::Initialize(); std::string result; CCurlFile curl; curl.SetMimeType("application/json"); ASSERT_TRUE(curl.Post(GetUrl(TEST_URL_JSONRPC), "{ \"jsonrpc\": \"2.0\", \"method\": \"JSONRPC.Version\", \"id\": 1 }", result)); ASSERT_FALSE(result.empty()); // parse the JSON-RPC response CVariant resultObj = CJSONVariantParser::Parse(reinterpret_cast<const unsigned char*>(result.c_str()), result.size()); // make sure it's an object ASSERT_TRUE(resultObj.isObject()); // get the HTTP header details const CHttpHeader& httpHeader = curl.GetHttpHeader(); // Content-Type must be "application/json" EXPECT_STREQ("application/json", httpHeader.GetMimeType().c_str()); // Accept-Ranges must be "none" EXPECT_STREQ("none", httpHeader.GetValue(MHD_HTTP_HEADER_ACCEPT_RANGES).c_str()); // Cache-Control must contain "mag-age=0" and "no-cache" std::string cacheControl = httpHeader.GetValue(MHD_HTTP_HEADER_CACHE_CONTROL); EXPECT_TRUE(cacheControl.find("max-age=0") != std::string::npos); EXPECT_TRUE(cacheControl.find("no-cache") != std::string::npos); // uninitialize JSON-RPC JSONRPC::CJSONRPC::Cleanup(); }
TEST_F(TestWebServer, CanHeadFile) { CCurlFile curl; ASSERT_TRUE(curl.Exists(CURL(GetUrlOfTestFile(TEST_FILES_HTML)))); CheckHtmlTestFileResponse(curl); }
bool CGUIDialogSongInfo::DownloadThumbnail(const CStdString &thumbFile) { // TODO: Obtain the source... CStdString source; CCurlFile http; http.Download(source, thumbFile); return true; }
bool CGUIDialogSongInfo::DownloadThumbnail(const std::string &thumbFile) { //! @todo Obtain the source... std::string source; CCurlFile http; http.Download(source, thumbFile); return true; }
int CDAVFile::Stat(const CURL& url, struct __stat64* buffer) { CCurlFile dav; std::string strRequest = "PROPFIND"; dav.SetCustomRequest(strRequest); dav.SetRequestHeader("depth", 0); return dav.Stat(url, buffer); }
CRepository::ResolveResult CRepository::ResolvePathAndHash(const AddonPtr& addon) const { std::string const& path = addon->Path(); auto dirIt = std::find_if(m_dirs.begin(), m_dirs.end(), [&path](DirInfo const& dir) { return URIUtils::PathHasParent(path, dir.datadir, true); }); if (dirIt == m_dirs.end()) { CLog::Log(LOGERROR, "Requested path {} not found in known repository directories", path); return {}; } if (dirIt->hashType == CDigest::Type::INVALID) { // We have a path, but need no hash return {path, {}}; } // Do not follow mirror redirect, we want the headers of the redirect response CURL url{path}; url.SetProtocolOption("redirect-limit", "0"); CCurlFile file; if (!file.Open(url)) { CLog::Log(LOGERROR, "Could not fetch addon location and hash from {}", path); return {}; } std::string hashTypeStr = CDigest::TypeToString(dirIt->hashType); // Return the location from the header so we don't have to look it up again // (saves one request per addon install) std::string location = file.GetRedirectURL(); // content-* headers are base64, convert to base16 TypedDigest hash{dirIt->hashType, StringUtils::ToHexadecimal(Base64::Decode(file.GetHttpHeader().GetValue(std::string("content-") + hashTypeStr)))}; if (hash.Empty()) { // Expected hash, but none found -> fall back to old method if (!FetchChecksum(path + "." + hashTypeStr, hash.value) || hash.Empty()) { CLog::Log(LOGERROR, "Failed to find hash for {} from HTTP header and in separate file", path); return {}; } } if (location.empty()) { // Fall back to original URL if we do not get a redirect location = path; } CLog::Log(LOGDEBUG, "Resolved addon path {} to {} hash {}", path, location, hash.value); return {location, hash}; }
void N7Xml::list_channels() { CStdString strUrl; strUrl.Format("http://%s:%i/n7channel_nt.xml", g_strHostname.c_str(), g_iPort); CStdString strXML; CCurlFile http; if(!http.Get(strUrl, strXML)) { XBMC->Log(LOG_DEBUG, "N7Xml - Could not open connection to N7 backend."); } else { TiXmlDocument xml; xml.Parse(strXML.c_str()); TiXmlElement* rootXmlNode = xml.RootElement(); if (rootXmlNode == NULL) return; TiXmlElement* channelsNode = rootXmlNode->FirstChildElement("channel"); if (channelsNode) { XBMC->Log(LOG_DEBUG, "N7Xml - Connected to N7 backend."); m_connected = true; int iUniqueChannelId = 0; TiXmlNode *pChannelNode = NULL; while ((pChannelNode = channelsNode->IterateChildren(pChannelNode)) != NULL) { CStdString strTmp; PVRChannel channel; /* unique ID */ channel.iUniqueId = ++iUniqueChannelId; /* channel number */ if (!XMLUtils::GetInt(pChannelNode, "number", channel.iChannelNumber)) channel.iChannelNumber = channel.iUniqueId; /* channel name */ if (!XMLUtils::GetString(pChannelNode, "title", strTmp)) continue; channel.strChannelName = strTmp; /* icon path */ const TiXmlElement* pElement = pChannelNode->FirstChildElement("media:thumbnail"); channel.strIconPath = pElement->Attribute("url"); /* channel url */ if (!XMLUtils::GetString(pChannelNode, "guid", strTmp)) channel.strStreamURL = ""; else channel.strStreamURL = strTmp; m_channels.push_back(channel); } } } }
TEST_F(TestWebServer, CanGetFile) { std::string result; CCurlFile curl; curl.SetRequestHeader(MHD_HTTP_HEADER_RANGE, ""); ASSERT_TRUE(curl.Get(GetUrlOfTestFile(TEST_FILES_HTML), result)); ASSERT_STREQ(TEST_FILES_DATA, result.c_str()); CheckHtmlTestFileResponse(curl); }
bool CFTPDirectory::Exists(const CURL& url) { // make sure ftp dir ends with slash, // curl need to known it's a dir to check ftp directory existence. std::string file = url.Get(); URIUtils::AddSlashAtEnd(file); CCurlFile ftp; CURL url2(file); return ftp.Exists(url2); }
bool CFTPDirectory::Exists(const char* strPath) { // make sure ftp dir ends with slash, // curl need to known it's a dir to check ftp directory existence. CStdString file = strPath; URIUtils::AddSlashAtEnd(file); CCurlFile ftp; CURL url(file); return ftp.Exists(url); }
void MythXmlCommand::execute(const CStdString& hostname, int port, const MythXmlCommandParameters& params, MythXmlCommandResult& result, int timeout){ CStdString strUrl = createRequestUrl(hostname, port, params); CStdString strXML; CCurlFile http; http.SetTimeout(timeout); if (http.Get(strUrl, strXML)) { CLog::Log(LOGDEBUG, "Got response from mythtv backend: %s", strUrl.c_str()); } http.Cancel(); result.parseData(strXML); }
bool CDAVDirectory::Exists(const CURL& url) { CCurlFile dav; // Set the PROPFIND custom request else we may not find folders, depending // on the server's configuration std::string strRequest = "PROPFIND"; dav.SetCustomRequest(strRequest); dav.SetRequestHeader("depth", 0); return dav.Exists(url); }
TEST_F(TestWebServer, CanGetCachedFileWithOlderIfUnmodifiedSince) { // get the last modified date of the file CDateTime lastModified; ASSERT_TRUE(GetLastModifiedOfTestFile(TEST_FILES_RANGES, lastModified)); CDateTime lastModifiedOlder = lastModified - CDateTimeSpan(1, 0, 0, 0); // get the file with an older If-Unmodified-Since value std::string result; CCurlFile curl; curl.SetRequestHeader(MHD_HTTP_HEADER_RANGE, ""); curl.SetRequestHeader(MHD_HTTP_HEADER_IF_UNMODIFIED_SINCE, lastModifiedOlder.GetAsRFC1123DateTime()); ASSERT_FALSE(curl.Get(GetUrlOfTestFile(TEST_FILES_RANGES), result)); }
bool CLastFmManager::RadioHandShake() { if (!m_RadioSession.IsEmpty()) return true; //already signed in if (dlgProgress) { dlgProgress->SetLine(2, 15251);//Connecting to Last.fm.. dlgProgress->Progress(); } m_RadioSession = ""; CCurlFile http; CStdString html; CStdString strPassword = g_guiSettings.GetString("scrobbler.lastfmpass"); CStdString strUserName = g_guiSettings.GetString("scrobbler.lastfmusername"); if (strUserName.IsEmpty() || strPassword.IsEmpty()) { CLog::Log(LOGERROR, "Last.fm stream selected but no username or password set."); return false; } CStdString passwordmd5(strPassword); passwordmd5.ToLower(); CStdString url; CURL::Encode(strUserName); url.Format("http://ws.audioscrobbler.com/radio/handshake.php?version=%s&platform=%s&username=%s&passwordmd5=%s&debug=%i&partner=%s", XBMC_LASTFM_VERSION, XBMC_LASTFM_ID, strUserName, passwordmd5, 0, ""); if (!http.Get(url, html)) { CLog::Log(LOGERROR, "Connect to Last.fm radio failed."); return false; } //CLog::Log(LOGDEBUG, "Handshake: %s", html.c_str()); Parameter("session", html, m_RadioSession); Parameter("base_url", html, m_RadioBaseUrl); Parameter("base_path", html, m_RadioBasePath); Parameter("subscriber", html, m_RadioSubscriber); Parameter("banned", html, m_RadioBanned); if (m_RadioSession.CompareNoCase("failed") == 0) { CLog::Log(LOGERROR, "Last.fm return failed response, possible bad username or password?"); m_RadioSession = ""; } return !m_RadioSession.IsEmpty(); }
TEST_F(TestWebServer, CanGetCachedFileWithExactIfModifiedSince) { // get the last modified date of the file CDateTime lastModified; ASSERT_TRUE(GetLastModifiedOfTestFile(TEST_FILES_RANGES, lastModified)); // get the file with the exact If-Modified-Since value std::string result; CCurlFile curl; curl.SetRequestHeader(MHD_HTTP_HEADER_RANGE, ""); curl.SetRequestHeader(MHD_HTTP_HEADER_IF_MODIFIED_SINCE, lastModified.GetAsRFC1123DateTime()); ASSERT_TRUE(curl.Get(GetUrlOfTestFile(TEST_FILES_RANGES), result)); ASSERT_TRUE(result.empty()); CheckRangesTestFileResponse(curl, MHD_HTTP_NOT_MODIFIED, true); }
TEST_F(TestWebServer, CanGetRangedFileRange0_2xEnd) { const std::string rangedFileContent = TEST_FILES_DATA_RANGES; const std::string range = GenerateRangeHeaderValue(0, rangedFileContent.size() * 2); CHttpRanges ranges; ASSERT_TRUE(ranges.Parse(range, rangedFileContent.size())); // get the whole file but specify a larger range std::string result; CCurlFile curl; curl.SetRequestHeader(MHD_HTTP_HEADER_RANGE, range); ASSERT_TRUE(curl.Get(GetUrlOfTestFile(TEST_FILES_RANGES), result)); CheckRangesTestFileResponse(curl, result, ranges); }
TEST_F(TestWebServer, CanGetRangedFileRange0_) { const std::string rangedFileContent = TEST_FILES_DATA_RANGES; const std::string range = "bytes=0-"; CHttpRanges ranges; ASSERT_TRUE(ranges.Parse(range, rangedFileContent.size())); // get the whole file but specify the beginning of the range std::string result; CCurlFile curl; curl.SetRequestHeader(MHD_HTTP_HEADER_RANGE, range); ASSERT_TRUE(curl.Get(GetUrlOfTestFile(TEST_FILES_RANGES), result)); CheckRangesTestFileResponse(curl, result, ranges); }
TEST_F(TestWebServer, CanGetCachedFileWithExactIfUnmodifiedSince) { // get the last modified date of the file CDateTime lastModified; ASSERT_TRUE(GetLastModifiedOfTestFile(TEST_FILES_RANGES, lastModified)); // get the file with an older If-Unmodified-Since value std::string result; CCurlFile curl; curl.SetRequestHeader(MHD_HTTP_HEADER_RANGE, ""); curl.SetRequestHeader(MHD_HTTP_HEADER_IF_UNMODIFIED_SINCE, lastModified.GetAsRFC1123DateTime()); ASSERT_TRUE(curl.Get(GetUrlOfTestFile(TEST_FILES_RANGES), result)); EXPECT_STREQ(TEST_FILES_DATA_RANGES, result.c_str()); CheckRangesTestFileResponse(curl); }
TEST_F(TestWebServer, CanGetRangedFileRangeFirst_Second) { const std::string rangedFileContent = TEST_FILES_DATA_RANGES; std::vector<std::string> rangedContent = StringUtils::Split(TEST_FILES_DATA_RANGES, ";"); const std::string range = GenerateRangeHeaderValue(rangedContent.front().size() + 1, rangedContent.front().size() + 1 + rangedContent.at(2).size() - 1); CHttpRanges ranges; ASSERT_TRUE(ranges.Parse(range, rangedFileContent.size())); // get the whole file but specify a larger range std::string result; CCurlFile curl; curl.SetRequestHeader(MHD_HTTP_HEADER_RANGE, range); ASSERT_TRUE(curl.Get(GetUrlOfTestFile(TEST_FILES_RANGES), result)); CheckRangesTestFileResponse(curl, result, ranges); }
void CheckRangesTestFileResponse(const CCurlFile& curl, int httpStatus = MHD_HTTP_OK, bool empty = false) { // get the HTTP header details const CHttpHeader& httpHeader = curl.GetHttpHeader(); // check the protocol line for the expected HTTP status std::string httpStatusString = StringUtils::Format(" %d ", httpStatus); std::string protocolLine = httpHeader.GetProtoLine(); ASSERT_TRUE(protocolLine.find(httpStatusString) != std::string::npos); // Content-Type must be "text/html" EXPECT_STREQ("text/plain", httpHeader.GetMimeType().c_str()); // check Content-Length if (empty) EXPECT_STREQ("0", httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_LENGTH).c_str()); else EXPECT_STREQ("20", httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_LENGTH).c_str()); // Accept-Ranges must be "bytes" EXPECT_STREQ("bytes", httpHeader.GetValue(MHD_HTTP_HEADER_ACCEPT_RANGES).c_str()); // check Last-Modified CDateTime lastModified; ASSERT_TRUE(GetLastModifiedOfTestFile(TEST_FILES_RANGES, lastModified)); ASSERT_STREQ(lastModified.GetAsRFC1123DateTime().c_str(), httpHeader.GetValue(MHD_HTTP_HEADER_LAST_MODIFIED).c_str()); // Cache-Control must contain "mag-age=0" and "no-cache" std::string cacheControl = httpHeader.GetValue(MHD_HTTP_HEADER_CACHE_CONTROL); EXPECT_TRUE(cacheControl.find("max-age=31536000") != std::string::npos); EXPECT_TRUE(cacheControl.find("public") != std::string::npos); }
TEST_F(TestWebServer, CanGetRangedFileRange_Last) { const std::string rangedFileContent = TEST_FILES_DATA_RANGES; std::vector<std::string> rangedContent = StringUtils::Split(TEST_FILES_DATA_RANGES, ";"); const std::string range = StringUtils::Format("bytes=-%u", static_cast<unsigned int>(rangedContent.back().size())); CHttpRanges ranges; ASSERT_TRUE(ranges.Parse(range, rangedFileContent.size())); // get the whole file but specify a larger range std::string result; CCurlFile curl; curl.SetRequestHeader(MHD_HTTP_HEADER_RANGE, range); ASSERT_TRUE(curl.Get(GetUrlOfTestFile(TEST_FILES_RANGES), result)); CheckRangesTestFileResponse(curl, result, ranges); }
bool CHTTPDirectory::Exists(const char* strPath) { CCurlFile http; CURL url(strPath); struct __stat64 buffer; if( http.Stat(url, &buffer) != 0 ) { return false; } if (buffer.st_mode == _S_IFDIR) return true; return false; }
TEST_F(TestWebServer, CanGetCachedFileWithNewerIfModifiedSinceForcingNoCache) { // get the last modified date of the file CDateTime lastModified; ASSERT_TRUE(GetLastModifiedOfTestFile(TEST_FILES_RANGES, lastModified)); CDateTime lastModifiedNewer = lastModified + CDateTimeSpan(1, 0, 0, 0); // get the file with a newer If-Modified-Since value but forcing no caching std::string result; CCurlFile curl; curl.SetRequestHeader(MHD_HTTP_HEADER_RANGE, ""); curl.SetRequestHeader(MHD_HTTP_HEADER_IF_MODIFIED_SINCE, lastModifiedNewer.GetAsRFC1123DateTime()); curl.SetRequestHeader(MHD_HTTP_HEADER_CACHE_CONTROL, "no-cache"); ASSERT_TRUE(curl.Get(GetUrlOfTestFile(TEST_FILES_RANGES), result)); EXPECT_STREQ(TEST_FILES_DATA_RANGES, result.c_str()); CheckRangesTestFileResponse(curl); }
/* STATIC FUNCTIONS */ bool CCurlFile::GetHttpHeader(const CURL &url, CHttpHeader &headers) { try { CCurlFile file; if(file.Stat(url, NULL) == 0) { headers = file.GetHttpHeader(); return true; } return false; } catch(...) { CLog::Log(LOGERROR, "%s - Exception thrown while trying to retrieve header url: %s", __FUNCTION__, url.Get().c_str()); return false; } }
bool CCurlFile::GetMimeType(const CURL &url, CStdString &content, CStdString useragent) { CCurlFile file; if (!useragent.IsEmpty()) file.SetUserAgent(useragent); struct __stat64 buffer; if( file.Stat(url, &buffer) == 0 ) { if (buffer.st_mode == _S_IFDIR) content = "x-directory/normal"; else content = file.GetMimeType(); CLog::Log(LOGDEBUG, "CCurlFile::GetMimeType - %s -> %s", url.Get().c_str(), content.c_str()); return true; } CLog::Log(LOGDEBUG, "CCurlFile::GetMimeType - %s -> failed", url.Get().c_str()); content = ""; return false; }
TEST_F(TestWebServer, CanGetJsonRpcApiDescription) { std::string result; CCurlFile curl; ASSERT_TRUE(curl.Get(GetUrl(TEST_URL_JSONRPC), result)); ASSERT_FALSE(result.empty()); // get the HTTP header details const CHttpHeader& httpHeader = curl.GetHttpHeader(); // Content-Type must be "application/json" EXPECT_STREQ("application/json", httpHeader.GetMimeType().c_str()); // Accept-Ranges must be "none" EXPECT_STREQ("none", httpHeader.GetValue(MHD_HTTP_HEADER_ACCEPT_RANGES).c_str()); // Cache-Control must contain "mag-age=0" and "no-cache" std::string cacheControl = httpHeader.GetValue(MHD_HTTP_HEADER_CACHE_CONTROL); EXPECT_TRUE(cacheControl.find("max-age=0") != std::string::npos); EXPECT_TRUE(cacheControl.find("no-cache") != std::string::npos); }
TEST_F(TestWebServer, CanGetCachedRangedFileWithExactIfRange) { const std::string rangedFileContent = TEST_FILES_DATA_RANGES; const std::string range = "bytes=0-"; CHttpRanges ranges; ASSERT_TRUE(ranges.Parse(range, rangedFileContent.size())); // get the last modified date of the file CDateTime lastModified; ASSERT_TRUE(GetLastModifiedOfTestFile(TEST_FILES_RANGES, lastModified)); // get the whole file (but ranged) with an older If-Range value std::string result; CCurlFile curl; curl.SetRequestHeader(MHD_HTTP_HEADER_RANGE, range); curl.SetRequestHeader(MHD_HTTP_HEADER_IF_RANGE, lastModified.GetAsRFC1123DateTime()); ASSERT_TRUE(curl.Get(GetUrlOfTestFile(TEST_FILES_RANGES), result)); CheckRangesTestFileResponse(curl, result, ranges); }
bool CPicture::CacheImage(const CStdString& sourceUrl, const CStdString& destFile, int width, int height) { if (width > 0 && height > 0) { CLog::Log(LOGINFO, "Caching image from: %s to %s with width %i and height %i", sourceUrl.c_str(), destFile.c_str(), width, height); DllImageLib dll; if (!dll.Load()) return false; if (URIUtils::IsInternetStream(sourceUrl, true)) { CCurlFile http; CStdString data; if (http.Get(sourceUrl, data)) { if (!dll.CreateThumbnailFromMemory((BYTE *)data.c_str(), data.GetLength(), URIUtils::GetExtension(sourceUrl).c_str(), destFile.c_str(), width, height)) { CLog::Log(LOGERROR, "%s Unable to create new image %s from image %s", __FUNCTION__, destFile.c_str(), sourceUrl.c_str()); return false; } return true; } return false; } if (!dll.CreateThumbnail(sourceUrl.c_str(), destFile.c_str(), width, height, g_guiSettings.GetBool("pictures.useexifrotation"))) { CLog::Log(LOGERROR, "%s Unable to create new image %s from image %s", __FUNCTION__, destFile.c_str(), sourceUrl.c_str()); return false; } return true; } else { CLog::Log(LOGINFO, "Caching image from: %s to %s", sourceUrl.c_str(), destFile.c_str()); return CFile::Cache(sourceUrl, destFile); } }
void CheckHtmlTestFileResponse(const CCurlFile& curl) { // get the HTTP header details const CHttpHeader& httpHeader = curl.GetHttpHeader(); // Content-Type must be "text/html" EXPECT_STREQ("text/html", httpHeader.GetMimeType().c_str()); // Content-Length must be "4" EXPECT_STREQ("4", httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_LENGTH).c_str()); // Accept-Ranges must be "bytes" EXPECT_STREQ("bytes", httpHeader.GetValue(MHD_HTTP_HEADER_ACCEPT_RANGES).c_str()); // check Last-Modified CDateTime lastModified; ASSERT_TRUE(GetLastModifiedOfTestFile(TEST_FILES_HTML, lastModified)); ASSERT_STREQ(lastModified.GetAsRFC1123DateTime().c_str(), httpHeader.GetValue(MHD_HTTP_HEADER_LAST_MODIFIED).c_str()); // Cache-Control must contain "mag-age=0" and "no-cache" std::string cacheControl = httpHeader.GetValue(MHD_HTTP_HEADER_CACHE_CONTROL); EXPECT_TRUE(cacheControl.find("max-age=0") != std::string::npos); EXPECT_TRUE(cacheControl.find("no-cache") != std::string::npos); }