diff options
-rw-r--r-- | xbmc/filesystem/CurlFile.cpp | 46 | ||||
-rw-r--r-- | xbmc/filesystem/CurlFile.h | 4 | ||||
-rw-r--r-- | xbmc/utils/HttpHeader.cpp | 75 | ||||
-rw-r--r-- | xbmc/utils/HttpHeader.h | 18 |
4 files changed, 107 insertions, 36 deletions
diff --git a/xbmc/filesystem/CurlFile.cpp b/xbmc/filesystem/CurlFile.cpp index be3c915a65..c951a09464 100644 --- a/xbmc/filesystem/CurlFile.cpp +++ b/xbmc/filesystem/CurlFile.cpp @@ -140,31 +140,16 @@ static inline void* realloc_simple(void *ptr, size_t size) size_t CCurlFile::CReadState::HeaderCallback(void *ptr, size_t size, size_t nmemb) { - // clear any previous header - if(m_headerdone) - { - m_httpheader.Clear(); - m_headerdone = false; - } - + std::string inString; // libcurl doc says that this info is not always \0 terminated - char* strData = (char*)ptr; - int iSize = size * nmemb; - - if (strData[iSize] != 0) - { - strData = (char*)malloc(iSize + 1); - strncpy(strData, (char*)ptr, iSize); - strData[iSize] = 0; - } - else strData = strdup((char*)ptr); - - if(strcmp(strData, "\r\n") == 0) - m_headerdone = true; - - m_httpheader.Parse(strData); + const char* strBuf = (const char*)ptr; + const size_t iSize = size * nmemb; + if (strBuf[iSize - 1] == 0) + inString.assign(strBuf, iSize - 1); // skip last char if it's zero + else + inString.append(strBuf, iSize); - free(strData); + m_httpheader.Parse(inString); return iSize; } @@ -248,7 +233,6 @@ CCurlFile::CReadState::CReadState() m_cancelled = false; m_bFirstLoop = true; m_sendRange = true; - m_headerdone = false; m_readBuffer = 0; m_isPaused = false; m_curlHeaderList = NULL; @@ -332,7 +316,7 @@ long CCurlFile::CReadState::Connect(unsigned int size) m_bufferSize = size; m_buffer.Destroy(); m_buffer.Create(size * 3); - m_headerdone = false; + m_httpheader.Clear(); // read some data in to try and obtain the length // maybe there's a better way to get this info?? @@ -652,7 +636,7 @@ void CCurlFile::SetCorrectHeaders(CReadState* state) if( !h.GetValue("icy-notice1").empty() || !h.GetValue("icy-name").empty() || !h.GetValue("icy-br").empty() ) - h.Parse("Content-Type: audio/mpeg\r\n"); + h.AddParam("Content-Type", "audio/mpeg"); } /* hack for google video */ @@ -661,7 +645,7 @@ void CCurlFile::SetCorrectHeaders(CReadState* state) { CStdString strValue = h.GetValue("Content-Disposition"); if (strValue.Find("filename=") > -1 && strValue.Find(".flv") > -1) - h.Parse("Content-Type: video/flv\r\n"); + h.AddParam("Content-Type", "video/flv"); } } @@ -1562,6 +1546,14 @@ void CCurlFile::SetRequestHeader(CStdString header, long value) m_requestheaders[header] = buffer; } +std::string CCurlFile::GetServerReportedCharset(void) +{ + if (!m_state) + return ""; + + return m_state->m_httpheader.GetCharset(); +} + /* STATIC FUNCTIONS */ bool CCurlFile::GetHttpHeader(const CURL &url, CHttpHeader &headers) { diff --git a/xbmc/filesystem/CurlFile.h b/xbmc/filesystem/CurlFile.h index a828c8895a..64f7b86a4b 100644 --- a/xbmc/filesystem/CurlFile.h +++ b/xbmc/filesystem/CurlFile.h @@ -90,6 +90,7 @@ namespace XFILE void SetBufferSize(unsigned int size); const CHttpHeader& GetHttpHeader() { return m_state->m_httpheader; } + std::string GetServerReportedCharset(void); /* static function that will get content type of a file */ static bool GetHttpHeader(const CURL &url, CHttpHeader &headers); @@ -120,7 +121,8 @@ namespace XFILE /* returned http header */ CHttpHeader m_httpheader; - bool m_headerdone; + bool IsHeaderDone(void) + { return m_httpheader.IsHeaderDone(); } struct XCURL::curl_slist* m_curlHeaderList; struct XCURL::curl_slist* m_curlAliasList; diff --git a/xbmc/utils/HttpHeader.cpp b/xbmc/utils/HttpHeader.cpp index fcc6732918..c9dade3669 100644 --- a/xbmc/utils/HttpHeader.cpp +++ b/xbmc/utils/HttpHeader.cpp @@ -23,6 +23,7 @@ CHttpHeader::CHttpHeader() { + m_headerdone = false; } CHttpHeader::~CHttpHeader() @@ -31,6 +32,9 @@ CHttpHeader::~CHttpHeader() void CHttpHeader::Parse(const std::string& strData) { + if (m_headerdone) + Clear(); + size_t pos = 0; const size_t len = strData.length(); while (pos < len) @@ -41,7 +45,12 @@ void CHttpHeader::Parse(const std::string& strData) if (lineEnd == std::string::npos) break; - if (valueStart != std::string::npos && valueStart < lineEnd) + if (lineEnd == pos) + { + m_headerdone = true; + break; + } + else if (valueStart != std::string::npos && valueStart < lineEnd) { std::string strParam(strData, pos, valueStart - pos); std::string strValue(strData, valueStart + 1, lineEnd - valueStart - 1); @@ -61,10 +70,40 @@ void CHttpHeader::Parse(const std::string& strData) } } -std::string CHttpHeader::GetValue(std::string strParam) const +void CHttpHeader::AddParam(const std::string& param, const std::string& value, const bool overwrite /*= false*/) { - StringUtils::ToLower(strParam); + if (param.empty() || value.empty()) + return; + + std::string paramLower(param); + if (overwrite) + { // delete ALL parameters with the same name + // note: 'GetValue' always returns last added parameter, + // so you probably don't need to overwrite + for (size_t i = 0; i < m_params.size();) + { + if (m_params[i].first == param) + m_params.erase(m_params.begin() + i); + else + ++i; + } + } + + StringUtils::ToLower(paramLower); + m_params.push_back(HeaderParams::value_type(paramLower, value)); +} + +std::string CHttpHeader::GetValue(const std::string& strParam) const +{ + std::string paramLower(strParam); + StringUtils::ToLower(paramLower); + + return GetValueRaw(paramLower); +} + +std::string CHttpHeader::GetValueRaw(const std::string& strParam) const +{ // look in reverse to find last parameter (probably most important) for (HeaderParams::const_reverse_iterator iter = m_params.rbegin(); iter != m_params.rend(); ++iter) { @@ -100,8 +139,38 @@ std::string CHttpHeader::GetHeader(void) const return strHeader; } +std::string CHttpHeader::GetMimeType(void) const +{ + std::string strValue(GetValueRaw("content-type")); + + return strValue.substr(0, strValue.find(';')); +} + +std::string CHttpHeader::GetCharset(void) const +{ + std::string strValue(GetValueRaw("content-type")); + if (strValue.empty()) + return strValue; + + const size_t semicolonPos = strValue.find(';'); + if (semicolonPos == std::string::npos) + return ""; + + StringUtils::ToUpper(strValue); + size_t posCharset; + if ((posCharset = strValue.find("; CHARSET=", semicolonPos)) != std::string::npos) + posCharset += 10; + else if ((posCharset = strValue.find(";CHARSET=", semicolonPos)) != std::string::npos) + posCharset += 9; + else + return ""; + + return strValue.substr(posCharset, strValue.find(';', posCharset) - posCharset); +} + void CHttpHeader::Clear() { m_params.clear(); m_protoLine.clear(); + m_headerdone = false; } diff --git a/xbmc/utils/HttpHeader.h b/xbmc/utils/HttpHeader.h index 4ddb279105..5e1b6b9061 100644 --- a/xbmc/utils/HttpHeader.h +++ b/xbmc/utils/HttpHeader.h @@ -24,8 +24,6 @@ #include <vector> #include <string> -#define HTTPHEADER_CONTENT_TYPE "Content-Type" - class CHttpHeader { public: @@ -37,18 +35,28 @@ public: ~CHttpHeader(); void Parse(const std::string& strData); - std::string GetValue(std::string strParam) const; + void AddParam(const std::string& param, const std::string& value, const bool overwrite = false); + + std::string GetValue(const std::string& strParam) const; std::vector<std::string> GetValues(std::string strParam) const; std::string GetHeader(void) const; - std::string GetMimeType() { return GetValue(HTTPHEADER_CONTENT_TYPE); } - std::string GetProtoLine() { return m_protoLine; } + std::string GetMimeType(void) const; + std::string GetCharset(void) const; + inline std::string GetProtoLine() const + { return m_protoLine; } + + inline bool IsHeaderDone(void) const + { return m_headerdone; } void Clear(); protected: + std::string GetValueRaw(const std::string& strParam) const; + HeaderParams m_params; std::string m_protoLine; + bool m_headerdone; }; |