11 #include <QDomDocument>
12 #include <QJsonDocument>
13 #include <QJsonObject>
16 #define LOC QString("HTTPEnc: ")
33 auto types = Accept.split(
",", Qt::SkipEmptyParts);
35 std::vector<MimePair> weightings;
36 for (
const auto &
type : std::as_const(
types))
38 QString mime =
type.trimmed();
41 if (
auto index =
type.lastIndexOf(
";"); index > -1)
43 mime =
type.mid(0, index).trimmed().toLower();
44 auto qual =
type.mid(index + 1).trimmed();
45 if (
auto index2 = qual.lastIndexOf(
"="); index2 > -1)
48 auto newquality = qual.mid(index2 + 1).toFloat(&ok);
53 weightings.emplace_back(quality, mime);
57 auto comp = [](
const MimePair& First,
const MimePair& Second) {
return First.first > Second.first; };
58 std::sort(weightings.begin(), weightings.end(), comp);
63 for (
const auto & weight : weightings)
64 result.append(weight.second);
68 result.append(
"application/xml");
82 auto types = contenttype.split(
";", Qt::SkipEmptyParts);
89 Request->m_content->m_mimeType = mime;
90 if (mime.Name() ==
"application/x-www-form-urlencoded")
92 else if (mime.Name() ==
"text/xml" || mime.Name() ==
"application/xml" ||
93 mime.Name() ==
"application/soap+xml")
95 else if (mime.Name() ==
"application/json")
98 LOG(VB_HTTP, LOG_ERR, QString(
"Don't know how to get the parameters for MIME type: '%1'").arg(mime.Name()));
101 LOG(VB_HTTP, LOG_ERR, QString(
"Unknown MIME type: '%1'").arg(
types[0]));
110 auto payload = QString::fromUtf8(
Request->m_content->constData(),
Request->m_content->size());
115 payload.replace(
"&",
"&");
116 if (!payload.isEmpty())
118 QStringList params = payload.split(
'&', Qt::SkipEmptyParts);
119 for (
const auto & param : std::as_const(params))
121 QString name = param.section(
'=', 0, 0);
122 QString value = param.section(
'=', 1);
123 value.replace(
"+",
" ");
126 name = QUrl::fromPercentEncoding(name.toUtf8());
127 value = QUrl::fromPercentEncoding(value.toUtf8());
128 Request->m_queries.insert(name.trimmed().toLower(), value);
136 LOG(VB_HTTP, LOG_DEBUG,
"Inspecting XML payload");
142 QString soapaction =
Request->m_headers->value(
"soapaction");
143 soapaction.remove(
'"');
144 int lastSlashPos= soapaction.lastIndexOf(
'/');
145 if (lastSlashPos < 0)
149 Request->m_fileName = soapaction.right(soapaction.size()-lastSlashPos-1);
150 LOG(VB_HTTP, LOG_DEBUG, QString(
"Found method call (%1)").arg(
Request->m_fileName));
152 auto payload = QDomDocument();
156 if (!payload.setContent(
static_cast<QByteArray
>(
Request->m_content->constData()),
157 true, &err_msg, &err_line, &err_col))
159 LOG(VB_HTTP, LOG_WARNING,
"Unable to parse XML request body");
160 LOG(VB_HTTP, LOG_WARNING, QString(
"- Error at line %1, column %2, msg: %3")
161 .arg(err_line).arg(err_col).arg(err_msg));
164 QString doc_name = payload.documentElement().localName();
165 if (doc_name.compare(
"envelope", Qt::CaseInsensitive) == 0)
167 LOG(VB_HTTP, LOG_DEBUG,
"Found SOAP XML message envelope");
168 auto doc_body = payload.documentElement().namedItem(
"Body");
169 if (doc_body.isNull() || !doc_body.hasChildNodes())
171 LOG(VB_HTTP, LOG_DEBUG,
"Missing or empty SOAP body");
174 auto body_contents = doc_body.firstChild();
175 if (body_contents.hasChildNodes())
177 for (QDomNode node = body_contents.firstChild(); !node.isNull(); node = node.nextSibling())
179 QString name = node.localName();
180 QString value = node.toElement().text();
184 Request->m_queries.insert(name.trimmed().toLower(), value);
185 LOG(VB_HTTP, LOG_DEBUG, QString(
"Found URL param (%1=%2)").arg(name, value));
194 LOG(VB_HTTP, LOG_DEBUG,
"Inspecting JSON payload");
199 QByteArray jstr =
static_cast<QByteArray
>(
Request->m_content->constData());
200 QJsonParseError parseError {};
201 QJsonDocument doc = QJsonDocument::fromJson(jstr, &parseError);
202 if (parseError.error != QJsonParseError::NoError)
204 LOG(VB_HTTP, LOG_WARNING,
205 QString(
"Unable to parse JSON request body - Error at position %1, msg: %2")
206 .arg(parseError.offset).arg(parseError.errorString()));
210 QJsonObject json = doc.object();
211 foreach(
const QString& key, json.keys())
216 if (json.value(key).isObject())
218 QJsonDocument vd(json.value(key).toObject());
219 value = vd.toJson(QJsonDocument::Compact);
223 value = json.value(key).toVariant().toString();
227 LOG(VB_HTTP, LOG_WARNING,
228 QString(
"Failed to parse value for key '%1' from %2")
229 .arg(key, QString(jstr)));
233 Request->m_queries.insert(key.trimmed().toLower(), value);
234 LOG(VB_HTTP, LOG_DEBUG,
235 QString(
"Found URL param (%1=%2)").arg(key, value));
244 auto * data = std::get_if<HTTPData>(&
Content);
257 if (
types.size() == 1)
258 return types.front();
262 static const std::map<QString,QString> s_mimeOverrides =
264 {
"ts",
"video/mp2t"}
268 for (
const auto &
type : s_mimeOverrides)
269 if (suffix.compare(
type.first, Qt::CaseInsensitive) == 0)
298 auto * data = std::get_if<HTTPData>(&Response->
m_response);
308 if ((data && !(*data)->m_ranges.empty()) || (
file && !(*file)->m_ranges.empty()))
321 bool chunky = Size > 102400;
327 bool gzipsize = Size > 512 && !chunky;
331 bool compressable = (data ? (*data)->m_mimeType : (*file)->m_mimeType).Inherits(
"text/plain");
334 bool gzip = wantgzip && gzipsize && compressable;
335 bool chunk = chunkable && chunky && allowchunk;
343 if (data) (*data)->m_encoding = result;
344 if (
file) (*file)->m_encoding = result;
355 Response->
AddHeader(
"Content-Encoding",
"gzip");
357 LOG(VB_HTTP, LOG_INFO,
LOC + QString(
"'%1' compressed from %2 to %3 bytes")
358 .arg(data ? (*data)->m_fileName : (*file)->fileName())
359 .arg(Size).arg(buffer->size()));
362 buffer->m_lastModified = data ? (*data)->m_lastModified : (*file)->m_lastModified;
363 buffer->m_etag = data ? (*data)->m_etag : (*file)->m_etag;
364 buffer->m_fileName = data ? (*data)->m_fileName : (*file)->m_fileName;
365 buffer->m_cacheType = data ? (*data)->m_cacheType : (*file)->m_cacheType;
368 Size = buffer->size();