3#include <QtBluetooth/QBluetoothLocalDevice>
4#include <QtCore/QCoreApplication>
6#include <QtCore/QIODevice>
7#include <QtCore/QJsonDocument>
8#include <QtCore/QUrlQuery>
9#include <QtNetwork/QHttpHeaders>
10#include <QtNetwork/QHttpPart>
11#include <QtNetwork/QNetworkAccessManager>
12#include <QtNetwork/QNetworkInformation>
13#include <QtNetwork/QNetworkProxy>
14#include <QtNetwork/QNetworkProxyFactory>
15#include <QtNetwork/QSslSocket>
32 if (code >= HttpStatusCode::Continue && code < HttpStatusCode::Ok) {
33 return HttpStatusClass::Informational;
35 if (code >= HttpStatusCode::Ok && code < HttpStatusCode::MultipleChoices) {
36 return HttpStatusClass::Success;
38 if (code >= HttpStatusCode::MultipleChoices && code < HttpStatusCode::BadRequest) {
39 return HttpStatusClass::Redirection;
41 if (code >= HttpStatusCode::BadRequest && code < HttpStatusCode::InternalServerError) {
42 return HttpStatusClass::ClientError;
44 if (code >= HttpStatusCode::InternalServerError && code <= HttpStatusCode::NetworkConnectTimeoutError) {
45 return HttpStatusClass::ServerError;
47 return HttpStatusClass::Unknown;
54 case HttpStatusCode::Continue:
55 return QStringLiteral(
"Continue");
56 case HttpStatusCode::SwitchingProtocols:
57 return QStringLiteral(
"Switching Protocols");
58 case HttpStatusCode::Processing:
59 return QStringLiteral(
"Processing");
61 case HttpStatusCode::Ok:
62 return QStringLiteral(
"OK");
63 case HttpStatusCode::Created:
64 return QStringLiteral(
"Created");
65 case HttpStatusCode::Accepted:
66 return QStringLiteral(
"Accepted");
67 case HttpStatusCode::NonAuthoritativeInformation:
68 return QStringLiteral(
"Non-Authoritative Information");
69 case HttpStatusCode::NoContent:
70 return QStringLiteral(
"No Content");
71 case HttpStatusCode::ResetContent:
72 return QStringLiteral(
"Reset Content");
73 case HttpStatusCode::PartialContent:
74 return QStringLiteral(
"Partial Content");
75 case HttpStatusCode::MultiStatus:
76 return QStringLiteral(
"Multi-Status");
77 case HttpStatusCode::AlreadyReported:
78 return QStringLiteral(
"Already Reported");
79 case HttpStatusCode::IMUsed:
80 return QStringLiteral(
"IM Used");
82 case HttpStatusCode::MultipleChoices:
83 return QStringLiteral(
"Multiple Choices");
84 case HttpStatusCode::MovedPermanently:
85 return QStringLiteral(
"Moved Permanently");
86 case HttpStatusCode::Found:
87 return QStringLiteral(
"Found");
88 case HttpStatusCode::SeeOther:
89 return QStringLiteral(
"See Other");
90 case HttpStatusCode::NotModified:
91 return QStringLiteral(
"Not Modified");
92 case HttpStatusCode::UseProxy:
93 return QStringLiteral(
"Use Proxy");
94 case HttpStatusCode::TemporaryRedirect:
95 return QStringLiteral(
"Temporary Redirect");
96 case HttpStatusCode::PermanentRedirect:
97 return QStringLiteral(
"Permanent Redirect");
99 case HttpStatusCode::BadRequest:
100 return QStringLiteral(
"Bad Request");
101 case HttpStatusCode::Unauthorized:
102 return QStringLiteral(
"Unauthorized");
103 case HttpStatusCode::PaymentRequired:
104 return QStringLiteral(
"Payment Required");
105 case HttpStatusCode::Forbidden:
106 return QStringLiteral(
"Forbidden");
107 case HttpStatusCode::NotFound:
108 return QStringLiteral(
"Not Found");
109 case HttpStatusCode::MethodNotAllowed:
110 return QStringLiteral(
"Method Not Allowed");
111 case HttpStatusCode::NotAcceptable:
112 return QStringLiteral(
"Not Acceptable");
113 case HttpStatusCode::ProxyAuthenticationRequired:
114 return QStringLiteral(
"Proxy Authentication Required");
115 case HttpStatusCode::RequestTimeout:
116 return QStringLiteral(
"Request Timeout");
117 case HttpStatusCode::Conflict:
118 return QStringLiteral(
"Conflict");
119 case HttpStatusCode::Gone:
120 return QStringLiteral(
"Gone");
121 case HttpStatusCode::LengthRequired:
122 return QStringLiteral(
"Length Required");
123 case HttpStatusCode::PreconditionFailed:
124 return QStringLiteral(
"Precondition Failed");
125 case HttpStatusCode::PayloadTooLarge:
126 return QStringLiteral(
"Payload Too Large");
127 case HttpStatusCode::UriTooLong:
128 return QStringLiteral(
"URI Too Long");
129 case HttpStatusCode::UnsupportedMediaType:
130 return QStringLiteral(
"Unsupported Media Type");
131 case HttpStatusCode::RequestRangeNotSatisfiable:
132 return QStringLiteral(
"Range Not Satisfiable");
133 case HttpStatusCode::ExpectationFailed:
134 return QStringLiteral(
"Expectation Failed");
135 case HttpStatusCode::ImATeapot:
136 return QStringLiteral(
"I'm a teapot");
137 case HttpStatusCode::MisdirectedRequest:
138 return QStringLiteral(
"Misdirected Request");
139 case HttpStatusCode::UnprocessableEntity:
140 return QStringLiteral(
"Unprocessable Entity");
141 case HttpStatusCode::Locked:
142 return QStringLiteral(
"Locked");
143 case HttpStatusCode::FailedDependency:
144 return QStringLiteral(
"Failed Dependency");
145 case HttpStatusCode::UpgradeRequired:
146 return QStringLiteral(
"Upgrade Required");
147 case HttpStatusCode::PreconditionRequired:
148 return QStringLiteral(
"Precondition Required");
149 case HttpStatusCode::TooManyRequests:
150 return QStringLiteral(
"Too Many Requests");
151 case HttpStatusCode::RequestHeaderFieldsTooLarge:
152 return QStringLiteral(
"Request Header Fields Too Large");
153 case HttpStatusCode::UnavailableForLegalReasons:
154 return QStringLiteral(
"Unavailable For Legal Reasons");
156 case HttpStatusCode::InternalServerError:
157 return QStringLiteral(
"Internal Server Error");
158 case HttpStatusCode::NotImplemented:
159 return QStringLiteral(
"Not Implemented");
160 case HttpStatusCode::BadGateway:
161 return QStringLiteral(
"Bad Gateway");
162 case HttpStatusCode::ServiceUnavailable:
163 return QStringLiteral(
"Service Unavailable");
164 case HttpStatusCode::GatewayTimeout:
165 return QStringLiteral(
"Gateway Timeout");
166 case HttpStatusCode::HttpVersionNotSupported:
167 return QStringLiteral(
"HTTP Version Not Supported");
168 case HttpStatusCode::VariantAlsoNegotiates:
169 return QStringLiteral(
"Variant Also Negotiates");
170 case HttpStatusCode::InsufficientStorage:
171 return QStringLiteral(
"Insufficient Storage");
172 case HttpStatusCode::LoopDetected:
173 return QStringLiteral(
"Loop Detected");
174 case HttpStatusCode::NotExtended:
175 return QStringLiteral(
"Not Extended");
176 case HttpStatusCode::NetworkAuthenticationRequired:
177 return QStringLiteral(
"Network Authentication Required");
178 case HttpStatusCode::NetworkConnectTimeoutError:
179 return QStringLiteral(
"Network Connect Timeout Error");
181 return QStringLiteral(
"Unknown Status (%1)").arg(
static_cast<int>(statusCode));
197 case HttpMethod::Get:
198 return QStringLiteral(
"GET");
199 case HttpMethod::Post:
200 return QStringLiteral(
"POST");
201 case HttpMethod::Put:
202 return QStringLiteral(
"PUT");
203 case HttpMethod::Delete:
204 return QStringLiteral(
"DELETE");
205 case HttpMethod::Head:
206 return QStringLiteral(
"HEAD");
207 case HttpMethod::Options:
208 return QStringLiteral(
"OPTIONS");
209 case HttpMethod::Patch:
210 return QStringLiteral(
"PATCH");
211 case HttpMethod::Connect:
212 return QStringLiteral(
"CONNECT");
213 case HttpMethod::Trace:
214 return QStringLiteral(
"TRACE");
216 return QStringLiteral(
"GET");
222 const QByteArray upper = methodStr.toUpper().toLatin1();
223 const char* str = upper.constData();
225 if (qstrcmp(str,
"GET") == 0)
226 return HttpMethod::Get;
227 if (qstrcmp(str,
"POST") == 0)
228 return HttpMethod::Post;
229 if (qstrcmp(str,
"PUT") == 0)
230 return HttpMethod::Put;
231 if (qstrcmp(str,
"DELETE") == 0)
232 return HttpMethod::Delete;
233 if (qstrcmp(str,
"HEAD") == 0)
234 return HttpMethod::Head;
235 if (qstrcmp(str,
"OPTIONS") == 0)
236 return HttpMethod::Options;
237 if (qstrcmp(str,
"PATCH") == 0)
238 return HttpMethod::Patch;
239 if (qstrcmp(str,
"CONNECT") == 0)
240 return HttpMethod::Connect;
241 if (qstrcmp(str,
"TRACE") == 0)
242 return HttpMethod::Trace;
244 return HttpMethod::Get;
253 if (!url.isValid()) {
257 const QString scheme = url.scheme().toLower();
258 return scheme == QLatin1String(
"http") || scheme == QLatin1String(
"https") || scheme == QLatin1String(
"file") ||
259 scheme == QLatin1String(
"qrc") || scheme.isEmpty();
264 const QString scheme = url.scheme().toLower();
265 return scheme == QLatin1String(
"http") || scheme == QLatin1String(
"https");
270 return url.scheme().toLower() == QLatin1String(
"https");
275 if (!url.isValid()) {
279 QUrl normalized = url.adjusted(QUrl::NormalizePathSegments | QUrl::StripTrailingSlash);
280 normalized.setScheme(normalized.scheme().toLower());
281 normalized.setHost(normalized.host().toLower());
283 const int port = normalized.port();
284 const QString scheme = normalized.scheme();
285 if ((scheme == QLatin1String(
"http") && port == 80) || (scheme == QLatin1String(
"https") && port == 443) ||
286 (scheme == QLatin1String(
"ftp") && port == 21)) {
287 normalized.setPort(-1);
295 if (!url.isValid()) {
299 if (url.scheme().isEmpty()) {
300 QUrl withScheme = url;
301 withScheme.setScheme(defaultScheme);
308QUrl
buildUrl(
const QString& baseUrl,
const QMap<QString, QString>& params)
311 if (!url.isValid()) {
316 for (
auto it = params.constBegin(); it != params.constEnd(); ++it) {
317 query.addQueryItem(it.key(), it.value());
324QUrl
buildUrl(
const QString& baseUrl,
const QList<QPair<QString, QString>>& params)
327 if (!url.isValid()) {
332 for (
const auto& [key, value] : params) {
333 query.addQueryItem(key, value);
342 return url.adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment);
352 request.setTransferTimeout(
config.timeoutMs);
355 if (
config.allowRedirects) {
356 request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
358 request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy);
362 request.setAttribute(QNetworkRequest::Http2AllowedAttribute,
config.http2Allowed);
365 if (
config.cacheEnabled) {
366 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
367 request.setAttribute(QNetworkRequest::CacheSaveControlAttribute,
true);
369 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
370 request.setAttribute(QNetworkRequest::CacheSaveControlAttribute,
false);
374 request.setAttribute(QNetworkRequest::BackgroundRequestAttribute,
config.backgroundRequest);
376 using WK = QHttpHeaders::WellKnownHeader;
377 QHttpHeaders headers = request.headers();
379 if (!
config.accept.isEmpty()) {
380 headers.replaceOrAppend(WK::Accept,
config.accept);
382 if (!
config.acceptEncoding.isEmpty()) {
383 headers.replaceOrAppend(WK::AcceptEncoding,
config.acceptEncoding);
385 if (!
config.contentType.isEmpty()) {
386 headers.replaceOrAppend(WK::ContentType,
config.contentType);
388 headers.replaceOrAppend(WK::Connection,
"keep-alive");
389 request.setHeaders(headers);
391 for (
const auto& [attribute, value] :
config.requestAttributes) {
392 request.setAttribute(attribute, value);
395 if (
config.connectionCacheExpirySecs >= 0) {
396 request.setAttribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute,
397 config.connectionCacheExpirySecs);
399 if (
config.tcpKeepAliveIdleSecs >= 0) {
400 request.setTcpKeepAliveIdleTimeBeforeProbes(std::chrono::seconds(
config.tcpKeepAliveIdleSecs));
402 if (
config.tcpKeepAliveIntervalSecs >= 0) {
403 request.setTcpKeepAliveIntervalBetweenProbes(std::chrono::seconds(
config.tcpKeepAliveIntervalSecs));
405 if (
config.tcpKeepAliveProbeCount >= 0) {
406 request.setTcpKeepAliveProbeCount(
config.tcpKeepAliveProbeCount);
412 QNetworkRequest request(url);
419 using WK = QHttpHeaders::WellKnownHeader;
420 QHttpHeaders headers = request.headers();
421 headers.replaceOrAppend(WK::UserAgent, userAgent.isEmpty() ?
defaultUserAgent() : userAgent);
422 headers.replaceOrAppend(WK::Accept,
"*/*");
423 headers.replaceOrAppend(WK::AcceptEncoding,
"gzip, deflate");
424 headers.replaceOrAppend(WK::Connection,
"keep-alive");
425 request.setHeaders(headers);
430 using WK = QHttpHeaders::WellKnownHeader;
431 QHttpHeaders headers = request.headers();
432 headers.replaceOrAppend(WK::Accept,
"application/json");
433 headers.replaceOrAppend(WK::ContentType,
"application/json");
434 request.setHeaders(headers);
439 request.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral(
"application/x-www-form-urlencoded"));
444 static QString userAgent;
445 if (userAgent.isEmpty()) {
446 userAgent = QStringLiteral(
"%1/%2 (Qt %3)")
447 .arg(QCoreApplication::applicationName())
448 .arg(QCoreApplication::applicationVersion())
449 .arg(QString::fromLatin1(qVersion()));
460 QHttpHeaders headers = request.headers();
461 headers.replaceOrAppend(QHttpHeaders::WellKnownHeader::Authorization,
"Basic " + credentials);
462 request.setHeaders(headers);
465void setBasicAuth(QNetworkRequest& request,
const QString& username,
const QString& password)
472 QHttpHeaders headers = request.headers();
473 headers.replaceOrAppend(QHttpHeaders::WellKnownHeader::Authorization,
"Bearer " + token);
474 request.setHeaders(headers);
479 const QString credentials = username + QLatin1Char(
':') + password;
480 return QString::fromLatin1(credentials.toUtf8().toBase64());
490 part.setHeader(QNetworkRequest::ContentDispositionHeader, QStringLiteral(
"form-data; name=\"%1\"").arg(name));
491 part.setBody(value.toUtf8());
495QHttpPart
createFilePart(
const QString& name,
const QString& fileName,
const QString& contentType, QIODevice* device)
498 part.setHeader(QNetworkRequest::ContentTypeHeader,
contentType);
499 part.setHeader(QNetworkRequest::ContentDispositionHeader,
500 QStringLiteral(
"form-data; name=\"%1\"; filename=\"%2\"").arg(name, fileName));
501 part.setBodyDevice(device);
505QHttpPart
createFilePart(
const QString& name,
const QString& fileName, QIODevice* device)
516 QSslConfiguration
config = QSslConfiguration::defaultConfiguration();
517 config.setProtocol(protocol);
523 QSslConfiguration
config = QSslConfiguration::defaultConfiguration();
524 config.setPeerVerifyMode(QSslSocket::VerifyNone);
530 request.setSslConfiguration(
config);
535 const auto certs = QSslCertificate::fromPath(filePath, QSsl::Pem);
536 if (certs.isEmpty() && errorOut) {
537 *errorOut = QStringLiteral(
"No certificates found in %1").arg(filePath);
542bool loadClientCertAndKey(
const QString& certPath,
const QString& keyPath, QSslCertificate& certOut, QSslKey& keyOut,
545 const auto certs = QSslCertificate::fromPath(certPath, QSsl::Pem);
546 if (certs.isEmpty()) {
548 *errorOut = QStringLiteral(
"No certificate found in %1").arg(certPath);
552 QFile keyFile(keyPath);
553 if (!keyFile.open(QIODevice::ReadOnly)) {
555 *errorOut = QStringLiteral(
"Cannot open key file %1").arg(keyPath);
559 QSslKey key(&keyFile, QSsl::Rsa);
562 key = QSslKey(&keyFile, QSsl::Ec);
566 *errorOut = QStringLiteral(
"Invalid key in %1").arg(keyPath);
570 certOut = certs.first();
581 QJsonParseError localError;
582 QJsonParseError* errorPtr = (
error !=
nullptr) ?
error : &localError;
584 QJsonDocument doc = QJsonDocument::fromJson(data, errorPtr);
586 if (errorPtr->error != QJsonParseError::NoError) {
587 qCWarning(QGCNetworkHelperLog) <<
"JSON parse error:" << errorPtr->errorString() <<
"at offset"
597 if (reply ==
nullptr) {
598 if (
error !=
nullptr) {
599 error->error = QJsonParseError::UnterminatedObject;
605 if (reply->error() != QNetworkReply::NoError) {
606 qCWarning(QGCNetworkHelperLog) <<
"Network error before JSON parse:" << reply->errorString();
607 if (
error !=
nullptr) {
608 error->error = QJsonParseError::UnterminatedObject;
619 if (data.isEmpty()) {
624 for (
int i = 0; i < data.size(); ++i) {
625 const char c = data.at(i);
626 if (c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r') {
629 return c ==
'{' || c ==
'[';
644 const QVariant statusAttr = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
645 return statusAttr.isValid() ? statusAttr.toInt() : -1;
654 const QVariant redirectAttr = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
655 if (redirectAttr.isNull()) {
659 const QUrl redirectTarget = redirectAttr.toUrl();
660 return reply->url().resolved(redirectTarget);
666 return QStringLiteral(
"No reply");
670 if (reply->error() != QNetworkReply::NoError) {
671 return reply->errorString();
677 return QStringLiteral(
"HTTP %1: %2").arg(status).arg(
httpStatusText(status));
689 if (reply->error() != QNetworkReply::NoError) {
712 return reply->header(QNetworkRequest::ContentTypeHeader).toString();
720 const QVariant lenAttr = reply->header(QNetworkRequest::ContentLengthHeader);
721 return lenAttr.isValid() ? lenAttr.toLongLong() : -1;
727 return type.contains(QLatin1String(
"application/json"), Qt::CaseInsensitive) ||
728 type.contains(QLatin1String(
"+json"), Qt::CaseInsensitive);
737 if (!QNetworkInformation::loadDefaultBackend()) {
738 qCDebug(QGCNetworkHelperLog) <<
"Failed to load network information backend";
742 const QNetworkInformation* netInfo = QNetworkInformation::instance();
743 if (netInfo ==
nullptr) {
747 return netInfo->reachability() != QNetworkInformation::Reachability::Disconnected;
752 if (QNetworkInformation::availableBackends().isEmpty()) {
756 if (!QNetworkInformation::loadDefaultBackend()) {
760 if (!QNetworkInformation::loadBackendByFeatures(QNetworkInformation::Feature::Reachability)) {
764 const QNetworkInformation* netInfo = QNetworkInformation::instance();
765 if (netInfo ==
nullptr) {
769 return netInfo->reachability() == QNetworkInformation::Reachability::Online;
774 if (QNetworkInformation::availableBackends().isEmpty()) {
778 if (!QNetworkInformation::loadDefaultBackend()) {
782 const QNetworkInformation* netInfo = QNetworkInformation::instance();
783 if (netInfo ==
nullptr) {
787 return netInfo->transportMedium() == QNetworkInformation::TransportMedium::Ethernet;
792 const QList<QBluetoothHostInfo> devices = QBluetoothLocalDevice::allDevices();
793 return !devices.isEmpty();
798 if (!QNetworkInformation::loadDefaultBackend()) {
799 return ConnectionType::Unknown;
802 const QNetworkInformation* netInfo = QNetworkInformation::instance();
804 return ConnectionType::Unknown;
807 if (netInfo->reachability() == QNetworkInformation::Reachability::Disconnected) {
808 return ConnectionType::None;
811 switch (netInfo->transportMedium()) {
812 case QNetworkInformation::TransportMedium::Ethernet:
813 return ConnectionType::Ethernet;
814 case QNetworkInformation::TransportMedium::WiFi:
815 return ConnectionType::WiFi;
816 case QNetworkInformation::TransportMedium::Cellular:
817 return ConnectionType::Cellular;
818 case QNetworkInformation::TransportMedium::Bluetooth:
819 return ConnectionType::Bluetooth;
821 return ConnectionType::Unknown;
828 case ConnectionType::None:
829 return QStringLiteral(
"None");
830 case ConnectionType::Ethernet:
831 return QStringLiteral(
"Ethernet");
832 case ConnectionType::WiFi:
833 return QStringLiteral(
"WiFi");
834 case ConnectionType::Cellular:
835 return QStringLiteral(
"Cellular");
836 case ConnectionType::Bluetooth:
837 return QStringLiteral(
"Bluetooth");
838 case ConnectionType::Unknown:
840 return QStringLiteral(
"Unknown");
854 QObject::connect(reply, &QNetworkReply::sslErrors, reply, [reply](
const QList<QSslError>& errors) {
855 qCWarning(QGCNetworkHelperLog) <<
"Ignoring SSL errors for" << reply->url();
856 for (
const QSslError&
error : errors) {
857 qCDebug(QGCNetworkHelperLog) <<
" -" <<
error.errorString();
859 reply->ignoreSslErrors();
870 const bool sslLibraryBuildIs1x = ((QSslSocket::sslLibraryBuildVersionNumber() & 0xf0000000) == 0x10000000);
871 const bool sslLibraryIs3x = ((QSslSocket::sslLibraryVersionNumber() & 0xf0000000) == 0x30000000);
872 if (sslLibraryBuildIs1x && sslLibraryIs3x) {
873 qCWarning(QGCNetworkHelperLog) <<
"Ignoring SSL certificate errors due to OpenSSL version mismatch";
874 QList<QSslError> errorsThatCanBeIgnored;
875 errorsThatCanBeIgnored << QSslError(QSslError::NoPeerCertificate);
876 reply->ignoreSslErrors(errorsThatCanBeIgnored);
882 return QSslSocket::supportsSsl();
887 return QSslSocket::sslLibraryVersionString();
896 QNetworkProxyFactory::setUseSystemConfiguration(
true);
901 auto* manager =
new QNetworkAccessManager(parent);
912#if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID)
913 QNetworkProxy proxy = manager->proxy();
914 proxy.setType(QNetworkProxy::DefaultProxy);
915 manager->setProxy(proxy);
#define QGC_LOGGING_CATEGORY(name, categoryStr)
HttpStatusClass classifyHttpStatus(int statusCode)
Classify an HTTP status code.
bool isSuccess(const QNetworkReply *reply)
Check if reply indicates success (no error and HTTP 2xx)
QHttpServerRequest::Method HttpMethod
HTTP request methods - uses Qt's QHttpServerRequest::Method enum.
HttpStatusClass
HTTP status code ranges.
void applySslConfig(QNetworkRequest &request, const QSslConfiguration &config)
QHttpServerResponder::StatusCode HttpStatusCode
HTTP status codes - uses Qt's QHttpServerResponder::StatusCode enum.
QList< QSslCertificate > loadCaCertificates(const QString &filePath, QString *errorOut)
bool looksLikeJson(const QByteArray &data)
void configureProxy(QNetworkAccessManager *manager)
Set up default proxy configuration on a network manager.
bool isJsonResponse(const QNetworkReply *reply)
Check if response is JSON based on Content-Type.
const QString kContentTypeOctetStream
void initializeProxySupport()
QNetworkAccessManager * createNetworkManager(QObject *parent)
ConnectionType
Network connection types.
QNetworkRequest createRequest(const QUrl &url, const RequestConfig &config)
bool isRedirect(const QNetworkReply *reply)
Check if reply indicates a redirect.
bool isNetworkEthernet()
Check if current network connection is Ethernet.
QString sslVersion()
Get SSL library version string.
bool isHttpRedirect(int statusCode)
Check if HTTP status indicates redirect (3xx)
HttpMethod parseHttpMethod(const QString &methodStr)
bool isHttpUrl(const QUrl &url)
Check if URL uses HTTP or HTTPS scheme.
QHttpPart createFormField(const QString &name, const QString &value)
void setFormHeaders(QNetworkRequest &request)
Set form data content headers.
QUrl redirectUrl(const QNetworkReply *reply)
void ignoreSslErrorsIfNeeded(QNetworkReply *reply)
void setStandardHeaders(QNetworkRequest &request, const QString &userAgent)
Set standard browser-like headers on a request.
bool isBluetoothAvailable()
Check if Bluetooth is available on this device.
QString contentType(const QNetworkReply *reply)
Get Content-Type header from reply.
bool loadClientCertAndKey(const QString &certPath, const QString &keyPath, QSslCertificate &certOut, QSslKey &keyOut, QString *errorOut)
int httpStatusCode(const QNetworkReply *reply)
QSslConfiguration createInsecureSslConfig()
QString defaultUserAgent()
Get the default User-Agent string for QGC.
QUrl buildUrl(const QString &baseUrl, const QMap< QString, QString > ¶ms)
Build URL with query parameters from a map.
bool isNetworkAvailable()
Check if network is available (not disconnected)
void setBasicAuth(QNetworkRequest &request, const QString &credentials)
QString createBasicAuthCredentials(const QString &username, const QString &password)
QString httpStatusText(HttpStatusCode statusCode)
bool isHttpsUrl(const QUrl &url)
Check if URL uses secure HTTPS scheme.
QString httpMethodName(HttpMethod method)
Get string name for an HTTP method (e.g., "GET", "POST")
bool isHttpSuccess(int statusCode)
Check if HTTP status indicates success (2xx)
ConnectionType connectionType()
Get current network connection type.
QJsonDocument parseJson(const QByteArray &data, QJsonParseError *error)
QSslConfiguration createSslConfig(QSsl::SslProtocol protocol)
void setBearerToken(QNetworkRequest &request, const QString &token)
bool isValidUrl(const QUrl &url)
QHttpPart createFilePart(const QString &name, const QString &fileName, const QString &contentType, QIODevice *device)
QJsonDocument parseJsonReply(QNetworkReply *reply, QJsonParseError *error)
QUrl normalizeUrl(const QUrl &url)
Normalize URL (lowercase scheme/host, remove default ports, trailing slashes)
QUrl urlWithoutQuery(const QUrl &url)
Get URL without query string and fragment.
void setJsonHeaders(QNetworkRequest &request)
Set JSON content headers (Accept and Content-Type)
qint64 contentLength(const QNetworkReply *reply)
Get Content-Length header from reply (-1 if not present)
QString connectionTypeName(ConnectionType type)
Get human-readable name for connection type.
QString errorMessage(const QNetworkReply *reply)
QUrl ensureScheme(const QUrl &url, const QString &defaultScheme)
Ensure URL has scheme, defaulting to https:// if missing.
bool isInternetAvailable()
Check if internet is reachable (online state, stricter than isNetworkAvailable)
void ignoreSslErrors(QNetworkReply *reply)
void configureRequest(QNetworkRequest &request, const RequestConfig &config)
bool isSslAvailable()
Check if SSL is available.
Common request configuration options.