swift
url.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2015 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "misc/network/url.h"
5 
6 #include <QJsonValue>
7 #include <QPair>
8 #include <QtGlobal>
9 
11 #include "misc/propertyindexref.h"
12 
13 SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::network, CUrl)
14 
15 namespace swift::misc::network
16 {
17  CUrl::CUrl(const QString &fullUrl)
18  {
19  if (!fullUrl.isEmpty()) { setFullUrl(fullUrl); }
20  }
21 
22  CUrl::CUrl(const char *url) : CUrl(QString(url)) {}
23 
24  CUrl::CUrl(const QUrl &url) { this->setQUrl(url); }
25 
26  CUrl::CUrl(const QString &address, int port) : CUrl("", address, port, "") {}
27 
28  CUrl::CUrl(const QString &scheme, const QString &address, int port, const QString &path)
29  : m_host(address.trimmed()), m_port(port), m_path(path.trimmed())
30  {
31  this->setScheme(scheme);
32  }
33 
34  void CUrl::setScheme(const QString &protocol) { m_scheme = protocol.trimmed().toLower().replace("://", ""); }
35 
36  void CUrl::setPath(const QString &path) { m_path = path.simplified(); }
37 
38  QString CUrl::appendPath(const QString &pathToAppend)
39  {
40  if (pathToAppend.isEmpty()) { return m_path; }
41  const QString p = CFileUtils::appendFilePaths(this->getPath(), pathToAppend);
42  this->setPath(p);
43  return m_path;
44  }
45 
46  int CUrl::getPort() const
47  {
48  if (m_port > 0) { return m_port; }
49  return protocolToDefaultPort(this->getScheme());
50  }
51 
52  bool CUrl::hasPort() const { return m_port >= 0; }
53 
54  bool CUrl::isEmpty() const { return m_host.isEmpty(); }
55 
56  bool CUrl::hasDefaultPort() const { return isDefaultPort(m_scheme, m_port); }
57 
58  void CUrl::setQuery(const QString &query)
59  {
60  const QString q(stripQueryString(query));
61  m_query = q;
62  }
63 
64  bool CUrl::hasQuery() const { return !m_query.isEmpty(); }
65 
66  void CUrl::appendQuery(const QString &queryToAppend)
67  {
68  if (queryToAppend.isEmpty()) { return; }
69  const QString q(stripQueryString(queryToAppend));
70  if (q.isEmpty()) { return; }
71  m_query += hasQuery() ? "&" + q : q;
72  }
73 
74  void CUrl::appendQuery(const QString &key, const QString &value)
75  {
76  if (key.isEmpty()) { return; }
77  this->appendQuery(key + "=" + value);
78  }
79 
80  bool CUrl::hasFragment() const { return !m_fragment.isEmpty(); }
81 
82  void CUrl::setFragment(const QString &fragment) { m_fragment = fragment; }
83 
84  QString CUrl::getFullUrl(bool withQuery) const
85  {
86  if (m_host.isEmpty()) { return {}; }
87 
88  QString qn(m_host);
89  if (!hasDefaultPort() && hasPort()) { qn = qn.append(":").append(QString::number(m_port)); }
90  if (hasPath()) { qn = qn.append("/").append(m_path).replace("//", "/"); }
91  if (hasFragment()) { qn = qn.append("#").append(m_fragment).replace("//", "/"); }
92  if (hasQuery() && withQuery) { qn = qn.append("?").append(m_query); }
93  if (hasScheme()) { qn = QString(this->getScheme()).append("://").append(qn); }
94  return qn;
95  }
96 
97  void CUrl::setFullUrl(const QString &fullUrl) { setQUrl(QUrl(fullUrl)); }
98 
99  QString CUrl::getFileName() const { return toQUrl().fileName(); }
100 
101  QUrl CUrl::toQUrl() const { return QUrl(getFullUrl()); }
102 
103  void CUrl::setQUrl(const QUrl &url)
104  {
105  this->setPort(url.port());
106  this->setHost(url.host());
107  this->setScheme(url.scheme());
108  this->setPath(url.path());
109  this->setQuery(url.query());
110  this->setFragment(url.fragment());
111  }
112 
113  QNetworkRequest CUrl::toNetworkRequest() const { return CNetworkUtils::getSwiftNetworkRequest(*this); }
114 
115  CUrl CUrl::withAppendedPath(const QString &path) const
116  {
117  if (path.isEmpty()) { return *this; }
118  CUrl url(*this);
119  url.appendPath(path);
120  return url;
121  }
122 
123  CUrl CUrl::withSwitchedScheme(const QString &scheme, int port) const
124  {
125  if (getPort() == port && getScheme() == scheme) { return *this; }
126  QUrl qurl(this->toQUrl());
127  qurl.setPort(port);
128  qurl.setScheme(scheme);
129  const CUrl url(qurl);
130  return url;
131  }
132 
133  bool CUrl::pathEndsWith(const QString &ending, Qt::CaseSensitivity cs) const { return m_path.endsWith(ending, cs); }
134 
135  bool CUrl::isFile() const
136  {
137  const QString f(this->getFileName());
138  return !f.isEmpty();
139  }
140 
141  bool CUrl::isFileWithSuffix(const QString &suffix) const
142  {
143  const QString f(this->getFileName());
144  if (suffix.isEmpty()) { return f.contains('.'); }
145  return f.endsWith(suffix, Qt::CaseInsensitive);
146  }
147 
149 
151 
152  QString CUrl::getFileSuffix() const
153  {
154  const QString f(this->getFileName());
155  const int i = f.lastIndexOf('.');
156  if (i < 0) return {};
157  if (f.length() <= i + 1) return {}; // ends with "."
158  return f.mid(i + 1); // suffix without dot
159  }
160 
162  {
163  const QString f(this->getFileName());
164  const int i = f.lastIndexOf('.');
165  if (i < 0) return {};
166  if (f.length() <= i + 1) return {}; // ends with "."
167  return f.mid(i); // suffix with dot
168  }
169 
171  {
172  static const QString h1(".html");
173  static const QString h2(".htm");
174  return this->isFileWithSuffix(h1) || this->isFileWithSuffix(h2);
175  }
176 
177  CUrl CUrl::withAppendedQuery(const QString &query) const
178  {
179  if (query.isEmpty()) { return *this; }
180  CUrl url(*this);
181  url.appendQuery(query);
182  return url;
183  }
184 
185  QString CUrl::convertToQString(bool i18n) const
186  {
187  Q_UNUSED(i18n);
188  return getFullUrl();
189  }
190 
191  QJsonObject CUrl::toJson() const
192  {
193  const QPair<QString, QJsonValue> v("url", getFullUrl());
194  const QJsonObject json({ v });
195  return json;
196  }
197 
198  void CUrl::convertFromJson(const QJsonObject &json)
199  {
200  const QJsonValue value = json.value("url");
201  if (value.isUndefined()) { throw CJsonException("Missing 'url'"); }
202  this->setFullUrl(value.toString());
203  }
204 
205  int CUrl::protocolToDefaultPort(const QString &protocol)
206  {
207  const QString p(protocol.trimmed().toLower());
208  if (p == "ftp") return 20;
209  if (p == "https") return 443;
210  if (p == "http") return 80;
211  return -1;
212  }
213 
214  bool CUrl::isDefaultPort(const QString &protocol, int port)
215  {
216  const int p = protocolToDefaultPort(protocol);
217  if (p < 0) { return false; }
218  return port == p;
219  }
220 
221  CUrl CUrl::fromLocalFile(const QString &localFile) { return QUrl::fromLocalFile(localFile); }
222 
223  QString CUrl::stripQueryString(const QString &query)
224  {
225  QString q(query.trimmed());
226  if (q.startsWith("?") || q.startsWith("&")) { q = q.mid(1); }
227  if (q.endsWith("?") || q.endsWith("&")) { q = q.left(q.size() - 1); }
228  return q;
229  }
230 
232  {
233  if (index.isMyself()) { return QVariant::fromValue(*this); }
234  const ColumnIndex i = index.frontCasted<ColumnIndex>();
235  switch (i)
236  {
237  case IndexHost: return QVariant::fromValue(m_host);
238  case IndexPort: return QVariant::fromValue(m_port);
239  case IndexScheme: return QVariant::fromValue(m_scheme);
240  case IndexPath: return QVariant::fromValue(m_path);
241  default: return CValueObject::propertyByIndex(index);
242  }
243  }
244 
245  void CUrl::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
246  {
247  if (index.isMyself())
248  {
249  (*this) = variant.value<CUrl>();
250  return;
251  }
252  const ColumnIndex i = index.frontCasted<ColumnIndex>();
253  switch (i)
254  {
255  case IndexHost: this->setHost(variant.value<QString>()); break;
256  case IndexPort: this->setPort(variant.value<qint32>()); break;
257  case IndexPath: this->setPath(variant.value<QString>()); break;
258  case IndexScheme: this->setScheme(variant.value<QString>()); break;
259  default: CValueObject::setPropertyByIndex(index, variant); break;
260  }
261  }
262 } // namespace swift::misc::network
static bool isExecutableFile(const QString &fileName)
Executable file (decided by appendix)
Definition: fileutils.cpp:543
static bool isSwiftInstaller(const QString &fileName)
swift installer
Definition: fileutils.cpp:552
static QString appendFilePaths(const QString &path1, const QString &path2)
Append file paths.
Definition: fileutils.cpp:95
Thrown when a convertFromJson method encounters an unrecoverable error in JSON data.
Definition: jsonexception.h:24
Non-owning reference to a CPropertyIndex with a subset of its features.
CastType frontCasted() const
First element casted to given type, usually the PropertIndex enum.
bool isMyself() const
Myself index, used with nesting.
ColumnIndex
Base class enums.
Definition: mixinindex.h:44
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: mixinindex.h:160
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: mixinindex.h:167
static QNetworkRequest getSwiftNetworkRequest(const QUrl &url, RequestType type=Get, const QString &userAgentDetails={})
Our tweaked network request with swift header.
Value object encapsulating information of a location, kind of simplified CValueObject compliant versi...
Definition: url.h:27
QString convertToQString(bool i18n=false) const
Cast as QString.
Definition: url.cpp:185
void setPropertyByIndex(swift::misc::CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: url.cpp:245
bool isSwiftInstaller() const
swift installer
Definition: url.cpp:150
CUrl withSwitchedScheme(const QString &protocol, int port) const
Switch protocol.
Definition: url.cpp:123
QString getFileSuffix() const
File appendix if any, otherwise empty, does not include the ".".
Definition: url.cpp:152
bool hasPath() const
Has path?
Definition: url.h:79
void setQUrl(const QUrl &url)
To QUrl.
Definition: url.cpp:103
QString getFileName() const
File name.
Definition: url.cpp:99
int getPort() const
Get port.
Definition: url.cpp:46
bool isFile() const
A path ends with "/", and file is anythingy beyond that, e.g. "path/file".
Definition: url.cpp:135
static int protocolToDefaultPort(const QString &protocol)
Protocol to default port.
Definition: url.cpp:205
bool hasScheme() const
Protocol.
Definition: url.h:67
QString appendPath(const QString &pathToAppend)
Append path.
Definition: url.cpp:38
QString getFileSuffixPlusDot() const
Suffix plus dot.
Definition: url.cpp:161
CUrl(const QString &fullUrl=QString())
Default constructor.
Definition: url.cpp:17
const QString & getScheme() const
Get protocl.
Definition: url.h:61
void setScheme(const QString &protocol)
Set protocol.
Definition: url.cpp:34
bool isEmpty() const
Empty.
Definition: url.cpp:54
void setQuery(const QString &query)
Set query.
Definition: url.cpp:58
CUrl withAppendedPath(const QString &path) const
Append path.
Definition: url.cpp:115
CUrl withAppendedQuery(const QString &query) const
Append path.
Definition: url.cpp:177
bool isHavingHtmlSuffix() const
Likely a HTM file?
Definition: url.cpp:170
bool isFileWithSuffix(const QString &suffix={}) const
Stricter version of isFile()
Definition: url.cpp:141
bool hasPort() const
Port?
Definition: url.cpp:52
bool hasQuery() const
Query string?
Definition: url.cpp:64
void appendQuery(const QString &queryToAppend)
Append query.
Definition: url.cpp:66
bool isExecutableFile() const
Executable file (decided by appendix)
Definition: url.cpp:148
void setHost(const QString &address)
Set address (e.g. myserver.foo.com)
Definition: url.h:58
void setPort(int port)
Set port.
Definition: url.h:85
QNetworkRequest toNetworkRequest() const
To request.
Definition: url.cpp:113
QJsonObject toJson() const
Cast to JSON object.
Definition: url.cpp:191
void setPath(const QString &path)
Set path.
Definition: url.cpp:36
QVariant propertyByIndex(swift::misc::CPropertyIndexRef index) const
Property by index.
Definition: url.cpp:231
const QString & getPath() const
Get path.
Definition: url.h:70
bool pathEndsWith(const QString &ending, Qt::CaseSensitivity cs=Qt::CaseInsensitive) const
Path ending with?
Definition: url.cpp:133
bool hasDefaultPort() const
Default port.
Definition: url.cpp:56
static bool isDefaultPort(const QString &protocol, int port)
Default port for given protocol.
Definition: url.cpp:214
static CUrl fromLocalFile(const QString &localFile)
From local file path.
Definition: url.cpp:221
void setFullUrl(const QString &fullUrl)
Set full URL.
Definition: url.cpp:97
QUrl toQUrl() const
To QUrl.
Definition: url.cpp:101
void convertFromJson(const QJsonObject &json)
Assign from JSON object.
Definition: url.cpp:198
void setFragment(const QString &fragment)
Set fragment.
Definition: url.cpp:82
bool hasFragment() const
Fragment string?
Definition: url.cpp:80
QString getFullUrl(bool withQuery=true) const
Qualified name.
Definition: url.cpp:84
#define SWIFT_DEFINE_VALUEOBJECT_MIXINS(Namespace, Class)
Explicit template definition of mixins for a CValueObject subclass.
Definition: valueobject.h:67