Beispiel #1
0
TEST_F(TestWebServer, CanNotGetNonExistingFile)
{
  std::string result;
  CCurlFile curl;
  ASSERT_FALSE(curl.Get(GetUrlOfTestFile("file_does_not_exist"), result));
  ASSERT_TRUE(result.empty());
}
Beispiel #2
0
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();
}
Beispiel #3
0
TEST_F(TestWebServer, CanHeadFile)
{
  CCurlFile curl;
  ASSERT_TRUE(curl.Exists(CURL(GetUrlOfTestFile(TEST_FILES_HTML))));

  CheckHtmlTestFileResponse(curl);
}
Beispiel #4
0
bool CGUIDialogSongInfo::DownloadThumbnail(const CStdString &thumbFile)
{
  // TODO: Obtain the source...
  CStdString source;
  CCurlFile http;
  http.Download(source, thumbFile);
  return true;
}
Beispiel #5
0
bool CGUIDialogSongInfo::DownloadThumbnail(const std::string &thumbFile)
{
  //! @todo Obtain the source...
  std::string source;
  CCurlFile http;
  http.Download(source, thumbFile);
  return true;
}
Beispiel #6
0
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);
}
Beispiel #7
0
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};
}
Beispiel #8
0
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);
      }
    }
  }
}
Beispiel #9
0
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);
}
Beispiel #10
0
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);
}
Beispiel #11
0
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);
}
Beispiel #12
0
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);
}
Beispiel #13
0
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);
}
Beispiel #14
0
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));
}
Beispiel #15
0
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();
}
Beispiel #16
0
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);
}
Beispiel #17
0
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);
}
Beispiel #18
0
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);
}
Beispiel #19
0
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);
}
Beispiel #20
0
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);
}
Beispiel #21
0
  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);
  }
Beispiel #22
0
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);
}
Beispiel #23
0
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;
}
Beispiel #24
0
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);
}
Beispiel #25
0
/* 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;
  }
}
Beispiel #26
0
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;
}
Beispiel #27
0
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);
}
Beispiel #28
0
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);
}
Beispiel #29
0
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);
  }
}
Beispiel #30
0
  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);
  }