[PVR][Estuary] Timer settings dialog: Show client name in timer type selection dialog...
[xbmc.git] / xbmc / utils / HttpHeader.cpp
blobad73bb2910f8e756b7d43cf0debc79f671c156fd
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "HttpHeader.h"
11 #include "utils/StringUtils.h"
13 // header white space characters according to RFC 2616
14 const char* const CHttpHeader::m_whitespaceChars = " \t";
17 CHttpHeader::CHttpHeader()
19 m_headerdone = false;
22 CHttpHeader::~CHttpHeader() = default;
24 void CHttpHeader::Parse(const std::string& strData)
26 size_t pos = 0;
27 const size_t len = strData.length();
28 const char* const strDataC = strData.c_str();
30 // According to RFC 2616 any header line can have continuation on next line, if next line is started from whitespace char
31 // This code at first checks for whitespace char at the begging of the line, and if found, then current line is appended to m_lastHeaderLine
32 // If current line is NOT started from whitespace char, then previously stored (and completed) m_lastHeaderLine is parsed and current line is assigned to m_lastHeaderLine (to be parsed later)
33 while (pos < len)
35 size_t lineEnd = strData.find('\x0a', pos); // use '\x0a' instead of '\n' to be platform independent
37 if (lineEnd == std::string::npos)
38 return; // error: expected only complete lines
40 const size_t nextLine = lineEnd + 1;
41 if (lineEnd > pos && strDataC[lineEnd - 1] == '\x0d') // use '\x0d' instead of '\r' to be platform independent
42 lineEnd--;
44 if (m_headerdone)
45 Clear(); // clear previous header and process new one
47 if (strDataC[pos] == ' ' || strDataC[pos] == '\t') // same chars as in CHttpHeader::m_whitespaceChars
48 { // line is started from whitespace char: this is continuation of previous line
49 pos = strData.find_first_not_of(m_whitespaceChars, pos);
51 m_lastHeaderLine.push_back(' '); // replace all whitespace chars at start of the line with single space
52 m_lastHeaderLine.append(strData, pos, lineEnd - pos); // append current line
54 else
55 { // this line is NOT continuation, this line is new header line
56 if (!m_lastHeaderLine.empty())
57 ParseLine(m_lastHeaderLine); // process previously stored completed line (if any)
59 m_lastHeaderLine.assign(strData, pos, lineEnd - pos); // store current line to (possibly) complete later. Will be parsed on next turns.
61 if (pos == lineEnd)
62 m_headerdone = true; // current line is bare "\r\n" (or "\n"), means end of header; no need to process current m_lastHeaderLine
65 pos = nextLine; // go to next line (if any)
69 bool CHttpHeader::ParseLine(const std::string& headerLine)
71 const size_t valueStart = headerLine.find(':');
73 if (valueStart != std::string::npos)
75 std::string strParam(headerLine, 0, valueStart);
76 std::string strValue(headerLine, valueStart + 1);
78 StringUtils::Trim(strParam, m_whitespaceChars);
79 StringUtils::ToLower(strParam);
81 StringUtils::Trim(strValue, m_whitespaceChars);
83 if (!strParam.empty() && !strValue.empty())
84 m_params.push_back(HeaderParams::value_type(strParam, strValue));
85 else
86 return false;
88 else if (m_protoLine.empty())
89 m_protoLine = headerLine;
91 return true;
94 void CHttpHeader::AddParam(const std::string& param, const std::string& value, const bool overwrite /*= false*/)
96 std::string paramLower(param);
97 StringUtils::ToLower(paramLower);
98 StringUtils::Trim(paramLower, m_whitespaceChars);
99 if (paramLower.empty())
100 return;
102 if (overwrite)
103 { // delete ALL parameters with the same name
104 // note: 'GetValue' always returns last added parameter,
105 // so you probably don't need to overwrite
106 for (size_t i = 0; i < m_params.size();)
108 if (m_params[i].first == paramLower)
109 m_params.erase(m_params.begin() + i);
110 else
111 ++i;
115 std::string valueTrim(value);
116 StringUtils::Trim(valueTrim, m_whitespaceChars);
117 if (valueTrim.empty())
118 return;
120 m_params.push_back(HeaderParams::value_type(paramLower, valueTrim));
123 std::string CHttpHeader::GetValue(const std::string& strParam) const
125 std::string paramLower(strParam);
126 StringUtils::ToLower(paramLower);
128 return GetValueRaw(paramLower);
131 std::string CHttpHeader::GetValueRaw(const std::string& strParam) const
133 // look in reverse to find last parameter (probably most important)
134 for (HeaderParams::const_reverse_iterator iter = m_params.rbegin(); iter != m_params.rend(); ++iter)
136 if (iter->first == strParam)
137 return iter->second;
140 return "";
143 std::vector<std::string> CHttpHeader::GetValues(std::string strParam) const
145 StringUtils::ToLower(strParam);
146 std::vector<std::string> values;
148 for (HeaderParams::const_iterator iter = m_params.begin(); iter != m_params.end(); ++iter)
150 if (iter->first == strParam)
151 values.push_back(iter->second);
154 return values;
157 std::string CHttpHeader::GetHeader(void) const
159 if (m_protoLine.empty() && m_params.empty())
160 return "";
162 std::string strHeader(m_protoLine + "\r\n");
164 for (HeaderParams::const_iterator iter = m_params.begin(); iter != m_params.end(); ++iter)
165 strHeader += ((*iter).first + ": " + (*iter).second + "\r\n");
167 strHeader += "\r\n";
168 return strHeader;
171 std::string CHttpHeader::GetMimeType(void) const
173 std::string strValue(GetValueRaw("content-type"));
175 std::string mimeType(strValue, 0, strValue.find(';'));
176 StringUtils::TrimRight(mimeType, m_whitespaceChars);
178 return mimeType;
181 std::string CHttpHeader::GetCharset(void) const
183 std::string strValue(GetValueRaw("content-type"));
184 if (strValue.empty())
185 return strValue;
187 StringUtils::ToUpper(strValue);
188 const size_t len = strValue.length();
190 // extract charset value from 'contenttype/contentsubtype;pram1=param1Val ; charset=XXXX\t;param2=param2Val'
191 // most common form: 'text/html; charset=XXXX'
192 // charset value can be in double quotes: 'text/xml; charset="XXX XX"'
194 size_t pos = strValue.find(';');
195 while (pos < len)
197 // move to the next non-whitespace character
198 pos = strValue.find_first_not_of(m_whitespaceChars, pos + 1);
200 if (pos != std::string::npos)
202 if (strValue.compare(pos, 8, "CHARSET=", 8) == 0)
204 pos += 8; // move position to char after 'CHARSET='
205 size_t len = strValue.find(';', pos);
206 if (len != std::string::npos)
207 len -= pos;
208 std::string charset(strValue, pos, len); // intentionally ignoring possible ';' inside quoted string
209 // as we don't support any charset with ';' in name
210 StringUtils::Trim(charset, m_whitespaceChars);
211 if (!charset.empty())
213 if (charset[0] != '"')
214 return charset;
215 else
216 { // charset contains quoted string (allowed according to RFC 2616)
217 StringUtils::Replace(charset, "\\", ""); // unescape chars, ignoring possible '\"' and '\\'
218 const size_t closingQ = charset.find('"', 1);
219 if (closingQ == std::string::npos)
220 return ""; // no closing quote
222 return charset.substr(1, closingQ - 1);
226 pos = strValue.find(';', pos); // find next parameter
230 return ""; // no charset is detected
233 void CHttpHeader::Clear()
235 m_params.clear();
236 m_protoLine.clear();
237 m_headerdone = false;
238 m_lastHeaderLine.clear();