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()));
102 LOG(VB_HTTP, LOG_ERR, QString(
"Unknown MIME type: '%1'").arg(
types[0]));
112 auto payload = QString::fromUtf8(
Request->m_content->constData(),
Request->m_content->size());
117 payload.replace(
"&",
"&");
118 if (!payload.isEmpty())
120 QStringList params = payload.split(
'&', Qt::SkipEmptyParts);
121 for (
const auto & param : std::as_const(params))
123 QString name = param.section(
'=', 0, 0);
124 QString value = param.section(
'=', 1);
125 value.replace(
"+",
" ");
128 name = QUrl::fromPercentEncoding(name.toUtf8());
129 value = QUrl::fromPercentEncoding(value.toUtf8());
130 Request->m_queries.insert(name.trimmed().toLower(), value);
138 LOG(VB_HTTP, LOG_DEBUG,
"Inspecting XML payload");
144 QString soapaction =
Request->m_headers->value(
"soapaction");
145 soapaction.remove(
'"');
146 int lastSlashPos= soapaction.lastIndexOf(
'/');
147 if (lastSlashPos < 0)
151 Request->m_fileName = soapaction.right(soapaction.size()-lastSlashPos-1);
152 LOG(VB_HTTP, LOG_DEBUG, QString(
"Found method call (%1)").arg(
Request->m_fileName));
154 auto payload = QDomDocument();
155 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
159 if (!payload.setContent(
static_cast<QByteArray
>(
Request->m_content->constData()),
160 true, &err_msg, &err_line, &err_col))
162 LOG(VB_HTTP, LOG_WARNING,
"Unable to parse XML request body");
163 LOG(VB_HTTP, LOG_WARNING, QString(
"- Error at line %1, column %2, msg: %3")
164 .arg(err_line).arg(err_col).arg(err_msg));
168 auto parseresult = payload.setContent(
Request->m_content->constData(),
169 QDomDocument::ParseOption::UseNamespaceProcessing);
172 LOG(VB_HTTP, LOG_WARNING,
"Unable to parse XML request body");
173 LOG(VB_HTTP, LOG_WARNING, QString(
"- Error at line %1, column %2, msg: %3")
174 .arg(parseresult.errorLine).arg(parseresult.errorColumn)
175 .arg(parseresult.errorMessage));
179 QString doc_name = payload.documentElement().localName();
180 if (doc_name.compare(
"envelope", Qt::CaseInsensitive) == 0)
182 LOG(VB_HTTP, LOG_DEBUG,
"Found SOAP XML message envelope");
183 auto doc_body = payload.documentElement().namedItem(
"Body");
184 if (doc_body.isNull() || !doc_body.hasChildNodes())
186 LOG(VB_HTTP, LOG_DEBUG,
"Missing or empty SOAP body");
189 auto body_contents = doc_body.firstChild();
190 if (body_contents.hasChildNodes())
192 for (QDomNode node = body_contents.firstChild(); !node.isNull(); node = node.nextSibling())
194 QString name = node.localName();
195 QString value = node.toElement().text();
199 Request->m_queries.insert(name.trimmed().toLower(), value);
200 LOG(VB_HTTP, LOG_DEBUG, QString(
"Found URL param (%1=%2)").arg(name, value));
209 LOG(VB_HTTP, LOG_DEBUG,
"Inspecting JSON payload");
214 QByteArray jstr =
static_cast<QByteArray
>(
Request->m_content->constData());
215 QJsonParseError parseError {};
216 QJsonDocument doc = QJsonDocument::fromJson(jstr, &parseError);
217 if (parseError.error != QJsonParseError::NoError)
219 LOG(VB_HTTP, LOG_WARNING,
220 QString(
"Unable to parse JSON request body - Error at position %1, msg: %2")
221 .arg(parseError.offset).arg(parseError.errorString()));
225 QJsonObject json = doc.object();
226 foreach(
const QString& key, json.keys())
231 if (json.value(key).isObject())
233 QJsonDocument vd(json.value(key).toObject());
234 value = vd.toJson(QJsonDocument::Compact);
238 value = json.value(key).toVariant().toString();
242 LOG(VB_HTTP, LOG_WARNING,
243 QString(
"Failed to parse value for key '%1' from %2")
244 .arg(key, QString(jstr)));
248 Request->m_queries.insert(key.trimmed().toLower(), value);
249 LOG(VB_HTTP, LOG_DEBUG,
250 QString(
"Found URL param (%1=%2)").arg(key, value));
259 auto * data = std::get_if<HTTPData>(&Content);
260 auto *
file = std::get_if<HTTPFile>(&Content);
272 if (
types.size() == 1)
273 return types.front();
277 static const std::map<QString,QString> s_mimeOverrides =
279 {
"ts",
"video/mp2t"}
283 for (
const auto &
type : s_mimeOverrides)
284 if (suffix.compare(
type.first, Qt::CaseInsensitive) == 0)
313 auto * data = std::get_if<HTTPData>(&Response->
m_response);
323 if ((data && !(*data)->m_ranges.empty()) || (
file && !(*file)->m_ranges.empty()))
336 bool chunky = Size > 102400;
342 bool gzipsize = Size > 512 && !chunky;
346 bool compressable = (data ? (*data)->m_mimeType : (*file)->m_mimeType).Inherits(
"text/plain");
349 bool gzip = wantgzip && gzipsize && compressable;
350 bool chunk = chunkable && chunky && allowchunk;
358 if (data) (*data)->m_encoding = result;
359 if (
file) (*file)->m_encoding = result;
370 Response->
AddHeader(
"Content-Encoding",
"gzip");
372 LOG(VB_HTTP, LOG_INFO,
LOC + QString(
"'%1' compressed from %2 to %3 bytes")
373 .arg(data ? (*data)->m_fileName : (*file)->fileName())
374 .arg(Size).arg(buffer->size()));
377 buffer->m_lastModified = data ? (*data)->m_lastModified : (*file)->m_lastModified;
378 buffer->m_etag = data ? (*data)->m_etag : (*file)->m_etag;
379 buffer->m_fileName = data ? (*data)->m_fileName : (*file)->m_fileName;
380 buffer->m_cacheType = data ? (*data)->m_cacheType : (*file)->m_cacheType;
383 Size = buffer->size();