6 #include <QAbstractSocket>
8 #include <QHostAddress>
11 #include <QNetworkInterface>
12 #include <QNetworkReply>
14 #include <QRegularExpression>
15 #include <QSignalMapper>
16 #include <QStringBuilder>
27 using namespace swift::config;
29 using namespace swift::misc::network;
31 namespace swift::misc::network
33 int CNetworkUtils::getTimeoutMs() {
return 5000; }
35 int CNetworkUtils::getLongTimeoutMs() {
return 3 * getTimeoutMs(); }
37 QStringList CNetworkUtils::getKnownLocalIpV4Addresses()
40 const QList<QHostAddress> allAddresses = QNetworkInterface::allAddresses();
41 for (
const QHostAddress &address : allAddresses)
43 if (address.isNull()) {
continue; }
44 if (address.protocol() == QAbstractSocket::IPv4Protocol)
46 const QString a = address.toString();
54 bool CNetworkUtils::canConnect(
const QString &hostAddress,
int port, QString &message,
int timeoutMs)
56 if (timeoutMs < 0) { timeoutMs = getTimeoutMs(); }
59 QObject::connect(&socket, &QTcpSocket::connected, &mapper, qOverload<>(&QSignalMapper::map));
60 QObject::connect(&socket, &QAbstractSocket::errorOccurred, &mapper, qOverload<>(&QSignalMapper::map));
61 mapper.setMapping(&socket, 0);
64 eventLoop.
stopWhen(&mapper, &QSignalMapper::mappedInt);
65 socket.connectToHost(hostAddress,
static_cast<quint16
>(port));
66 const bool timedOut = !eventLoop.
exec(timeoutMs);
68 if (socket.state() != QTcpSocket::ConnectedState)
70 static const QString e(
"Connection failed: '%1'");
71 message = timedOut ? e.arg(
"Timed out") : e.arg(socket.errorString());
76 static const QString ok(
"OK, connected");
82 bool CNetworkUtils::canConnect(
const network::CServer &server, QString &message,
int timeoutMs)
84 return CNetworkUtils::canConnect(server.
getAddress(), server.
getPort(), message, timeoutMs);
87 bool CNetworkUtils::canConnect(
const QString &url, QString &message,
int timeoutMs)
91 message = QObject::tr(
"Missing URL",
"Misc");
94 return canConnect(QUrl(url), message, timeoutMs);
97 bool CNetworkUtils::canConnect(
const QUrl &url, QString &message,
int timeoutMs)
101 message = QObject::tr(
"Invalid URL: %1",
"Misc").arg(url.toString());
105 if (url.isRelative())
107 message = QObject::tr(
"Relative URL cannot be tested: %1",
"Misc").arg(url.toString());
111 const QString host(url.host());
112 const QString scheme(url.scheme().toLower());
114 if (p < 0) { p = scheme.contains(
"https") ? 443 : 80; }
115 return canConnect(host, p, message, timeoutMs);
118 bool CNetworkUtils::canConnect(
const QUrl &url,
int timeoutMs)
121 return canConnect(url, m, timeoutMs);
124 bool CNetworkUtils::isValidIPv4Address(
const QString &candidate)
126 QHostAddress address(candidate);
127 return (QAbstractSocket::IPv4Protocol == address.protocol());
130 bool CNetworkUtils::isValidIPv6Address(
const QString &candidate)
132 QHostAddress address(candidate);
133 return (QAbstractSocket::IPv6Protocol == address.protocol());
136 bool CNetworkUtils::isValidPort(
const QString &port)
139 int p = port.toInt(&success);
140 if (!success)
return false;
141 return (p >= 1 && p <= 65535);
144 QString CNetworkUtils::buildUrl(
const QString &protocol,
const QString &server,
const QString &baseUrl,
145 const QString &serviceUrl)
147 Q_ASSERT_X(protocol.length() > 3, Q_FUNC_INFO,
"worng protocol");
148 Q_ASSERT_X(!server.isEmpty(), Q_FUNC_INFO,
"missing server");
149 Q_ASSERT_X(!serviceUrl.isEmpty(), Q_FUNC_INFO,
"missing service URL");
152 if (!baseUrl.isEmpty()) { url.append(
"/").append(baseUrl); }
153 url.append(
"/").append(serviceUrl);
154 url.replace(
"//",
"/");
155 return protocol +
"://" + url;
158 void CNetworkUtils::setSwiftUserAgent(QNetworkRequest &request,
const QString &userAgentDetails)
163 const QVariant agent = QVariant::fromValue(
164 userAgentDetails.isEmpty() ? defaultUserAgent : defaultUserAgent +
"/" + userAgentDetails);
165 request.setHeader(QNetworkRequest::UserAgentHeader, agent);
168 void CNetworkUtils::addDebugFlag(QUrlQuery &qurl) { qurl.addQueryItem(
"XDEBUG_SESSION_START",
"ECLIPSE_DBGP"); }
170 QNetworkRequest CNetworkUtils::getSwiftNetworkRequest(
const QUrl &url,
RequestType type,
171 const QString &userAgentDetails)
173 QNetworkRequest request(url);
177 request.setHeader(QNetworkRequest::ContentTypeHeader,
"application/x-www-form-urlencoded");
181 CNetworkUtils::setSwiftUserAgent(request, userAgentDetails);
185 QNetworkRequest CNetworkUtils::getSwiftNetworkRequest(
const QNetworkRequest &request,
186 const QString &userAgentDetails)
188 QNetworkRequest req(request);
189 CNetworkUtils::setSwiftUserAgent(req, userAgentDetails);
193 qint64 CNetworkUtils::lastModifiedMsSinceEpoch(
const QNetworkReply *nwReply)
196 const QDateTime lm = CNetworkUtils::lastModifiedDateTime(nwReply);
197 return lm.isValid() ? lm.toMSecsSinceEpoch() : -1;
200 QDateTime CNetworkUtils::lastModifiedDateTime(
const QNetworkReply *nwReply)
203 const QVariant lastModifiedQv = nwReply->header(QNetworkRequest::LastModifiedHeader);
204 if (lastModifiedQv.isValid() && lastModifiedQv.canConvert<QDateTime>())
206 return lastModifiedQv.value<QDateTime>();
211 qint64 CNetworkUtils::lastModifiedSinceNow(
const QNetworkReply *nwReply)
213 const qint64 sinceEpoch = CNetworkUtils::lastModifiedMsSinceEpoch(nwReply);
214 return sinceEpoch > 0 ? std::max(0LL, QDateTime::currentMSecsSinceEpoch() - sinceEpoch) :
215 QDateTime::currentMSecsSinceEpoch();
218 qint64 CNetworkUtils::requestDuration(
const QNetworkReply *nwReply)
220 if (!nwReply) {
return -1; }
221 const QVariant started = nwReply->property(
"started");
222 if (started.isValid() && started.canConvert<qint64>())
224 const qint64 now = QDateTime::currentMSecsSinceEpoch();
225 const qint64 start = started.value<qint64>();
226 return (now - start);
231 int CNetworkUtils::getHttpStatusCode(QNetworkReply *nwReply)
233 if (!nwReply) {
return -1; }
234 const QVariant statusCode = nwReply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
235 if (!statusCode.isValid()) {
return -1; }
236 const int status = statusCode.toInt();
240 bool CNetworkUtils::isHttpStatusRedirect(QNetworkReply *nwReply)
242 if (!nwReply) {
return false; }
243 const int code = CNetworkUtils::getHttpStatusCode(nwReply);
244 return code == 301 || code == 302 || code == 303 || code == 307;
247 QUrl CNetworkUtils::getHttpRedirectUrl(QNetworkReply *nwReply)
249 if (!nwReply) {
return QUrl(); }
250 const QVariant possibleRedirectUrl = nwReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
251 if (!possibleRedirectUrl.isValid()) {
return QUrl(); }
252 QUrl redirectUrl = possibleRedirectUrl.toUrl();
253 if (redirectUrl.isRelative()) { redirectUrl = nwReply->url().resolved(redirectUrl); }
257 QString CNetworkUtils::removeHtmlPartsFromPhpErrorMessage(
const QString &errorMessage)
259 if (errorMessage.isEmpty()) {
return errorMessage; }
260 QString phpError(errorMessage);
261 thread_local
const QRegularExpression regEx(
"<[^>]*>");
262 return phpError.remove(regEx);
265 bool CNetworkUtils::looksLikePhpErrorMessage(
const QString &errorMessage)
267 if (errorMessage.length() < 50) {
return false; }
268 if (errorMessage.contains(
"xdebug", Qt::CaseInsensitive)) {
return true; }
272 const QString &CNetworkUtils::networkOperationToString(QNetworkAccessManager::Operation operation)
274 static const QString h(
"HEAD");
275 static const QString g(
"GET");
276 static const QString put(
"PUT");
277 static const QString d(
"DELETE");
278 static const QString post(
"POST");
279 static const QString c(
"custom");
280 static const QString u(
"unknown");
284 case QNetworkAccessManager::HeadOperation:
return h;
285 case QNetworkAccessManager::GetOperation:
return g;
286 case QNetworkAccessManager::PutOperation:
return put;
287 case QNetworkAccessManager::PostOperation:
return post;
288 case QNetworkAccessManager::DeleteOperation:
return d;
289 case QNetworkAccessManager::CustomOperation:
return c;
290 case QNetworkAccessManager::UnknownOperation:
static const QString & getVersionString()
Version as QVersionNumber.
Utility class which blocks until a signal is emitted or timeout reached.
bool exec(int timeoutMs)
Begin processing events until the timeout or stop condition occurs.
void stopWhen(const T *sender, F signal)
Event loop will stop if the given signal is received.
Value object encapsulating information of a server.
int getPort() const
Get port.
const QString & getAddress() const
Get address.
Free functions in swift::misc.