Repository: xbmc/xbmc
File: xbmc/filesystem/CurlFile.cpp (C++)

Code before:

  if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_curlDisableHTTP2)
    g_curlInterface.easy_setopt(h, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  else
    // enable HTTP2 support. default: CURL_HTTP_VERSION_1_1. Curl >= 7.62.0 defaults to CURL_HTTP_VERSION_2TLS
    g_curlInterface.easy_setopt(h, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);

  // set CA bundle file
  std::string caCert = CSpecialProtocol::TranslatePath(
      CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_caTrustFile);
  if (!caCert.empty() && XFILE::CFile::Exists(caCert))
    g_curlInterface.easy_setopt(h, CURLOPT_CAINFO, caCert.c_str());

#ifdef TARGET_WINDOWS_STORE
  // From OpenSSL 3.0 CURLOPT_CAINFO not works (on UWP), use CURLOPT_CAINFO_BLOB instead
  static std::vector<uint8_t> cachedBuffer;
  static bool bufferLoaded = false;
  if (!bufferLoaded)
  {
    XFILE::CFile file;
    if (file.LoadFile(CSpecialProtocol::TranslatePath("special://xbmc/system/certs/cacert.pem"),
                      cachedBuffer))
    {
      bufferLoaded = true;
    }
  }

  if (bufferLoaded && !cachedBuffer.empty())
  {
    curl_blob blob{cachedBuffer.data(), cachedBuffer.size(), CURL_BLOB_NOCOPY};
    g_curlInterface.easy_setopt(h, CURLOPT_CAINFO_BLOB, &blob);
  }
#endif
}

void CCurlFile::SetRequestHeaders(CReadState* state)
{
  if(state->m_curlHeaderList)
  {
    g_curlInterface.slist_free_all(state->m_curlHeaderList);
    state->m_curlHeaderList = NULL;
  }

  for (const auto& it : m_requestheaders)
  {
    std::string buffer = it.first + ": " + it.second;
    state->m_curlHeaderList = g_curlInterface.slist_append(state->m_curlHeaderList, buffer.c_str());
  }

  // add user defined headers
  if (state->m_easyHandle)

Review comment (bug):
```suggestion
static std::vector<uint8_t> cachedBuffer;
static std::once_flag loadBufferFlag;
std::call_once(loadBufferFlag, []() {
  XFILE::CFile file;
  file.LoadFile(CSpecialProtocol::TranslatePath("special://xbmc/system/certs/cacert.pem"), cachedBuffer);
});
```
This is pretty lightweight in terms of locking overhead but it does not retry fetching the certificate if the first call fails.

Code after:
  if (!m_cipherlist.empty())
    g_curlInterface.easy_setopt(h, CURLOPT_SSL_CIPHER_LIST, m_cipherlist.c_str());

  if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_curlDisableHTTP2)
    g_curlInterface.easy_setopt(h, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  else
    // enable HTTP2 support. default: CURL_HTTP_VERSION_1_1. Curl >= 7.62.0 defaults to CURL_HTTP_VERSION_2TLS
    g_curlInterface.easy_setopt(h, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);

  // set CA bundle file
  std::string caCert = CSpecialProtocol::TranslatePath(
      CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_caTrustFile);
  if (!caCert.empty() && XFILE::CFile::Exists(caCert))
    g_curlInterface.easy_setopt(h, CURLOPT_CAINFO, caCert.c_str());

  // From OpenSSL 3.0 CURLOPT_CAINFO not works (on UWP), use CURLOPT_CAINFO_BLOB instead
  if (!cachedCaCertsBlob.empty())
  {
    curl_blob blob{cachedCaCertsBlob.data(), cachedCaCertsBlob.size(), CURL_BLOB_NOCOPY};
    g_curlInterface.easy_setopt(h, CURLOPT_CAINFO_BLOB, &blob);
  }
}

void CCurlFile::SetRequestHeaders(CReadState* state)
{
  if(state->m_curlHeaderList)
  {
    g_curlInterface.slist_free_all(state->m_curlHeaderList);
    state->m_curlHeaderList = NULL;
  }

  for (const auto& it : m_requestheaders)
  {
    std::string buffer = it.first + ": " + it.second;
    state->m_curlHeaderList = g_curlInterface.slist_append(state->m_curlHeaderList, buffer.c_str());
  }

  // add user defined headers
  if (state->m_easyHandle)
    g_curlInterface.easy_setopt(state->m_easyHandle, CURLOPT_HTTPHEADER, state->m_curlHeaderList);
}

void CCurlFile::SetCorrectHeaders(CReadState* state)
{
  CHttpHeader& h = state->m_httpheader;
  /* workaround for shoutcast server which doesn't set content type on standard mp3 */
  if( h.GetMimeType().empty() )
  {
    if( !h.GetValue("icy-notice1").empty()
    || !h.GetValue("icy-name").empty()
    || !h.GetValue("icy-br").empty() )